Skip to content

Commit 942110f

Browse files
committed
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2020-05-29 1) Several fixes for ESP gro/gso in transport and beet mode when IPv6 extension headers are present. From Xin Long. 2) Fix a wrong comment on XFRMA_OFFLOAD_DEV. From Antony Antony. 3) Fix sk_destruct callback handling on ESP in TCP encapsulation. From Sabrina Dubroca. 4) Fix a use after free in xfrm_output_gso when used with vxlan. From Xin Long. 5) Fix secpath handling of VTI when used wiuth IPCOMP. From Xin Long. 6) Fix an oops when deleting a x-netns xfrm interface. From Nicolas Dichtel. 7) Fix a possible warning on policy updates. We had a case where it was possible to add two policies with the same lookup keys. From Xin Long. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7c6d2ec + f6a23d8 commit 942110f

File tree

11 files changed

+104
-44
lines changed

11 files changed

+104
-44
lines changed

include/net/espintcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct espintcp_ctx {
2525
struct espintcp_msg partial;
2626
void (*saved_data_ready)(struct sock *sk);
2727
void (*saved_write_space)(struct sock *sk);
28+
void (*saved_destruct)(struct sock *sk);
2829
struct work_struct work;
2930
bool tx_running;
3031
};

include/uapi/linux/xfrm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ enum xfrm_attr_type_t {
304304
XFRMA_PROTO, /* __u8 */
305305
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
306306
XFRMA_PAD,
307-
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
307+
XFRMA_OFFLOAD_DEV, /* struct xfrm_user_offload */
308308
XFRMA_SET_MARK, /* __u32 */
309309
XFRMA_SET_MARK_MASK, /* __u32 */
310310
XFRMA_IF_ID, /* __u32 */

net/ipv4/esp4_offload.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,8 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
6363
sp->olen++;
6464

6565
xo = xfrm_offload(skb);
66-
if (!xo) {
67-
xfrm_state_put(x);
66+
if (!xo)
6867
goto out_reset;
69-
}
7068
}
7169

7270
xo->flags |= XFRM_GRO;
@@ -139,19 +137,27 @@ static struct sk_buff *xfrm4_beet_gso_segment(struct xfrm_state *x,
139137
struct xfrm_offload *xo = xfrm_offload(skb);
140138
struct sk_buff *segs = ERR_PTR(-EINVAL);
141139
const struct net_offload *ops;
142-
int proto = xo->proto;
140+
u8 proto = xo->proto;
143141

144142
skb->transport_header += x->props.header_len;
145143

146-
if (proto == IPPROTO_BEETPH) {
147-
struct ip_beet_phdr *ph = (struct ip_beet_phdr *)skb->data;
144+
if (x->sel.family != AF_INET6) {
145+
if (proto == IPPROTO_BEETPH) {
146+
struct ip_beet_phdr *ph =
147+
(struct ip_beet_phdr *)skb->data;
148+
149+
skb->transport_header += ph->hdrlen * 8;
150+
proto = ph->nexthdr;
151+
} else {
152+
skb->transport_header -= IPV4_BEET_PHMAXLEN;
153+
}
154+
} else {
155+
__be16 frag;
148156

149-
skb->transport_header += ph->hdrlen * 8;
150-
proto = ph->nexthdr;
151-
} else if (x->sel.family != AF_INET6) {
152-
skb->transport_header -= IPV4_BEET_PHMAXLEN;
153-
} else if (proto == IPPROTO_TCP) {
154-
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
157+
skb->transport_header +=
158+
ipv6_skip_exthdr(skb, 0, &proto, &frag);
159+
if (proto == IPPROTO_TCP)
160+
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
155161
}
156162

157163
__skb_pull(skb, skb_transport_offset(skb));

net/ipv4/ip_vti.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,28 @@ static int vti_rcv_proto(struct sk_buff *skb)
9393

9494
static int vti_rcv_tunnel(struct sk_buff *skb)
9595
{
96-
return vti_rcv(skb, ip_hdr(skb)->saddr, true);
96+
struct ip_tunnel_net *itn = net_generic(dev_net(skb->dev), vti_net_id);
97+
const struct iphdr *iph = ip_hdr(skb);
98+
struct ip_tunnel *tunnel;
99+
100+
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
101+
iph->saddr, iph->daddr, 0);
102+
if (tunnel) {
103+
struct tnl_ptk_info tpi = {
104+
.proto = htons(ETH_P_IP),
105+
};
106+
107+
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
108+
goto drop;
109+
if (iptunnel_pull_header(skb, 0, tpi.proto, false))
110+
goto drop;
111+
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, false);
112+
}
113+
114+
return -EINVAL;
115+
drop:
116+
kfree_skb(skb);
117+
return 0;
97118
}
98119

