Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ben Hutchings and committed by
David S. Miller
e0bccd31 be20250c

+90 -44
+7 -1
include/net/rose.h
··· 14 14 15 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 23 #define ROSE_GFI 0x10 18 24 #define ROSE_Q_BIT 0x80 19 25 #define ROSE_D_BIT 0x40 ··· 220 214 extern int rose_validate_nr(struct sock *, unsigned short); 221 215 extern void rose_write_internal(struct sock *, int); 222 216 extern int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *); 223 - extern int rose_parse_facilities(unsigned char *, struct rose_facilities_struct *); 217 + extern int rose_parse_facilities(unsigned char *, unsigned int, struct rose_facilities_struct *); 224 218 extern void rose_disconnect(struct sock *, int, int, int); 225 219 226 220 /* rose_timer.c */
+4 -4
net/rose/af_rose.c
··· 978 978 struct sock *make; 979 979 struct rose_sock *make_rose; 980 980 struct rose_facilities_struct facilities; 981 - int n, len; 981 + int n; 982 982 983 983 skb->sk = NULL; /* Initially we don't know who it's for */ 984 984 ··· 987 987 */ 988 988 memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); 989 989 990 - len = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1; 991 - len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1; 992 - if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { 990 + if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF, 991 + skb->len - ROSE_CALL_REQ_FACILITIES_OFF, 992 + &facilities)) { 993 993 rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76); 994 994 return 0; 995 995 }
+12 -1
net/rose/rose_loopback.c
··· 73 73 unsigned int lci_i, lci_o; 74 74 75 75 while ((skb = skb_dequeue(&loopback_queue)) != NULL) { 76 + if (skb->len < ROSE_MIN_LEN) { 77 + kfree_skb(skb); 78 + continue; 79 + } 76 80 lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 77 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 90 lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; 80 91 81 92 skb_reset_transport_header(skb);
+13 -7
net/rose/rose_route.c
··· 861 861 unsigned int lci, new_lci; 862 862 unsigned char cause, diagnostic; 863 863 struct net_device *dev; 864 - int len, res = 0; 864 + int res = 0; 865 865 char buf[11]; 866 866 867 867 #if 0 ··· 869 869 return res; 870 870 #endif 871 871 872 + if (skb->len < ROSE_MIN_LEN) 873 + return res; 872 874 frametype = skb->data[2]; 873 875 lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 874 - src_addr = (rose_address *)(skb->data + 9); 875 - dest_addr = (rose_address *)(skb->data + 4); 876 + if (frametype == ROSE_CALL_REQUEST && 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 884 spin_lock_bh(&rose_neigh_list_lock); 878 885 spin_lock_bh(&rose_route_list_lock); ··· 1017 1010 goto out; 1018 1011 } 1019 1012 1020 - len = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1; 1021 - len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1; 1022 - 1023 1013 memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); 1024 1014 1025 - if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { 1015 + if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF, 1016 + skb->len - ROSE_CALL_REQ_FACILITIES_OFF, 1017 + &facilities)) { 1026 1018 rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76); 1027 1019 goto out; 1028 1020 }
+54 -31
net/rose/rose_subr.c
··· 142 142 *dptr++ = ROSE_GFI | lci1; 143 143 *dptr++ = lci2; 144 144 *dptr++ = frametype; 145 - *dptr++ = 0xAA; 145 + *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL; 146 146 memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); 147 147 dptr += ROSE_ADDR_LEN; 148 148 memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); ··· 246 246 do { 247 247 switch (*p & 0xC0) { 248 248 case 0x00: 249 + if (len < 2) 250 + return -1; 249 251 p += 2; 250 252 n += 2; 251 253 len -= 2; 252 254 break; 253 255 254 256 case 0x40: 257 + if (len < 3) 258 + return -1; 255 259 if (*p == FAC_NATIONAL_RAND) 256 260 facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); 257 261 p += 3; ··· 264 260 break; 265 261 266 262 case 0x80: 263 + if (len < 4) 264 + return -1; 267 265 p += 4; 268 266 n += 4; 269 267 len -= 4; 270 268 break; 271 269 272 270 case 0xC0: 271 + if (len < 2) 272 + return -1; 273 273 l = p[1]; 274 + if (len < 2 + l) 275 + return -1; 274 276 if (*p == FAC_NATIONAL_DEST_DIGI) { 275 277 if (!fac_national_digis_received) { 278 + if (l < AX25_ADDR_LEN) 279 + return -1; 276 280 memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); 277 281 facilities->source_ndigis = 1; 278 282 } 279 283 } 280 284 else if (*p == FAC_NATIONAL_SRC_DIGI) { 281 285 if (!fac_national_digis_received) { 286 + if (l < AX25_ADDR_LEN) 287 + return -1; 282 288 memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); 283 289 facilities->dest_ndigis = 1; 284 290 } 285 291 } 286 292 else if (*p == FAC_NATIONAL_FAIL_CALL) { 293 + if (l < AX25_ADDR_LEN) 294 + return -1; 287 295 memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); 288 296 } 289 297 else if (*p == FAC_NATIONAL_FAIL_ADD) { 298 + if (l < 1 + ROSE_ADDR_LEN) 299 + return -1; 290 300 memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); 291 301 } 292 302 else if (*p == FAC_NATIONAL_DIGIS) { 303 + if (l % AX25_ADDR_LEN) 304 + return -1; 293 305 fac_national_digis_received = 1; 294 306 facilities->source_ndigis = 0; 295 307 facilities->dest_ndigis = 0; ··· 339 319 do { 340 320 switch (*p & 0xC0) { 341 321 case 0x00: 322 + if (len < 2) 323 + return -1; 342 324 p += 2; 343 325 n += 2; 344 326 len -= 2; 345 327 break; 346 328 347 329 case 0x40: 330 + if (len < 3) 331 + return -1; 348 332 p += 3; 349 333 n += 3; 350 334 len -= 3; 351 335 break; 352 336 353 337 case 0x80: 338 + if (len < 4) 339 + return -1; 354 340 p += 4; 355 341 n += 4; 356 342 len -= 4; 357 343 break; 358 344 359 345 case 0xC0: 346 + if (len < 2) 347 + return -1; 360 348 l = p[1]; 361 349 362 350 /* Prevent overflows*/ ··· 393 365 return n; 394 366 } 395 367 396 - int rose_parse_facilities(unsigned char *p, 368 + int rose_parse_facilities(unsigned char *p, unsigned packet_len, 397 369 struct rose_facilities_struct *facilities) 398 370 { 399 371 int facilities_len, len; 400 372 401 373 facilities_len = *p++; 402 374 403 - if (facilities_len == 0) 375 + if (facilities_len == 0 || (unsigned)facilities_len > packet_len) 404 376 return 0; 405 377 406 - while (facilities_len > 0) { 407 - if (*p == 0x00) { 408 - facilities_len--; 409 - p++; 378 + while (facilities_len >= 3 && *p == 0x00) { 379 + facilities_len--; 380 + p++; 410 381 411 - switch (*p) { 412 - case FAC_NATIONAL: /* National */ 413 - len = rose_parse_national(p + 1, facilities, facilities_len - 1); 414 - if (len < 0) 415 - return 0; 416 - facilities_len -= len + 1; 417 - p += len + 1; 418 - break; 382 + switch (*p) { 383 + case FAC_NATIONAL: /* National */ 384 + len = rose_parse_national(p + 1, facilities, facilities_len - 1); 385 + break; 419 386 420 - case FAC_CCITT: /* CCITT */ 421 - len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); 422 - if (len < 0) 423 - return 0; 424 - facilities_len -= len + 1; 425 - p += len + 1; 426 - break; 387 + case FAC_CCITT: /* CCITT */ 388 + len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); 389 + break; 427 390 428 - default: 429 - printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); 430 - facilities_len--; 431 - p++; 432 - break; 433 - } 434 - } else 435 - break; /* Error in facilities format */ 391 + default: 392 + printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); 393 + len = 1; 394 + break; 395 + } 396 + 397 + if (len < 0) 398 + return 0; 399 + if (WARN_ON(len >= facilities_len)) 400 + return 0; 401 + facilities_len -= len + 1; 402 + p += len + 1; 436 403 } 437 404 438 - return 1; 405 + return facilities_len == 0; 439 406 } 440 407 441 408 static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)