Skip to content

Conversation

SchrodingerZhu
Copy link
Contributor

@SchrodingerZhu SchrodingerZhu commented Dec 10, 2024

This PR implements the getrandom emulation using BCryptGenRandom.

@llvmbot
Copy link
Member

llvmbot commented Dec 10, 2024

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

Changes

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

16 Files Affected:

  • (modified) libc/config/windows/entrypoints.txt (+3)
  • (modified) libc/config/windows/headers.txt (+1)
  • (modified) libc/hdr/CMakeLists.txt (+9)
  • (added) libc/hdr/sys_random_macros.h (+22)
  • (modified) libc/hdr/types/CMakeLists.txt (+8)
  • (modified) libc/hdr/types/ssize_t.h (+2-1)
  • (modified) libc/include/llvm-libc-types/ssize_t.h (+6)
  • (modified) libc/src/CMakeLists.txt (+1-1)
  • (modified) libc/src/sys/random/getrandom.h (+2-1)
  • (modified) libc/src/sys/random/linux/CMakeLists.txt (+2-2)
  • (added) libc/src/sys/random/windows/CMakeLists.txt (+14)
  • (added) libc/src/sys/random/windows/getrandom.cpp (+67)
  • (modified) libc/test/src/CMakeLists.txt (+1-1)
  • (modified) libc/test/src/sys/random/CMakeLists.txt (+15-3)
  • (renamed) libc/test/src/sys/random/getrandom_test.cpp (+2)
  • (removed) libc/test/src/sys/random/linux/CMakeLists.txt (-15)
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 4ecc3ada9c7682..e615c5fc284f82 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -101,6 +101,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # time.h entrypoints
     libc.src.time.time
     libc.src.time.clock_getres
+
+    # sys/random.h entrypoints
+    libc.src.sys.random.getrandom
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/windows/headers.txt b/libc/config/windows/headers.txt
index bccc04f7697e56..8670dede45df26 100644
--- a/libc/config/windows/headers.txt
+++ b/libc/config/windows/headers.txt
@@ -6,4 +6,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.errno
     libc.include.fenv
     libc.include.math
+    libc.include.sys_random
 )
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 5eb311f4bb2298..f2396575b06d58 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -189,6 +189,15 @@ add_proxy_header_library(
     libc.include.sys_auxv
 )
 
