Commit 199c6550 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 2015-10-22

1) Fix IPsec pre-encap fragmentation for GSO packets.
   From Herbert Xu.

2) Fix some header checks in _decode_session6.
   We skip the header informations if the data pointer points
   already behind the header in question for some protocols.
   This is because we call pskb_may_pull with a negative value
   converted to unsigened int from pskb_may_pull in this case.
   Skipping the header informations can lead to incorrect policy
   lookups. From Mathias Krause.

3) Allow to change the replay threshold and expiry timer of a
   state without having to set other attributes like replay
   counter and byte lifetime. Changing these other attributes
   may break the SA. From Michael Rossberg.

4) Fix pmtu discovery for local generated packets.
   We may fail dispatch to the inner address family.
   As a reault, the local error handler is not called
   and the mtu value is not reported back to userspace.

Please pull or let me know if there are problems.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d46a9d67 ca064bd8
...@@ -30,6 +30,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) ...@@ -30,6 +30,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
mtu = dst_mtu(skb_dst(skb)); mtu = dst_mtu(skb_dst(skb));
if (skb->len > mtu) { if (skb->len > mtu) {
skb->protocol = htons(ETH_P_IP);
if (skb->sk) if (skb->sk)
xfrm_local_error(skb, mtu); xfrm_local_error(skb, mtu);
else else
......
...@@ -79,6 +79,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) ...@@ -79,6 +79,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
if (!skb->ignore_df && skb->len > mtu) { if (!skb->ignore_df && skb->len > mtu) {
skb->dev = dst->dev; skb->dev = dst->dev;
skb->protocol = htons(ETH_P_IPV6);
if (xfrm6_local_dontfrag(skb)) if (xfrm6_local_dontfrag(skb))
xfrm6_local_rxpmtu(skb, mtu); xfrm6_local_rxpmtu(skb, mtu);
...@@ -136,6 +137,7 @@ static int __xfrm6_output(struct sock *sk, struct sk_buff *skb) ...@@ -136,6 +137,7 @@ static int __xfrm6_output(struct sock *sk, struct sk_buff *skb)
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm; struct xfrm_state *x = dst->xfrm;
int mtu; int mtu;
bool toobig;
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
if (!x) { if (!x) {
...@@ -144,25 +146,29 @@ static int __xfrm6_output(struct sock *sk, struct sk_buff *skb) ...@@ -144,25 +146,29 @@ static int __xfrm6_output(struct sock *sk, struct sk_buff *skb)
} }
#endif #endif
if (x->props.mode != XFRM_MODE_TUNNEL)
goto skip_frag;
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
mtu = dst_mtu(skb_dst(skb)); mtu = dst_mtu(skb_dst(skb));
if (skb->len > mtu && xfrm6_local_dontfrag(skb)) { toobig = skb->len > mtu && !skb_is_gso(skb);
if (toobig && xfrm6_local_dontfrag(skb)) {
xfrm6_local_rxpmtu(skb, mtu); xfrm6_local_rxpmtu(skb, mtu);
return -EMSGSIZE; return -EMSGSIZE;
} else if (!skb->ignore_df && skb->len > mtu && skb->sk) { } else if (!skb->ignore_df && toobig && skb->sk) {
xfrm_local_error(skb, mtu); xfrm_local_error(skb, mtu);
return -EMSGSIZE; return -EMSGSIZE;
} }
if (x->props.mode == XFRM_MODE_TUNNEL && if (toobig || dst_allfrag(skb_dst(skb)))
((skb->len > mtu && !skb_is_gso(skb)) ||
dst_allfrag(skb_dst(skb)))) {
return ip6_fragment(sk, skb, return ip6_fragment(sk, skb,
x->outer_mode->afinfo->output_finish); x->outer_mode->afinfo->output_finish);
}
skip_frag:
return x->outer_mode->afinfo->output_finish(sk, skb); return x->outer_mode->afinfo->output_finish(sk, skb);
} }
......
...@@ -179,7 +179,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) ...@@ -179,7 +179,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
return; return;
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) { if (!onlyproto && (nh + offset + 2 < skb->data ||
pskb_may_pull(skb, nh + offset + 2 - skb->data))) {
u8 *icmp; u8 *icmp;
nh = skb_network_header(skb); nh = skb_network_header(skb);
...@@ -193,7 +194,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) ...@@ -193,7 +194,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
#if IS_ENABLED(CONFIG_IPV6_MIP6) #if IS_ENABLED(CONFIG_IPV6_MIP6)
case IPPROTO_MH: case IPPROTO_MH:
offset += ipv6_optlen(exthdr); offset += ipv6_optlen(exthdr);
if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) { if (!onlyproto && (nh + offset + 3 < skb->data ||
pskb_may_pull(skb, nh + offset + 3 - skb->data))) {
struct ip6_mh *mh; struct ip6_mh *mh;
nh = skb_network_header(skb); nh = skb_network_header(skb);
......
...@@ -1928,8 +1928,10 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1928,8 +1928,10 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
if (!lt && !rp && !re) if (!lt && !rp && !re && !et && !rt)
return err; return err;
/* pedantic mode - thou shalt sayeth replaceth */ /* pedantic mode - thou shalt sayeth replaceth */
......
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