[libc-commits] [libc] [libc] implement unistd/getentropy (PR #122692)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Jan 14 00:17:59 PST 2025


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/122692

>From 48a3a1c59cfa44ab9cf2dce78cb7b009fab04ff8 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Mon, 13 Jan 2025 11:30:59 +0000
Subject: [PATCH 1/5] [libc] implement unistd/getentropy

---
 libc/config/linux/aarch64/entrypoints.txt |  1 +
 libc/config/linux/x86_64/entrypoints.txt  |  1 +
 libc/include/unistd.yaml                  |  7 ++++
 libc/src/unistd/CMakeLists.txt            |  7 ++++
 libc/src/unistd/getentropy.h              | 19 +++++++++
 libc/src/unistd/linux/CMakeLists.txt      | 14 +++++++
 libc/src/unistd/linux/getentropy.cpp      | 48 +++++++++++++++++++++++
 libc/test/src/unistd/CMakeLists.txt       | 12 ++++++
 libc/test/src/unistd/getentropy_test.cpp  | 33 ++++++++++++++++
 9 files changed, 142 insertions(+)
 create mode 100644 libc/src/unistd/getentropy.h
 create mode 100644 libc/src/unistd/linux/getentropy.cpp
 create mode 100644 libc/test/src/unistd/getentropy_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index fc2b0e91c1286d..f5ba3414117682 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -322,6 +322,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.fsync
     libc.src.unistd.ftruncate
     libc.src.unistd.getcwd
+    libc.src.unistd.getentropy
     libc.src.unistd.geteuid
     libc.src.unistd.getpid
     libc.src.unistd.getppid
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e7b049c0a66388..10a1c9893cea16 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -321,6 +321,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.fsync
     libc.src.unistd.ftruncate
     libc.src.unistd.getcwd
+    libc.src.unistd.getentropy
     libc.src.unistd.geteuid
     libc.src.unistd.getpid
     libc.src.unistd.getppid
diff --git a/libc/include/unistd.yaml b/libc/include/unistd.yaml
index fada365e0103d0..c1901be446fe5c 100644
--- a/libc/include/unistd.yaml
+++ b/libc/include/unistd.yaml
@@ -128,6 +128,13 @@ functions:
     arguments:
       - type: char *
       - type: size_t
+  - name: getentropy
+    standards:
+      - GNUExtensions
+    return_type: int
+    arguments:
+      - type: void *
+      - type: size_t
   - name: geteuid
     standards:
       - POSIX
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 1a0b2e3293d03c..6bdea0c7693bd9 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -350,3 +350,10 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.threads.identifier
 )
+
+add_entrypoint_object(
+  getentropy
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.getentropy
+)
diff --git a/libc/src/unistd/getentropy.h b/libc/src/unistd/getentropy.h
new file mode 100644
index 00000000000000..27e13d2352d817
--- /dev/null
+++ b/libc/src/unistd/getentropy.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for getentropy ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/types/size_t.h"
+#include "src/__support/common.h"
+
+#ifndef LLVM_LIBC_SRC_UNISTD_GETENTROPY_H
+#define LLVM_LIBC_SRC_UNISTD_GETENTROPY_H
+
+namespace LIBC_NAMESPACE_DECL {
+int getentropy(void *buffer, size_t length);
+}
+
+#endif // LLVM_LIBC_SRC_UNISTD_GETENTROPY_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index ed360c73354ac4..39aa172e2a9b02 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -570,3 +570,17 @@ add_entrypoint_object(
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
+
+add_entrypoint_object(
+  getentropy
+  SRCS
+    getentropy.cpp
+  HDRS
+    ../getentropy.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.hdr.types.ssize_t
+    libc.hdr.errno_macros
+    libc.src.sys.random.getrandom
+    libc.src.errno.errno
+)
diff --git a/libc/src/unistd/linux/getentropy.cpp b/libc/src/unistd/linux/getentropy.cpp
new file mode 100644
index 00000000000000..adcd8ed7f16437
--- /dev/null
+++ b/libc/src/unistd/linux/getentropy.cpp
@@ -0,0 +1,48 @@
+//===-- Linux implementation of getentropy --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/getentropy.h"
+#include "hdr/errno_macros.h"
+#include "src/__support/common.h"
+#include "src/errno/libc_errno.h"
+#include "src/sys/random/getrandom.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(int, getentropy, (void *buffer, size_t length)) {
+  // check the length limit
+  if (length > 256) {
+    libc_errno = EIO;
+    return -1;
+  }
+
+  char *cursor = static_cast<char *>(buffer);
+  while (length != 0) {
+    // 0 flag means urandom and blocking, which meets the assumption of
+    // getentropy
+    ssize_t ret = LIBC_NAMESPACE::getrandom(cursor, length, 0);
+
+    // on success, advance the buffer pointer
+    if (ret != -1) {
+      length -= static_cast<size_t>(ret);
+      cursor += ret;
+      continue;
+    }
+
+    // on EINTR, try again
+    if (libc_errno == EINTR)
+      continue;
+
+    // on ENOSYS, forward errno and exit;
+    // otherwise, set EIO and exit
+    if (libc_errno != ENOSYS)
+      libc_errno = EIO;
+    return -1;
+  }
+  return 0;
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index e036e09cde702e..c3eebdf2a877d3 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -488,6 +488,18 @@ add_libc_test(
     libc.src.stdio.fflush
 )
 