+add_proxy_header_library(
+  sys_random_macros
+  HDRS
+    sys_random_macros.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-macros.sys_random_macros
+    libc.include.sys_random
+)
+
 add_header_library(wchar_overlay HDRS wchar_overlay.h)
 
 add_proxy_header_library(
diff --git a/libc/hdr/sys_random_macros.h b/libc/hdr/sys_random_macros.h
new file mode 100644
index 00000000000000..3c1fce2ca5cc42
--- /dev/null
+++ b/libc/hdr/sys_random_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from sys/auxv.h ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_SYS_RANDOM_MACROS_H
+#define LLVM_LIBC_HDR_SYS_RANDOM_MACROS_H
+
+#if defined(LIBC_FULL_BUILD) || defined(_WIN32)
+
+#include "include/llvm-libc-macros/sys-random-macros.h"
+
+#else // Overlay mode
+
+#include <sys/random.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_RANDOM_MACROS_H
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 68a0e9603f9752..fcc1776f1e7eda 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -93,6 +93,14 @@ add_proxy_header_library(
     libc.include.llvm-libc-types.size_t
 )
 
+add_proxy_header_library(
+  ssize_t
+  HDRS
+    ssize_t.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-types.ssize_t
+)
+
 add_proxy_header_library(
   mode_t
   HDRS
diff --git a/libc/hdr/types/ssize_t.h b/libc/hdr/types/ssize_t.h
index 4d2000780ee11f..9ebc822434b914 100644
--- a/libc/hdr/types/ssize_t.h
+++ b/libc/hdr/types/ssize_t.h
@@ -8,7 +8,8 @@
 #ifndef LLVM_LIBC_HDR_TYPES_SSIZE_T_H
 #define LLVM_LIBC_HDR_TYPES_SSIZE_T_H
 
-#ifdef LIBC_FULL_BUILD
+// stddef does not provide ssize_t on windows.
+#if defined(LIBC_FULL_BUILD) || defined(_WIN32)
 
 #include "include/llvm-libc-types/ssize_t.h"
 
diff --git a/libc/include/llvm-libc-types/ssize_t.h b/libc/include/llvm-libc-types/ssize_t.h
index 41e4b6d2c500ad..5f2f325753166f 100644
--- a/libc/include/llvm-libc-types/ssize_t.h
+++ b/libc/include/llvm-libc-types/ssize_t.h
@@ -9,6 +9,12 @@
 #ifndef LLVM_LIBC_TYPES_SSIZE_T_H
 #define LLVM_LIBC_TYPES_SSIZE_T_H
 
+// https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
+#if __has_include(<BaseTsd.h>)
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#else
 typedef __INT64_TYPE__ ssize_t;
+#endif
 
 #endif // LLVM_LIBC_TYPES_SSIZE_T_H
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 9fc331ad18a391..e6ac299f7346e5 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -16,7 +16,7 @@ add_subdirectory(strings)
 add_subdirectory(wchar)
 add_subdirectory(time)
 
-if(${LIBC_TARGET_OS} STREQUAL "linux")
+if(${LIBC_TARGET_OS} STREQUAL "linux" OR ${LIBC_TARGET_OS} STREQUAL "windows")
   add_subdirectory(dirent)
   add_subdirectory(fcntl)
   add_subdirectory(pthread)
diff --git a/libc/src/sys/random/getrandom.h b/libc/src/sys/random/getrandom.h
index 134bd0cd9468d8..376ec389e582fb 100644
--- a/libc/src/sys/random/getrandom.h
+++ b/libc/src/sys/random/getrandom.h
@@ -9,8 +9,9 @@
 #ifndef LLVM_LIBC_SRC_SYS_RANDOM_GETRANDOM_H
 #define LLVM_LIBC_SRC_SYS_RANDOM_GETRANDOM_H
 
+#include "hdr/sys_random_macros.h"
+#include "hdr/types/ssize_t.h"
 #include "src/__support/macros/config.h"
-#include <sys/random.h>
 
 namespace LIBC_NAMESPACE_DECL {
 
diff --git a/libc/src/sys/random/linux/CMakeLists.txt b/libc/src/sys/random/linux/CMakeLists.txt
index 474e275ee597a8..dc6506adfc5cd1 100644
--- a/libc/src/sys/random/linux/CMakeLists.txt
+++ b/libc/src/sys/random/linux/CMakeLists.txt
@@ -5,8 +5,8 @@ add_entrypoint_object(
   HDRS
     ../getrandom.h
   DEPENDS
-    libc.include.sys_random
-    libc.include.sys_syscall
+    libc.hdr.sys_random_macros
+    libc.hdr.types.ssize_t
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
diff --git a/libc/src/sys/random/windows/CMakeLists.txt b/libc/src/sys/random/windows/CMakeLists.txt
new file mode 100644
index 00000000000000..948b343bb69e88
--- /dev/null
+++ b/libc/src/sys/random/windows/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_entrypoint_object(
+  getrandom
+  SRCS
+    getrandom.cpp
+  HDRS
+    ../getrandom.h
+  DEPENDS
+    # Maybe we should include the following 
+    # but we don't really care the flags on Windows
+    # libc.hdr.sys_random_macros
+    libc.hdr.types.ssize_t
+    libc.src.errno.errno
+    libc.src.__support.CPP.limits
+)
diff --git a/libc/src/sys/random/windows/getrandom.cpp b/libc/src/sys/random/windows/getrandom.cpp
new file mode 100644
index 00000000000000..af5cc2e05edc99
--- /dev/null
+++ b/libc/src/sys/random/windows/getrandom.cpp
@@ -0,0 +1,67 @@
+//===-- Windows implementation of getrandom -------------------------------===//
+//
+// 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/sys/random/getrandom.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/errno/libc_errno.h"
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#include <bcrypt.h>
+#include <ntstatus.h>
+#pragma comment(lib, "bcrypt.lib")
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(ssize_t, getrandom,
+                   (void *buf, size_t buflen,
+                    [[maybe_unused]] unsigned int flags)) {
+  // https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
+  // BCRYPT_USE_SYSTEM_PREFERRED_RNG
+  // Use the system-preferred random number generator algorithm. The hAlgorithm
+  // parameter must be NULL.
+
+  // flags are ignored as Windows does not distinguish between urandom/random.
+  // size_t is larger than ULONG. Linux API allows getrandom to return fewer
+  // bytes than required. Hence, we trancate the size_t to ULONG. If user really
+  // needs huge amount of bytes (which is highly unlikely), they can call
+  // getrandom multiple times in a loop. This is also the common pattern in
+  // Linux.
+
+  // https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces
+  // A 64-bit process on 64-bit Windows has a virtual address space within the
+  // 128-terabyte range 0x000'00000000 through 0x7FFF'FFFFFFFF.
+  if (buf == nullptr || cpp::bit_cast<INT_PTR>(buf) < 0) {
+    libc_errno = EFAULT;
+    return -1;
+  }
+
+  constexpr size_t PARAM_LIMIT =
+      static_cast<size_t>(cpp::numeric_limits<ULONG>::max());
+  constexpr size_t RETURN_LIMIT =
+      static_cast<size_t>(cpp::numeric_limits<ssize_t>::max());
+  buflen = buflen > PARAM_LIMIT ? PARAM_LIMIT : buflen;
+  buflen = buflen > RETURN_LIMIT ? RETURN_LIMIT : buflen;
+  NTSTATUS result = ::BCryptGenRandom(nullptr, static_cast<PUCHAR>(buf),
+                                      static_cast<ULONG>(buflen),
+                                      BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+
+  // not possible to overflow as we have truncated the limit.
+  if (LIBC_LIKELY(result == STATUS_SUCCESS))
+    return static_cast<ssize_t>(buflen);
+
+  libc_errno = EINVAL;
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 31008508d64928..ee393ed76969a3 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -65,7 +65,7 @@ add_subdirectory(time)
 # Depends on utilities in stdlib
 add_subdirectory(inttypes)
 
-if(${LIBC_TARGET_OS} STREQUAL "linux")
+if(${LIBC_TARGET_OS} STREQUAL "linux" OR ${LIBC_TARGET_OS} STREQUAL "windows")
   add_subdirectory(fcntl)
   add_subdirectory(sched)
   add_subdirectory(sys)
diff --git a/libc/test/src/sys/random/CMakeLists.txt b/libc/test/src/sys/random/CMakeLists.txt
index b4bbe81c92ff2e..c7146c2d478622 100644
--- a/libc/test/src/sys/random/CMakeLists.txt
+++ b/libc/test/src/sys/random/CMakeLists.txt
@@ -1,3 +1,15 @@
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
-  add_subdirectory(${LIBC_TARGET_OS})
-endif()
+add_custom_target(libc_sys_random_unittests)
+
+add_libc_unittest(
+  getrandom_test
+  SUITE
+    libc_sys_random_unittests
+  SRCS
+    getrandom_test.cpp
+  DEPENDS
+    libc.hdr.sys_random_macros
+    libc.src.errno.errno
+    libc.src.math.fabs
+    libc.src.sys.random.getrandom
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/sys/random/linux/getrandom_test.cpp b/libc/test/src/sys/random/getrandom_test.cpp
similarity index 98%
rename from libc/test/src/sys/random/linux/getrandom_test.cpp
rename to libc/test/src/sys/random/getrandom_test.cpp
index e3481b73ca0027..10d0577d05c62e 100644
--- a/libc/test/src/sys/random/linux/getrandom_test.cpp
+++ b/libc/test/src/sys/random/getrandom_test.cpp
@@ -13,12 +13,14 @@
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
+#ifndef _WIN32
 TEST(LlvmLibcGetRandomTest, InvalidFlag) {
   LIBC_NAMESPACE::cpp::array<char, 10> buffer;
   LIBC_NAMESPACE::libc_errno = 0;
   ASSERT_THAT(LIBC_NAMESPACE::getrandom(buffer.data(), buffer.size(), -1),
               LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails(EINVAL));
 }
+#endif
 
 TEST(LlvmLibcGetRandomTest, InvalidBuffer) {
   LIBC_NAMESPACE::libc_errno = 0;
diff --git a/libc/test/src/sys/random/linux/CMakeLists.txt b/libc/test/src/sys/random/linux/CMakeLists.txt
deleted file mode 100644
index 737326cb158ce5..00000000000000
--- a/libc/test/src/sys/random/linux/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-add_custom_target(libc_sys_random_unittests)
-
-add_libc_unittest(
-  getrandom_test
-  SUITE
-    libc_sys_random_unittests
-  SRCS
-    getrandom_test.cpp
-  DEPENDS
-    libc.include.sys_random
-    libc.src.errno.errno
-    libc.src.math.fabs
-    libc.src.sys.random.getrandom
-    libc.test.UnitTest.ErrnoSetterMatcher
-)

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? getrandom is a linux specific function.

Comment on lines +96 to +103
add_proxy_header_library(
ssize_t
HDRS
ssize_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.ssize_t
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is important, but should probably be in a separate patch.

#define LLVM_LIBC_TYPES_SSIZE_T_H

// https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
#if __has_include(<BaseTsd.h>)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__has_include isn't the appropriate way to check if this is a windows target. I'd recommend doing #ifdef WIN32 instead.

@SchrodingerZhu
Copy link
Contributor Author

SchrodingerZhu commented Dec 10, 2024

Good point. I made this as there are other parts of code that assumes getrandom on default. Maybe I should chane them instead. Closing this now. I will separate out the ssize_t changes.

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.

3 participants