diff --git a/CLAUDE.md b/CLAUDE.md index ea09d36..acd3782 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -100,7 +100,8 @@ independent implementations (C#, Go, Rust, TypeScript). - Build: CMake. `cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build --parallel`, then `ctest --test-dir build --output-on-failure` runs the suite (51 tests). The `netcode_test` target compiles netcode.c into itself with `NETCODE_ENABLE_TESTS`, so it - links only sodium. `-DNETCODE_SANITIZE=ON` adds ASan+UBSan (sodium gets ASan only); + links only sodium. `-DNETCODE_SANITIZE=ON` adds ASan+UBSan (sodium keeps UBSan + except alignment); `-DNETCODE_FUZZ=ON` builds the `fuzz/` harnesses (libFuzzer where available, else a standalone file replayer); `-DNETCODE_NONCE_AUDIT=ON` records the key and nonce of every packet the tests encrypt and fails the run on a repeat (test-only, nothing enters the diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b1dcf2..cae41c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,9 +81,9 @@ endif() include(GNUInstallDirs) -# sanitizers apply to the whole build. the vendored crypto is exempted from UBSan -# below (third-party SIMD code uses intentional type punning / unaligned access that -# UBSan flags but is not netcode's to fix); it still gets AddressSanitizer. +# sanitizers apply to the whole build. the vendored crypto is exempted only from +# UBSan alignment (SIMD kernels use unaligned loads and type punning). nonnull-attribute +# stays on so a NULL zero-length additional-data pointer is a real failure (netcode#186). if(NETCODE_SANITIZE) if(MSVC) @@ -125,7 +125,7 @@ else() -Wno-unused-variable -Wno-type-limits) if(NETCODE_SANITIZE) - target_compile_options(sodium PRIVATE -fno-sanitize=undefined) + target_compile_options(sodium PRIVATE -fno-sanitize=alignment) endif() endif() diff --git a/netcode.c b/netcode.c index 9245ca5..9ab3f46 100755 --- a/netcode.c +++ b/netcode.c @@ -6351,7 +6351,7 @@ static void test_connect_token() static void test_challenge_token() { - // generate a challenge token + // additional data is NULL, 0. CMakeLists.txt keeps sodium's UBSan exemption as alignment only, so this path guards #186. struct netcode_challenge_token_t input_token; diff --git a/sodium/NOTES.md b/sodium/NOTES.md index 20a4d64..feb16fb 100644 --- a/sodium/NOTES.md +++ b/sodium/NOTES.md @@ -62,6 +62,27 @@ Reviewing a new release means: ### Review log +- **1.0.22 attributes (2026-09-08, revised 2026-09-13).** Ten crypto + declarations netcode actually calls now match upstream 1.0.22 + (`crypto_stream_chacha20{,_ietf}_xor{,_ic}`, + `crypto_onetimeauth{,_poly1305}{,_verify,_update}`, and + `crypto_aead_xchacha20poly1305_ietf_decrypt_detached` which had + `nonnull(3, 5, 9, 9)` — nonce missing, parameter 9 twice; upstream is + `nonnull(3, 5, 8, 9)`). A NULL additional-data pointer with length zero is a + valid call and is how netcode encrypts challenge tokens; the bare attribute + aborted a UBSAN build on that path. `sodium_memzero` is reachable from + netcode.c (ten call sites, including `netcode.c:2985`); this revision + matches upstream 1.0.22 (no nonnull). Eight other utils divergences remain: + `sodium_memcmp` and `sodium_compare` keep a bare nonnull beside unused-result + where upstream has unused-result only; `sodium_bin2hex` and + `sodium_bin2base64` keep bare nonnull against upstream `nonnull(1)`; + `sodium_hex2bin` and `sodium_base642bin` carry `nonnull(1, 3)` against + upstream `nonnull(1)`; `sodium_add` and `sodium_sub` carry a bare nonnull + where upstream declares none. Header attributes only; crypto text unchanged. + The vendored sodium object's UBSan exemption is alignment only (`CMakeLists.txt`), + not all of undefined, so `test_challenge_token` (additional data NULL, 0) is a + real nonnull-attribute guard. See netcode#186 / #187. + - **1.0.22 (reviewed AND incorporated, 2026-07-25).** The vendored slice now carries the 1.0.22 text. Most of 1.0.21/1.0.22 is outside the slice — the ed25519 small-order-point fix, ipcrypt, XOF/SHA-3, ML-KEM768 / X-Wing and assorted build work do not touch the diff --git a/sodium/sodium.h b/sodium/sodium.h index 37c6590..ada96ca 100644 --- a/sodium/sodium.h +++ b/sodium/sodium.h @@ -113,13 +113,13 @@ int crypto_stream_chacha20(unsigned char *c, unsigned long long clen, int crypto_stream_chacha20_xor(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1, 4, 5))); int crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, uint64_t ic, const unsigned char *k) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1, 4, 6))); void crypto_stream_chacha20_keygen(unsigned char k[crypto_stream_chacha20_KEYBYTES]) __attribute__ ((nonnull)); @@ -143,13 +143,13 @@ int crypto_stream_chacha20_ietf(unsigned char *c, unsigned long long clen, int crypto_stream_chacha20_ietf_xor(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1, 4, 5))); int crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, uint32_t ic, const unsigned char *k) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1, 4, 6))); void crypto_stream_chacha20_ietf_keygen(unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]) __attribute__ ((nonnull)); @@ -431,7 +431,7 @@ int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, unsigned long long adlen, const unsigned char *npub, const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 9, 9))); + __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 8, 9))); void crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES]) __attribute__ ((nonnull)); @@ -514,13 +514,13 @@ int crypto_onetimeauth_poly1305(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1, 4))); int crypto_onetimeauth_poly1305_verify(const unsigned char *h, const unsigned char *in, unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); + __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); int crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, const unsigned char *key) @@ -529,7 +529,7 @@ int crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, int crypto_onetimeauth_poly1305_update(crypto_onetimeauth_poly1305_state *state, const unsigned char *in, unsigned long long inlen) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1))); int crypto_onetimeauth_poly1305_final(crypto_onetimeauth_poly1305_state *state, unsigned char *out) @@ -572,11 +572,11 @@ const char *crypto_onetimeauth_primitive(void); int crypto_onetimeauth(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1, 4))); int crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in, unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); + __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); int crypto_onetimeauth_init(crypto_onetimeauth_state *state, const unsigned char *key) __attribute__ ((nonnull)); @@ -584,7 +584,7 @@ int crypto_onetimeauth_init(crypto_onetimeauth_state *state, int crypto_onetimeauth_update(crypto_onetimeauth_state *state, const unsigned char *in, unsigned long long inlen) - __attribute__ ((nonnull)); + __attribute__ ((nonnull(1))); int crypto_onetimeauth_final(crypto_onetimeauth_state *state, unsigned char *out) __attribute__ ((nonnull)); @@ -1272,7 +1272,7 @@ extern "C" { # endif #endif -void sodium_memzero(void * const pnt, const size_t len) __attribute__ ((nonnull)); +void sodium_memzero(void * const pnt, const size_t len); void sodium_stackzero(const size_t len);