| From be20250c13f88375345ad99950190685eda51eb8 Mon Sep 17 00:00:00 2001 |
| From: Dan Rosenberg <drosenberg@vsecurity.com> |
| Date: Sat, 19 Mar 2011 20:43:43 +0000 |
| Subject: ROSE: prevent heap corruption with bad facilities |
| |
| From: Dan Rosenberg <drosenberg@vsecurity.com> |
| |
| commit be20250c13f88375345ad99950190685eda51eb8 upstream. |
| |
| 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> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/rose/rose_subr.c | 18 ++++++++++++++++-- |
| 1 file changed, 16 insertions(+), 2 deletions(-) |
| |
| --- a/net/rose/rose_subr.c |
| +++ b/net/rose/rose_subr.c |
| @@ -289,10 +289,15 @@ static int rose_parse_national(unsigned |
| facilities->source_ndigis = 0; |
| facilities->dest_ndigis = 0; |
| for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { |
| - if (pt[6] & AX25_HBIT) |
| + if (pt[6] & AX25_HBIT) { |
| + if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) |
| + return -1; |
| memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); |
| - else |
| + } else { |
| + if (facilities->source_ndigis >= ROSE_MAX_DIGIS) |
| + return -1; |
| memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); |
| + } |
| } |
| } |
| p += l + 2; |
| @@ -332,6 +337,11 @@ static int rose_parse_ccitt(unsigned cha |
| |
| case 0xC0: |
| l = p[1]; |
| + |
| + /* Prevent overflows*/ |
| + if (l < 10 || l > 20) |
| + return -1; |
| + |
| if (*p == FAC_CCITT_DEST_NSAP) { |
| memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); |
| memcpy(callsign, p + 12, l - 10); |
| @@ -372,12 +382,16 @@ int rose_parse_facilities(unsigned char |
| switch (*p) { |
| case FAC_NATIONAL: /* National */ |
| len = rose_parse_national(p + 1, facilities, facilities_len - 1); |
| + if (len < 0) |
| + return 0; |
| facilities_len -= len + 1; |
| p += len + 1; |
| break; |
| |
| case FAC_CCITT: /* CCITT */ |
| len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); |
| + if (len < 0) |
| + return 0; |
| facilities_len -= len + 1; |
| p += len + 1; |
| break; |