Skip to content

Commit d132926

Browse files
authored
Merge pull request #36 from dsprenkels/pr_30
Refactor PR #30 and add tests
2 parents 588372e + 74f9820 commit d132926

File tree

3 files changed

+82
-17
lines changed

3 files changed

+82
-17
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CFLAGS ?= -g -O2 -std=gnu99 \
33
-Wformat-security -Werror=format-security -Wstrict-prototypes \
44
-D_FORTIFY_SOURCE=2 -fPIC -fno-strict-overflow
55

6-
TEST_WRAPS := -Wl,-wrap=ioctl,-wrap=syscall
6+
TEST_WRAPS := -Wl,-wrap=ioctl,-wrap=getrandom,-wrap=syscall
77

88
ifeq ($(shell uname -o), GNU/Linux)
99
TEST_LDFLAGS := $(TEST_WRAPS)

randombytes.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
# include <stdint.h>
3434
# include <stdio.h>
3535
# include <sys/ioctl.h>
36+
# if defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24))
37+
# define USE_GLIBC
38+
# include <sys/random.h>
39+
# endif /* defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24)) */
3640
# include <sys/stat.h>
3741
# include <sys/syscall.h>
3842
# include <sys/types.h>
@@ -89,7 +93,15 @@ static int randombytes_wasi_randombytes(void *buf, size_t n) {
8993
}
9094
#endif /* defined(__wasi__) */
9195

92-
#if defined(__linux__) && defined(SYS_getrandom)
96+
#if defined(__linux__) && (defined(USE_GLIBC) || defined(SYS_getrandom))
97+
# if defined(USE_GLIBC)
98+
// getrandom is declared in glibc.
99+
# elif defined(SYS_getrandom)
100+
static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
101+
return syscall(SYS_getrandom, buf, buflen, flags);
102+
}
103+
# endif
104+
93105
static int randombytes_linux_randombytes_getrandom(void *buf, size_t n)
94106
{
95107
/* I have thought about using a separate PRF, seeded by getrandom, but
@@ -102,7 +114,7 @@ static int randombytes_linux_randombytes_getrandom(void *buf, size_t n)
102114
/* getrandom does not allow chunks larger than 33554431 */
103115
chunk = n <= 33554431 ? n : 33554431;
104116
do {
105-
ret = syscall(SYS_getrandom, (char *)buf + offset, chunk, 0);
117+
ret = getrandom((char *)buf + offset, chunk, 0);
106118
} while (ret == -1 && errno == EINTR);
107119
if (ret < 0) return ret;
108120
offset += ret;
@@ -111,7 +123,7 @@ static int randombytes_linux_randombytes_getrandom(void *buf, size_t n)
111123
assert(n == 0);
112124
return 0;
113125
}
114-
#endif /* defined(__linux__) && defined(SYS_getrandom) */
126+
#endif // defined(__linux__) && (defined(USE_GLIBC) || defined(SYS_getrandom))
115127

116128

117129
#if defined(__linux__) && !defined(SYS_getrandom)
@@ -296,7 +308,11 @@ int randombytes(void *buf, size_t n)
296308
# pragma message("Using crypto api from NodeJS")
297309
return randombytes_js_randombytes_nodejs(buf, n);
298310
#elif defined(__linux__)
299-
# if defined(SYS_getrandom)
311+
# if defined(USE_GLIBC)
312+
# pragma message("Using getrandom function call")
313+
/* Use getrandom system call */
314+
return randombytes_linux_randombytes_getrandom(buf, n);
315+
# elif defined(SYS_getrandom)
300316
# pragma message("Using getrandom system call")
301317
/* Use getrandom system call */
302318
return randombytes_linux_randombytes_getrandom(buf, n);

randombytes_test.c

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
static void *current_test = NULL;
99
static int syscall_called = 0;
10+
static int glib_getrandom_called = 0;
1011

1112
// ======== Helper macros and functions ========
1213

