forked from Minki/linux
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:
commit
942110fdf2
@ -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;
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user