diff options
Diffstat (limited to 'net/rose')
| -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 | 22 | ||||
| -rw-r--r-- | net/rose/rose_subr.c | 101 |
4 files changed, 99 insertions, 45 deletions
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..479cae57d187 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c | |||
| @@ -587,7 +587,7 @@ static int rose_clear_routes(void) | |||
| 587 | 587 | ||
| 588 | /* | 588 | /* |
| 589 | * Check that the device given is a valid AX.25 interface that is "up". | 589 | * Check that the device given is a valid AX.25 interface that is "up". |
| 590 | * called whith RTNL | 590 | * called with RTNL |
| 591 | */ | 591 | */ |
| 592 | static struct net_device *rose_ax25_dev_find(char *devname) | 592 | static struct net_device *rose_ax25_dev_find(char *devname) |
| 593 | { | 593 | { |
| @@ -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 1734abba26a2..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,40 +264,61 @@ 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 -1; | ||
| 263 | p += 4; | 269 | p += 4; |
| 264 | n += 4; | 270 | n += 4; |
| 265 | len -= 4; | 271 | len -= 4; |
| 266 | break; | 272 | break; |
| 267 | 273 | ||
| 268 | case 0xC0: | 274 | case 0xC0: |
| 275 | if (len < 2) | ||
| 276 | return -1; | ||
| 269 | l = p[1]; | 277 | l = p[1]; |
| 278 | if (len < 2 + l) | ||
| 279 | return -1; | ||
| 270 | if (*p == FAC_NATIONAL_DEST_DIGI) { | 280 | if (*p == FAC_NATIONAL_DEST_DIGI) { |
| 271 | if (!fac_national_digis_received) { | 281 | if (!fac_national_digis_received) { |
| 282 | if (l < AX25_ADDR_LEN) | ||
| 283 | return -1; | ||
| 272 | memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); | 284 | memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); |
| 273 | facilities->source_ndigis = 1; | 285 | facilities->source_ndigis = 1; |
| 274 | } | 286 | } |
| 275 | } | 287 | } |
| 276 | else if (*p == FAC_NATIONAL_SRC_DIGI) { | 288 | else if (*p == FAC_NATIONAL_SRC_DIGI) { |
| 277 | if (!fac_national_digis_received) { | 289 | if (!fac_national_digis_received) { |
| 290 | if (l < AX25_ADDR_LEN) | ||
| 291 | return -1; | ||
| 278 | memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); | 292 | memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); |
| 279 | facilities->dest_ndigis = 1; | 293 | facilities->dest_ndigis = 1; |
| 280 | } | 294 | } |
| 281 | } | 295 | } |
| 282 | else if (*p == FAC_NATIONAL_FAIL_CALL) { | 296 | else if (*p == FAC_NATIONAL_FAIL_CALL) { |
| 297 | if (l < AX25_ADDR_LEN) | ||
| 298 | return -1; | ||
| 283 | memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); | 299 | memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); |
| 284 | } | 300 | } |
| 285 | else if (*p == FAC_NATIONAL_FAIL_ADD) { | 301 | else if (*p == FAC_NATIONAL_FAIL_ADD) { |
| 302 | if (l < 1 + ROSE_ADDR_LEN) | ||
| 303 | return -1; | ||
| 286 | memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); | 304 | memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); |
| 287 | } | 305 | } |
| 288 | else if (*p == FAC_NATIONAL_DIGIS) { | 306 | else if (*p == FAC_NATIONAL_DIGIS) { |
| 307 | if (l % AX25_ADDR_LEN) | ||
| 308 | return -1; | ||
| 289 | fac_national_digis_received = 1; | 309 | fac_national_digis_received = 1; |
| 290 | facilities->source_ndigis = 0; | 310 | facilities->source_ndigis = 0; |
| 291 | facilities->dest_ndigis = 0; | 311 | facilities->dest_ndigis = 0; |
| 292 | for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { | 312 | for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { |
| 293 | if (pt[6] & AX25_HBIT) | 313 | if (pt[6] & AX25_HBIT) { |
| 314 | if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) | ||
| 315 | return -1; | ||
| 294 | memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); | 316 | memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); |
| 295 | else | 317 | } else { |
| 318 | if (facilities->source_ndigis >= ROSE_MAX_DIGIS) | ||
| 319 | return -1; | ||
| 296 | memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); | 320 | memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); |
| 321 | } | ||
| 297 | } | 322 | } |
| 298 | } | 323 | } |
| 299 | p += l + 2; | 324 | p += l + 2; |
| @@ -314,25 +339,38 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac | |||
| 314 | do { | 339 | do { |
| 315 | switch (*p & 0xC0) { | 340 | switch (*p & 0xC0) { |
| 316 | case 0x00: | 341 | case 0x00: |
| 342 | if (len < 2) | ||
| 343 | return -1; | ||
| 317 | p += 2; | 344 | p += 2; |
| 318 | n += 2; | 345 | n += 2; |
| 319 | len -= 2; | 346 | len -= 2; |
| 320 | break; | 347 | break; |
| 321 | 348 | ||
| 322 | case 0x40: | 349 | case 0x40: |
| 350 | if (len < 3) | ||
| 351 | return -1; | ||
| 323 | p += 3; | 352 | p += 3; |
| 324 | n += 3; | 353 | n += 3; |
| 325 | len -= 3; | 354 | len -= 3; |
| 326 | break; | 355 | break; |
| 327 | 356 | ||
| 328 | case 0x80: | 357 | case 0x80: |
| 358 | if (len < 4) | ||
| 359 | return -1; | ||
| 329 | p += 4; | 360 | p += 4; |
| 330 | n += 4; | 361 | n += 4; |
| 331 | len -= 4; | 362 | len -= 4; |
| 332 | break; | 363 | break; |
| 333 | 364 | ||
| 334 | case 0xC0: | 365 | case 0xC0: |
| 366 | if (len < 2) | ||
| 367 | return -1; | ||
| 335 | l = p[1]; | 368 | l = p[1]; |
| 369 | |||
| 370 | /* Prevent overflows*/ | ||
| 371 | if (l < 10 || l > 20) | ||
| 372 | return -1; | ||
| 373 | |||
| 336 | if (*p == FAC_CCITT_DEST_NSAP) { | 374 | if (*p == FAC_CCITT_DEST_NSAP) { |
| 337 | memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); | 375 | memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); |
| 338 | memcpy(callsign, p + 12, l - 10); | 376 | memcpy(callsign, p + 12, l - 10); |
| @@ -355,45 +393,44 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac | |||
| 355 | return n; | 393 | return n; |
| 356 | } | 394 | } |
| 357 | 395 | ||
| 358 | int rose_parse_facilities(unsigned char *p, | 396 | int rose_parse_facilities(unsigned char *p, unsigned packet_len, |
| 359 | struct rose_facilities_struct *facilities) | 397 | struct rose_facilities_struct *facilities) |
| 360 | { | 398 | { |
| 361 | int facilities_len, len; | 399 | int facilities_len, len; |
| 362 | 400 | ||
| 363 | facilities_len = *p++; | 401 | facilities_len = *p++; |
| 364 | 402 | ||
| 365 | if (facilities_len == 0) | 403 | if (facilities_len == 0 || (unsigned)facilities_len > packet_len) |
| 366 | return 0; | 404 | return 0; |
| 367 | 405 | ||
| 368 | while (facilities_len > 0) { | 406 | while (facilities_len >= 3 && *p == 0x00) { |
| 369 | if (*p == 0x00) { | 407 | facilities_len--; |
| 370 | facilities_len--; | 408 | p++; |
| 371 | p++; | 409 | |
| 372 | 410 | switch (*p) { | |
| 373 | switch (*p) { | 411 | case FAC_NATIONAL: /* National */ |
| 374 | case FAC_NATIONAL: /* National */ | 412 | len = rose_parse_national(p + 1, facilities, facilities_len - 1); |
| 375 | len = rose_parse_national(p + 1, facilities, facilities_len - 1); | 413 | break; |
| 376 | facilities_len -= len + 1; | 414 | |
| 377 | p += len + 1; | 415 | case FAC_CCITT: /* CCITT */ |
| 378 | break; | 416 | len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); |
| 379 | 417 | break; | |
| 380 | case FAC_CCITT: /* CCITT */ | 418 | |
| 381 | len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); | 419 | default: |
| 382 | facilities_len -= len + 1; | 420 | printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); |
| 383 | p += len + 1; | 421 | len = 1; |
| 384 | break; | 422 | break; |
| 385 | 423 | } | |
| 386 | default: | 424 | |
| 387 | printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); | 425 | if (len < 0) |
| 388 | facilities_len--; | 426 | return 0; |
| 389 | p++; | 427 | if (WARN_ON(len >= facilities_len)) |
| 390 | break; | 428 | return 0; |
| 391 | } | 429 | facilities_len -= len + 1; |
| 392 | } else | 430 | p += len + 1; |
| 393 | break; /* Error in facilities format */ | ||
| 394 | } | 431 | } |
| 395 | 432 | ||
| 396 | return 1; | 433 | return facilities_len == 0; |
| 397 | } | 434 | } |
| 398 | 435 | ||
| 399 | static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) | 436 | static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) |
