Skip to content

Commit c3995fc

Browse files
committed
Merge tag 'ipsec-2025-11-18' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2025-11-18 1) Misc fixes for xfrm_state creation/modification/deletion. Patchset from Sabrina Dubroca. 2) Fix inner packet family determination for xfrm offloads. From Jianbo Liu. 3) Don't push locally generated packets directly to L2 tunnel mode offloading, they still need processing from the standard xfrm path. From Jianbo Liu. 4) Fix memory leaks in xfrm_add_acquire for policy offloads and policy security contexts. From Zilin Guan. * tag 'ipsec-2025-11-18' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec: xfrm: fix memory leak in xfrm_add_acquire() xfrm: Prevent locally generated packets from direct output in tunnel mode xfrm: Determine inner GSO type from packet inner protocol xfrm: Check inner packet family directly from skb_dst xfrm: check all hash buckets for leftover states during netns deletion xfrm: set err and extack on failure to create pcpu SA xfrm: call xfrm_dev_state_delete when xfrm_state_migrate fails to add the state xfrm: make state as DEAD before final put when migrate fails xfrm: also call xfrm_state_delete_tunnel at destroy time for states that were never added xfrm: drop SA reference in xfrm_state_update if dir doesn't match ==================== Link: https://patch.msgid.link/20251118085344.2199815-1-steffen.klassert@secunet.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents f94c1a1 + a55ef3b commit c3995fc

File tree

7 files changed

+46
-17
lines changed

7 files changed

+46
-17
lines changed

include/net/xfrm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,8 @@ static inline int xfrm_af2proto(unsigned int family)
536536

537537
static inline const struct xfrm_mode *xfrm_ip2inner_mode(struct xfrm_state *x, int ipproto)
538538
{
539-
if ((ipproto == IPPROTO_IPIP && x->props.family == AF_INET) ||
539+
if ((x->sel.family != AF_UNSPEC) ||
540+
(ipproto == IPPROTO_IPIP && x->props.family == AF_INET) ||
540541
(ipproto == IPPROTO_IPV6 && x->props.family == AF_INET6))
541542
return &x->inner_mode;
542543
else

net/ipv4/esp4_offload.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,10 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x,
122122
struct sk_buff *skb,
123123
netdev_features_t features)
124124
{
125-
__be16 type = x->inner_mode.family == AF_INET6 ? htons(ETH_P_IPV6)
126-
: htons(ETH_P_IP);
125+
const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x,
126+
XFRM_MODE_SKB_CB(skb)->protocol);
127+
__be16 type = inner_mode->family == AF_INET6 ? htons(ETH_P_IPV6)
128+
: htons(ETH_P_IP);
127129

128130
return skb_eth_gso_segment(skb, features, type);
129131
}

net/ipv6/esp6_offload.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,10 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x,
158158
struct sk_buff *skb,
159159
netdev_features_t features)
160160
{
161-
__be16 type = x->inner_mode.family == AF_INET ? htons(ETH_P_IP)
162-
: htons(ETH_P_IPV6);
161+
const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x,
162+
XFRM_MODE_SKB_CB(skb)->protocol);
163+
__be16 type = inner_mode->family == AF_INET ? htons(ETH_P_IP)
164+
: htons(ETH_P_IPV6);
163165

164166
return skb_eth_gso_segment(skb, features, type);
165167
}

net/xfrm/xfrm_device.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
438438

