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 <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-05-29 13:05:56 -07:00
commit 942110fdf2
11 changed files with 104 additions and 44 deletions

View File

@ -25,6 +25,7 @@ struct espintcp_ctx {
struct espintcp_msg partial;
void (*saved_data_ready)(struct sock *sk);
void (*saved_write_space)(struct sock *sk);
void (*saved_destruct)(struct sock *sk);
struct work_struct work;
bool tx_running;
};

View File

@ -304,7 +304,7 @@ enum xfrm_attr_type_t {
XFRMA_PROTO, /* __u8 */
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
XFRMA_PAD,
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
XFRMA_OFFLOAD_DEV, /* struct xfrm_user_offload */
XFRMA_SET_MARK, /* __u32 */
XFRMA_SET_MARK_MASK, /* __u32 */
XFRMA_IF_ID, /* __u32 */

View File

@ -63,10 +63,8 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
sp->olen++;
xo = xfrm_offload(skb);
if (!xo) {
xfrm_state_put(x);
if (!xo)
goto out_reset;
}
}
xo->flags |= XFRM_GRO;
@ -139,19 +137,27 @@ static struct sk_buff *xfrm4_beet_gso_segment(struct xfrm_state *x,
struct xfrm_offload *xo = xfrm_offload(skb);
struct sk_buff *segs = ERR_PTR(-EINVAL);
const struct net_offload *ops;
int proto = xo->proto;
u8 proto = xo->proto;
skb->transport_header += x->props.header_len;
if (proto == IPPROTO_BEETPH) {
struct ip_beet_phdr *ph = (struct ip_beet_phdr *)skb->data;
if (x->sel.family != AF_INET6) {
if (proto == IPPROTO_BEETPH) {
struct ip_beet_phdr *ph =
(struct ip_beet_phdr *)skb->data;
skb->transport_header += ph->hdrlen * 8;
proto = ph->nexthdr;
} else if (x->sel.family != AF_INET6) {
skb->transport_header -= IPV4_BEET_PHMAXLEN;
} else if (proto == IPPROTO_TCP) {
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
skb->transport_header += ph->hdrlen * 8;
proto = ph->nexthdr;
} else {
skb->transport_header -= IPV4_BEET_PHMAXLEN;
}
} else {
__be16 frag;
skb->transport_header +=
ipv6_skip_exthdr(skb, 0, &proto, &frag);
if (proto == IPPROTO_TCP)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
}
__skb_pull(skb, skb_transport_offset(skb));

View File

@ -93,7 +93,28 @@ static int vti_rcv_proto(struct sk_buff *skb)
static int vti_rcv_tunnel(struct sk_buff *skb)
{
return vti_rcv(skb, ip_hdr(skb)->saddr, true);
struct ip_tunnel_net *itn = net_generic(dev_net(skb->dev), vti_net_id);
const struct iphdr *iph = ip_hdr(skb);
struct ip_tunnel *tunnel;
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
iph->saddr, iph->daddr, 0);
if (tunnel) {
struct tnl_ptk_info tpi = {
.proto = htons(ETH_P_IP),
};
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop;
if (iptunnel_pull_header(skb, 0, tpi.proto, false))
goto drop;
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, false);
}
return -EINVAL;
drop:
kfree_skb(skb);
return 0;
}
static int vti_rcv_cb(struct sk_buff *skb, int err)

View File

@ -85,10 +85,8 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
sp->olen++;
xo = xfrm_offload(skb);
if (!xo) {
xfrm_state_put(x);
if (!xo)
goto out_reset;
}
}
xo->flags |= XFRM_GRO;
@ -123,9 +121,16 @@ static void esp6_gso_encap(struct xfrm_state *x, struct sk_buff *skb)
struct ip_esp_hdr *esph;
struct ipv6hdr *iph = ipv6_hdr(skb);
struct xfrm_offload *xo = xfrm_offload(skb);
int proto = iph->nexthdr;
u8 proto = iph->nexthdr;
skb_push(skb, -skb_network_offset(skb));
if (x->outer_mode.encap == XFRM_MODE_TRANSPORT) {
__be16 frag;
ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &proto, &frag);
}
esph = ip_esp_hdr(skb);
*skb_mac_header(skb) = IPPROTO_ESP;
@ -166,23 +171,31 @@ static struct sk_buff *xfrm6_beet_gso_segment(struct xfrm_state *x,
struct xfrm_offload *xo = xfrm_offload(skb);
struct sk_buff *segs = ERR_PTR(-EINVAL);
const struct net_offload *ops;
int proto = xo->proto;
u8 proto = xo->proto;
skb->transport_header += x->props.header_len;
if (proto == IPPROTO_BEETPH) {
struct ip_beet_phdr *ph = (struct ip_beet_phdr *)skb->data;
skb->transport_header += ph->hdrlen * 8;
proto = ph->nexthdr;
}
if (x->sel.family != AF_INET6) {
skb->transport_header -=
(sizeof(struct ipv6hdr) - sizeof(struct iphdr));
if (proto == IPPROTO_BEETPH) {
struct ip_beet_phdr *ph =
(struct ip_beet_phdr *)skb->data;
skb->transport_header += ph->hdrlen * 8;
proto = ph->nexthdr;
} else {
skb->transport_header -= IPV4_BEET_PHMAXLEN;
}
if (proto == IPPROTO_TCP)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
} else {
__be16 frag;
skb->transport_header +=
ipv6_skip_exthdr(skb, 0, &proto, &frag);
}
__skb_pull(skb, skb_transport_offset(skb));

View File

@ -379,6 +379,7 @@ static void espintcp_destruct(struct sock *sk)
{
struct espintcp_ctx *ctx = espintcp_getctx(sk);
ctx->saved_destruct(sk);
kfree(ctx);
}
@ -419,6 +420,7 @@ static int espintcp_init_sk(struct sock *sk)
sk->sk_socket->ops = &espintcp_ops;
ctx->saved_data_ready = sk->sk_data_ready;
ctx->saved_write_space = sk->sk_write_space;
ctx->saved_destruct = sk->sk_destruct;
sk->sk_data_ready = espintcp_data_ready;
sk->sk_write_space = espintcp_write_space;
sk->sk_destruct = espintcp_destruct;

View File

@ -25,12 +25,10 @@ static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb,
struct xfrm_offload *xo = xfrm_offload(skb);
skb_reset_mac_len(skb);
pskb_pull(skb, skb->mac_len + hsize + x->props.header_len);
if (xo->flags & XFRM_GSO_SEGMENT) {
skb_reset_transport_header(skb);
if (xo->flags & XFRM_GSO_SEGMENT)
skb->transport_header -= x->props.header_len;
}
pskb_pull(skb, skb_transport_offset(skb) + x->props.header_len);
}
static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb,

View File

@ -644,7 +644,7 @@ resume:
dev_put(skb->dev);
spin_lock(&x->lock);
if (nexthdr <= 0) {
if (nexthdr < 0) {
if (nexthdr == -EBADMSG) {
xfrm_audit_state_icvfail(x, skb,
x->type->proto);

View File

@ -750,7 +750,28 @@ static struct rtnl_link_ops xfrmi_link_ops __read_mostly = {
.get_link_net = xfrmi_get_link_net,
};
static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list)
{
struct net *net;
LIST_HEAD(list);
rtnl_lock();
list_for_each_entry(net, net_exit_list, exit_list) {
struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
struct xfrm_if __rcu **xip;
struct xfrm_if *xi;
for (xip = &xfrmn->xfrmi[0];
(xi = rtnl_dereference(*xip)) != NULL;
xip = &xi->next)
unregister_netdevice_queue(xi->dev, &list);
}
unregister_netdevice_many(&list);
rtnl_unlock();
}
static struct pernet_operations xfrmi_net_ops = {
.exit_batch = xfrmi_exit_batch_net,
.id = &xfrmi_net_id,
.size = sizeof(struct xfrmi_net),
};

View File

@ -583,18 +583,20 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
xfrm_state_hold(x);
if (skb_is_gso(skb)) {
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
if (skb->inner_protocol)
return xfrm_output_gso(net, sk, skb);
return xfrm_output2(net, sk, skb);
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
goto out;
}
if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
goto out;
} else {
if (skb_is_gso(skb))
return xfrm_output_gso(net, sk, skb);
}
if (skb_is_gso(skb))
return xfrm_output_gso(net, sk, skb);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
err = skb_checksum_help(skb);
if (err) {
@ -640,7 +642,8 @@ void xfrm_local_error(struct sk_buff *skb, int mtu)
if (skb->protocol == htons(ETH_P_IP))
proto = AF_INET;
else if (skb->protocol == htons(ETH_P_IPV6))
else if (skb->protocol == htons(ETH_P_IPV6) &&
skb->sk->sk_family == AF_INET6)
proto = AF_INET6;
else
return;

View File

@ -1436,12 +1436,7 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
struct xfrm_policy *pol)
{
u32 mark = policy->mark.v & policy->mark.m;
if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m)
return true;
if ((mark & pol->mark.m) == pol->mark.v &&
if (policy->mark.v == pol->mark.v &&
policy->priority == pol->priority)
return true;