99120
static int vti_rcv_cb(struct sk_buff *skb, int err)

net/ipv6/esp6_offload.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
8585
sp->olen++;
8686

8787
xo = xfrm_offload(skb);
88-
if (!xo) {
89-
xfrm_state_put(x);
88+
if (!xo)
9089
goto out_reset;
91-
}
9290
}
9391

9492
xo->flags |= XFRM_GRO;
@@ -123,9 +121,16 @@ static void esp6_gso_encap(struct xfrm_state *x, struct sk_buff *skb)
123121
struct ip_esp_hdr *esph;
124122
struct ipv6hdr *iph = ipv6_hdr(skb);
125123
struct xfrm_offload *xo = xfrm_offload(skb);
126-
int proto = iph->nexthdr;
124+
u8 proto = iph->nexthdr;
127125

128126
skb_push(skb, -skb_network_offset(skb));
127+
128+
if (x->outer_mode.encap == XFRM_MODE_TRANSPORT) {
129+
__be16 frag;
130+
131+
ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &proto, &frag);
132+
}
133+
129134
esph = ip_esp_hdr(skb);
130135
*skb_mac_header(skb) = IPPROTO_ESP;
131136

@@ -166,23 +171,31 @@ static struct sk_buff *xfrm6_beet_gso_segment(struct xfrm_state *x,
166171
struct xfrm_offload *xo = xfrm_offload(skb);
167172
struct sk_buff *segs = ERR_PTR(-EINVAL);
168173
const struct net_offload *ops;
169-
int proto = xo->proto;
174+
u8 proto = xo->proto;
170175

171176
skb->transport_header += x->props.header_len;
172177

173-
if (proto == IPPROTO_BEETPH) {
174-
struct ip_beet_phdr *ph = (struct ip_beet_phdr *)skb->data;
175-
176-
skb->transport_header += ph->hdrlen * 8;
177-
proto = ph->nexthdr;
178-
}
179-
180178
if (x->sel.family != AF_INET6) {
181179
skb->transport_header -=
182180
(sizeof(struct ipv6hdr) - sizeof(struct iphdr));
183181

182+
if (proto == IPPROTO_BEETPH) {
183+
struct ip_beet_phdr *ph =
184+
(struct ip_beet_phdr *)skb->data;
185+
186+
skb->transport_header += ph->hdrlen * 8;
187+
proto = ph->nexthdr;
188+
} else {
189+
skb->transport_header -= IPV4_BEET_PHMAXLEN;
190+
}
191+
184192
if (proto == IPPROTO_TCP)
185193
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
194+
} else {
195+
__be16 frag;
196+
197+
skb->transport_header +=
198+
ipv6_skip_exthdr(skb, 0, &proto, &frag);
186199
}
187200

188201
__skb_pull(skb, skb_transport_offset(skb));

net/xfrm/espintcp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ static void espintcp_destruct(struct sock *sk)
379379
{
380380
struct espintcp_ctx *ctx = espintcp_getctx(sk);
381381

382+
ctx->saved_destruct(sk);
382383
kfree(ctx);
383384
}
384385

@@ -419,6 +420,7 @@ static int espintcp_init_sk(struct sock *sk)
419420
sk->sk_socket->ops = &espintcp_ops;
420421
ctx->saved_data_ready = sk->sk_data_ready;
421422
ctx->saved_write_space = sk->sk_write_space;
423+
ctx->saved_destruct = sk->sk_destruct;
422424
sk->sk_data_ready = espintcp_data_ready;
423425
sk->sk_write_space = espintcp_write_space;
424426
sk->sk_destruct = espintcp_destruct;

net/xfrm/xfrm_device.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb,
2525
struct xfrm_offload *xo = xfrm_offload(skb);
2626

2727
skb_reset_mac_len(skb);
28-
pskb_pull(skb, skb->mac_len + hsize + x->props.header_len);
29-
30-
if (xo->flags & XFRM_GSO_SEGMENT) {
31-
skb_reset_transport_header(skb);
28+
if (xo->flags & XFRM_GSO_SEGMENT)
3229
skb->transport_header -= x->props.header_len;
33-
}
30+
31+
pskb_pull(skb, skb_transport_offset(skb) + x->props.header_len);
3432
}
3533

