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/__support/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 |
52 | |