Commit 942110fd authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 7c6d2ecb f6a23d85
...@@ -25,6 +25,7 @@ struct espintcp_ctx { ...@@ -25,6 +25,7 @@ struct espintcp_ctx {
struct espintcp_msg partial; struct espintcp_msg partial;
void (*saved_data_ready)(struct sock *sk); void (*saved_data_ready)(struct sock *sk);
void (*saved_write_space)(struct sock *sk); void (*saved_write_space)(struct sock *sk);
void (*saved_destruct)(struct sock *sk);
struct work_struct work; struct work_struct work;
bool tx_running; bool tx_running;
}; };
......
...@@ -304,7 +304,7 @@ enum xfrm_attr_type_t { ...@@ -304,7 +304,7 @@ enum xfrm_attr_type_t {
XFRMA_PROTO, /* __u8 */ XFRMA_PROTO, /* __u8 */
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
XFRMA_PAD, XFRMA_PAD,
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ XFRMA_OFFLOAD_DEV, /* struct xfrm_user_offload */
XFRMA_SET_MARK, /* __u32 */ XFRMA_SET_MARK, /* __u32 */
XFRMA_SET_MARK_MASK, /* __u32 */ XFRMA_SET_MARK_MASK, /* __u32 */
XFRMA_IF_ID, /* __u32 */ XFRMA_IF_ID, /* __u32 */
......
...@@ -63,10 +63,8 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head, ...@@ -63,10 +63,8 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
sp->olen++; sp->olen++;
xo = xfrm_offload(skb); xo = xfrm_offload(skb);
if (!xo) { if (!xo)
xfrm_state_put(x);
goto out_reset; goto out_reset;
}
} }
xo->flags |= XFRM_GRO; xo->flags |= XFRM_GRO;
...@@ -139,19 +137,27 @@ static struct sk_buff *xfrm4_beet_gso_segment(struct xfrm_state *x, ...@@ -139,19 +137,27 @@ static struct sk_buff *xfrm4_beet_gso_segment(struct xfrm_state *x,
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
struct sk_buff *segs = ERR_PTR(-EINVAL); struct sk_buff *segs = ERR_PTR(-EINVAL);
const struct net_offload *ops; const struct net_offload *ops;
int proto = xo->proto; u8 proto = xo->proto;
skb->transport_header += x->props.header_len; skb->transport_header += x->props.header_len;
if (proto == IPPROTO_BEETPH) { if (x->sel.family != AF_INET6) {
struct ip_beet_phdr *ph = (struct ip_beet_phdr *)skb->data; 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;
}
} else {
__be16 frag;
skb->transport_header += ph->hdrlen * 8; skb->transport_header +=
proto = ph->nexthdr; ipv6_skip_exthdr(skb, 0, &proto, &frag);
} else if (x->sel.family != AF_INET6) { if (proto == IPPROTO_TCP)
skb->transport_header -= IPV4_BEET_PHMAXLEN; skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
} else if (proto == IPPROTO_TCP) {
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
} }
__skb_pull(skb, skb_transport_offset(skb)); __skb_pull(skb, skb_transport_offset(skb));
......
...@@ -93,7 +93,28 @@ static int vti_rcv_proto(struct sk_buff *skb) ...@@ -93,7 +93,28 @@ static int vti_rcv_proto(struct sk_buff *skb)
static int vti_rcv_tunnel(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) static int vti_rcv_cb(struct sk_buff *skb, int err)
......
...@@ -85,10 +85,8 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head, ...@@ -85,10 +85,8 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
sp->olen++; sp->olen++;
xo = xfrm_offload(skb); xo = xfrm_offload(skb);
if (!xo) { if (!xo)
xfrm_state_put(x);
goto out_reset; goto out_reset;
}
} }
xo->flags |= XFRM_GRO; xo->flags |= XFRM_GRO;
...@@ -123,9 +121,16 @@ static void esp6_gso_encap(struct xfrm_state *x, struct sk_buff *skb) ...@@ -123,9 +121,16 @@ static void esp6_gso_encap(struct xfrm_state *x, struct sk_buff *skb)
struct ip_esp_hdr *esph; struct ip_esp_hdr *esph;
struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6hdr *iph = ipv6_hdr(skb);
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
int proto = iph->nexthdr; u8 proto = iph->nexthdr;
skb_push(skb, -skb_network_offset(skb)); 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); esph = ip_esp_hdr(skb);
*skb_mac_header(skb) = IPPROTO_ESP; *skb_mac_header(skb) = IPPROTO_ESP;
...@@ -166,23 +171,31 @@ static struct sk_buff *xfrm6_beet_gso_segment(struct xfrm_state *x, ...@@ -166,23 +171,31 @@ static struct sk_buff *xfrm6_beet_gso_segment(struct xfrm_state *x,
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
struct sk_buff *segs = ERR_PTR(-EINVAL); struct sk_buff *segs = ERR_PTR(-EINVAL);
const struct net_offload *ops; const struct net_offload *ops;
int proto = xo->proto; u8 proto = xo->proto;
skb->transport_header += x->props.header_len; 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) { if (x->sel.family != AF_INET6) {
skb->transport_header -= skb->transport_header -=
(sizeof(struct ipv6hdr) - sizeof(struct iphdr)); (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) if (proto == IPPROTO_TCP)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6; 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)); __skb_pull(skb, skb_transport_offset(skb));
......
...@@ -379,6 +379,7 @@ static void espintcp_destruct(struct sock *sk) ...@@ -379,6 +379,7 @@ static void espintcp_destruct(struct sock *sk)
{ {
struct espintcp_ctx *ctx = espintcp_getctx(sk); struct espintcp_ctx *ctx = espintcp_getctx(sk);
ctx->saved_destruct(sk);
kfree(ctx); kfree(ctx);
} }
...@@ -419,6 +420,7 @@ static int espintcp_init_sk(struct sock *sk) ...@@ -419,6 +420,7 @@ static int espintcp_init_sk(struct sock *sk)
sk->sk_socket->ops = &espintcp_ops; sk->sk_socket->ops = &espintcp_ops;
ctx->saved_data_ready = sk->sk_data_ready; ctx->saved_data_ready = sk->sk_data_ready;
ctx->saved_write_space = sk->sk_write_space; ctx->saved_write_space = sk->sk_write_space;
ctx->saved_destruct = sk->sk_destruct;
sk->sk_data_ready = espintcp_data_ready; sk->sk_data_ready = espintcp_data_ready;
sk->sk_write_space = espintcp_write_space; sk->sk_write_space = espintcp_write_space;
sk->sk_destruct = espintcp_destruct; sk->sk_destruct = espintcp_destruct;
......
...@@ -25,12 +25,10 @@ static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb, ...@@ -25,12 +25,10 @@ static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb,
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
skb_reset_mac_len(skb); skb_reset_mac_len(skb);
pskb_pull(skb, skb->mac_len + hsize + x->props.header_len); if (xo->flags & XFRM_GSO_SEGMENT)
if (xo->flags & XFRM_GSO_SEGMENT) {
skb_reset_transport_header(skb);
skb->transport_header -= x->props.header_len; 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, static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb,
......
...@@ -644,7 +644,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -644,7 +644,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
dev_put(skb->dev); dev_put(skb->dev);
spin_lock(&x->lock); spin_lock(&x->lock);
if (nexthdr <= 0) { if (nexthdr < 0) {
if (nexthdr == -EBADMSG) { if (nexthdr == -EBADMSG) {
xfrm_audit_state_icvfail(x, skb, xfrm_audit_state_icvfail(x, skb,
x->type->proto); x->type->proto);
......
...@@ -750,7 +750,28 @@ static struct rtnl_link_ops xfrmi_link_ops __read_mostly = { ...@@ -750,7 +750,28 @@ static struct rtnl_link_ops xfrmi_link_ops __read_mostly = {
.get_link_net = xfrmi_get_link_net, .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 = { static struct pernet_operations xfrmi_net_ops = {
.exit_batch = xfrmi_exit_batch_net,
.id = &xfrmi_net_id, .id = &xfrmi_net_id,
.size = sizeof(struct xfrmi_net), .size = sizeof(struct xfrmi_net),
}; };
......
...@@ -583,18 +583,20 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb) ...@@ -583,18 +583,20 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
xfrm_state_hold(x); xfrm_state_hold(x);
if (skb_is_gso(skb)) { 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) if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
goto out; 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) { if (skb->ip_summed == CHECKSUM_PARTIAL) {
err = skb_checksum_help(skb); err = skb_checksum_help(skb);
if (err) { if (err) {
...@@ -640,7 +642,8 @@ void xfrm_local_error(struct sk_buff *skb, int mtu) ...@@ -640,7 +642,8 @@ void xfrm_local_error(struct sk_buff *skb, int mtu)
if (skb->protocol == htons(ETH_P_IP)) if (skb->protocol == htons(ETH_P_IP))
proto = AF_INET; 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; proto = AF_INET6;
else else
return; return;
......
...@@ -1436,12 +1436,7 @@ static void xfrm_policy_requeue(struct xfrm_policy *old, ...@@ -1436,12 +1436,7 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
static bool xfrm_policy_mark_match(struct xfrm_policy *policy, static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
struct xfrm_policy *pol) struct xfrm_policy *pol)
{ {
u32 mark = policy->mark.v & policy->mark.m; if (policy->mark.v == pol->mark.v &&
if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m)
return true;
if ((mark & pol->mark.m) == pol->mark.v &&
policy->priority == pol->priority) policy->priority == pol->priority)
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment