From bbd687d107ab1a6a2e695afdde4f666029e37944 Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Fri, 17 Apr 2026 14:07:20 -0700 Subject: [PATCH] perf: embed Hmac in cookie_checker to eliminate make_cookie malloc (ue7.14) make_cookie() previously malloc'd an 832-byte Hmac struct on every call. It is only called under rate-limiting conditions (never on the normal data path), so serialisation on the existing secret_lock write semaphore is acceptable. Add a struct Hmac make_cookie_hmac field to struct cookie_checker (embedded in the heap-allocated struct wg_device). Restructure make_cookie() to hold secret_lock for write throughout, covering both the optional secret refresh and the Hmac operation, eliminating the per-call kmalloc/free of the Hmac struct. --- kernel-src/cookie.c | 49 +++++++++++++++++++++------------------------ kernel-src/cookie.h | 5 +++++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/kernel-src/cookie.c b/kernel-src/cookie.c index 2accd9b..895cb3e 100644 --- a/kernel-src/cookie.c +++ b/kernel-src/cookie.c @@ -103,52 +103,49 @@ static int __must_check compute_mac2(u8 mac2[COOKIE_LEN], const void *message, s static int __must_check make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb, struct cookie_checker *checker) { - int ret; - struct Hmac *wc_hmac; /* sizeof(struct Hmac) is 832 if SHA3 is enabled. */ - - wc_hmac = (struct Hmac *)malloc(sizeof(*wc_hmac)); - if (! wc_hmac) - return -ENOMEM; + int ret = 0; - ret = wc_HmacInit(wc_hmac, NULL /* heap */, INVALID_DEVID); - if (ret < 0) - goto out_hmac_uninited; + /* Take write lock for the entire operation to ensure exclusive access + * to checker->make_cookie_hmac. make_cookie is only invoked under + * rate-limiting conditions, so serialising on the write lock is fine. + */ + down_write(&checker->secret_lock); - if ((ret == 0) && wg_birthdate_has_expired(checker->secret_birthdate, + if (wg_birthdate_has_expired(checker->secret_birthdate, COOKIE_SECRET_MAX_AGE)) { - down_write(&checker->secret_lock); ret = wc_get_random_bytes(checker->secret, NOISE_HASH_LEN); if (ret == 0) checker->secret_birthdate = ktime_get_coarse_boottime_ns(); - up_write(&checker->secret_lock); } - if (ret == 0) { - down_read(&checker->secret_lock); + if (ret == 0) + ret = wc_HmacInit(&checker->make_cookie_hmac, NULL /* heap */, INVALID_DEVID); - ret = wc_HmacSetKey(wc_hmac, WC_SHA256, checker->secret, NOISE_HASH_LEN); + if (ret == 0) { + ret = wc_HmacSetKey(&checker->make_cookie_hmac, WC_SHA256, + checker->secret, NOISE_HASH_LEN); if ((ret == 0) && (skb->protocol == htons(ETH_P_IP))) - ret = wc_HmacUpdate(wc_hmac, (u8 *)&ip_hdr(skb)->saddr, + ret = wc_HmacUpdate(&checker->make_cookie_hmac, + (u8 *)&ip_hdr(skb)->saddr, (word32)sizeof(struct in_addr)); else if ((ret == 0) && (skb->protocol == htons(ETH_P_IPV6))) - ret = wc_HmacUpdate(wc_hmac, (u8 *)&ipv6_hdr(skb)->saddr, + ret = wc_HmacUpdate(&checker->make_cookie_hmac, + (u8 *)&ipv6_hdr(skb)->saddr, (word32)sizeof(struct in6_addr)); - + if (ret == 0) - ret = wc_HmacUpdate(wc_hmac, (u8 *)&udp_hdr(skb)->source, sizeof(__be16)); + ret = wc_HmacUpdate(&checker->make_cookie_hmac, + (u8 *)&udp_hdr(skb)->source, + sizeof(__be16)); if (ret == 0) - ret = wc_HmacFinal(wc_hmac, cookie); + ret = wc_HmacFinal(&checker->make_cookie_hmac, cookie); - up_read(&checker->secret_lock); + wc_HmacFree(&checker->make_cookie_hmac); } - wc_HmacFree(wc_hmac); - -out_hmac_uninited: - - free(wc_hmac); + up_write(&checker->secret_lock); return ret; } diff --git a/kernel-src/cookie.h b/kernel-src/cookie.h index d2c2761..ad03cbf 100644 --- a/kernel-src/cookie.h +++ b/kernel-src/cookie.h @@ -9,6 +9,7 @@ #define _WG_COOKIE_H #include "messages.h" +#include "wolfcrypt_glue.h" #include struct wg_peer; @@ -19,6 +20,10 @@ struct cookie_checker { u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN]; u64 secret_birthdate; struct rw_semaphore secret_lock; + /* Scratch buffer for make_cookie() — avoids per-call kmalloc of the + * 832-byte Hmac struct. Used only while secret_lock is held for write. + */ + struct Hmac make_cookie_hmac; struct wg_device *device; };