Commit d70d6222 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Ben Hutchings

bpf: try harder on clones when writing into skb

commit 3697649f upstream.

When we're dealing with clones and the area is not writeable, try
harder and get a copy via pskb_expand_head(). Replace also other
occurences in tc actions with the new skb_try_make_writable().
Reported-by: default avatarAshhad Sheikh <ashhadsheikh394@gmail.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
[bwh: Backported to 3.2: drop changes to bpf; only tc actions need fixing]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent e5cae00e
...@@ -1926,6 +1926,13 @@ static inline int skb_clone_writable(const struct sk_buff *skb, unsigned int len ...@@ -1926,6 +1926,13 @@ static inline int skb_clone_writable(const struct sk_buff *skb, unsigned int len
skb_headroom(skb) + len <= skb->hdr_len; skb_headroom(skb) + len <= skb->hdr_len;
} }
static inline int skb_try_make_writable(struct sk_buff *skb,
unsigned int write_len)
{
return skb_cloned(skb) && !skb_clone_writable(skb, write_len) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
}
static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
int cloned) int cloned)
{ {
......
...@@ -122,9 +122,7 @@ static void *tcf_csum_skb_nextlayer(struct sk_buff *skb, ...@@ -122,9 +122,7 @@ static void *tcf_csum_skb_nextlayer(struct sk_buff *skb,
int hl = ihl + jhl; int hl = ihl + jhl;
if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) || if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) ||
(skb_cloned(skb) && skb_try_make_writable(skb, hl + ntkoff))
!skb_clone_writable(skb, hl + ntkoff) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
return NULL; return NULL;
else else
return (void *)(skb_network_header(skb) + ihl); return (void *)(skb_network_header(skb) + ihl);
...@@ -372,9 +370,7 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags) ...@@ -372,9 +370,7 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
} }
if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) { if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
if (skb_cloned(skb) && if (skb_try_make_writable(skb, sizeof(*iph) + ntkoff))
!skb_clone_writable(skb, sizeof(*iph) + ntkoff) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto fail; goto fail;
ip_send_check(iph); ip_send_check(iph);
......
...@@ -144,9 +144,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a, ...@@ -144,9 +144,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
addr = iph->daddr; addr = iph->daddr;
if (!((old_addr ^ addr) & mask)) { if (!((old_addr ^ addr) & mask)) {
if (skb_cloned(skb) && if (skb_try_make_writable(skb, sizeof(*iph) + noff))
!skb_clone_writable(skb, sizeof(*iph) + noff) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto drop; goto drop;
new_addr &= mask; new_addr &= mask;
...@@ -174,9 +172,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a, ...@@ -174,9 +172,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
struct tcphdr *tcph; struct tcphdr *tcph;
if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) ||
(skb_cloned(skb) && skb_try_make_writable(skb, ihl + sizeof(*tcph) + noff))
!skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
goto drop; goto drop;
tcph = (void *)(skb_network_header(skb) + ihl); tcph = (void *)(skb_network_header(skb) + ihl);
...@@ -188,9 +184,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a, ...@@ -188,9 +184,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
struct udphdr *udph; struct udphdr *udph;
if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) ||
(skb_cloned(skb) && skb_try_make_writable(skb, ihl + sizeof(*udph) + noff))
!skb_clone_writable(skb, ihl + sizeof(*udph) + noff) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
goto drop; goto drop;
udph = (void *)(skb_network_header(skb) + ihl); udph = (void *)(skb_network_header(skb) + ihl);
...@@ -230,10 +224,8 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a, ...@@ -230,10 +224,8 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
if ((old_addr ^ addr) & mask) if ((old_addr ^ addr) & mask)
break; break;
if (skb_cloned(skb) && if (skb_try_make_writable(skb, ihl + sizeof(*icmph) +
!skb_clone_writable(skb, ihl + sizeof(*icmph) + sizeof(*iph) + noff))
sizeof(*iph) + noff) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto drop; goto drop;
icmph = (void *)(skb_network_header(skb) + ihl); icmph = (void *)(skb_network_header(skb) + ihl);
......
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