Skip to content

Commit e0f9f0e

Browse files
committed
Merge tag 'ipsec-next-2023-10-28' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2023-10-28 1) Remove unused function declarations of xfrm4_extract_input and xfrm6_extract_input. From Yue Haibing. 2) Annotate struct xfrm_sec_ctx with __counted_by. From Kees Cook. 3) Support GRO decapsulation for ESP in UDP encapsulation. From Antony Antony et all. 4) Replace the xfrm session decode with flow dissector. From Florian Westphal. 5) Fix a use after free in __xfrm6_udp_encap_rcv. 6) Fix the layer 4 flowi decoding. From Florian Westphal. * tag 'ipsec-next-2023-10-28' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next: xfrm: policy: fix layer 4 flowi decoding xfrm Fix use after free in __xfrm6_udp_encap_rcv. xfrm: policy: replace session decode with flow dissector xfrm: move mark and oif flowi decode into common code xfrm: pass struct net to xfrm_decode_session wrappers xfrm: Support GRO for IPv6 ESP in UDP encapsulation xfrm: Support GRO for IPv4 ESP in UDP encapsulation xfrm: Use the XFRM_GRO to indicate a GRO call on input xfrm: Annotate struct xfrm_sec_ctx with __counted_by xfrm: Remove unused function declarations ==================== Link: https://lore.kernel.org/r/20231028084328.3119236-1-steffen.klassert@secunet.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 55c9004 + eefed76 commit e0f9f0e

20 files changed

+343
-241
lines changed

include/net/gro.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct napi_gro_cb {
4141
/* Number of segments aggregated. */
4242
u16 count;
4343

44-
/* Used in ipv6_gro_receive() and foo-over-udp */
44+
/* Used in ipv6_gro_receive() and foo-over-udp and esp-in-udp */
4545
u16 proto;
4646

4747
/* Used in napi_gro_cb::free */

include/net/ipv6_stubs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ struct ipv6_stub {
6060
#if IS_ENABLED(CONFIG_XFRM)
6161
void (*xfrm6_local_rxpmtu)(struct sk_buff *skb, u32 mtu);
6262
int (*xfrm6_udp_encap_rcv)(struct sock *sk, struct sk_buff *skb);
63+
struct sk_buff *(*xfrm6_gro_udp_encap_rcv)(struct sock *sk,
64+
struct list_head *head,
65+
struct sk_buff *skb);
6366
int (*xfrm6_rcv_encap)(struct sk_buff *skb, int nexthdr, __be32 spi,
6467
int encap_type);
6568
#endif

include/net/xfrm.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,20 +1207,20 @@ static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir,
12071207
return __xfrm_policy_check2(sk, dir, skb, AF_INET6, 1);
12081208
}
12091209

1210-
int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
1210+
int __xfrm_decode_session(struct net *net, struct sk_buff *skb, struct flowi *fl,
12111211
unsigned int family, int reverse);
12121212

1213-
static inline int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
1213+
static inline int xfrm_decode_session(struct net *net, struct sk_buff *skb, struct flowi *fl,
12141214
unsigned int family)
12151215
{
1216-
return __xfrm_decode_session(skb, fl, family, 0);
1216+
return __xfrm_decode_session(net, skb, fl, family, 0);
12171217
}
12181218

1219-
static inline int xfrm_decode_session_reverse(struct sk_buff *skb,
1219+
static inline int xfrm_decode_session_reverse(struct net *net, struct sk_buff *skb,
12201220
struct flowi *fl,
12211221
unsigned int family)
12221222
{
1223-
return __xfrm_decode_session(skb, fl, family, 1);
1223+
return __xfrm_decode_session(net, skb, fl, family, 1);
12241224
}
12251225

12261226
int __xfrm_route_forward(struct sk_buff *skb, unsigned short family);
@@ -1296,7 +1296,7 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk
12961296
{
12971297
return 1;
12981298
}
1299-
static inline int xfrm_decode_session_reverse(struct sk_buff *skb,
1299+
static inline int xfrm_decode_session_reverse(struct net *net, struct sk_buff *skb,
13001300
struct flowi *fl,
13011301
unsigned int family)
13021302
{
@@ -1669,7 +1669,6 @@ int pktgen_xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb);
16691669
#endif
16701670

16711671
void xfrm_local_error(struct sk_buff *skb, int mtu);
1672-
int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
16731672
int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
16741673
int encap_type);
16751674
int xfrm4_transport_finish(struct sk_buff *skb, int async);
@@ -1689,7 +1688,6 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char prot
16891688
int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
16901689
int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
16911690
void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
1692-
int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
16931691
int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi,
16941692
struct ip6_tnl *t);
16951693
int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
@@ -1712,6 +1710,10 @@ int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb);
17121710
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu);
17131711
int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
17141712
int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
1713+
struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
1714+
struct sk_buff *skb);
1715+
struct sk_buff *xfrm6_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
1716+
struct sk_buff *skb);
17151717
int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval,
17161718
int optlen);
17171719
#else

