ipsec-2025-05-21
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH7ZpcWbFyOOp6OJbrB3Eaf9PW7cFAmgtYgEACgkQrB3Eaf9P W7e1ag//da84UIRyJwMfDO4Y3MXDNPslNSDuq0HuvwRtdLIBLFtwitSzU1uhKsxY yn5v7RSsxvp6lXW2RT+Ycor2qZ/mGHJsHcVfG7m0YjxH6unw7yzjqn5LNNzRbYN4 NcD8P0skuX6d80EFPUB3Hsnmdj1VKR62OsWyk3rAPb4CLBVKJt9OsseVfN4bn1R0 TaZSIkdh5EDGYXTBKb49jc8LFfQo7+uVg/AjtZ/2ZsWt+Qgw3XevTIcwLokH00rt GzXcLjC1g+b6TeVncOuD1oiNJUtQVGYV23t2yQlk9k2HFzCdNnq0YM9pzawwiI+l icBV2X/QFjhdCRkvJRF4dkXq/4tnnEmYoY/1vSOoWR9VmY2u8Lr3VRiDD/h0gYJT KXd8YPMtZLDnLgmH+DwWbv4vdLtHvQTmB8XFzb/4VN6Ikucenry3loJsUsLnS+Je t1/7unLrg9yyJC6UPzweqjAx+6VgZvem/M5kejIVxHpk+Wg2dXGZ2jz4fsVuZYPB dMLj1h1MLn4gOt2b/bdI2do0C+p2R1axrTNw+RiqwCrb1h5Ey+7RAhWyXyaHUEs3 1brMAgOcvdbaaeSIpoHJ8eJx/PgRxDrxRnUC3HjCGPNApYQXC3FM3POk7wwJ9C0i odlHrq+yOdzLCZyU+YKdR1q3kPq9AWpUSmc4Olg359OQ9IxDGQw= =bgyq -----END PGP SIGNATURE----- Merge tag 'ipsec-2025-05-21' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec Steffen Klassert says: ==================== pull request (net): ipsec 2025-05-21 1) Fix some missing kfree_skb in the error paths of espintcp. From Sabrina Dubroca. 2) Fix a reference leak in espintcp. From Sabrina Dubroca. 3) Fix UDP GRO handling for ESPINUDP. From Tobias Brunner. 4) Fix ipcomp truesize computation on the receive path. From Sabrina Dubroca. 5) Sanitize marks before policy/state insertation. From Paul Chaignon. * tag 'ipsec-2025-05-21' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec: xfrm: Sanitize marks before insert xfrm: ipcomp: fix truesize computation on receive xfrm: Fix UDP GRO handling for some corner cases espintcp: remove encap socket caching to avoid reference leak espintcp: fix skb leaks ==================== Link: https://patch.msgid.link/20250521054348.4057269-1-steffen.klassert@secunet.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
bd2ec34d00
9 changed files with 44 additions and 115 deletions
|
@ -236,7 +236,6 @@ struct xfrm_state {
|
|||
|
||||
/* Data for encapsulator */
|
||||
struct xfrm_encap_tmpl *encap;
|
||||
struct sock __rcu *encap_sk;
|
||||
|
||||
/* NAT keepalive */
|
||||
u32 nat_keepalive_interval; /* seconds */
|
||||
|
|
|
@ -120,47 +120,16 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_INET_ESPINTCP
|
||||
struct esp_tcp_sk {
|
||||
struct sock *sk;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
static void esp_free_tcp_sk(struct rcu_head *head)
|
||||
{
|
||||
struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);
|
||||
|
||||
sock_put(esk->sk);
|
||||
kfree(esk);
|
||||
}
|
||||
|
||||
static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
|
||||
{
|
||||
struct xfrm_encap_tmpl *encap = x->encap;
|
||||
struct net *net = xs_net(x);
|
||||
struct esp_tcp_sk *esk;
|
||||
__be16 sport, dport;
|
||||
struct sock *nsk;
|
||||
struct sock *sk;
|
||||
|
||||
sk = rcu_dereference(x->encap_sk);
|
||||
if (sk && sk->sk_state == TCP_ESTABLISHED)
|
||||
return sk;
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
sport = encap->encap_sport;
|
||||
dport = encap->encap_dport;
|
||||
nsk = rcu_dereference_protected(x->encap_sk,
|
||||
lockdep_is_held(&x->lock));
|
||||
if (sk && sk == nsk) {
|
||||
esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
|
||||
if (!esk) {
|
||||
spin_unlock_bh(&x->lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
RCU_INIT_POINTER(x->encap_sk, NULL);
|
||||
esk->sk = sk;
|
||||
call_rcu(&esk->rcu, esp_free_tcp_sk);
|
||||
}
|
||||
spin_unlock_bh(&x->lock);
|
||||
|
||||
sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, x->id.daddr.a4,
|
||||
|
@ -173,20 +142,6 @@ static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
nsk = rcu_dereference_protected(x->encap_sk,
|
||||
lockdep_is_held(&x->lock));
|
||||
if (encap->encap_sport != sport ||
|
||||
encap->encap_dport != dport) {
|
||||
sock_put(sk);
|
||||
sk = nsk ?: ERR_PTR(-EREMCHG);
|
||||
} else if (sk == nsk) {
|
||||
sock_put(sk);
|
||||
} else {
|
||||
rcu_assign_pointer(x->encap_sk, sk);
|
||||
}
|
||||
spin_unlock_bh(&x->lock);
|
||||
|
||||
return sk;
|
||||
}
|
||||
|
||||
|
@ -199,8 +154,10 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
|
|||
|
||||
sk = esp_find_tcp_sk(x);
|
||||
err = PTR_ERR_OR_ZERO(sk);
|
||||
if (err)
|
||||
if (err) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bh_lock_sock(sk);
|
||||
if (sock_owned_by_user(sk))
|
||||
|
@ -209,6 +166,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
|
|||
err = espintcp_push_skb(sk, skb);
|
||||
bh_unlock_sock(sk);
|
||||
|
||||
sock_put(sk);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
|
@ -392,6 +351,8 @@ static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
|
|||
if (IS_ERR(sk))
|
||||
return ERR_CAST(sk);
|
||||
|
||||
sock_put(sk);
|
||||
|
||||
*lenp = htons(len);
|
||||
esph = (struct ip_esp_hdr *)(lenp + 1);
|
||||
|
||||
|
|
|
@ -182,11 +182,15 @@ struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
|
|||
int offset = skb_gro_offset(skb);
|
||||
const struct net_offload *ops;
|
||||
struct sk_buff *pp = NULL;
|
||||
int ret;
|
||||
int len, dlen;
|
||||
__u8 *udpdata;
|
||||
__be32 *udpdata32;
|
||||
|
||||
offset = offset - sizeof(struct udphdr);
|
||||
|
||||
if (!pskb_pull(skb, offset))
|
||||
len = skb->len - offset;
|
||||
dlen = offset + min(len, 8);
|
||||
udpdata = skb_gro_header(skb, dlen, offset);
|
||||
udpdata32 = (__be32 *)udpdata;
|
||||
if (unlikely(!udpdata))
|
||||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -194,11 +198,10 @@ struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
|
|||
if (!ops || !ops->callbacks.gro_receive)
|
||||
goto out;
|
||||
|
||||
ret = __xfrm4_udp_encap_rcv(sk, skb, false);
|
||||
if (ret)
|
||||
/* check if it is a keepalive or IKE packet */
|
||||
if (len <= sizeof(struct ip_esp_hdr) || udpdata32[0] == 0)
|
||||
goto out;
|
||||
|
||||
skb_push(skb, offset);
|
||||
NAPI_GRO_CB(skb)->proto = IPPROTO_UDP;
|
||||
|
||||
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
|
||||
|
@ -208,7 +211,6 @@ struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
|
|||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
skb_push(skb, offset);
|
||||
NAPI_GRO_CB(skb)->same_flow = 0;
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
|
||||
|
|
|
@ -137,47 +137,16 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_INET6_ESPINTCP
|
||||
struct esp_tcp_sk {
|
||||
struct sock *sk;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
static void esp_free_tcp_sk(struct rcu_head *head)
|
||||
{
|
||||
struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);
|
||||
|
||||
sock_put(esk->sk);
|
||||
kfree(esk);
|
||||
}
|
||||
|
||||
static struct sock *esp6_find_tcp_sk(struct xfrm_state *x)
|
||||
{
|
||||
struct xfrm_encap_tmpl *encap = x->encap;
|
||||
struct net *net = xs_net(x);
|
||||
struct esp_tcp_sk *esk;
|
||||
__be16 sport, dport;
|
||||
struct sock *nsk;
|
||||
struct sock *sk;
|
||||
|
||||
sk = rcu_dereference(x->encap_sk);
|
||||
if (sk && sk->sk_state == TCP_ESTABLISHED)
|
||||
return sk;
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
sport = encap->encap_sport;
|
||||
dport = encap->encap_dport;
|
||||
nsk = rcu_dereference_protected(x->encap_sk,
|
||||
lockdep_is_held(&x->lock));
|
||||
if (sk && sk == nsk) {
|
||||
esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
|
||||
if (!esk) {
|
||||
spin_unlock_bh(&x->lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
RCU_INIT_POINTER(x->encap_sk, NULL);
|
||||
esk->sk = sk;
|
||||
call_rcu(&esk->rcu, esp_free_tcp_sk);
|
||||
}
|
||||
spin_unlock_bh(&x->lock);
|
||||
|
||||
sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, &x->id.daddr.in6,
|
||||
|
@ -190,20 +159,6 @@ static struct sock *esp6_find_tcp_sk(struct xfrm_state *x)
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
nsk = rcu_dereference_protected(x->encap_sk,
|
||||
lockdep_is_held(&x->lock));
|
||||
if (encap->encap_sport != sport ||
|
||||
encap->encap_dport != dport) {
|
||||
sock_put(sk);
|
||||
sk = nsk ?: ERR_PTR(-EREMCHG);
|
||||
} else if (sk == nsk) {
|
||||
sock_put(sk);
|
||||
} else {
|
||||
rcu_assign_pointer(x->encap_sk, sk);
|
||||
}
|
||||
spin_unlock_bh(&x->lock);
|
||||
|
||||
return sk;
|
||||
}
|
||||
|
||||
|
@ -216,8 +171,10 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
|
|||
|
||||
sk = esp6_find_tcp_sk(x);
|
||||
err = PTR_ERR_OR_ZERO(sk);
|
||||
if (err)
|
||||
if (err) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bh_lock_sock(sk);
|
||||
if (sock_owned_by_user(sk))
|
||||
|
@ -226,6 +183,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
|
|||
err = espintcp_push_skb(sk, skb);
|
||||
bh_unlock_sock(sk);
|
||||
|
||||
sock_put(sk);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
|
@ -422,6 +381,8 @@ static struct ip_esp_hdr *esp6_output_tcp_encap(struct xfrm_state *x,
|
|||
if (IS_ERR(sk))
|
||||
return ERR_CAST(sk);
|
||||
|
||||
sock_put(sk);
|
||||
|
||||
*lenp = htons(len);
|
||||
esph = (struct ip_esp_hdr *)(lenp + 1);
|
||||
|
||||
|
|
|
@ -179,14 +179,18 @@ struct sk_buff *xfrm6_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
|
|||
int offset = skb_gro_offset(skb);
|
||||
const struct net_offload *ops;
|
||||
struct sk_buff *pp = NULL;
|
||||
int ret;
|
||||
int len, dlen;
|
||||
__u8 *udpdata;
|
||||
__be32 *udpdata32;
|
||||
|
||||
if (skb->protocol == htons(ETH_P_IP))
|
||||
return xfrm4_gro_udp_encap_rcv(sk, head, skb);
|
||||
|
||||
offset = offset - sizeof(struct udphdr);
|
||||
|
||||
if (!pskb_pull(skb, offset))
|
||||
len = skb->len - offset;
|
||||
dlen = offset + min(len, 8);
|
||||
udpdata = skb_gro_header(skb, dlen, offset);
|
||||
udpdata32 = (__be32 *)udpdata;
|
||||
if (unlikely(!udpdata))
|
||||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -194,11 +198,10 @@ struct sk_buff *xfrm6_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
|
|||
if (!ops || !ops->callbacks.gro_receive)
|
||||
goto out;
|
||||
|
||||
ret = __xfrm6_udp_encap_rcv(sk, skb, false);
|
||||
if (ret)
|
||||
/* check if it is a keepalive or IKE packet */
|
||||
if (len <= sizeof(struct ip_esp_hdr) || udpdata32[0] == 0)
|
||||
goto out;
|
||||
|
||||
skb_push(skb, offset);
|
||||
NAPI_GRO_CB(skb)->proto = IPPROTO_UDP;
|
||||
|
||||
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
|
||||
|
@ -208,7 +211,6 @@ struct sk_buff *xfrm6_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
|
|||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
skb_push(skb, offset);
|
||||
NAPI_GRO_CB(skb)->same_flow = 0;
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
|
||||
|
|
|
@ -171,8 +171,10 @@ int espintcp_queue_out(struct sock *sk, struct sk_buff *skb)
|
|||
struct espintcp_ctx *ctx = espintcp_getctx(sk);
|
||||
|
||||
if (skb_queue_len(&ctx->out_queue) >=
|
||||
READ_ONCE(net_hotdata.max_backlog))
|
||||
READ_ONCE(net_hotdata.max_backlog)) {
|
||||
kfree_skb(skb);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
__skb_queue_tail(&ctx->out_queue, skb);
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ static int ipcomp_post_acomp(struct sk_buff *skb, int err, int hlen)
|
|||
{
|
||||
struct acomp_req *req = ipcomp_cb(skb)->req;
|
||||
struct ipcomp_req_extra *extra;
|
||||
const int plen = skb->data_len;
|
||||
struct scatterlist *dsg;
|
||||
int len, dlen;
|
||||
|
||||
|
@ -64,7 +63,7 @@ static int ipcomp_post_acomp(struct sk_buff *skb, int err, int hlen)
|
|||
|
||||
/* Only update truesize on input. */
|
||||
if (!hlen)
|
||||
skb->truesize += dlen - plen;
|
||||
skb->truesize += dlen;
|
||||
skb->data_len = dlen;
|
||||
skb->len += dlen;
|
||||
|
||||
|
|
|
@ -1581,6 +1581,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
|
|||
struct xfrm_policy *delpol;
|
||||
struct hlist_head *chain;
|
||||
|
||||
/* Sanitize mark before store */
|
||||
policy->mark.v &= policy->mark.m;
|
||||
|
||||
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
|
||||
chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
|
||||
if (chain)
|
||||
|
|
|
@ -838,9 +838,6 @@ int __xfrm_state_delete(struct xfrm_state *x)
|
|||
xfrm_nat_keepalive_state_updated(x);
|
||||
spin_unlock(&net->xfrm.xfrm_state_lock);
|
||||
|
||||
if (x->encap_sk)
|
||||
sock_put(rcu_dereference_raw(x->encap_sk));
|
||||
|
||||
xfrm_dev_state_delete(x);
|
||||
|
||||
/* All xfrm_state objects are created by xfrm_state_alloc.
|
||||
|
@ -1721,6 +1718,9 @@ static void __xfrm_state_insert(struct xfrm_state *x)
|
|||
|
||||
list_add(&x->km.all, &net->xfrm.state_all);
|
||||
|
||||
/* Sanitize mark before store */
|
||||
x->mark.v &= x->mark.m;
|
||||
|
||||
h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
|
||||
x->props.reqid, x->props.family);
|
||||
XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue