Skip to content

Commit 8f08ccc

Browse files
authored
Implement getentropy via __wasi_random_get (#22820)
This allows it to work in standalone mode. Fixes: #22782
1 parent 29e98f8 commit 8f08ccc

15 files changed

+103
-107
lines changed

src/library.js

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,65 +1292,6 @@ addToLibrary({
12921292

12931293
#endif // PROXY_POSIX_SOCKETS == 0
12941294

1295-
// random.h
1296-
1297-
$initRandomFill: () => {
1298-
if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') {
1299-
// for modern web browsers
1300-
#if SHARED_MEMORY
1301-
// like with most Web APIs, we can't use Web Crypto API directly on shared memory,
1302-
// so we need to create an intermediate buffer and copy it to the destination
1303-
return (view) => (
1304-
view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))),
1305-
// Return the original view to match modern native implementations.
1306-
view
1307-
);
1308-
#else
1309-
return (view) => crypto.getRandomValues(view);
1310-
#endif
1311-
} else
1312-
#if ENVIRONMENT_MAY_BE_NODE
1313-
if (ENVIRONMENT_IS_NODE) {
1314-
// for nodejs with or without crypto support included
1315-
try {
1316-
var crypto_module = require('crypto');
1317-
var randomFillSync = crypto_module['randomFillSync'];
1318-
if (randomFillSync) {
1319-
// nodejs with LTS crypto support
1320-
return (view) => crypto_module['randomFillSync'](view);
1321-
}
1322-
// very old nodejs with the original crypto API
1323-
var randomBytes = crypto_module['randomBytes'];
1324-
return (view) => (
1325-
view.set(randomBytes(view.byteLength)),
1326-
// Return the original view to match modern native implementations.
1327-
view
1328-
);
1329-
} catch (e) {
1330-
// nodejs doesn't have crypto support
1331-
}
1332-
}
1333-
#endif // ENVIRONMENT_MAY_BE_NODE
1334-
// we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096
1335-
#if ASSERTIONS
1336-
abort('no cryptographic support found for randomDevice. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: (array) => { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };');
1337-
#else
1338-
abort('initRandomDevice');
1339-
#endif
1340-
},
1341-
1342-
$randomFill__deps: ['$initRandomFill'],
1343-
$randomFill: (view) => {
1344-
// Lazily init on the first invocation.
1345-
return (randomFill = initRandomFill())(view);
1346-
},
1347-
1348-
getentropy__deps: ['$randomFill'],
1349-
getentropy: (buffer, size) => {
1350-
randomFill(HEAPU8.subarray(buffer, buffer + size));
1351-
return 0;
1352-
},
1353-
13541295
$timers: {},
13551296

13561297
// Helper function for setitimer that registers timers with the eventloop.