+add_libc_test(
+  getentropy_test
+  SUITE
+    libc_unistd_unittests
+  SRCS
+    getentropy_test.cpp
+  DEPENDS
+    libc.src.unistd.getentropy
+    libc.src.errno.errno
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
+
 if(LLVM_LIBC_FULL_BUILD)
   add_libc_test(
     _exit_test
diff --git a/libc/test/src/unistd/getentropy_test.cpp b/libc/test/src/unistd/getentropy_test.cpp
new file mode 100644
index 00000000000000..b15cca176004da
--- /dev/null
+++ b/libc/test/src/unistd/getentropy_test.cpp
@@ -0,0 +1,33 @@
+//===-- Unittests for getentropy ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/errno/libc_errno.h"
+#include "src/unistd/getentropy.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+
+TEST(LlvmLibcUnistdGetEntropyTest, LengthTooLong) {
+  char buf[1024];
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 257), Fails(EIO));
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 1024), Fails(EIO));
+}
+
+TEST(LlvmLibcUnistdGetEntropyTest, SmokeTest) {
+  char buf[256];
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 256), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 0), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 1), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 16), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 17), Succeeds());
+}
+
+TEST(LlvmLibcUnistdGetEntropyTest, OtherError) {
+  ASSERT_THAT(LIBC_NAMESPACE::getentropy(nullptr, 1), Fails(EIO));
+}

>From 7dc7442e59b46b380e4d58b632f1c30ec6a15f68 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 14 Jan 2025 07:39:19 +0000
Subject: [PATCH 2/5] [libc] remove dependency from getentropy to getrandom

