Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/klassert/ipsec

Steffen Klassert says:

====================
pull request (net): ipsec 2017-06-23

1) Fix xfrm garbage collecting when unregistering a netdevice.
   From Hangbin Liu.

2) Fix NULL pointer derefernce when exiting a network namespace.
   From Hangbin Liu.

3) Fix some error codes in pfkey to prevent a NULL pointer derefernce.
   From Dan Carpenter.

4) Fix NULL pointer derefernce on allocation failure in pfkey.
   From Dan Carpenter.

5) Adjust IPv6 payload_len to include extension headers. Otherwise
   we corrupt the packets when doing ESP GRO on transport mode.
   From Yossi Kuperman.

6) Set nhoff to the proper offset of the IPv6 nexthdr when doing ESP GRO.
   From Yossi Kuperman.

Please pull or let me know if there are problems.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 23, 2017
2 parents 0ccc22f + ca3a1b8 commit 43b786c
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 16 deletions.
7 changes: 2 additions & 5 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1850,8 +1850,9 @@ static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
}
#endif

#ifdef CONFIG_XFRM_OFFLOAD
void __net_init xfrm_dev_init(void);

#ifdef CONFIG_XFRM_OFFLOAD
int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo);
Expand All @@ -1877,10 +1878,6 @@ static inline void xfrm_dev_state_free(struct xfrm_state *x)
}
}
#else
static inline void __net_init xfrm_dev_init(void)
{
}

static inline int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features)
{
return 0;
Expand Down
25 changes: 25 additions & 0 deletions net/ipv6/esp6_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@
#include <net/ipv6.h>
#include <linux/icmpv6.h>

static __u16 esp6_nexthdr_esp_offset(struct ipv6hdr *ipv6_hdr, int nhlen)
{
int off = sizeof(struct ipv6hdr);
struct ipv6_opt_hdr *exthdr;

if (likely(ipv6_hdr->nexthdr == NEXTHDR_ESP))
return offsetof(struct ipv6hdr, nexthdr);

while (off < nhlen) {
exthdr = (void *)ipv6_hdr + off;
if (exthdr->nexthdr == NEXTHDR_ESP)
return off;

off += ipv6_optlen(exthdr);
}

return 0;
}

static struct sk_buff **esp6_gro_receive(struct sk_buff **head,
struct sk_buff *skb)
{
Expand All @@ -38,6 +57,7 @@ static struct sk_buff **esp6_gro_receive(struct sk_buff **head,
struct xfrm_state *x;
__be32 seq;
__be32 spi;
int nhoff;
int err;

skb_pull(skb, offset);
Expand Down Expand Up @@ -72,6 +92,11 @@ static struct sk_buff **esp6_gro_receive(struct sk_buff **head,

xo->flags |= XFRM_GRO;

nhoff = esp6_nexthdr_esp_offset(ipv6_hdr(skb), offset);
if (!nhoff)
goto out;

IP6CB(skb)->nhoff = nhoff;
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/xfrm6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
return 1;
#endif

ipv6_hdr(skb)->payload_len = htons(skb->len);
__skb_push(skb, skb->data - skb_network_header(skb));
ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));

if (xo && (xo->flags & XFRM_GRO)) {
skb_mac_header_rebuild(skb);
Expand Down
19 changes: 15 additions & 4 deletions net/key/af_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
goto out;
}

err = -ENOBUFS;
key = ext_hdrs[SADB_EXT_KEY_AUTH - 1];
if (sa->sadb_sa_auth) {
int keysize = 0;
Expand All @@ -1168,8 +1169,10 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
if (key)
keysize = (key->sadb_key_bits + 7) / 8;
x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL);
if (!x->aalg)
if (!x->aalg) {
err = -ENOMEM;
goto out;
}
strcpy(x->aalg->alg_name, a->name);
x->aalg->alg_key_len = 0;
if (key) {
Expand All @@ -1188,8 +1191,10 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
goto out;
}
x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL);
if (!x->calg)
if (!x->calg) {
err = -ENOMEM;
goto out;
}
strcpy(x->calg->alg_name, a->name);
x->props.calgo = sa->sadb_sa_encrypt;
} else {
Expand All @@ -1203,8 +1208,10 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
if (key)
keysize = (key->sadb_key_bits + 7) / 8;
x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);
if (!x->ealg)
if (!x->ealg) {
err = -ENOMEM;
goto out;
}
strcpy(x->ealg->alg_name, a->name);
x->ealg->alg_key_len = 0;
if (key) {
Expand Down Expand Up @@ -1249,8 +1256,10 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
struct xfrm_encap_tmpl *natt;

x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL);
if (!x->encap)
if (!x->encap) {
err = -ENOMEM;
goto out;
}

natt = x->encap;
n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1];
Expand Down Expand Up @@ -2755,6 +2764,8 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, const struct sad
int err, err2;

err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, true);
if (!err)
xfrm_garbage_collect(net);
err2 = unicast_flush_resp(sk, hdr);
if (err || err2) {
if (err == -ESRCH) /* empty table - old silent behavior */
Expand Down
3 changes: 1 addition & 2 deletions net/xfrm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
xfrm_input.o xfrm_output.o \
xfrm_sysctl.o xfrm_replay.o
obj-$(CONFIG_XFRM_OFFLOAD) += xfrm_device.o
xfrm_sysctl.o xfrm_replay.o xfrm_device.o
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
Expand Down
2 changes: 2 additions & 0 deletions net/xfrm/xfrm_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <net/xfrm.h>
#include <linux/notifier.h>

#ifdef CONFIG_XFRM_OFFLOAD
int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features)
{
int err;
Expand Down Expand Up @@ -137,6 +138,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
return true;
}
EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok);
#endif

int xfrm_dev_register(struct net_device *dev)
{
Expand Down
4 changes: 0 additions & 4 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1006,10 +1006,6 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
err = -ESRCH;
out:
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);

if (cnt)
xfrm_garbage_collect(net);

return err;
}
EXPORT_SYMBOL(xfrm_policy_flush);
Expand Down
1 change: 1 addition & 0 deletions net/xfrm/xfrm_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,7 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
return 0;
return err;
}
xfrm_garbage_collect(net);

c.data.type = type;
c.event = nlh->nlmsg_type;
Expand Down

0 comments on commit 43b786c

Please sign in to comment.