src/library_sigs.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,6 @@ sigs = {
972972
filledEllipseColor__sig: 'ipiiiii',
973973
filledEllipseRGBA__sig: 'ipiiiiiiii',
974974
getaddrinfo__sig: 'ipppp',
975-
getentropy__sig: 'ipp',
976975
getnameinfo__sig: 'ipipipii',
977976
getprotobyname__sig: 'pp',
978977
getprotobynumber__sig: 'pi',

src/library_wasi.js

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ var WasiLibrary = {
4141
sched_yield__nothrow: true,
4242
sched_yield: () => 0,
4343

44-
random_get__deps: ['getentropy'],
45-
random_get: (buf, buf_len) => {
46-
_getentropy(buf, buf_len);
47-
return 0;
48-
},
49-
5044
$getEnvStrings__deps: ['$ENV', '$getExecutableName'],
5145
$getEnvStrings: () => {
5246
if (!getEnvStrings.strings) {
@@ -568,6 +562,66 @@ var WasiLibrary = {
568562
#endif // SYSCALLS_REQUIRE_FILESYSTEM
569563
},
570564
fd_sync__async: true,
565+
566+
// random.h
567+
568+
$initRandomFill: () => {
569+
if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') {
570+
// for modern web browsers
571+
#if SHARED_MEMORY
572+
// like with most Web APIs, we can't use Web Crypto API directly on shared memory,
573+
// so we need to create an intermediate buffer and copy it to the destination
574+
return (view) => (
575+
view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))),
576+
// Return the original view to match modern native implementations.
577+
view
578+
);
579+
#else
580+
return (view) => crypto.getRandomValues(view);
581+
#endif
582+
} else
583+
#if ENVIRONMENT_MAY_BE_NODE
584+
if (ENVIRONMENT_IS_NODE) {
585+
// for nodejs with or without crypto support included
586+
try {
587+
var crypto_module = require('crypto');
588+
var randomFillSync = crypto_module['randomFillSync'];
589+
if (randomFillSync) {
590+
// nodejs with LTS crypto support
591+
return (view) => crypto_module['randomFillSync'](view);
592+
}
593+
// very old nodejs with the original crypto API
594+
var randomBytes = crypto_module['randomBytes'];
595+
return (view) => (
596+
view.set(randomBytes(view.byteLength)),
597+
// Return the original view to match modern native implementations.
598+
view
599+
);
600+
} catch (e) {
601+
// nodejs doesn't have crypto support
602+
}
603+
}
604+
#endif // ENVIRONMENT_MAY_BE_NODE
605+
// we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096
606+
#if ASSERTIONS
607+
abort('no cryptographic support found for randomDevice. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: (array) => { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };');
608+
#else
609+
abort('initRandomDevice');
610+
#endif
611+
},
612+
613+
$randomFill__deps: ['$initRandomFill'],
614+
$randomFill: (view) => {
615+
// Lazily init on the first invocation.
616+
return (randomFill = initRandomFill())(view);
617+
},
618+
619+
random_get__proxy: 'none',
620+
random_get__deps: ['$randomFill'],
621+
random_get: (buffer, size) => {
622+
randomFill(HEAPU8.subarray(buffer, buffer + size));
623+
return 0;
624+
},
571625
};
572626

