From 12ad95e64caffc6b2172033878562a40f5e5c955 Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 10 Dec 2024 11:24:00 -0800 Subject: [PATCH] [libc] implement getrandom for windows --- libc/config/windows/entrypoints.txt | 3 + libc/config/windows/headers.txt | 1 + libc/hdr/CMakeLists.txt | 9 +++ libc/hdr/sys_random_macros.h | 22 ++++++ libc/hdr/types/CMakeLists.txt | 8 +++ libc/hdr/types/ssize_t.h | 3 +- libc/include/llvm-libc-types/ssize_t.h | 6 ++ libc/src/CMakeLists.txt | 2 +- libc/src/sys/random/getrandom.h | 3 +- libc/src/sys/random/linux/CMakeLists.txt | 4 +- libc/src/sys/random/windows/CMakeLists.txt | 14 ++++ libc/src/sys/random/windows/getrandom.cpp | 67 +++++++++++++++++++ libc/test/src/CMakeLists.txt | 2 +- libc/test/src/sys/random/CMakeLists.txt | 18 ++++- .../sys/random/{linux => }/getrandom_test.cpp | 2 + libc/test/src/sys/random/linux/CMakeLists.txt | 15 ----- 16 files changed, 155 insertions(+), 24 deletions(-) create mode 100644 libc/hdr/sys_random_macros.h create mode 100644 libc/src/sys/random/windows/CMakeLists.txt create mode 100644 libc/src/sys/random/windows/getrandom.cpp rename libc/test/src/sys/random/{linux => }/getrandom_test.cpp (98%) delete mode 100644 libc/test/src/sys/random/linux/CMakeLists.txt diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index 4ecc3ada9c768..e615c5fc284f8 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 bccc04f7697e5..8670dede45df2 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 5eb311f4bb229..f2396575b06d5 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 0000000000000..3c1fce2ca5cc4 --- /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 + +#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 68a0e9603f975..fcc1776f1e7ed 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 4d2000780ee11..9ebc822434b91 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 41e4b6d2c500a..5f2f325753166 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() +#include +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 9fc331ad18a39..e6ac299f7346e 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 134bd0cd9468d..376ec389e582f 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 namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/random/linux/CMakeLists.txt b/libc/src/sys/random/linux/CMakeLists.txt index 474e275ee597a..dc6506adfc5cd 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 0000000000000..948b343bb69e8 --- /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 0000000000000..af5cc2e05edc9 --- /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 +#include +#include +#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(buf) < 0) { + libc_errno = EFAULT; + return -1; + } + + constexpr size_t PARAM_LIMIT = + static_cast(cpp::numeric_limits::max()); + constexpr size_t RETURN_LIMIT = + static_cast(cpp::numeric_limits::max()); + buflen = buflen > PARAM_LIMIT ? PARAM_LIMIT : buflen; + buflen = buflen > RETURN_LIMIT ? RETURN_LIMIT : buflen; + NTSTATUS result = ::BCryptGenRandom(nullptr, static_cast(buf), + static_cast(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(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 31008508d6492..ee393ed76969a 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 b4bbe81c92ff2..c7146c2d47862 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 e3481b73ca002..10d0577d05c62 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 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 737326cb158ce..0000000000000 --- 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 -)