Skip to content

[libc] implement unistd/getentropy #122692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 15, 2025

Conversation

SchrodingerZhu
Copy link
Contributor

Implement GNU extension getentropy. This function is used by many programs to acquire entropy without handling the loop of getrandom.

@llvmbot
Copy link
Member

llvmbot commented Jan 13, 2025

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

Changes

Implement GNU extension getentropy. This function is used by many programs to acquire entropy without handling the loop of getrandom.


Full diff: https://github.com/llvm/llvm-project/pull/122692.diff

9 Files Affected:

  • (modified) libc/config/linux/aarch64/entrypoints.txt (+1)
  • (modified) libc/config/linux/x86_64/entrypoints.txt (+1)
  • (modified) libc/include/unistd.yaml (+7)
  • (modified) libc/src/unistd/CMakeLists.txt (+7)
  • (added) libc/src/unistd/getentropy.h (+19)
  • (modified) libc/src/unistd/linux/CMakeLists.txt (+14)
  • (added) libc/src/unistd/linux/getentropy.cpp (+48)
  • (modified) libc/test/src/unistd/CMakeLists.txt (+12)
  • (added) libc/test/src/unistd/getentropy_test.cpp (+33)
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));
+}

@SchrodingerZhu SchrodingerZhu requested a review from lntue January 14, 2025 05:10
Copy link

github-actions bot commented Jan 14, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@SchrodingerZhu SchrodingerZhu force-pushed the libc/src/unistd/getentropy branch from 6fb364f to a561bf1 Compare January 14, 2025 08:23
@SchrodingerZhu SchrodingerZhu force-pushed the libc/src/unistd/getentropy branch from a561bf1 to 68b6e3b Compare January 14, 2025 08:24
@SchrodingerZhu SchrodingerZhu merged commit defd0d9 into llvm:main Jan 15, 2025
11 checks passed
@SchrodingerZhu SchrodingerZhu deleted the libc/src/unistd/getentropy branch January 15, 2025 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants