diff options
author | Dan Rosenberg <drosenberg@vsecurity.com> | 2011-03-19 16:43:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-27 20:59:03 -0400 |
commit | be20250c13f88375345ad99950190685eda51eb8 (patch) | |
tree | 71135bced4717604dff6e37d00f06f20870bbe1c /net/rose | |
parent | d370af0ef7951188daeb15bae75db7ba57c67846 (diff) |
ROSE: prevent heap corruption with bad facilities
When parsing the FAC_NATIONAL_DIGIS facilities field, it's possible for
a remote host to provide more digipeaters than expected, resulting in
heap corruption. Check against ROSE_MAX_DIGIS to prevent overflows, and
abort facilities parsing on failure.
Additionally, when parsing the FAC_CCITT_DEST_NSAP and
FAC_CCITT_SRC_NSAP facilities fields, a remote host can provide a length
of less than 10, resulting in an underflow in a memcpy size, causing a
kernel panic due to massive heap corruption. A length of greater than
20 results in a stack overflow of the callsign array. Abort facilities
parsing on these invalid length values.
Signed-off-by: Dan Rosenberg <drosenberg@vsecurity.com>
Cc: stable@kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rose')
-rw-r--r-- | net/rose/rose_subr.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 1734abba26a2..174d51c9ce37 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c | |||
@@ -290,10 +290,15 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct * | |||
290 | facilities->source_ndigis = 0; | 290 | facilities->source_ndigis = 0; |
291 | facilities->dest_ndigis = 0; | 291 | facilities->dest_ndigis = 0; |
292 | for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { | 292 | for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { |
293 | if (pt[6] & AX25_HBIT) | 293 | if (pt[6] & AX25_HBIT) { |
294 | if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) | ||
295 | return -1; | ||
294 | memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); | 296 | memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); |
295 | else | 297 | } else { |
298 | if (facilities->source_ndigis >= ROSE_MAX_DIGIS) | ||
299 | return -1; | ||
296 | memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); | 300 | memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); |
301 | } | ||
297 | } | 302 | } |
298 | } | 303 | } |
299 | p += l + 2; | 304 | p += l + 2; |
@@ -333,6 +338,11 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac | |||
333 | 338 | ||
334 | case 0xC0: | 339 | case 0xC0: |
335 | l = p[1]; | 340 | l = p[1]; |
341 | |||
342 | /* Prevent overflows*/ | ||
343 | if (l < 10 || l > 20) | ||
344 | return -1; | ||
345 | |||
336 | if (*p == FAC_CCITT_DEST_NSAP) { | 346 | if (*p == FAC_CCITT_DEST_NSAP) { |
337 | memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); | 347 | memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); |
338 | memcpy(callsign, p + 12, l - 10); | 348 | memcpy(callsign, p + 12, l - 10); |
@@ -373,12 +383,16 @@ int rose_parse_facilities(unsigned char *p, | |||
373 | switch (*p) { | 383 | switch (*p) { |
374 | case FAC_NATIONAL: /* National */ | 384 | case FAC_NATIONAL: /* National */ |
375 | len = rose_parse_national(p + 1, facilities, facilities_len - 1); | 385 | len = rose_parse_national(p + 1, facilities, facilities_len - 1); |
386 | if (len < 0) | ||
387 | return 0; | ||
376 | facilities_len -= len + 1; | 388 | facilities_len -= len + 1; |
377 | p += len + 1; | 389 | p += len + 1; |
378 | break; | 390 | break; |
379 | 391 | ||
380 | case FAC_CCITT: /* CCITT */ | 392 | case FAC_CCITT: /* CCITT */ |
381 | len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); | 393 | len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); |
394 | if (len < 0) | ||
395 | return 0; | ||
382 | facilities_len -= len + 1; | 396 | facilities_len -= len + 1; |
383 | p += len + 1; | 397 | p += len + 1; |
384 | break; | 398 | break; |