diff options
| author | Ben Hutchings <ben@decadent.org.uk> | 2011-03-20 02:48:05 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-03-27 20:59:04 -0400 |
| commit | e0bccd315db0c2f919e7fcf9cb60db21d9986f52 (patch) | |
| tree | 8cf512f43221087f964c0f55c7665e293e96921b | |
| parent | be20250c13f88375345ad99950190685eda51eb8 (diff) | |
rose: Add length checks to CALL_REQUEST parsing
Define some constant offsets for CALL_REQUEST based on the description
at <http://www.techfest.com/networking/wan/x25plp.htm> and the
definition of ROSE as using 10-digit (5-byte) addresses. Use them
consistently. Validate all implicit and explicit facilities lengths.
Validate the address length byte rather than either trusting or
assuming its value.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/rose.h | 8 | ||||
| -rw-r--r-- | net/rose/af_rose.c | 8 | ||||
| -rw-r--r-- | net/rose/rose_loopback.c | 13 | ||||
| -rw-r--r-- | net/rose/rose_route.c | 20 | ||||
| -rw-r--r-- | net/rose/rose_subr.c | 91 |
5 files changed, 93 insertions, 47 deletions
diff --git a/include/net/rose.h b/include/net/rose.h index 5ba9f02731eb..555dd198aab7 100644 --- a/include/net/rose.h +++ b/include/net/rose.h | |||
| @@ -14,6 +14,12 @@ | |||
| 14 | 14 | ||
| 15 | #define ROSE_MIN_LEN 3 | 15 | #define ROSE_MIN_LEN 3 |
| 16 | 16 | ||
| 17 | #define ROSE_CALL_REQ_ADDR_LEN_OFF 3 | ||
| 18 | #define ROSE_CALL_REQ_ADDR_LEN_VAL 0xAA /* each address is 10 digits */ | ||
| 19 | #define ROSE_CALL_REQ_DEST_ADDR_OFF 4 | ||
| 20 | #define ROSE_CALL_REQ_SRC_ADDR_OFF 9 | ||
| 21 | #define ROSE_CALL_REQ_FACILITIES_OFF 14 | ||
| 22 | |||
| 17 | #define ROSE_GFI 0x10 | 23 | #define ROSE_GFI 0x10 |
| 18 | #define ROSE_Q_BIT 0x80 | 24 | #define ROSE_Q_BIT 0x80 |
| 19 | #define ROSE_D_BIT 0x40 | 25 | #define ROSE_D_BIT 0x40 |
| @@ -214,7 +220,7 @@ extern void rose_requeue_frames(struct sock *); | |||
| 214 | extern int rose_validate_nr(struct sock *, unsigned short); | 220 | extern int rose_validate_nr(struct sock *, unsigned short); |
| 215 | extern void rose_write_internal(struct sock *, int); | 221 | extern void rose_write_internal(struct sock *, int); |
| 216 | extern int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *); | 222 | extern int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *); |
| 217 | extern int rose_parse_facilities(unsigned char *, struct rose_facilities_struct *); | 223 | extern int rose_parse_facilities(unsigned char *, unsigned int, struct rose_facilities_struct *); |
| 218 | extern void rose_disconnect(struct sock *, int, int, int); | 224 | extern void rose_disconnect(struct sock *, int, int, int); |
| 219 | 225 | ||
| 220 | /* rose_timer.c */ | 226 | /* rose_timer.c */ |
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 5ee0c62046a0..a80aef6e3d1f 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
| @@ -978,7 +978,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros | |||
| 978 | struct sock *make; | 978 | struct sock *make; |
| 979 | struct rose_sock *make_rose; | 979 | struct rose_sock *make_rose; |
| 980 | struct rose_facilities_struct facilities; | 980 | struct rose_facilities_struct facilities; |
| 981 | int n, len; | 981 | int n; |
| 982 | 982 | ||
| 983 | skb->sk = NULL; /* Initially we don't know who it's for */ | 983 | skb->sk = NULL; /* Initially we don't know who it's for */ |
| 984 | 984 | ||
| @@ -987,9 +987,9 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros | |||
| 987 | */ | 987 | */ |
| 988 | memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); | 988 | memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); |
| 989 | 989 | ||
| 990 | len = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1; | 990 | if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF, |
| 991 | len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1; | 991 | skb->len - ROSE_CALL_REQ_FACILITIES_OFF, |
| 992 | if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { | 992 | &facilities)) { |
| 993 | rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76); | 993 | rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76); |
| 994 | return 0; | 994 | return 0; |
| 995 | } | 995 | } |
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c index ae4a9d99aec7..344456206b70 100644 --- a/net/rose/rose_loopback.c +++ b/net/rose/rose_loopback.c | |||
| @@ -73,9 +73,20 @@ static void rose_loopback_timer(unsigned long param) | |||
| 73 | unsigned int lci_i, lci_o; | 73 | unsigned int lci_i, lci_o; |
| 74 | 74 | ||
| 75 | while ((skb = skb_dequeue(&loopback_queue)) != NULL) { | 75 | while ((skb = skb_dequeue(&loopback_queue)) != NULL) { |
| 76 | if (skb->len < ROSE_MIN_LEN) { | ||
| 77 | kfree_skb(skb); | ||
| 78 | continue; | ||
| 79 | } | ||
| 76 | lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); | 80 | lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); |
| 77 | frametype = skb->data[2]; | 81 | frametype = skb->data[2]; |
| 78 | dest = (rose_address *)(skb->data + 4); | 82 | if (frametype == ROSE_CALL_REQUEST && |
| 83 | (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || | ||
| 84 | skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != | ||
| 85 | ROSE_CALL_REQ_ADDR_LEN_VAL)) { | ||
| 86 | kfree_skb(skb); | ||
| 87 | continue; | ||
| 88 | } | ||
| 89 | dest = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); | ||
| 79 | lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; | 90 | lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; |
| 80 | 91 | ||
| 81 | skb_reset_transport_header(skb); | 92 | skb_reset_transport_header(skb); |
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 88a77e90e7e8..08dcd2f29cdc 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c | |||
| @@ -861,7 +861,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
| 861 | unsigned int lci, new_lci; | 861 | unsigned int lci, new_lci; |
| 862 | unsigned char cause, diagnostic; | 862 | unsigned char cause, diagnostic; |
| 863 | struct net_device *dev; | 863 | struct net_device *dev; |
| 864 | int len, res = 0; | 864 | int res = 0; |
| 865 | char buf[11]; | 865 | char buf[11]; |
| 866 | 866 | ||
| 867 | #if 0 | 867 | #if 0 |
| @@ -869,10 +869,17 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
| 869 | return res; | 869 | return res; |
| 870 | #endif | 870 | #endif |
| 871 | 871 | ||
| 872 | if (skb->len < ROSE_MIN_LEN) | ||
| 873 | return res; | ||
| 872 | frametype = skb->data[2]; | 874 | frametype = skb->data[2]; |
| 873 | lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); | 875 | lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); |
| 874 | src_addr = (rose_address *)(skb->data + 9); | 876 | if (frametype == ROSE_CALL_REQUEST && |
| 875 | dest_addr = (rose_address *)(skb->data + 4); | 877 | (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || |
| 878 | skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != | ||
| 879 | ROSE_CALL_REQ_ADDR_LEN_VAL)) | ||
| 880 | return res; | ||
| 881 | src_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_SRC_ADDR_OFF); | ||
| 882 | dest_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); | ||
| 876 | 883 | ||
| 877 | spin_lock_bh(&rose_neigh_list_lock); | 884 | spin_lock_bh(&rose_neigh_list_lock); |
| 878 | spin_lock_bh(&rose_route_list_lock); | 885 | spin_lock_bh(&rose_route_list_lock); |
| @@ -1010,12 +1017,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
| 1010 | goto out; | 1017 | goto out; |
| 1011 | } | 1018 | } |
| 1012 | 1019 | ||
| 1013 | len = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1; | ||
| 1014 | len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1; | ||
| 1015 | |||
| 1016 | memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); | 1020 | memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); |
| 1017 | 1021 | ||
| 1018 | if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { | 1022 | if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF, |
| 1023 | skb->len - ROSE_CALL_REQ_FACILITIES_OFF, | ||
| 1024 | &facilities)) { | ||
| 1019 | rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76); | 1025 | rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76); |
| 1020 | goto out; | 1026 | goto out; |
| 1021 | } | 1027 | } |
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 174d51c9ce37..f6c71caa94b9 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c | |||
| @@ -142,7 +142,7 @@ void rose_write_internal(struct sock *sk, int frametype) | |||
| 142 | *dptr++ = ROSE_GFI | lci1; | 142 | *dptr++ = ROSE_GFI | lci1; |
| 143 | *dptr++ = lci2; | 143 | *dptr++ = lci2; |
| 144 | *dptr++ = frametype; | 144 | *dptr++ = frametype; |
| 145 | *dptr++ = 0xAA; | 145 | *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL; |
| 146 | memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); | 146 | memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); |
| 147 | dptr += ROSE_ADDR_LEN; | 147 | dptr += ROSE_ADDR_LEN; |
| 148 | memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); | 148 | memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); |
| @@ -246,12 +246,16 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct * | |||
| 246 | do { | 246 | do { |
| 247 | switch (*p & 0xC0) { | 247 | switch (*p & 0xC0) { |
| 248 | case 0x00: | 248 | case 0x00: |
| 249 | if (len < 2) | ||
| 250 | return -1; | ||
| 249 | p += 2; | 251 | p += 2; |
| 250 | n += 2; | 252 | n += 2; |
| 251 | len -= 2; | 253 | len -= 2; |
| 252 | break; | 254 | break; |
| 253 | 255 | ||
| 254 | case 0x40: | 256 | case 0x40: |
| 257 | if (len < 3) | ||
| 258 | return -1; | ||
| 255 | if (*p == FAC_NATIONAL_RAND) | 259 | if (*p == FAC_NATIONAL_RAND) |
| 256 | facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); | 260 | facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); |
| 257 | p += 3; | 261 | p += 3; |
| @@ -260,32 +264,48 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct * | |||
| 260 | break; | 264 | break; |
| 261 | 265 | ||
| 262 | case 0x80: | 266 | case 0x80: |
| 267 | if (len < 4) | ||
| 268 | return | ||