include/uapi/linux/xfrm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <linux/in6.h>
66
#include <linux/types.h>
7+
#include <linux/stddef.h>
78

89
/* All of the structures in this file may not change size as they are
910
* passed into the kernel from userspace via netlink sockets.
@@ -33,7 +34,7 @@ struct xfrm_sec_ctx {
3334
__u8 ctx_alg;
3435
__u16 ctx_len;
3536
__u32 ctx_sid;
36-
char ctx_str[];
37+
char ctx_str[] __counted_by(ctx_len);
3738
};
3839

3940
/* Security Context Domains of Interpretation */

net/ipv4/esp4_offload.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
3333
int offset = skb_gro_offset(skb);
3434
struct xfrm_offload *xo;
3535
struct xfrm_state *x;
36+
int encap_type = 0;
3637
__be32 seq;
3738
__be32 spi;
3839

@@ -70,14 +71,17 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
7071

7172
xo->flags |= XFRM_GRO;
7273

74+
if (NAPI_GRO_CB(skb)->proto == IPPROTO_UDP)
75+
encap_type = UDP_ENCAP_ESPINUDP;
76+
7377
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
7478
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
7579
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
7680
XFRM_SPI_SKB_CB(skb)->seq = seq;
7781

7882
/* We don't need to handle errors from xfrm_input, it does all
7983
* the error handling and frees the resources on error. */
80-
xfrm_input(skb, IPPROTO_ESP, spi, -2);
84+
xfrm_input(skb, IPPROTO_ESP, spi, encap_type);
8185

8286
return ERR_PTR(-EINPROGRESS);
8387
out_reset:

net/ipv4/icmp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
517517
} else
518518
return rt;
519519

520-
err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4_dec), AF_INET);
520+
err = xfrm_decode_session_reverse(net, skb_in, flowi4_to_flowi(&fl4_dec), AF_INET);
521521
if (err)
522522
goto relookup_failed;
523523

net/ipv4/ip_vti.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,11 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
288288
switch (skb->protocol) {
289289
case htons(ETH_P_IP):
290290
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
291-
xfrm_decode_session(skb, &fl, AF_INET);
291+
xfrm_decode_session(dev_net(dev), skb, &fl, AF_INET);
292292
break;
293293
case htons(ETH_P_IPV6):
294294
memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
295-
xfrm_decode_session(skb, &fl, AF_INET6);
295+
xfrm_decode_session(dev_net(dev), skb, &fl, AF_INET6);
296296
break;
297297
default:
298298
goto tx_err;

net/ipv4/netfilter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ int ip_route_me_harder(struct net *net, struct sock *sk, struct sk_buff *skb, un
6262

6363
#ifdef CONFIG_XFRM
6464
if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
65-
xfrm_decode_session(skb, flowi4_to_flowi(&fl4), AF_INET) == 0) {
65+
xfrm_decode_session(net, skb, flowi4_to_flowi(&fl4), AF_INET) == 0) {
6666
struct dst_entry *dst = skb_dst(skb);
6767
skb_dst_set(skb, NULL);
6868
dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), sk, 0);

net/ipv4/udp.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,6 +2630,19 @@ void udp_destroy_sock(struct sock *sk)
26302630
}
26312631
}
26322632

2633+
static void set_xfrm_gro_udp_encap_rcv(__u16 encap_type, unsigned short family,
2634+
struct sock *sk)
2635+
{
2636+
#ifdef CONFIG_XFRM
2637+
if (udp_test_bit(GRO_ENABLED, sk) && encap_type == UDP_ENCAP_ESPINUDP) {
2638+
if (family == AF_INET)
2639+
WRITE_ONCE(udp_sk(sk)->gro_receive, xfrm4_gro_udp_encap_rcv);
2640+
else if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
2641+
WRITE_ONCE(udp_sk(sk)->gro_receive, ipv6_stub->xfrm6_gro_udp_encap_rcv);
2642+
}
2643+
#endif
2644+
}
2645+
26332646
/*
26342647
* Socket option code for UDP
26352648
*/
@@ -2679,6 +2692,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
26792692
case 0:
26802693
#ifdef CONFIG_XFRM
26812694
case UDP_ENCAP_ESPINUDP:
2695+
set_xfrm_gro_udp_encap_rcv(val, sk->sk_family, sk);
2696+
fallthrough;
26822697
case UDP_ENCAP_ESPINUDP_NON_IKE:
26832698
#if IS_ENABLED(CONFIG_IPV6)
26842699
if (sk->sk_family == AF_INET6)
@@ -2721,6 +2736,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
27212736
udp_tunnel_encap_enable(sk);
27222737
udp_assign_bit(GRO_ENABLED, sk, valbool);
27232738
udp_assign_bit(ACCEPT_L4, sk, valbool);
2739+
set_xfrm_gro_udp_encap_rcv(up->encap_type, sk->sk_family, sk);
27242740
break;
27252741