---
 libc/src/unistd/linux/CMakeLists.txt |  3 ++-
 libc/src/unistd/linux/getentropy.cpp | 15 +++++++++------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 39aa172e2a9b02..2bb17f56f7b32e 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -581,6 +581,7 @@ add_entrypoint_object(
     libc.hdr.types.size_t
     libc.hdr.types.ssize_t
     libc.hdr.errno_macros
-    libc.src.sys.random.getrandom
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
diff --git a/libc/src/unistd/linux/getentropy.cpp b/libc/src/unistd/linux/getentropy.cpp
index adcd8ed7f16437..976a5ef0fc7b45 100644
--- a/libc/src/unistd/linux/getentropy.cpp
+++ b/libc/src/unistd/linux/getentropy.cpp
@@ -10,7 +10,9 @@
 #include "hdr/errno_macros.h"
 #include "src/__support/common.h"
 #include "src/errno/libc_errno.h"
-#include "src/sys/random/getrandom.h"
+#include "src/__support/OSUtil/syscall.h"
+
+#include <sys/syscall.h> // For syscall numbers.
 
 namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(int, getentropy, (void *buffer, size_t length)) {
@@ -24,23 +26,24 @@ LLVM_LIBC_FUNCTION(int, getentropy, (void *buffer, size_t length)) {
   while (length != 0) {
     // 0 flag means urandom and blocking, which meets the assumption of
     // getentropy
-    ssize_t ret = LIBC_NAMESPACE::getrandom(cursor, length, 0);
+    auto ret = syscall_impl<long>(SYS_getrandom, cursor, length, 0);
 
     // on success, advance the buffer pointer
-    if (ret != -1) {
+    if (ret >= 0) {
       length -= static_cast<size_t>(ret);
       cursor += ret;
       continue;
     }
 
+    auto error = -static_cast<int>(ret);
+
     // on EINTR, try again
-    if (libc_errno == EINTR)
+    if (error == EINTR)
       continue;
 
     // on ENOSYS, forward errno and exit;
     // otherwise, set EIO and exit
-    if (libc_errno != ENOSYS)
-      libc_errno = EIO;
+    libc_errno = (error == ENOSYS) ? ENOSYS : EIO;
     return -1;
   }
   return 0;

>From bd915409fe16f683ffe15af8fd8bc6b5b61ffd89 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 14 Jan 2025 07:51:02 +0000
Subject: [PATCH 3/5] [libc] move unistd out of linux scope

---
 libc/src/CMakeLists.txt      | 2 +-
 libc/test/src/CMakeLists.txt | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 32308ba147940c..41183429f67a75 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -15,6 +15,7 @@ add_subdirectory(string)
 add_subdirectory(strings)
 add_subdirectory(wchar)
 add_subdirectory(time)
+add_subdirectory(unistd)
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(dirent)
@@ -23,7 +24,6 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(sched)
   add_subdirectory(sys)
   add_subdirectory(termios)
-  add_subdirectory(unistd)
 endif()
 
 if(NOT LLVM_LIBC_FULL_BUILD)
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 31008508d64928..22ec43588f7448 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -61,6 +61,7 @@ add_subdirectory(string)
 add_subdirectory(strings)
 add_subdirectory(wchar)
 add_subdirectory(time)
+add_subdirectory(unistd)
 
 # Depends on utilities in stdlib
 add_subdirectory(inttypes)
@@ -70,7 +71,6 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(sched)
   add_subdirectory(sys)
   add_subdirectory(termios)
-  add_subdirectory(unistd)
 endif()
 
 if(NOT LLVM_LIBC_FULL_BUILD)

>From cb858336311983be63f6fb3868e16fdf15576922 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 14 Jan 2025 07:54:11 +0000
Subject: [PATCH 4/5] format

---
 libc/src/unistd/linux/getentropy.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/unistd/linux/getentropy.cpp b/libc/src/unistd/linux/getentropy.cpp
index 976a5ef0fc7b45..168a1197734ed6 100644
--- a/libc/src/unistd/linux/getentropy.cpp
+++ b/libc/src/unistd/linux/getentropy.cpp
@@ -8,9 +8,9 @@
 
 #include "src/unistd/getentropy.h"
 #include "hdr/errno_macros.h"
+#include "src/__support/OSUtil/syscall.h"
 #include "src/__support/common.h"
 #include "src/errno/libc_errno.h"
-#include "src/__support/OSUtil/syscall.h"
 
 #include <sys/syscall.h> // For syscall numbers.
 

>From 6fb364f4e961fb406593fa197b0cf20589406289 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 14 Jan 2025 08:17:34 +0000
Subject: [PATCH 5/5] [libc] add windows implementation

---
 libc/src/unistd/windows/CMakeLists.txt | 11 +++++++
 libc/src/unistd/windows/getentropy.cpp | 42 ++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 libc/src/unistd/windows/CMakeLists.txt
 create mode 100644 libc/src/unistd/windows/getentropy.cpp

diff --git a/libc/src/unistd/windows/CMakeLists.txt b/libc/src/unistd/windows/CMakeLists.txt
new file mode 100644
index 00000000000000..195d98cdb51d4c
--- /dev/null
+++ b/libc/src/unistd/windows/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_entrypoint_object(
+  getentropy
+  SRCS
+    getentropy.cpp
+  HDRS
+    ../getentropy.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.hdr.errno_macros
+    libc.src.errno.errno
+)
diff --git a/libc/src/unistd/windows/getentropy.cpp b/libc/src/unistd/windows/getentropy.cpp
new file mode 100644
index 00000000000000..bfaec723ac63d1
--- /dev/null
+++ b/libc/src/unistd/windows/getentropy.cpp
@@ -0,0 +1,42 @@
+//===-- Windows implementation of getentropy ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/getentropy.h"
+#include "hdr/errno_macros.h"
+#include "src/__support/common.h"
+#include "src/errno/libc_errno.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <bcrypt.h>
+#include <ntstatus.h>
+#pragma comment(lib, "bcrypt.lib")
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, getentropy, (void *buffer, size_t length)) {
+  __try {
+    // check the length limit
+    if (length > 256)
+      __leave;
+
+    NTSTATUS result = ::BCryptGenRandom(nullptr, static_cast<PUCHAR>(buffer),
+                                        static_cast<ULONG>(length),
+                                        BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+
+    if (result == STATUS_SUCCESS)
+      return 0;
+
+  } __except (EXCEPTION_EXECUTE_HANDLER) {
+    // no need to handle exceptions specially
+  }
+
+  libc_errno = EIO;
+  return -1;
+}
+} // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list