diff options
author | Amir Vadai <amir@vadai.me> | 2016-11-28 05:56:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-29 19:46:00 -0500 |
commit | 95c2027bfeda21a28eb245121e6a249f38d0788e (patch) | |
tree | 12a0611996a2975e5e1c527f034eabe1d65e84d6 /net | |
parent | 2dbb4c05d048995455857a7c2927a4297fc66c3b (diff) |
net/sched: pedit: make sure that offset is valid
Add a validation function to make sure offset is valid:
1. Not below skb head (could happen when offset is negative).
2. Validate both 'offset' and 'at'.
Signed-off-by: Amir Vadai <amir@vadai.me>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/act_pedit.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index b54d56d4959b..cf9b2fe8eac6 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c | |||
@@ -108,6 +108,17 @@ static void tcf_pedit_cleanup(struct tc_action *a, int bind) | |||
108 | kfree(keys); | 108 | kfree(keys); |
109 | } | 109 | } |
110 | 110 | ||
111 | static bool offset_valid(struct sk_buff *skb, int offset) | ||
112 | { | ||
113 | if (offset > 0 && offset > skb->len) | ||
114 | return false; | ||
115 | |||
116 | if (offset < 0 && -offset > skb_headroom(skb)) | ||
117 | return false; | ||
118 | |||
119 | return true; | ||
120 | } | ||
121 | |||
111 | static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, | 122 | static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, |
112 | struct tcf_result *res) | 123 | struct tcf_result *res) |
113 | { | 124 | { |
@@ -134,6 +145,11 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, | |||
134 | if (tkey->offmask) { | 145 | if (tkey->offmask) { |
135 | char *d, _d; | 146 | char *d, _d; |
136 | 147 | ||
148 | if (!offset_valid(skb, off + tkey->at)) { | ||
149 | pr_info("tc filter pedit 'at' offset %d out of bounds\n", | ||
150 | off + tkey->at); | ||
151 | goto bad; | ||
152 | } | ||
137 | d = skb_header_pointer(skb, off + tkey->at, 1, | 153 | d = skb_header_pointer(skb, off + tkey->at, 1, |
138 | &_d); | 154 | &_d); |
139 | if (!d) | 155 | if (!d) |
@@ -146,10 +162,10 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, | |||
146 | " offset must be on 32 bit boundaries\n"); | 162 | " offset must be on 32 bit boundaries\n"); |
147 | goto bad; | 163 | goto bad; |
148 | } | 164 | } |
149 | if (offset > 0 && offset > skb->len) { | 165 | |
150 | pr_info("tc filter pedit" | 166 | if (!offset_valid(skb, off + offset)) { |
151 | " offset %d can't exceed pkt length %d\n", | 167 | pr_info("tc filter pedit offset %d out of bounds\n", |
152 | offset, skb->len); | 168 | offset); |
153 | goto bad; | 169 | goto bad; |
154 | } | 170 | } |
155 | 171 | ||