From 688d27700833258a139a6fbd5661334bd2c9fa98 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Sat, 16 Dec 2023 21:16:33 +0000 Subject: [PATCH] dpp: fix data corruption around prf_plus() call Without the change test-dpp fails on aarch64-linux as: $ unit/test-dpp TEST: DPP test responder-only key derivation TEST: DPP test mutual key derivation TEST: DPP test PKEX key derivation test-dpp: unit/test-dpp.c:514: test_pkex_key_derivation: Assertion `!memcmp(tmp, __tmp, 32)' failed. This happens due to int/size_t type mismatch passed to vararg parameters to prf_plus(): bool prf_plus(enum l_checksum_type type, const void *key, size_t key_len, void *out, size_t out_len, size_t n_extra, ...) { // ... va_start(va, n_extra); for (i = 0; i < n_extra; i++) { iov[i + 1].iov_base = va_arg(va, void *); iov[i + 1].iov_len = va_arg(va, size_t); // ... Note that varargs here could only be a sequence of `void *` / `size_t` values. But in src/dpp-util.c `iwd` attempted to pass `int` there: prf_plus(sha, prk, bytes, z_out, bytes, 5, mac_i, 6, // <- here mac_r, 6, // <- and here m_x, bytes, n_x, bytes, key, strlen(key)); aarch64 stores only 32-bit value part of the register: mov w7, #0x6 str w7, [sp, #...] and loads full 64-bit form of the register: ldr x3, [x3] As a result higher bits of `iov[].iov_len` contain unexpected values and sendmsg sends a lot more data than expected to the kernel. The change fixes test-dpp test for me. While at it fixed obvious `int` / `size_t` mismatch in src/erp.c. Fixes: 6320d6db0f ("crypto: remove label from prf_plus, instead use va_args") --- src/dpp-util.c | 5 +++-- src/erp.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dpp-util.c b/src/dpp-util.c index c805b14a..cfdedbdd 100644 --- a/src/dpp-util.c +++ b/src/dpp-util.c @@ -1376,8 +1376,9 @@ bool dpp_derive_z(const uint8_t *mac_i, const uint8_t *mac_r, hkdf_extract(sha, NULL, 0, 1, prk, k_x, bytes); /* HKDF-Extract (since it doesn't take non-string arguments)*/ - prf_plus(sha, prk, bytes, z_out, bytes, 5, mac_i, 6, mac_r, 6, m_x, - bytes, n_x, bytes, key, strlen(key)); + prf_plus(sha, prk, bytes, z_out, bytes, 5, + mac_i, (size_t) 6, mac_r, (size_t) 6, m_x, bytes, + n_x, bytes, key, strlen(key)); *z_len = bytes; diff --git a/src/erp.c b/src/erp.c index 85923346..05d1b3e2 100644 --- a/src/erp.c +++ b/src/erp.c @@ -325,7 +325,7 @@ static bool erp_derive_reauth_keys(const uint8_t *emsk, size_t emsk_len, if (!prf_plus(L_CHECKSUM_SHA256, r_rk, emsk_len, r_ik, emsk_len, 3, ERP_RIK_LABEL, strlen(ERP_RIK_LABEL) + 1, - &cryptosuite, 1, &len, sizeof(len))) + &cryptosuite, (size_t) 1, &len, sizeof(len))) return false; return true;