Previously, crypto.getRandomValues() obtained the destination bytes
with njs_vm_value_to_bytes(), which also accepts strings and does not
make a private copy of shared data. As a result:
- for a string argument the random bytes were written into the
string data, which may be shared with other strings, including
literals in the script;
- for r.requestBuffer in nginx the request body seen by subsequent
reads was modified.
Now, only typed arrays and DataView objects are accepted, and the
buffer is made writable before the write.
The issue was introduced in
7b2b7612 (0.7.0).
buffer = njs_arg(args, nargs, 1);
- ret = njs_vm_value_to_bytes(vm, &fill, buffer);
+ ret = njs_value_buffer_get(vm, buffer, &fill);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
"[b[0], $r.buffer[0]]"),
njs_str("64,208") },
+#if (NJS_HAVE_OPENSSL)
+ { njs_str("var b = $r.buffer; crypto.getRandomValues(b);"
+ "[b.length, $r.buffer[0]]"),
+ njs_str("22,208") },
+
+ { njs_str("var v = new DataView(new ArrayBuffer(4));"
+ "crypto.getRandomValues(v) === v"),
+ njs_str("true") },
+
+ { njs_str("var s = 'abc' + 'defgh'; crypto.getRandomValues(s)"),
+ njs_str("TypeError: first argument must be a Buffer or DataView") },
+#endif
+
{ njs_str("$r.buffer instanceof Buffer"),
njs_str("true") },