Commit f895f0cf 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

Conflicts:
	net/ipv4/ip_vti.c

Steffen Klassert says:

====================
pull request (net): ipsec 2014-05-15

This pull request has a merge conflict in net/ipv4/ip_vti.c
between commit 8d89dcdf ("vti: don't allow to add the same
tunnel twice") and commit a3245236  ("vti4:Don't count header
length twice"). It can be solved like it is done in linux-next.

1) Fix a ipv6 xfrm output crash when a packet is rerouted
   by netfilter to not use IPsec.

2) vti4 counts some header lengths twice leading to an incorrect
   device mtu. Fix this by counting these headers only once.

3) We don't catch the case if an unsupported protocol is submitted
   to the xfrm protocol handlers, this can lead to NULL pointer
   dereferences. Fix this by adding the appropriate checks.

4) vti6 may unregister pernet ops twice on init errors.
   Fix this by removing one of the calls to do it only once.
   From Mathias Krause.

5) Set the vti tunnel mark before doing a lookup in the error
   handlers. Otherwise we don't find the correct xfrm state.
====================

The conflict in ip_vti.c was simple, 'net' had a commit
removing a line from vti_tunnel_init() and this tree
being merged had a commit adding a line to the same
location.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b394745d 6d004d6c
...@@ -239,6 +239,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -239,6 +239,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
static int vti4_err(struct sk_buff *skb, u32 info) static int vti4_err(struct sk_buff *skb, u32 info)
{ {
__be32 spi; __be32 spi;
__u32 mark;
struct xfrm_state *x; struct xfrm_state *x;
struct ip_tunnel *tunnel; struct ip_tunnel *tunnel;
struct ip_esp_hdr *esph; struct ip_esp_hdr *esph;
...@@ -254,6 +255,8 @@ static int vti4_err(struct sk_buff *skb, u32 info) ...@@ -254,6 +255,8 @@ static int vti4_err(struct sk_buff *skb, u32 info)
if (!tunnel) if (!tunnel)
return -1; return -1;
mark = be32_to_cpu(tunnel->parms.o_key);
switch (protocol) { switch (protocol) {
case IPPROTO_ESP: case IPPROTO_ESP:
esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
...@@ -281,7 +284,7 @@ static int vti4_err(struct sk_buff *skb, u32 info) ...@@ -281,7 +284,7 @@ static int vti4_err(struct sk_buff *skb, u32 info)
return 0; return 0;
} }
x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, x = xfrm_state_lookup(net, mark, (const xfrm_address_t *)&iph->daddr,
spi, protocol, AF_INET); spi, protocol, AF_INET);
if (!x) if (!x)
return 0; return 0;
......
...@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
if (err) if (err)
return err; return err;
memset(IPCB(skb), 0, sizeof(*IPCB(skb))); IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
skb->protocol = htons(ETH_P_IP);
return x->outer_mode->output2(x, skb); return x->outer_mode->output2(x, skb);
} }
...@@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output); ...@@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
int xfrm4_output_finish(struct sk_buff *skb) int xfrm4_output_finish(struct sk_buff *skb)
{ {
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
skb->protocol = htons(ETH_P_IP);
#ifdef CONFIG_NETFILTER
IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
#endif
return xfrm_output(skb);
}
static int __xfrm4_output(struct sk_buff *skb)
{
struct xfrm_state *x = skb_dst(skb)->xfrm;
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
if (!skb_dst(skb)->xfrm) { if (!x) {
IPCB(skb)->flags |= IPSKB_REROUTED; IPCB(skb)->flags |= IPSKB_REROUTED;
return dst_output(skb); return dst_output(skb);
} }
IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
#endif #endif
skb->protocol = htons(ETH_P_IP); return x->outer_mode->afinfo->output_finish(skb);
return xfrm_output(skb);
} }
int xfrm4_output(struct sock *sk, struct sk_buff *skb) int xfrm4_output(struct sock *sk, struct sk_buff *skb)
{ {
struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm;
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
NULL, dst->dev, NULL, skb_dst(skb)->dev, __xfrm4_output,
x->outer_mode->afinfo->output_finish,
!(IPCB(skb)->flags & IPSKB_REROUTED)); !(IPCB(skb)->flags & IPSKB_REROUTED));
} }
......
...@@ -50,8 +50,12 @@ int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) ...@@ -50,8 +50,12 @@ int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
{ {
int ret; int ret;
struct xfrm4_protocol *handler; struct xfrm4_protocol *handler;
struct xfrm4_protocol __rcu **head = proto_handlers(protocol);
for_each_protocol_rcu(*proto_handlers(protocol), handler) if (!head)
return 0;
for_each_protocol_rcu(*head, handler)
if ((ret = handler->cb_handler(skb, err)) <= 0) if ((ret = handler->cb_handler(skb, err)) <= 0)
return ret; return ret;
...@@ -64,15 +68,20 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, ...@@ -64,15 +68,20 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
{ {
int ret; int ret;
struct xfrm4_protocol *handler; struct xfrm4_protocol *handler;
struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr);
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
XFRM_SPI_SKB_CB(skb)->family = AF_INET; XFRM_SPI_SKB_CB(skb)->family = AF_INET;
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
for_each_protocol_rcu(*proto_handlers(nexthdr), handler) if (!head)
goto out;
for_each_protocol_rcu(*head, handler)
if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
return ret; return ret;
out:
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
kfree_skb(skb); kfree_skb(skb);
...@@ -208,6 +217,9 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler, ...@@ -208,6 +217,9 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler,
int ret = -EEXIST; int ret = -EEXIST;
int priority = handler->priority; int priority = handler->priority;
if (!proto_handlers(protocol) || !netproto(protocol))
return -EINVAL;
mutex_lock(&xfrm4_protocol_mutex); mutex_lock(&xfrm4_protocol_mutex);
if (!rcu_dereference_protected(*proto_handlers(protocol), if (!rcu_dereference_protected(*proto_handlers(protocol),
...@@ -250,6 +262,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, ...@@ -250,6 +262,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
struct xfrm4_protocol *t; struct xfrm4_protocol *t;
int ret = -ENOENT; int ret = -ENOENT;
if (!proto_handlers(protocol) || !netproto(protocol))
return -EINVAL;
mutex_lock(&xfrm4_protocol_mutex); mutex_lock(&xfrm4_protocol_mutex);
for (pprev = proto_handlers(protocol); for (pprev = proto_handlers(protocol);
......
...@@ -511,6 +511,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -511,6 +511,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info) u8 type, u8 code, int offset, __be32 info)
{ {
__be32 spi; __be32 spi;
__u32 mark;
struct xfrm_state *x; struct xfrm_state *x;
struct ip6_tnl *t; struct ip6_tnl *t;
struct ip_esp_hdr *esph; struct ip_esp_hdr *esph;
...@@ -524,6 +525,8 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -524,6 +525,8 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!t) if (!t)
return -1; return -1;
mark = be32_to_cpu(t->parms.o_key);
switch (protocol) { switch (protocol) {
case IPPROTO_ESP: case IPPROTO_ESP:
esph = (struct ip_esp_hdr *)(skb->data + offset); esph = (struct ip_esp_hdr *)(skb->data + offset);
...@@ -545,7 +548,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -545,7 +548,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
type != NDISC_REDIRECT) type != NDISC_REDIRECT)
return 0; return 0;
x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, x = xfrm_state_lookup(net, mark, (const xfrm_address_t *)&iph->daddr,
spi, protocol, AF_INET6); spi, protocol, AF_INET6);
if (!x) if (!x)
return 0; return 0;
...@@ -1097,7 +1100,6 @@ static int __init vti6_tunnel_init(void) ...@@ -1097,7 +1100,6 @@ static int __init vti6_tunnel_init(void)
err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP);
if (err < 0) { if (err < 0) {
unregister_pernet_device(&vti6_net_ops);
pr_err("%s: can't register vti6 protocol\n", __func__); pr_err("%s: can't register vti6 protocol\n", __func__);
goto out; goto out;
...@@ -1106,7 +1108,6 @@ static int __init vti6_tunnel_init(void) ...@@ -1106,7 +1108,6 @@ static int __init vti6_tunnel_init(void)
err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH);
if (err < 0) { if (err < 0) {
xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
unregister_pernet_device(&vti6_net_ops);
pr_err("%s: can't register vti6 protocol\n", __func__); pr_err("%s: can't register vti6 protocol\n", __func__);
goto out; goto out;
...@@ -1116,7 +1117,6 @@ static int __init vti6_tunnel_init(void) ...@@ -1116,7 +1117,6 @@ static int __init vti6_tunnel_init(void)
if (err < 0) { if (err < 0) {
xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
unregister_pernet_device(&vti6_net_ops);
pr_err("%s: can't register vti6 protocol\n", __func__); pr_err("%s: can't register vti6 protocol\n", __func__);
goto out; goto out;
......
...@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
if (err) if (err)
return err; return err;
memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
#ifdef CONFIG_NETFILTER
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
#endif
skb->protocol = htons(ETH_P_IPV6);
skb->local_df = 1; skb->local_df = 1;
return x->outer_mode->output2(x, skb); return x->outer_mode->output2(x, skb);
...@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output); ...@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
int xfrm6_output_finish(struct sk_buff *skb) int xfrm6_output_finish(struct sk_buff *skb)
{ {
memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
skb->protocol = htons(ETH_P_IPV6);
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
#endif #endif
skb->protocol = htons(ETH_P_IPV6);
return xfrm_output(skb); return xfrm_output(skb);
} }
...@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb) ...@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb)
struct xfrm_state *x = dst->xfrm; struct xfrm_state *x = dst->xfrm;
int mtu; int mtu;
#ifdef CONFIG_NETFILTER
if (!x) {
IP6CB(skb)->flags |= IP6SKB_REROUTED;
return dst_output(skb);
}
#endif
if (skb->protocol == htons(ETH_P_IPV6)) if (skb->protocol == htons(ETH_P_IPV6))
mtu = ip6_skb_dst_mtu(skb); mtu = ip6_skb_dst_mtu(skb);
else else
...@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb) ...@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb)
int xfrm6_output(struct sock *sk, struct sk_buff *skb) int xfrm6_output(struct sock *sk, struct sk_buff *skb)
{ {
return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
skb_dst(skb)->dev, __xfrm6_output); NULL, skb_dst(skb)->dev, __xfrm6_output,
!(IP6CB(skb)->flags & IP6SKB_REROUTED));
} }
...@@ -50,6 +50,10 @@ int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) ...@@ -50,6 +50,10 @@ int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
{ {
int ret; int ret;
struct xfrm6_protocol *handler; struct xfrm6_protocol *handler;
struct xfrm6_protocol __rcu **head = proto_handlers(protocol);
if (!head)
return 0;
for_each_protocol_rcu(*proto_handlers(protocol), handler) for_each_protocol_rcu(*proto_handlers(protocol), handler)
if ((ret = handler->cb_handler(skb, err)) <= 0) if ((ret = handler->cb_handler(skb, err)) <= 0)
...@@ -184,10 +188,12 @@ int xfrm6_protocol_register(struct xfrm6_protocol *handler, ...@@ -184,10 +188,12 @@ int xfrm6_protocol_register(struct xfrm6_protocol *handler,
struct xfrm6_protocol __rcu **pprev; struct xfrm6_protocol __rcu **pprev;
struct xfrm6_protocol *t; struct xfrm6_protocol *t;
bool add_netproto = false; bool add_netproto = false;
int ret = -EEXIST; int ret = -EEXIST;
int priority = handler->priority; int priority = handler->priority;
if (!proto_handlers(protocol) || !netproto(protocol))
return -EINVAL;
mutex_lock(&xfrm6_protocol_mutex); mutex_lock(&xfrm6_protocol_mutex);
if (!rcu_dereference_protected(*proto_handlers(protocol), if (!rcu_dereference_protected(*proto_handlers(protocol),
...@@ -230,6 +236,9 @@ int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, ...@@ -230,6 +236,9 @@ int xfrm6_protocol_deregister(struct xfrm6_protocol *handler,
struct xfrm6_protocol *t; struct xfrm6_protocol *t;
int ret = -ENOENT; int ret = -ENOENT;
if (!proto_handlers(protocol) || !netproto(protocol))
return -EINVAL;
mutex_lock(&xfrm6_protocol_mutex); mutex_lock(&xfrm6_protocol_mutex);
for (pprev = proto_handlers(protocol); for (pprev = proto_handlers(protocol);
......
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