mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07:00
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>
This commit is contained in:
@@ -536,7 +536,8 @@ static inline int xfrm_af2proto(unsigned int family)
|
||||
|
||||
static inline const struct xfrm_mode *xfrm_ip2inner_mode(struct xfrm_state *x, int ipproto)
|
||||
{
|
||||
if ((ipproto == IPPROTO_IPIP && x->props.family == AF_INET) ||
|
||||
if ((x->sel.family != AF_UNSPEC) ||
|
||||
(ipproto == IPPROTO_IPIP && x->props.family == AF_INET) ||
|
||||
(ipproto == IPPROTO_IPV6 && x->props.family == AF_INET6))
|
||||
return &x->inner_mode;
|
||||
else
|
||||
|
||||
@@ -122,8 +122,10 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x,
|
||||
struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
__be16 type = x->inner_mode.family == AF_INET6 ? htons(ETH_P_IPV6)
|
||||
: htons(ETH_P_IP);
|
||||
const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x,
|
||||
XFRM_MODE_SKB_CB(skb)->protocol);
|
||||
__be16 type = inner_mode->family == AF_INET6 ? htons(ETH_P_IPV6)
|
||||
: htons(ETH_P_IP);
|
||||
|
||||
return skb_eth_gso_segment(skb, features, type);
|
||||
}
|
||||
|
||||
@@ -158,8 +158,10 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x,
|
||||
struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
__be16 type = x->inner_mode.family == AF_INET ? htons(ETH_P_IP)
|
||||
: htons(ETH_P_IPV6);
|
||||
const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x,
|
||||
XFRM_MODE_SKB_CB(skb)->protocol);
|
||||
__be16 type = inner_mode->family == AF_INET ? htons(ETH_P_IP)
|
||||
: htons(ETH_P_IPV6);
|
||||
|
||||
return skb_eth_gso_segment(skb, features, type);
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ ok:
|
||||
|
||||
check_tunnel_size = x->xso.type == XFRM_DEV_OFFLOAD_PACKET &&
|
||||
x->props.mode == XFRM_MODE_TUNNEL;
|
||||
switch (x->inner_mode.family) {
|
||||
switch (skb_dst(skb)->ops->family) {
|
||||
case AF_INET:
|
||||
/* Check for IPv4 options */
|
||||
if (ip_hdr(skb)->ihl != 5)
|
||||
|
||||
@@ -698,7 +698,7 @@ static void xfrm_get_inner_ipproto(struct sk_buff *skb, struct xfrm_state *x)
|
||||
return;
|
||||
|
||||
if (x->outer_mode.encap == XFRM_MODE_TUNNEL) {
|
||||
switch (x->outer_mode.family) {
|
||||
switch (skb_dst(skb)->ops->family) {
|
||||
case AF_INET:
|
||||
xo->inner_ipproto = ip_hdr(skb)->protocol;
|
||||
break;
|
||||
@@ -772,8 +772,12 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
|
||||
/* Exclusive direct xmit for tunnel mode, as
|
||||
* some filtering or matching rules may apply
|
||||
* in transport mode.
|
||||
* Locally generated packets also require
|
||||
* the normal XFRM path for L2 header setup,
|
||||
* as the hardware needs the L2 header to match
|
||||
* for encryption, so skip direct output as well.
|
||||
*/
|
||||
if (x->props.mode == XFRM_MODE_TUNNEL)
|
||||
if (x->props.mode == XFRM_MODE_TUNNEL && !skb->sk)
|
||||
return xfrm_dev_direct_output(sk, x, skb);
|
||||
|
||||
return xfrm_output_resume(sk, skb, 0);
|
||||
|
||||
@@ -592,6 +592,7 @@ void xfrm_state_free(struct xfrm_state *x)
|
||||
}
|
||||
EXPORT_SYMBOL(xfrm_state_free);
|
||||
|
||||
static void xfrm_state_delete_tunnel(struct xfrm_state *x);
|
||||
static void xfrm_state_gc_destroy(struct xfrm_state *x)
|
||||
{
|
||||
if (x->mode_cbs && x->mode_cbs->destroy_state)
|
||||
@@ -607,6 +608,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
|
||||
kfree(x->replay_esn);
|
||||
kfree(x->preplay_esn);
|
||||
xfrm_unset_type_offload(x);
|
||||
xfrm_state_delete_tunnel(x);
|
||||
if (x->type) {
|
||||
x->type->destructor(x);
|
||||
xfrm_put_type(x->type);
|
||||
@@ -806,7 +808,6 @@ void __xfrm_state_destroy(struct xfrm_state *x)
|
||||
}
|
||||
EXPORT_SYMBOL(__xfrm_state_destroy);
|
||||
|
||||
static void xfrm_state_delete_tunnel(struct xfrm_state *x);
|
||||
int __xfrm_state_delete(struct xfrm_state *x)
|
||||
{
|
||||
struct net *net = xs_net(x);
|
||||
@@ -2073,6 +2074,7 @@ static struct xfrm_state *xfrm_state_clone_and_setup(struct xfrm_state *orig,
|
||||
return x;
|
||||
|
||||
error:
|
||||
x->km.state = XFRM_STATE_DEAD;
|
||||
xfrm_state_put(x);
|
||||
out:
|
||||
return NULL;
|
||||
@@ -2157,11 +2159,15 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
|
||||
xfrm_state_insert(xc);
|
||||
} else {
|
||||
if (xfrm_state_add(xc) < 0)
|
||||
goto error;
|
||||
goto error_add;
|
||||
}
|
||||
|
||||
return xc;
|
||||
error_add:
|
||||
if (xuo)
|
||||
xfrm_dev_state_delete(xc);
|
||||
error:
|
||||
xc->km.state = XFRM_STATE_DEAD;
|
||||
xfrm_state_put(xc);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2191,14 +2197,18 @@ int xfrm_state_update(struct xfrm_state *x)
|
||||
}
|
||||
|
||||
if (x1->km.state == XFRM_STATE_ACQ) {
|
||||
if (x->dir && x1->dir != x->dir)
|
||||
if (x->dir && x1->dir != x->dir) {
|
||||
to_put = x1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
__xfrm_state_insert(x);
|
||||
x = NULL;
|
||||
} else {
|
||||
if (x1->dir != x->dir)
|
||||
if (x1->dir != x->dir) {
|
||||
to_put = x1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
err = 0;
|
||||
|
||||
@@ -3298,6 +3308,7 @@ out_bydst:
|
||||
void xfrm_state_fini(struct net *net)
|
||||
{
|
||||
unsigned int sz;
|
||||
int i;
|
||||
|
||||
flush_work(&net->xfrm.state_hash_work);
|
||||
xfrm_state_flush(net, 0, false);
|
||||
@@ -3305,14 +3316,17 @@ void xfrm_state_fini(struct net *net)
|
||||
|
||||
WARN_ON(!list_empty(&net->xfrm.state_all));
|
||||
|
||||
for (i = 0; i <= net->xfrm.state_hmask; i++) {
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_byseq + i));
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_byspi + i));
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_bysrc + i));
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_bydst + i));
|
||||
}
|
||||
|
||||
sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_byseq));
|
||||
xfrm_hash_free(net->xfrm.state_byseq, sz);
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_byspi));
|
||||
xfrm_hash_free(net->xfrm.state_byspi, sz);
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
|
||||
xfrm_hash_free(net->xfrm.state_bysrc, sz);
|
||||
WARN_ON(!hlist_empty(net->xfrm.state_bydst));
|
||||
xfrm_hash_free(net->xfrm.state_bydst, sz);
|
||||
free_percpu(net->xfrm.state_cache_input);
|
||||
}
|
||||
|
||||
@@ -947,8 +947,11 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
|
||||
|
||||
if (attrs[XFRMA_SA_PCPU]) {
|
||||
x->pcpu_num = nla_get_u32(attrs[XFRMA_SA_PCPU]);
|
||||
if (x->pcpu_num >= num_possible_cpus())
|
||||
if (x->pcpu_num >= num_possible_cpus()) {
|
||||
err = -ERANGE;
|
||||
NL_SET_ERR_MSG(extack, "pCPU number too big");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
err = __xfrm_init_state(x, extack);
|
||||
@@ -3035,6 +3038,9 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
}
|
||||
|
||||
xfrm_state_free(x);
|
||||
xfrm_dev_policy_delete(xp);
|
||||
xfrm_dev_policy_free(xp);
|
||||
security_xfrm_policy_free(xp->security);
|
||||
kfree(xp);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user