aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDan Rosenberg <drosenberg@vsecurity.com>2011-03-19 16:43:43 -0400
committerDavid S. Miller <davem@davemloft.net>2011-03-27 20:59:03 -0400
commitbe20250c13f88375345ad99950190685eda51eb8 (patch)
tree71135bced4717604dff6e37d00f06f20870bbe1c /net
parentd370af0ef7951188daeb15bae75db7ba57c67846 (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')
-rw-r--r--net/rose/rose_subr.c18
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;