From efce2469de8b784ed6497b20cfac10236e107884 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Thu, 29 Oct 2026 09:17:33 -0700 Subject: [PATCH] WebCrypto: fix AES-CTR out-of-bounds write on empty input Previously, the AES-CTR block count helper computed the number of blocks as "1 + (dend - 1) / dsor". This underflows for a zero-length input, so njs_ceil_div(0, 16) and qjs_ceiling_div(0, 16) returned 2^28 instead of 0. The fix is to use the zero-safe "(dend + dsor - 1) / dsor" form. The njs engine code was introduced in 7b2b7612 (0.7.0) and the QuickJS counterpart in 75ca26f8 (0.8.10). --- external/njs_webcrypto_module.c | 2 +- external/qjs_webcrypto_module.c | 2 +- test/webcrypto/aes.t.mjs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/external/njs_webcrypto_module.c b/external/njs_webcrypto_module.c index 547917a4..8ed5fbbd 100644 --- a/external/njs_webcrypto_module.c +++ b/external/njs_webcrypto_module.c @@ -1185,7 +1185,7 @@ fail: njs_inline njs_uint_t njs_ceil_div(njs_uint_t dend, njs_uint_t dsor) { - return (dsor == 0) ? 0 : 1 + (dend - 1) / dsor; + return (dsor == 0) ? 0 : (dend + dsor - 1) / dsor; } diff --git a/external/qjs_webcrypto_module.c b/external/qjs_webcrypto_module.c index 4a70b942..3b4bfc5a 100644 --- a/external/qjs_webcrypto_module.c +++ b/external/qjs_webcrypto_module.c @@ -985,7 +985,7 @@ qjs_bn_counter128(njs_str_t *ctr, unsigned bits) njs_inline unsigned qjs_ceiling_div(unsigned dend, unsigned dsor) { - return (dsor == 0) ? 0 : 1 + (dend - 1) / dsor; + return (dsor == 0) ? 0 : (dend + dsor - 1) / dsor; } diff --git a/test/webcrypto/aes.t.mjs b/test/webcrypto/aes.t.mjs index 7c482583..88ebe402 100644 --- a/test/webcrypto/aes.t.mjs +++ b/test/webcrypto/aes.t.mjs @@ -87,6 +87,8 @@ let aes_tsuite = { { name: "AES-CTR", data: "aabbcc", key: "001122330011223300112233001122330011223300112233" }, { name: "AES-CTR", data: "aabbccdd", length: 129, exception: "TypeError: AES-CTR algorithm.length must be between 1 and 128" }, + { name: "AES-CTR", data: "", length: 128 }, + { name: "AES-CTR", data: "", counter: "ffffffffffffffffffffffffffffffff", length: 128 }, { name: "AES-CBC", data: "aa" }, { name: "AES-CBC", data: "aabbccdd".repeat(4) }, -- 2.47.3