27262742
/*

net/ipv4/xfrm4_input.c

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <linux/netfilter_ipv4.h>
1818
#include <net/ip.h>
1919
#include <net/xfrm.h>
20+
#include <net/protocol.h>
21+
#include <net/gro.h>
2022

2123
static int xfrm4_rcv_encap_finish2(struct net *net, struct sock *sk,
2224
struct sk_buff *skb)
@@ -72,14 +74,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
7274
return 0;
7375
}
7476

75-
/* If it's a keepalive packet, then just eat it.
76-
* If it's an encapsulated packet, then pass it to the
77-
* IPsec xfrm input.
78-
* Returns 0 if skb passed to xfrm or was dropped.
79-
* Returns >0 if skb should be passed to UDP.
80-
* Returns <0 if skb should be resubmitted (-ret is protocol)
81-
*/
82-
int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
77+
static int __xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb, bool pull)
8378
{
8479
struct udp_sock *up = udp_sk(sk);
8580
struct udphdr *uh;
@@ -110,7 +105,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
110105
case UDP_ENCAP_ESPINUDP:
111106
/* Check if this is a keepalive packet. If so, eat it. */
112107
if (len == 1 && udpdata[0] == 0xff) {
113-
goto drop;
108+
return -EINVAL;
114109
} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
115110
/* ESP Packet without Non-ESP header */
116111
len = sizeof(struct udphdr);
@@ -121,7 +116,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
121116
case UDP_ENCAP_ESPINUDP_NON_IKE:
122117
/* Check if this is a keepalive packet. If so, eat it. */
123118
if (len == 1 && udpdata[0] == 0xff) {
124-
goto drop;
119+
return -EINVAL;
125120
} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
126121
udpdata32[0] == 0 && udpdata32[1] == 0) {
127122

@@ -139,33 +134,97 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
139134
* protocol to ESP, and then call into the transform receiver.
140135
*/
141136
if (skb_unclone(skb, GFP_ATOMIC))
142-
goto drop;
137+
return -EINVAL;
143138

144139
/* Now we can update and verify the packet length... */
145140
iph = ip_hdr(skb);
146141
iphlen = iph->ihl << 2;
147142
iph->tot_len = htons(ntohs(iph->tot_len) - len);
148143
if (skb->len < iphlen + len) {
149144
/* packet is too small!?! */
150-
goto drop;
145+
return -EINVAL;
151146
}
152147

153148
/* pull the data buffer up to the ESP header and set the
154149
* transport header to point to ESP. Keep UDP on the stack
155150
* for later.
156151
*/
157-
__skb_pull(skb, len);
158-
skb_reset_transport_header(skb);
152+
if (pull) {
153+
__skb_pull(skb, len);
154+
skb_reset_transport_header(skb);
155+
} else {
156+
skb_set_transport_header(skb, len);
157+
}
159158

160159
/* process ESP */
161-
return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
162-
163-
drop:
164-
kfree_skb(skb);
165160
return 0;
166161
}
162+
163+
/* If it's a keepalive packet, then just eat it.
164+
* If it's an encapsulated packet, then pass it to the
165+
* IPsec xfrm input.
166+
* Returns 0 if skb passed to xfrm or was dropped.
167+
* Returns >0 if skb should be passed to UDP.
168+
* Returns <0 if skb should be resubmitted (-ret is protocol)
169+
*/
170+
int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
171+
{
172+
int ret;
173+
174+
ret = __xfrm4_udp_encap_rcv(sk, skb, true);
175+
if (!ret)
176+
return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0,
177+
udp_sk(sk)->encap_type);
178+
179+
if (ret < 0) {
180+
kfree_skb(skb);
181+
return 0;
182+
}
183+
184+
return ret;
185+
}
167186
EXPORT_SYMBOL(xfrm4_udp_encap_rcv);
168187

188+
struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
189+
struct sk_buff *skb)
190+
{
191+
int offset = skb_gro_offset(skb);
192+
const struct net_offload *ops;
193+
struct sk_buff *pp = NULL;
194+
int ret;
195+
196+
offset = offset - sizeof(struct udphdr);
197+
198+
if (!pskb_pull(skb, offset))
199+
return NULL;
200+
201+
rcu_read_lock();
202+
ops = rcu_dereference(inet_offloads[IPPROTO_ESP]);
203+
if (!ops || !ops->callbacks.gro_receive)
204+
goto out;
205+
206+
ret = __xfrm4_udp_encap_rcv(sk, skb, false);
207+
if (ret)
208+
goto out;
209+
210+
skb_push(skb, offset);
211+
NAPI_GRO_CB(skb)->proto = IPPROTO_UDP;
212+
213+
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
214+
rcu_read_unlock();
215+
216+
return pp;
217+
218+
out:
219+
rcu_read_unlock();
220+
skb_push(skb, offset);
221+
NAPI_GRO_CB(skb)->same_flow = 0;
222+
NAPI_GRO_CB(skb)->flush = 1;
223+
224+
return NULL;
225+
}
226+
EXPORT_SYMBOL(xfrm4_gro_udp_encap_rcv);
227+
169228
int xfrm4_rcv(struct sk_buff *skb)
170229
{
171230
return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);

0 commit comments

Comments
 (0)