[libc] implement unistd/getentropy (#122692)
Implement GNU extension getentropy. This function is used by many programs to acquire entropy without handling the loop of getrandom.
This commit is contained in:
committed by
GitHub
parent
2a044f8a09
commit
defd0d966d
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -101,6 +101,9 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
# time.h entrypoints
|
||||
libc.src.time.time
|
||||
libc.src.time.clock_getres
|
||||
|
||||
# unistd.h entrypoints
|
||||
libc.src.unistd.getentropy
|
||||
)
|
||||
|
||||
set(TARGET_LIBM_ENTRYPOINTS
|
||||
|
||||
@@ -6,4 +6,5 @@ set(TARGET_PUBLIC_HEADERS
|
||||
libc.include.errno
|
||||
libc.include.fenv
|
||||
libc.include.math
|
||||
libc.include.unistd
|
||||
)
|
||||
|
||||
@@ -15,3 +15,10 @@ functions:
|
||||
- type: void *
|
||||
- type: size_t
|
||||
- type: unsigned int
|
||||
- name: getentropy
|
||||
standards:
|
||||
- GNUExtensions
|
||||
return_type: int
|
||||
arguments:
|
||||
- type: void *
|
||||
- type: size_t
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -350,3 +350,10 @@ add_entrypoint_object(
|
||||
DEPENDS
|
||||
libc.src.__support.threads.identifier
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
getentropy
|
||||
ALIAS
|
||||
DEPENDS
|
||||
.${LIBC_TARGET_OS}.getentropy
|
||||
)
|
||||
|
||||
19
libc/src/unistd/getentropy.h
Normal file
19
libc/src/unistd/getentropy.h
Normal file
@@ -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
|
||||
@@ -570,3 +570,18 @@ 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.include.sys_syscall
|
||||
libc.src.__support.OSUtil.osutil
|
||||
libc.src.errno.errno
|
||||
)
|
||||
|
||||
51
libc/src/unistd/linux/getentropy.cpp
Normal file
51
libc/src/unistd/linux/getentropy.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//===-- 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/OSUtil/syscall.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/errno/libc_errno.h"
|
||||
|
||||
#include <sys/syscall.h> // For syscall numbers.
|
||||
|
||||
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
|
||||
auto ret = syscall_impl<long>(SYS_getrandom, cursor, length, 0);
|
||||
|
||||
// on success, advance the buffer pointer
|
||||
if (ret >= 0) {
|
||||
length -= static_cast<size_t>(ret);
|
||||
cursor += ret;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto error = -static_cast<int>(ret);
|
||||
|
||||
// on EINTR, try again
|
||||
if (error == EINTR)
|
||||
continue;
|
||||
|
||||
// on ENOSYS, forward errno and exit;
|
||||
// otherwise, set EIO and exit
|
||||
libc_errno = (error == ENOSYS) ? ENOSYS : EIO;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
11
libc/src/unistd/windows/CMakeLists.txt
Normal file
11
libc/src/unistd/windows/CMakeLists.txt
Normal file
@@ -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
|
||||
)
|
||||
42
libc/src/unistd/windows/getentropy.cpp
Normal file
42
libc/src/unistd/windows/getentropy.cpp
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
28
libc/test/src/unistd/getentropy_test.cpp
Normal file
28
libc/test/src/unistd/getentropy_test.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
//===-- 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 "hdr/errno_macros.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));
|
||||
}
|
||||
|
||||
TEST(LlvmLibcUnistdGetEntropyTest, SmokeTest) {
|
||||
char buf[256];
|
||||
ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 256), Succeeds());
|
||||
}
|
||||
|
||||
TEST(LlvmLibcUnistdGetEntropyTest, OtherError) {
|
||||
ASSERT_THAT(LIBC_NAMESPACE::getentropy(nullptr, 1), Fails(EIO));
|
||||
}
|
||||
Reference in New Issue
Block a user