573627
for (var x in WasiLibrary) {

system/lib/libc/musl/src/misc/getentropy.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#include <pthread.h>
55
#include <errno.h>
66

7+
#ifdef __EMSCRIPTEN__
8+
#include <wasi/wasi-helpers.h>
9+
#endif
10+
711
int getentropy(void *buffer, size_t len)
812
{
913
int cs, ret = 0;
@@ -16,6 +20,9 @@ int getentropy(void *buffer, size_t len)
1620

1721
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
1822

23+
#ifdef __EMSCRIPTEN__
24+
ret = __wasi_syscall_ret(__wasi_random_get(buffer, len));
25+
#else
1926
while (len) {
2027
ret = getrandom(pos, len, 0);
2128
if (ret < 0) {
@@ -26,6 +33,7 @@ int getentropy(void *buffer, size_t len)
2633
len -= ret;
2734
ret = 0;
2835
}
36+
#endif
2937

3038
pthread_setcancelstate(cs, 0);
3139

system/lib/standalone/standalone.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,6 @@ weak int __syscall_lstat64(intptr_t path, intptr_t buf) {
136136
return -ENOSYS;
137137
}
138138

139-
// There is no good source of entropy without an import. Make this weak so that
140-
// it can be replaced with a pRNG or a proper import.
141-
weak int getentropy(void* buffer, size_t length) {
142-
abort();
143-
}
144-
145139
// Emscripten additions
146140

147141
size_t emscripten_get_heap_max() {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3899
1+
3895

test/other/codesize/test_codesize_cxx_wasmfs.imports

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ env.emscripten_date_now
1515
env.emscripten_err
1616
env.emscripten_out
1717
env.emscripten_resize_heap
18-
env.getentropy
1918
wasi_snapshot_preview1.environ_get
2019
wasi_snapshot_preview1.environ_sizes_get
20+
wasi_snapshot_preview1.random_get

test/other/codesize/test_codesize_cxx_wasmfs.sent

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ emscripten_out
1717
emscripten_resize_heap
1818
environ_get
1919
environ_sizes_get
20-
getentropy
20+
random_get
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
169486
1+
169554
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
a (emscripten_date_now)
22
b (emscripten_err)
3-
c (getentropy)
4-
d (emscripten_resize_heap)
5-
e (emscripten_out)
6-
f (_wasmfs_stdin_get_char)
7-
g (_wasmfs_get_preloaded_path_name)
8-
h (_wasmfs_get_preloaded_parent_path)
9-
i (_wasmfs_get_preloaded_file_size)
10-
j (_wasmfs_get_preloaded_file_mode)
11-
k (_wasmfs_get_preloaded_child_path)
12-
l (_wasmfs_get_num_preloaded_files)
13-
m (_wasmfs_get_num_preloaded_dirs)
14-
n (_wasmfs_copy_preloaded_file_data)
15-
o (_emscripten_memcpy_js)
16-
p (_abort_js)
3+
c (emscripten_resize_heap)
4+
d (emscripten_out)
5+
e (_wasmfs_stdin_get_char)
6+
f (_wasmfs_get_preloaded_path_name)
7+
g (_wasmfs_get_preloaded_parent_path)
8+
h (_wasmfs_get_preloaded_file_size)
9+
i (_wasmfs_get_preloaded_file_mode)
10+
j (_wasmfs_get_preloaded_child_path)
11+
k (_wasmfs_get_num_preloaded_files)
12+
l (_wasmfs_get_num_preloaded_dirs)
13+
m (_wasmfs_copy_preloaded_file_data)
14+
n (_emscripten_memcpy_js)
15+
o (_abort_js)
16+
p (random_get)
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
a (emscripten_date_now)
22
b (emscripten_err)
3-
c (getentropy)
4-
d (emscripten_resize_heap)
5-
e (emscripten_out)
6-
f (_wasmfs_stdin_get_char)
7-
g (_wasmfs_get_preloaded_path_name)
8-
h (_wasmfs_get_preloaded_parent_path)
9-
i (_wasmfs_get_preloaded_file_size)
10-
j (_wasmfs_get_preloaded_file_mode)
11-
k (_wasmfs_get_preloaded_child_path)
12-
l (_wasmfs_get_num_preloaded_files)
13-
m (_wasmfs_get_num_preloaded_dirs)
14-
n (_wasmfs_copy_preloaded_file_data)
15-
o (_emscripten_memcpy_js)
16-
p (_abort_js)
3+
c (emscripten_resize_heap)
4+
d (emscripten_out)
5+
e (_wasmfs_stdin_get_char)
6+
f (_wasmfs_get_preloaded_path_name)
7+
g (_wasmfs_get_preloaded_parent_path)
8+
h (_wasmfs_get_preloaded_file_size)
9+
i (_wasmfs_get_preloaded_file_mode)
10+
j (_wasmfs_get_preloaded_child_path)
11+
k (_wasmfs_get_num_preloaded_files)
12+
l (_wasmfs_get_num_preloaded_dirs)
13+
m (_wasmfs_copy_preloaded_file_data)
14+
n (_emscripten_memcpy_js)
15+
o (_abort_js)
16+
p (random_get)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
51099
1+
51157
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6576
1+
6577

tools/building.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,7 @@ def metadce(js_file, wasm_file, debug_info, last):
807807
'clock_res_get',
808808
'clock_time_get',
809809
'path_open',
810+
'random_get',
810811
}
811812
for item in graph:
812813
if 'import' in item and item['import'][1] in WASI_IMPORTS:

tools/system_libs.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,6 @@ def get_files(self):
10981098
'ppoll.c',
10991099
'syscall.c', 'popen.c', 'pclose.c',
11001100
'getgrouplist.c', 'initgroups.c', 'wordexp.c', 'timer_create.c',
1101-
'getentropy.c',
11021101
'getauxval.c',
11031102
'lookup_name.c',
11041103
# 'process' exclusion

0 commit comments

Comments
 (0)