@@ -45,6 +46,9 @@ static void test_functional(void) {
4546
uint8_t buf1[20] = {}, buf2[sizeof(buf1)] = {};
4647
const int ret1 = randombytes(buf1, sizeof(buf1));
4748
const int ret2 = randombytes(buf2, sizeof(buf2));
49+
if (ret1 != 0 || ret2 != 0) {
50+
printf("error: %s\n", strerror(errno));
51+
}
4852
assert(ret1 == 0);
4953
assert(ret2 == 0);
5054
assert(memcmp(buf1, buf2, sizeof(buf1)) != 0);
@@ -58,7 +62,7 @@ static void test_empty(void) {
5862
assert(memcmp(buf, zero, sizeof(zero)) == 0);
5963
}
6064

61-
static void test_getrandom_partial(void) {
65+
static void test_getrandom_syscall_partial(void) {
6266
syscall_called = 0;
6367
uint8_t buf[100] = {};
6468
const int ret = randombytes(buf, sizeof(buf));
@@ -69,7 +73,7 @@ static void test_getrandom_partial(void) {
6973
}
7074
}
7175

72-
static void test_getrandom_interrupted(void) {
76+
static void test_getrandom_syscall_interrupted(void) {
7377
syscall_called = 0;
7478
uint8_t zero[20] = {};
7579
uint8_t buf[sizeof(zero)] = {};
@@ -78,6 +82,26 @@ static void test_getrandom_interrupted(void) {
7882
assert(memcmp(buf, zero, 20) != 0);
7983
}
8084

85+
static void test_getrandom_glib_partial(void) {
86+
glib_getrandom_called = 0;
87+
uint8_t buf[100] = {};
88+
const int ret = randombytes(buf, sizeof(buf));
89+
assert(ret == 0);
90+
assert(glib_getrandom_called >= 5);
91+
for (int i = 1; i < 5; i++) {
92+
assert(memcmp(&buf[0], &buf[20*i], 20) != 0);
93+
}
94+
}
95+
96+
static void test_getrandom_glib_interrupted(void) {
97+
glib_getrandom_called = 0;
98+
uint8_t zero[20] = {};
99+
uint8_t buf[sizeof(zero)] = {};
100+
const int ret = randombytes(buf, sizeof(buf));
101+
assert(ret == 0);
102+
assert(memcmp(buf, zero, 20) != 0);
103+
}
104+
81105
static void test_issue_17(void) {
82106
uint8_t buf1[20] = {}, buf2[sizeof(buf1)] = {};
83107
const int ret1 = randombytes(buf1, sizeof(buf1));
@@ -109,22 +133,38 @@ static void test_issue_33(void) {
109133

110134
// ======== Mock OS functions to simulate uncommon behavior ========
111135

112-
#if defined(__linux__) && defined(SYS_getrandom)
136+
#if defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24))
137+
int __wrap_getrandom(char *buf, size_t buflen, int flags) {
138+
glib_getrandom_called++;
139+
if (current_test == test_getrandom_glib_partial) {
140+
// Fill only 16 bytes, the caller should retry
141+
const size_t current_buflen = buflen <= 16 ? buflen : 16;
142+
return __real_getrandom(buf, current_buflen, flags);
143+
} else if (current_test == test_getrandom_glib_interrupted) {
144+
if (glib_getrandom_called < 5) {
145+
errno = EINTR;
146+
return -1;
147+
}
148+
}
149+
return __real_getrandom(buf, buflen, flags);
150+
}
151+
152+
#elif defined(__linux__) && defined(SYS_getrandom)
113153
int __wrap_syscall(int n, char *buf, size_t buflen, int flags) {
114154
syscall_called++;
115-
if (current_test == test_getrandom_partial) {
155+
if (current_test == test_getrandom_syscall_partial) {
116156
// Fill only 16 bytes, the caller should retry
117157
const size_t current_buflen = buflen <= 16 ? buflen : 16;
118158
return __real_syscall(n, buf, current_buflen, flags);
119-
} else if (current_test == test_getrandom_interrupted) {
159+
} else if (current_test == test_getrandom_syscall_interrupted) {
120160
if (syscall_called < 5) {
121161
errno = EINTR;
122162
return -1;
123163
}
124164
}
125165
return __real_syscall(n, buf, buflen, flags);
126166
}
127-
#endif /* defined(__linux__) && defined(SYS_getrandom) */
167+
#endif /* defined(__linux__) && (defined(SYS_getrandom) or glibc version > 2.24) */
128168

129169
#if defined(__linux__) && !defined(SYS_getrandom)
130170
int __wrap_ioctl(int fd, int code, int* ret) {
@@ -148,13 +188,22 @@ int main(void) {
148188

149189
RUN_TEST(test_functional)
150190
RUN_TEST(test_empty)
151-
#if defined(__linux__) && defined(SYS_getrandom)
152-
RUN_TEST(test_getrandom_partial)
153-
RUN_TEST(test_getrandom_interrupted)
191+
#if defined(__linux__) && defined(USE_GLIBC)
192+
RUN_TEST(test_getrandom_glib_partial)
193+
RUN_TEST(test_getrandom_glib_interrupted)
194+
SKIP_TEST(test_getrandom_syscall_partial)
195+
SKIP_TEST(test_getrandom_syscall_interrupted)
196+
#elif defined(__linux__) && defined(SYS_getrandom)
197+
SKIP_TEST(test_getrandom_glib_partial)
198+
SKIP_TEST(test_getrandom_glib_interrupted)
199+
RUN_TEST(test_getrandom_syscall_partial)
200+
RUN_TEST(test_getrandom_syscall_interrupted)
154201
#else
155-
SKIP_TEST(test_getrandom_partial)
156-
SKIP_TEST(test_getrandom_interrupted)
157-
#endif /* defined(__linux__) && defined(SYS_getrandom) */
202+
SKIP_TEST(test_getrandom_glib_partial)
203+
SKIP_TEST(test_getrandom_glib_interrupted)
204+
SKIP_TEST(test_getrandom_syscall_partial)
205+
SKIP_TEST(test_getrandom_syscall_interrupted)
206+
#endif /* defined(__linux__) && (defined(SYS_getrandom) or glibc version > 2.24) */
158207
#if defined(__linux__) && !defined(SYS_getrandom)
159208
RUN_TEST(test_issue_17)
160209
RUN_TEST(test_issue_22)

0 commit comments

Comments
 (0)