439439
check_tunnel_size = x->xso.type == XFRM_DEV_OFFLOAD_PACKET &&
440440
x->props.mode == XFRM_MODE_TUNNEL;
441-
switch (x->inner_mode.family) {
441+
switch (skb_dst(skb)->ops->family) {
442442
case AF_INET:
443443
/* Check for IPv4 options */
444444
if (ip_hdr(skb)->ihl != 5)

net/xfrm/xfrm_output.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ static void xfrm_get_inner_ipproto(struct sk_buff *skb, struct xfrm_state *x)
698698
return;
699699

700700
if (x->outer_mode.encap == XFRM_MODE_TUNNEL) {
701-
switch (x->outer_mode.family) {
701+
switch (skb_dst(skb)->ops->family) {
702702
case AF_INET:
703703
xo->inner_ipproto = ip_hdr(skb)->protocol;
704704
break;
@@ -772,8 +772,12 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
772772
/* Exclusive direct xmit for tunnel mode, as
773773
* some filtering or matching rules may apply
774774
* in transport mode.
775+
* Locally generated packets also require
776+
* the normal XFRM path for L2 header setup,
777+
* as the hardware needs the L2 header to match
778+
* for encryption, so skip direct output as well.
775779
*/
776-
if (x->props.mode == XFRM_MODE_TUNNEL)
780+
if (x->props.mode == XFRM_MODE_TUNNEL && !skb->sk)
777781
return xfrm_dev_direct_output(sk, x, skb);
778782

779783
return xfrm_output_resume(sk, skb, 0);

net/xfrm/xfrm_state.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ void xfrm_state_free(struct xfrm_state *x)
592592
}
593593
EXPORT_SYMBOL(xfrm_state_free);
594594

595+
static void xfrm_state_delete_tunnel(struct xfrm_state *x);
595596
static void xfrm_state_gc_destroy(struct xfrm_state *x)
596597
{
597598
if (x->mode_cbs && x->mode_cbs->destroy_state)
@@ -607,6 +608,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
607608
kfree(x->replay_esn);
608609
kfree(x->preplay_esn);
609610
xfrm_unset_type_offload(x);
611+
xfrm_state_delete_tunnel(x);
610612
if (x->type) {
611613
x->type->destructor(x);
612614
xfrm_put_type(x->type);
@@ -806,7 +808,6 @@ void __xfrm_state_destroy(struct xfrm_state *x)
806808
}
807809
EXPORT_SYMBOL(__xfrm_state_destroy);
808810

809-
static void xfrm_state_delete_tunnel(struct xfrm_state *x);
810811
int __xfrm_state_delete(struct xfrm_state *x)
811812
{
812813
struct net *net = xs_net(x);
@@ -2073,6 +2074,7 @@ static struct xfrm_state *xfrm_state_clone_and_setup(struct xfrm_state *orig,
20732074
return x;
20742075

20752076
error:
2077+
x->km.state = XFRM_STATE_DEAD;
20762078
xfrm_state_put(x);
20772079
out:
20782080
return NULL;
@@ -2157,11 +2159,15 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
21572159
xfrm_state_insert(xc);
21582160
} else {
21592161
if (xfrm_state_add(xc) < 0)
2160-
goto error;
2162+
goto error_add;
21612163
}
21622164

21632165
return xc;
2166+
error_add:
2167+
if (xuo)
2168+
xfrm_dev_state_delete(xc);
21642169
error:
2170+
xc->km.state = XFRM_STATE_DEAD;
21652171
xfrm_state_put(xc);
21662172
return NULL;
21672173
}
@@ -2191,14 +2197,18 @@ int xfrm_state_update(struct xfrm_state *x)
21912197
}
21922198

21932199
if (x1->km.state == XFRM_STATE_ACQ) {
2194-
if (x->dir && x1->dir != x->dir)
2200+
if (x->dir && x1->dir != x->dir) {
2201+
to_put = x1;
21952202
goto out;
2203+
}
21962204

21972205
__xfrm_state_insert(x);
21982206
x = NULL;
21992207
} else {
2200-
if (x1->dir != x->dir)
2208+
if (x1->dir != x->dir) {
2209+
to_put = x1;
22012210
goto out;
2211+
}
22022212
}
22032213
err = 0;
22042214

@@ -3298,21 +3308,25 @@ int __net_init xfrm_state_init(struct net *net)
32983308
void xfrm_state_fini(struct net *net)
32993309
{
33003310
unsigned int sz;
3311+
int i;
33013312

33023313
flush_work(&net->xfrm.state_hash_work);
33033314
xfrm_state_flush(net, 0, false);
33043315
flush_work(&xfrm_state_gc_work);
33053316

33063317
WARN_ON(!list_empty(&net->xfrm.state_all));
33073318

3319+
for (i = 0; i <= net->xfrm.state_hmask; i++) {
3320+
WARN_ON(!hlist_empty(net->xfrm.state_byseq + i));
3321+
WARN_ON(!hlist_empty(net->xfrm.state_byspi + i));
3322+
WARN_ON(!hlist_empty(net->xfrm.state_bysrc + i));
3323+
WARN_ON(!hlist_empty(net->xfrm.state_bydst + i));
3324+
}
3325+
33083326
sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
3309-
WARN_ON(!hlist_empty(net->xfrm.state_byseq));
33103327
xfrm_hash_free(net->xfrm.state_byseq, sz);
3311-
WARN_ON(!hlist_empty(net->xfrm.state_byspi));
33123328
xfrm_hash_free(net->xfrm.state_byspi, sz);
3313-
WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
33143329
xfrm_hash_free(net->xfrm.state_bysrc, sz);
3315-
WARN_ON(!hlist_empty(net->xfrm.state_bydst));
33163330
xfrm_hash_free(net->xfrm.state_bydst, sz);
33173331
free_percpu(net->xfrm.state_cache_input);
33183332
}

net/xfrm/xfrm_user.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,8 +947,11 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
947947

948948
if (attrs[XFRMA_SA_PCPU]) {
949949
x->pcpu_num = nla_get_u32(attrs[XFRMA_SA_PCPU]);
950-
if (x->pcpu_num >= num_possible_cpus())
950+
if (x->pcpu_num >= num_possible_cpus()) {
951+
err = -ERANGE;
952+
NL_SET_ERR_MSG(extack, "pCPU number too big");
951953
goto error;
954+
}
952955
}
953956

954957
err = __xfrm_init_state(x, extack);
@@ -3035,6 +3038,9 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
30353038
}
30363039

30373040
xfrm_state_free(x);
3041+
xfrm_dev_policy_delete(xp);
3042+
xfrm_dev_policy_free(xp);
3043+
security_xfrm_policy_free(xp->security);
30383044
kfree(xp);
30393045

30403046
return 0;

0 commit comments

Comments
 (0)