Skip to content

Commit defd0d9

Browse files
[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.
1 parent 2a044f8 commit defd0d9

File tree

16 files changed

+207
-2
lines changed

16 files changed

+207
-2
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ set(TARGET_LIBC_ENTRYPOINTS
322322
libc.src.unistd.fsync
323323
libc.src.unistd.ftruncate
324324
libc.src.unistd.getcwd
325+
libc.src.unistd.getentropy
325326
libc.src.unistd.geteuid
326327
libc.src.unistd.getpid
327328
libc.src.unistd.getppid

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ set(TARGET_LIBC_ENTRYPOINTS
321321
libc.src.unistd.fsync
322322
libc.src.unistd.ftruncate
323323
libc.src.unistd.getcwd
324+
libc.src.unistd.getentropy
324325
libc.src.unistd.geteuid
325326
libc.src.unistd.getpid
326327
libc.src.unistd.getppid

libc/config/windows/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ set(TARGET_LIBC_ENTRYPOINTS
101101
# time.h entrypoints
102102
libc.src.time.time
103103
libc.src.time.clock_getres
104+
105+
# unistd.h entrypoints
106+
libc.src.unistd.getentropy
104107
)
105108

106109
set(TARGET_LIBM_ENTRYPOINTS

libc/config/windows/headers.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ set(TARGET_PUBLIC_HEADERS
66
libc.include.errno
77
libc.include.fenv
88
libc.include.math
9+
libc.include.unistd
910
)

libc/include/sys/random.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ functions:
1515
- type: void *
1616
- type: size_t
1717
- type: unsigned int
18+
- name: getentropy
19+
standards:
20+
- GNUExtensions
21+
return_type: int
22+
arguments:
23+
- type: void *
24+
- type: size_t

libc/include/unistd.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ functions:
128128
arguments:
129129
- type: char *
130130
- type: size_t
131+
- name: getentropy
132+
standards:
133+
- GNUExtensions
134+
return_type: int
135+
arguments:
136+
- type: void *
137+
- type: size_t
131138
- name: geteuid
132139
standards:
133140
- POSIX

libc/src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_subdirectory(string)
1515
add_subdirectory(strings)
1616
add_subdirectory(wchar)
1717
add_subdirectory(time)
18+
add_subdirectory(unistd)
1819

1920
if(${LIBC_TARGET_OS} STREQUAL "linux")
2021
add_subdirectory(dirent)
@@ -23,7 +24,6 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
2324
add_subdirectory(sched)
2425
add_subdirectory(sys)
2526
add_subdirectory(termios)
26-
add_subdirectory(unistd)
2727
endif()
2828

2929
if(NOT LLVM_LIBC_FULL_BUILD)

libc/src/unistd/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,10 @@ add_entrypoint_object(
350350
DEPENDS
351351
libc.src.__support.threads.identifier
352352
)
353+
354+
add_entrypoint_object(
355+
getentropy
356+
ALIAS
357+
DEPENDS
358+
.${LIBC_TARGET_OS}.getentropy
359+
)

libc/src/unistd/getentropy.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation header for getentropy ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/types/size_t.h"
10+
#include "src/__support/common.h"
11+
12+
#ifndef LLVM_LIBC_SRC_UNISTD_GETENTROPY_H
13+
#define LLVM_LIBC_SRC_UNISTD_GETENTROPY_H
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
int getentropy(void *buffer, size_t length);
17+
}
18+
19+
#endif // LLVM_LIBC_SRC_UNISTD_GETENTROPY_H

libc/src/unistd/linux/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,3 +570,18 @@ add_entrypoint_object(
570570
libc.src.__support.OSUtil.osutil
571571
libc.src.errno.errno
572572
)
573+
574+
add_entrypoint_object(
575+
getentropy
576+
SRCS
577+
getentropy.cpp
578+
HDRS
579+
../getentropy.h
580+
DEPENDS
581+
libc.hdr.types.size_t
582+
libc.hdr.types.ssize_t
583+
libc.hdr.errno_macros
584+
libc.include.sys_syscall
585+
libc.src.__support.OSUtil.osutil
586+
libc.src.errno.errno
587+
)

libc/src/unistd/linux/getentropy.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===-- Linux implementation of getentropy --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/unistd/getentropy.h"
10+
#include "hdr/errno_macros.h"
11+
#include "src/__support/OSUtil/syscall.h"
12+
#include "src/__support/common.h"
13+
#include "src/errno/libc_errno.h"
14+
15+
#include <sys/syscall.h> // For syscall numbers.
16+
17+
namespace LIBC_NAMESPACE_DECL {
18+
LLVM_LIBC_FUNCTION(int, getentropy, (void *buffer, size_t length)) {
19+
// check the length limit
20+
if (length > 256) {
21+
libc_errno = EIO;
22+
return -1;
23+
}
24+
25+
char *cursor = static_cast<char *>(buffer);
26+
while (length != 0) {
27+
// 0 flag means urandom and blocking, which meets the assumption of
28+
// getentropy
29+
auto ret = syscall_impl<long>(SYS_getrandom, cursor, length, 0);
30+
31+
// on success, advance the buffer pointer
32+
if (ret >= 0) {
33+
length -= static_cast<size_t>(ret);
34+
cursor += ret;
35+
continue;
36+
}
37+
38+
auto error = -static_cast<int>(ret);
39+
40+
// on EINTR, try again
41+
if (error == EINTR)
42+
continue;
43+
44+
// on ENOSYS, forward errno and exit;
45+
// otherwise, set EIO and exit
46+
libc_errno = (error == ENOSYS) ? ENOSYS : EIO;
47+
return -1;
48+
}
49+
return 0;
50+
}
51+
} // namespace LIBC_NAMESPACE_DECL
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
add_entrypoint_object(
2+
getentropy
3+
SRCS
4+
getentropy.cpp
5+
HDRS
6+
../getentropy.h
7+
DEPENDS
8+
libc.hdr.types.size_t
9+
libc.hdr.errno_macros
10+
libc.src.errno.errno
11+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- Windows implementation of getentropy ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/unistd/getentropy.h"
10+
#include "hdr/errno_macros.h"
11+
#include "src/__support/common.h"
12+
#include "src/errno/libc_errno.h"
13+
14+
#define WIN32_LEAN_AND_MEAN
15+
#include <Windows.h>
16+
#include <bcrypt.h>
17+
#include <ntstatus.h>
18+
#pragma comment(lib, "bcrypt.lib")
19+
20+
namespace LIBC_NAMESPACE_DECL {
21+
22+
LLVM_LIBC_FUNCTION(int, getentropy, (void *buffer, size_t length)) {
23+
__try {
24+
// check the length limit
25+
if (length > 256)
26+
__leave;
27+
28+
NTSTATUS result = ::BCryptGenRandom(nullptr, static_cast<PUCHAR>(buffer),
29+
static_cast<ULONG>(length),
30+
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
31+
32+
if (result == STATUS_SUCCESS)
33+
return 0;
34+
35+
} __except (EXCEPTION_EXECUTE_HANDLER) {
36+
// no need to handle exceptions specially
37+
}
38+
39+
libc_errno = EIO;
40+
return -1;
41+
}
42+
} // namespace LIBC_NAMESPACE_DECL

libc/test/src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ add_subdirectory(string)
6161
add_subdirectory(strings)
6262
add_subdirectory(wchar)
6363
add_subdirectory(time)
64+
add_subdirectory(unistd)
6465

6566
# Depends on utilities in stdlib
6667
add_subdirectory(inttypes)
@@ -70,7 +71,6 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
7071
add_subdirectory(sched)
7172
add_subdirectory(sys)
7273
add_subdirectory(termios)
73-
add_subdirectory(unistd)
7474
endif()
7575

7676
if(NOT LLVM_LIBC_FULL_BUILD)

libc/test/src/unistd/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,18 @@ add_libc_test(
488488
libc.src.stdio.fflush
489489
)
490490

491+
add_libc_test(
492+
getentropy_test
493+
SUITE
494+
libc_unistd_unittests
495+
SRCS
496+
getentropy_test.cpp
497+
DEPENDS
498+
libc.src.unistd.getentropy
499+
libc.src.errno.errno
500+
libc.test.UnitTest.ErrnoSetterMatcher
501+
)
502+
491503
if(LLVM_LIBC_FULL_BUILD)
492504
add_libc_test(
493505
_exit_test
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- Unittests for getentropy ------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/errno_macros.h"
10+
#include "src/unistd/getentropy.h"
11+
#include "test/UnitTest/ErrnoSetterMatcher.h"
12+
#include "test/UnitTest/Test.h"
13+
14+
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
15+
16+
TEST(LlvmLibcUnistdGetEntropyTest, LengthTooLong) {
17+
char buf[1024];
18+
ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 257), Fails(EIO));
19+
}
20+
21+
TEST(LlvmLibcUnistdGetEntropyTest, SmokeTest) {
22+
char buf[256];
23+
ASSERT_THAT(LIBC_NAMESPACE::getentropy(buf, 256), Succeeds());
24+
}
25+
26+
TEST(LlvmLibcUnistdGetEntropyTest, OtherError) {
27+
ASSERT_THAT(LIBC_NAMESPACE::getentropy(nullptr, 1), Fails(EIO));
28+
}

0 commit comments

Comments
 (0)