From 40fcd96cffa97e1f31d9f16442b6b591ec6d4d7e Mon Sep 17 00:00:00 2001 From: Bailey Hayes Date: Mon, 2 Mar 2026 20:43:27 -0500 Subject: [PATCH] feat(random): make get-random-bytes fallible get-random-bytes and get-insecure-random-bytes accept a u64 length with no way to signal failure, allowing guests to request up to 2^64-1 bytes and forcing hosts to allocate unbounded memory or hard-trap. Add an error enum with a too-many-bytes case and change both functions to return result, error>. Add max-random-bytes-length and max-insecure-random-bytes-length query functions so guests can check limits upfront. Hosts MUST support at least 4096 bytes. The error type is defined in the random interface and reused by insecure via use. get-random-u64 and get-insecure-random-u64 are unchanged. Part of #888 --- proposals/cli/wit-0.3.0-draft/deps.lock | 12 ++++---- proposals/http/wit-0.3.0-draft/deps.lock | 12 ++++---- proposals/random/README.md | 28 +++++++++++++++++-- proposals/random/wit-0.3.0-draft/insecure.wit | 10 ++++++- proposals/random/wit-0.3.0-draft/random.wit | 21 +++++++++++++- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/proposals/cli/wit-0.3.0-draft/deps.lock b/proposals/cli/wit-0.3.0-draft/deps.lock index 7d4bde4e2..9fe9c3527 100644 --- a/proposals/cli/wit-0.3.0-draft/deps.lock +++ b/proposals/cli/wit-0.3.0-draft/deps.lock @@ -5,15 +5,15 @@ sha512 = "f08a2828b88fc6ddea935af584531c484ad4a7a5f30340265e11e91b2bfe0f81e74a66 [filesystem] path = "../../filesystem/wit-0.3.0-draft" -sha256 = "184861e98785957311bfaab242cdf9e66a9ecca11fe2c493b840c461b2361088" -sha512 = "50fa8801fc0a2c1ecfa3cea52af57836f98a12bb0a264439c13bbdcc0e269b3b37ade38b903d6ce10594d1f585d02ef993f3f769c4cddeebdfc00bf93734ed25" +sha256 = "8808ea3adfbc1a025d649b82ddf4f38232ca4377100cfe671d80d5ee37fa3147" +sha512 = "19f4eb8fa62e96ba37b3ea231af6a3bc396c28f82935018a3322441321936b34fb0e44360b378145fcb681d9fea810745969d8baab02ae6017be1784be8abe45" [random] path = "../../random/wit-0.3.0-draft" -sha256 = "5794796c909d6656fcbae6bed28265210ca57308a624119ac0a472326a75aa8f" -sha512 = "812ce57aa13ff3128779d41f4dad50714365e4f9cfd2e1b13458a885fa65da05e409f145deefa25c4a82e0e301a41e2e6572705b35752dc33908d565a73a2e9c" +sha256 = "e51ca727c7bbc0f5b6d7e52bb68d5d838a1c8f3d3ae683cf1c0f247b91b0633f" +sha512 = "77791400acebdea60c35a3ca455ad73bc64584840a42fb2365bcfee6cff835fb14fb625145cdbde6cb7a153c841b479393dde8aa0f21bc7bab7046aca541aefb" [sockets] path = "../../sockets/wit-0.3.0-draft" -sha256 = "985821e86f2643d90b7a100420a44a5a60a6838adcf76fdb90a66255e3926dde" -sha512 = "9ba1e9456c0dc02800ba738acd382a4113103bed72127396546c5f0ad3d38dd5c8e077443bd508b15f86f6095706907e9cb258cccab37c273b4c597a238987e7" +sha256 = "0be70fab90ec1d62e620f37f8fc55397222ceb68ca8387eb0503df7173782634" +sha512 = "997e336258dd3d8d1bf1b27463e77d1dc2160eb13fff899c93b446973f5efbc59448a23279b60568679c08e006a20cc88769ec74d6d30baa4e7a17df0bdb2c30" diff --git a/proposals/http/wit-0.3.0-draft/deps.lock b/proposals/http/wit-0.3.0-draft/deps.lock index e8f05aec3..983160cef 100644 --- a/proposals/http/wit-0.3.0-draft/deps.lock +++ b/proposals/http/wit-0.3.0-draft/deps.lock @@ -10,13 +10,13 @@ sha256 = "888647625fec3eaaf276cb884e426bc32bfa79ced22955f10eb239df74c8550c" sha512 = "f08a2828b88fc6ddea935af584531c484ad4a7a5f30340265e11e91b2bfe0f81e74a660a512f72e5197d60278feccc00534833ebd73868e801859dd31a61bdbb" [filesystem] -sha256 = "184861e98785957311bfaab242cdf9e66a9ecca11fe2c493b840c461b2361088" -sha512 = "50fa8801fc0a2c1ecfa3cea52af57836f98a12bb0a264439c13bbdcc0e269b3b37ade38b903d6ce10594d1f585d02ef993f3f769c4cddeebdfc00bf93734ed25" +sha256 = "8808ea3adfbc1a025d649b82ddf4f38232ca4377100cfe671d80d5ee37fa3147" +sha512 = "19f4eb8fa62e96ba37b3ea231af6a3bc396c28f82935018a3322441321936b34fb0e44360b378145fcb681d9fea810745969d8baab02ae6017be1784be8abe45" [random] -sha256 = "5794796c909d6656fcbae6bed28265210ca57308a624119ac0a472326a75aa8f" -sha512 = "812ce57aa13ff3128779d41f4dad50714365e4f9cfd2e1b13458a885fa65da05e409f145deefa25c4a82e0e301a41e2e6572705b35752dc33908d565a73a2e9c" +sha256 = "329785794587f27cc531d19e23fe872237f052d7d839b29ae2288db5ae9f0533" +sha512 = "691a26b30ce4fdfce070d0a9ccfe8b4f998b8dca6f58a7e22298457a8e0d05eba2f5fd38aa19879cc25bcc5f73a99358b33ae2690dde4e1dfea80fc841b1d69b" [sockets] -sha256 = "985821e86f2643d90b7a100420a44a5a60a6838adcf76fdb90a66255e3926dde" -sha512 = "9ba1e9456c0dc02800ba738acd382a4113103bed72127396546c5f0ad3d38dd5c8e077443bd508b15f86f6095706907e9cb258cccab37c273b4c597a238987e7" +sha256 = "0be70fab90ec1d62e620f37f8fc55397222ceb68ca8387eb0503df7173782634" +sha512 = "997e336258dd3d8d1bf1b27463e77d1dc2160eb13fff899c93b446973f5efbc59448a23279b60568679c08e006a20cc88769ec74d6d30baa4e7a17df0bdb2c30" diff --git a/proposals/random/README.md b/proposals/random/README.md index d13e67256..632b4904c 100644 --- a/proposals/random/README.md +++ b/proposals/random/README.md @@ -50,9 +50,12 @@ The primary goals of WASI Random are: ### Non-goals -WASI Random is not aiming to allow programs to handle errors or to query for +In WASIp2, WASI Random does not allow programs to handle errors or to query for availability. It always succeeds (though on platforms where randomness is -unavailable, programs may fail to be instantiated or may trap). +unavailable, programs may fail to be instantiated or may trap). In WASIp3, +`get-random-bytes` and `get-insecure-random-bytes` return `result` types so that +hosts can reject oversized requests gracefully (see +[Resource exhaustion](#resource-exhaustion) below). WASI Random is not aiming to be a full DRBG API. Such an API could be considered in WASI, but it should be a separate proposal. @@ -171,6 +174,27 @@ their bits of security, and it doesn't seem desirable to require wasm engines to run their own CSPRNG on a platform which already has one, so for now, the API does not specify a specific number. +### Resource exhaustion + +In WASIp2, `get-random-bytes` and `get-insecure-random-bytes` accept a `u64` +length and return `list` with no way to signal failure. A guest can request +up to 2^64-1 bytes, forcing hosts to either allocate unbounded memory or +hard-trap. This was reported as [GHSA-852m-cvvp-9p4w]. + +WASIp3 addresses this by changing both functions to return +`result, error>` where `error` is a variant with a `too-many-bytes` +case and an `other(option)` catch-all. This allows hosts to reject +oversized requests gracefully instead of trapping. Callers that need more bytes +than the host supports can simply retry in smaller chunks. + +The `error` variant is defined once in the `random` interface and reused by +`insecure` via `use random.{error}`, keeping the error type consistent. + +The `get-random-u64` and `get-insecure-random-u64` functions are unchanged since +they always return exactly 8 bytes, posing no resource exhaustion risk. + +[GHSA-852m-cvvp-9p4w]: https://github.com/WebAssembly/WASI/security/advisories/GHSA-852m-cvvp-9p4w + ### Why is insecure-random a fixed-sized return value? This limits the amount of data that can be obtained through it. Since it's diff --git a/proposals/random/wit-0.3.0-draft/insecure.wit b/proposals/random/wit-0.3.0-draft/insecure.wit index 9ce8c2d9d..39b4c262e 100644 --- a/proposals/random/wit-0.3.0-draft/insecure.wit +++ b/proposals/random/wit-0.3.0-draft/insecure.wit @@ -5,6 +5,9 @@ package wasi:random@0.3.0-rc-2026-02-09; /// Windows. @since(version = 0.3.0-rc-2026-02-09) interface insecure { + @since(version = 0.3.0-rc-2026-02-09) + use random.{error}; + /// Return `len` insecure pseudo-random bytes. /// /// This function is not cryptographically secure. Do not use it for @@ -13,8 +16,13 @@ interface insecure { /// There are no requirements on the values of the returned bytes, however /// implementations are encouraged to return evenly distributed values with /// a long period. + /// + /// # Errors + /// + /// Returns `error::too-many-bytes` if `len` exceeds the host's supported + /// limit. @since(version = 0.3.0-rc-2026-02-09) - get-insecure-random-bytes: func(len: u64) -> list; + get-insecure-random-bytes: func(len: u64) -> result, error>; /// Return an insecure pseudo-random `u64` value. /// diff --git a/proposals/random/wit-0.3.0-draft/random.wit b/proposals/random/wit-0.3.0-draft/random.wit index 5adbdca4e..03a97a646 100644 --- a/proposals/random/wit-0.3.0-draft/random.wit +++ b/proposals/random/wit-0.3.0-draft/random.wit @@ -5,6 +5,20 @@ package wasi:random@0.3.0-rc-2026-02-09; /// Windows. @since(version = 0.3.0-rc-2026-02-09) interface random { + /// An error type for random byte generation. + @since(version = 0.3.0-rc-2026-02-09) + variant error { + /// The requested number of bytes exceeds the host's supported limit. + too-many-bytes, + + /// A catch-all error for anything that doesn't fit into a more + /// specific case. The optional string provides an unstructured + /// description of the error. Users should not depend on the string + /// for diagnosing errors, as it is not required to be consistent + /// between implementations. + other(option), + } + /// Return `len` cryptographically-secure random or pseudo-random bytes. /// /// This function must produce data at least as cryptographically secure and @@ -17,8 +31,13 @@ interface random { /// This function must always return fresh data. Deterministic environments /// must omit this function, rather than implementing it with deterministic /// data. + /// + /// # Errors + /// + /// Returns `error::too-many-bytes` if `len` exceeds the host's supported + /// limit. @since(version = 0.3.0-rc-2026-02-09) - get-random-bytes: func(len: u64) -> list; + get-random-bytes: func(len: u64) -> result, error>; /// Return a cryptographically-secure random or pseudo-random `u64` value. ///