[PATCH v2] xfrm: account XFRMA_IF_ID and XFRMA_OFFLOAD_DEV in acquire/polexpire/expire size calculations
flat view
HOTtoday
From: Adrian Martinez Garcia <hidden>
Date: 2026-10-12 14:39:44
Subsystem:
networking [general], networking [ipsec], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Steffen Klassert, Herbert Xu, Linus Torvalds
From 534cb2b5fb8da81677f2955aac8a98d9aa89694b Mon Sep 17 00:00:00 2001
From: Adrian Martinez <redacted>
Date: Sun, 11 Oct 2026 06:53:31 +0000
Subject: [PATCH] xfrm: account XFRMA_IF_ID and XFRMA_OFFLOAD_DEV in
acquire/polexpire/expire size calculations
xfrm_send_acquire() and xfrm_exp_policy_notify() allocate their reply skb
with xfrm_acquire_msgsize() and xfrm_polexpire_msgsize(), then build_acquire()
and build_polexpire() append attributes including XFRMA_IF_ID (when the
policy if_id is set) and XFRMA_OFFLOAD_DEV (when the policy is bound to an
xfrm offload device). Neither size helper reserves space for these two
conditionally emitted attributes, so for policies carrying if_id, mark,
pcpu and/or an offload device the builders can run out of skb tailroom,
fail with -EMSGSIZE and hit BUG_ON(err < 0), turning a netlink event into
a kernel panic.
build_expire() has the same XFRMA_IF_ID undercount in xfrm_expire_msgsize();
its caller already handles -EMSGSIZE gracefully, so the only effect there
is a dropped EXPIRE notification.
This is the same bug class as CVE-2026-43107, whose fix (7081d46d32)
only covered the aevent pair.
Account XFRMA_IF_ID and XFRMA_OFFLOAD_DEV in the three size calculations
unconditionally, and replace the two BUG_ONs with normal error unwinding,
mirroring the aevent fix.
Fixes: 7e6526404ade ("xfrm: Add a new lookup key to match xfrm interfaces.")
Signed-off-by: Adrian Martinez <redacted>
---
net/xfrm/xfrm_user.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a2587c7e..5eb79b0b 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c@@ -3927,7 +3927,8 @@ static inline unsigned int xfrm_expire_msgsize(void) return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) + nla_total_size(sizeof(struct xfrm_mark)) + nla_total_size(sizeof_field(struct xfrm_state, dir)) + - nla_total_size(4); /* XFRMA_SA_PCPU */ + nla_total_size(4) + /* XFRMA_SA_PCPU */ + nla_total_size(4); /* XFRMA_IF_ID */ } static int build_expire(struct sk_buff *skb, struct xfrm_state *x,
const struct km_event *c)
@@ -4177,6 +4178,8 @@ static inline unsigned intxfrm_acquire_msgsize(struct xfrm_state *x, + nla_total_size(sizeof(struct xfrm_mark)) + nla_total_size(xfrm_user_sec_ctx_size(x->security)) + nla_total_size(4) /* XFRMA_SA_PCPU */ + + nla_total_size(sizeof(xp->if_id)) /* XFRMA_IF_ID */ + + nla_total_size(sizeof(struct xfrm_user_offload)) /* XFRMA_OFFLOAD_DEV */ + userpolicy_type_attrsize(); }
@@ -4236,7 +4239,10 @@ static int xfrm_send_acquire(struct xfrm_state*x, struct xfrm_tmpl *xt,
return -ENOMEM;
err = build_acquire(skb, x, xt, xp);
- BUG_ON(err < 0);
+ if (err < 0) {
+ kfree_skb(skb);
+ return err;
+ }
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE);
}@@ -4307,6 +4313,8 @@ static inline unsigned intxfrm_polexpire_msgsize(struct xfrm_policy *xp) + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) + nla_total_size(sizeof(struct xfrm_mark)) + + nla_total_size(sizeof(xp->if_id)) /* XFRMA_IF_ID */ + + nla_total_size(sizeof(struct xfrm_user_offload)) /* XFRMA_OFFLOAD_DEV */ + userpolicy_type_attrsize(); }
@@ -4358,7 +4366,10 @@ static int xfrm_exp_policy_notify(structxfrm_policy *xp, int dir, const struct
return -ENOMEM;
err = build_polexpire(skb, xp, dir, c);
- BUG_ON(err < 0);
+ if (err < 0) {
+ kfree_skb(skb);
+ return err;
+ }
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
}
--
2.43.0