diff options
author | Matthew Daley <mattjd@gmail.com> | 2011-10-14 14:45:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-17 19:31:39 -0400 |
commit | cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9df (patch) | |
tree | 3d266ac18673ebc85a99e4d10d8d381ff1ebd782 /net/x25/x25_in.c | |
parent | c7fd0d48bde943e228e9c28ce971a22d6a1744c4 (diff) |
x25: Handle undersized/fragmented skbs
There are multiple locations in the X.25 packet layer where a skb is
assumed to be of at least a certain size and that all its data is
currently available at skb->data. These assumptions are not checked,
hence buffer overreads may occur. Use pskb_may_pull to check these
minimal size assumptions and ensure that data is available at skb->data
when necessary, as well as use skb_copy_bits where needed.
Signed-off-by: Matthew Daley <mattjd@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Andrew Hendry <andrew.hendry@gmail.com>
Cc: stable <stable@kernel.org>
Acked-by: Andrew Hendry <andrew.hendry@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/x25/x25_in.c')
-rw-r--r-- | net/x25/x25_in.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index 63488fd4885a..a49cd4ec551a 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c | |||
@@ -107,6 +107,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
107 | /* | 107 | /* |
108 | * Parse the data in the frame. | 108 | * Parse the data in the frame. |
109 | */ | 109 | */ |
110 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) | ||
111 | goto out_clear; | ||
110 | skb_pull(skb, X25_STD_MIN_LEN); | 112 | skb_pull(skb, X25_STD_MIN_LEN); |
111 | 113 | ||
112 | len = x25_parse_address_block(skb, &source_addr, | 114 | len = x25_parse_address_block(skb, &source_addr, |
@@ -130,9 +132,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
130 | if (skb->len > X25_MAX_CUD_LEN) | 132 | if (skb->len > X25_MAX_CUD_LEN) |
131 | goto out_clear; | 133 | goto out_clear; |
132 | 134 | ||
133 | skb_copy_from_linear_data(skb, | 135 | skb_copy_bits(skb, 0, x25->calluserdata.cuddata, |
134 | x25->calluserdata.cuddata, | 136 | skb->len); |
135 | skb->len); | ||
136 | x25->calluserdata.cudlength = skb->len; | 137 | x25->calluserdata.cudlength = skb->len; |
137 | } | 138 | } |
138 | if (!sock_flag(sk, SOCK_DEAD)) | 139 | if (!sock_flag(sk, SOCK_DEAD)) |
@@ -140,6 +141,9 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
140 | break; | 141 | break; |
141 | } | 142 | } |
142 | case X25_CLEAR_REQUEST: | 143 | case X25_CLEAR_REQUEST: |
144 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
145 | goto out_clear; | ||
146 | |||
143 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 147 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
144 | x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); | 148 | x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); |
145 | break; | 149 | break; |
@@ -167,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
167 | switch (frametype) { | 171 | switch (frametype) { |
168 | 172 | ||
169 | case X25_CLEAR_REQUEST: | 173 | case X25_CLEAR_REQUEST: |
174 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
175 | goto out_clear; | ||
176 | |||
170 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 177 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
171 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); | 178 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); |
172 | break; | 179 | break; |
@@ -180,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
180 | } | 187 | } |
181 | 188 | ||
182 | return 0; | 189 | return 0; |
190 | |||
191 | out_clear: | ||
192 | x25_write_internal(sk, X25_CLEAR_REQUEST); | ||
193 | x25_start_t23timer(sk); | ||
194 | return 0; | ||
183 | } | 195 | } |
184 | 196 | ||
185 | /* | 197 | /* |
@@ -209,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
209 | break; | 221 | break; |
210 | 222 | ||
211 | case X25_CLEAR_REQUEST: | 223 | case X25_CLEAR_REQUEST: |
224 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
225 | goto out_clear; | ||
226 | |||
212 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 227 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
213 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); | 228 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); |
214 | break; | 229 | break; |
@@ -307,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
307 | } | 322 | } |
308 | 323 | ||
309 | return queued; | 324 | return queued; |
325 | |||
326 | out_clear: | ||
327 | x25_write_internal(sk, X25_CLEAR_REQUEST); | ||
328 | x25->state = X25_STATE_2; | ||
329 | x25_start_t23timer(sk); | ||
330 | return 0; | ||
310 | } | 331 | } |
311 | 332 | ||
312 | /* | 333 | /* |
@@ -316,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
316 | */ | 337 | */ |
317 | static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) | 338 | static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) |
318 | { | 339 | { |
340 | struct x25_sock *x25 = x25_sk(sk); | ||
341 | |||
319 | switch (frametype) { | 342 | switch (frametype) { |
320 | 343 | ||
321 | case X25_RESET_REQUEST: | 344 | case X25_RESET_REQUEST: |
322 | x25_write_internal(sk, X25_RESET_CONFIRMATION); | 345 | x25_write_internal(sk, X25_RESET_CONFIRMATION); |
323 | case X25_RESET_CONFIRMATION: { | 346 | case X25_RESET_CONFIRMATION: { |
324 | struct x25_sock *x25 = x25_sk(sk); | ||
325 | |||
326 | x25_stop_timer(sk); | 347 | x25_stop_timer(sk); |
327 | x25->condition = 0x00; | 348 | x25->condition = 0x00; |
328 | x25->va = 0; | 349 | x25->va = 0; |
@@ -334,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
334 | break; | 355 | break; |
335 | } | 356 | } |
336 | case X25_CLEAR_REQUEST: | 357 | case X25_CLEAR_REQUEST: |
358 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
359 | goto out_clear; | ||
360 | |||
337 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 361 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
338 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); | 362 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); |
339 | break; | 363 | break; |
@@ -343,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
343 | } | 367 | } |
344 | 368 | ||
345 | return 0; | 369 | return 0; |
370 | |||
371 | out_clear: | ||
372 | x25_write_internal(sk, X25_CLEAR_REQUEST); | ||
373 | x25->state = X25_STATE_2; | ||
374 | x25_start_t23timer(sk); | ||
375 | return 0; | ||
346 | } | 376 | } |
347 | 377 | ||
348 | /* Higher level upcall for a LAPB frame */ | 378 | /* Higher level upcall for a LAPB frame */ |