3634
static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb,

net/xfrm/xfrm_input.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
644644
dev_put(skb->dev);
645645

646646
spin_lock(&x->lock);
647-
if (nexthdr <= 0) {
647+
if (nexthdr < 0) {
648648
if (nexthdr == -EBADMSG) {
649649
xfrm_audit_state_icvfail(x, skb,
650650
x->type->proto);

net/xfrm/xfrm_interface.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,28 @@ static struct rtnl_link_ops xfrmi_link_ops __read_mostly = {
750750
.get_link_net = xfrmi_get_link_net,
751751
};
752752

753+
static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list)
754+
{
755+
struct net *net;
756+
LIST_HEAD(list);
757+
758+
rtnl_lock();
759+
list_for_each_entry(net, net_exit_list, exit_list) {
760+
struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
761+
struct xfrm_if __rcu **xip;
762+
struct xfrm_if *xi;
763+
764+
for (xip = &xfrmn->xfrmi[0];
765+
(xi = rtnl_dereference(*xip)) != NULL;
766+
xip = &xi->next)
767+
unregister_netdevice_queue(xi->dev, &list);
768+
}
769+
unregister_netdevice_many(&list);
770+
rtnl_unlock();
771+
}
772+
753773
static struct pernet_operations xfrmi_net_ops = {
774+
.exit_batch = xfrmi_exit_batch_net,
754775
.id = &xfrmi_net_id,
755776
.size = sizeof(struct xfrmi_net),
756777
};

net/xfrm/xfrm_output.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,20 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
583583
xfrm_state_hold(x);
584584

585585
if (skb_is_gso(skb)) {
586-
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
586+
if (skb->inner_protocol)
587+
return xfrm_output_gso(net, sk, skb);
587588

588-
return xfrm_output2(net, sk, skb);
589+
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
590+
goto out;
589591
}
590592

591593
if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
592594
goto out;
595+
} else {
596+
if (skb_is_gso(skb))
597+
return xfrm_output_gso(net, sk, skb);
593598
}
594599

595-
if (skb_is_gso(skb))
596-
return xfrm_output_gso(net, sk, skb);
597-
598600
if (skb->ip_summed == CHECKSUM_PARTIAL) {
599601
err = skb_checksum_help(skb);
600602
if (err) {
@@ -640,7 +642,8 @@ void xfrm_local_error(struct sk_buff *skb, int mtu)
640642

641643
if (skb->protocol == htons(ETH_P_IP))
642644
proto = AF_INET;
643-
else if (skb->protocol == htons(ETH_P_IPV6))
645+
else if (skb->protocol == htons(ETH_P_IPV6) &&
646+
skb->sk->sk_family == AF_INET6)
644647
proto = AF_INET6;
645648
else
646649
return;

0 commit comments

Comments
 (0)