| .. | .. |
|---|
| 433 | 433 | } |
|---|
| 434 | 434 | #endif /* 0 */ |
|---|
| 435 | 435 | |
|---|
| 436 | | -static void ses_process_descriptor(struct enclosure_component *ecomp, |
|---|
| 437 | | - unsigned char *desc) |
|---|
| 436 | +static int ses_process_descriptor(struct enclosure_component *ecomp, |
|---|
| 437 | + unsigned char *desc, int max_desc_len) |
|---|
| 438 | 438 | { |
|---|
| 439 | 439 | int eip = desc[0] & 0x10; |
|---|
| 440 | 440 | int invalid = desc[0] & 0x80; |
|---|
| .. | .. |
|---|
| 445 | 445 | unsigned char *d; |
|---|
| 446 | 446 | |
|---|
| 447 | 447 | if (invalid) |
|---|
| 448 | | - return; |
|---|
| 448 | + return 0; |
|---|
| 449 | 449 | |
|---|
| 450 | 450 | switch (proto) { |
|---|
| 451 | 451 | case SCSI_PROTOCOL_FCP: |
|---|
| 452 | 452 | if (eip) { |
|---|
| 453 | + if (max_desc_len <= 7) |
|---|
| 454 | + return 1; |
|---|
| 453 | 455 | d = desc + 4; |
|---|
| 454 | 456 | slot = d[3]; |
|---|
| 455 | 457 | } |
|---|
| 456 | 458 | break; |
|---|
| 457 | 459 | case SCSI_PROTOCOL_SAS: |
|---|
| 460 | + |
|---|
| 458 | 461 | if (eip) { |
|---|
| 462 | + if (max_desc_len <= 27) |
|---|
| 463 | + return 1; |
|---|
| 459 | 464 | d = desc + 4; |
|---|
| 460 | 465 | slot = d[3]; |
|---|
| 461 | 466 | d = desc + 8; |
|---|
| 462 | | - } else |
|---|
| 467 | + } else { |
|---|
| 468 | + if (max_desc_len <= 23) |
|---|
| 469 | + return 1; |
|---|
| 463 | 470 | d = desc + 4; |
|---|
| 471 | + } |
|---|
| 472 | + |
|---|
| 473 | + |
|---|
| 464 | 474 | /* only take the phy0 addr */ |
|---|
| 465 | 475 | addr = (u64)d[12] << 56 | |
|---|
| 466 | 476 | (u64)d[13] << 48 | |
|---|
| .. | .. |
|---|
| 477 | 487 | } |
|---|
| 478 | 488 | ecomp->slot = slot; |
|---|
| 479 | 489 | scomp->addr = addr; |
|---|
| 490 | + |
|---|
| 491 | + return 0; |
|---|
| 480 | 492 | } |
|---|
| 481 | 493 | |
|---|
| 482 | 494 | struct efd { |
|---|
| .. | .. |
|---|
| 490 | 502 | struct efd *efd = data; |
|---|
| 491 | 503 | int i; |
|---|
| 492 | 504 | struct ses_component *scomp; |
|---|
| 493 | | - |
|---|
| 494 | | - if (!edev->component[0].scratch) |
|---|
| 495 | | - return 0; |
|---|
| 496 | 505 | |
|---|
| 497 | 506 | for (i = 0; i < edev->components; i++) { |
|---|
| 498 | 507 | scomp = edev->component[i].scratch; |
|---|
| .. | .. |
|---|
| 549 | 558 | /* skip past overall descriptor */ |
|---|
| 550 | 559 | desc_ptr += len + 4; |
|---|
| 551 | 560 | } |
|---|
| 552 | | - if (ses_dev->page10) |
|---|
| 561 | + if (ses_dev->page10 && ses_dev->page10_len > 9) |
|---|
| 553 | 562 | addl_desc_ptr = ses_dev->page10 + 8; |
|---|
| 554 | 563 | type_ptr = ses_dev->page1_types; |
|---|
| 555 | 564 | components = 0; |
|---|
| .. | .. |
|---|
| 557 | 566 | for (j = 0; j < type_ptr[1]; j++) { |
|---|
| 558 | 567 | char *name = NULL; |
|---|
| 559 | 568 | struct enclosure_component *ecomp; |
|---|
| 569 | + int max_desc_len; |
|---|
| 560 | 570 | |
|---|
| 561 | 571 | if (desc_ptr) { |
|---|
| 562 | | - if (desc_ptr >= buf + page7_len) { |
|---|
| 572 | + if (desc_ptr + 3 >= buf + page7_len) { |
|---|
| 563 | 573 | desc_ptr = NULL; |
|---|
| 564 | 574 | } else { |
|---|
| 565 | 575 | len = (desc_ptr[2] << 8) + desc_ptr[3]; |
|---|
| 566 | 576 | desc_ptr += 4; |
|---|
| 567 | | - /* Add trailing zero - pushes into |
|---|
| 568 | | - * reserved space */ |
|---|
| 569 | | - desc_ptr[len] = '\0'; |
|---|
| 570 | | - name = desc_ptr; |
|---|
| 577 | + if (desc_ptr + len > buf + page7_len) |
|---|
| 578 | + desc_ptr = NULL; |
|---|
| 579 | + else { |
|---|
| 580 | + /* Add trailing zero - pushes into |
|---|
| 581 | + * reserved space */ |
|---|
| 582 | + desc_ptr[len] = '\0'; |
|---|
| 583 | + name = desc_ptr; |
|---|
| 584 | + } |
|---|
| 571 | 585 | } |
|---|
| 572 | 586 | } |
|---|
| 573 | 587 | if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || |
|---|
| .. | .. |
|---|
| 579 | 593 | components++, |
|---|
| 580 | 594 | type_ptr[0], |
|---|
| 581 | 595 | name); |
|---|
| 582 | | - else |
|---|
| 596 | + else if (components < edev->components) |
|---|
| 583 | 597 | ecomp = &edev->component[components++]; |
|---|
| 598 | + else |
|---|
| 599 | + ecomp = ERR_PTR(-EINVAL); |
|---|
| 584 | 600 | |
|---|
| 585 | 601 | if (!IS_ERR(ecomp)) { |
|---|
| 586 | | - if (addl_desc_ptr) |
|---|
| 587 | | - ses_process_descriptor( |
|---|
| 588 | | - ecomp, |
|---|
| 589 | | - addl_desc_ptr); |
|---|
| 602 | + if (addl_desc_ptr) { |
|---|
| 603 | + max_desc_len = ses_dev->page10_len - |
|---|
| 604 | + (addl_desc_ptr - ses_dev->page10); |
|---|
| 605 | + if (ses_process_descriptor(ecomp, |
|---|
| 606 | + addl_desc_ptr, |
|---|
| 607 | + max_desc_len)) |
|---|
| 608 | + addl_desc_ptr = NULL; |
|---|
| 609 | + } |
|---|
| 590 | 610 | if (create) |
|---|
| 591 | 611 | enclosure_component_register( |
|---|
| 592 | 612 | ecomp); |
|---|
| .. | .. |
|---|
| 603 | 623 | /* these elements are optional */ |
|---|
| 604 | 624 | type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT || |
|---|
| 605 | 625 | type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT || |
|---|
| 606 | | - type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) |
|---|
| 626 | + type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) { |
|---|
| 607 | 627 | addl_desc_ptr += addl_desc_ptr[1] + 2; |
|---|
| 608 | | - |
|---|
| 628 | + if (addl_desc_ptr + 1 >= ses_dev->page10 + ses_dev->page10_len) |
|---|
| 629 | + addl_desc_ptr = NULL; |
|---|
| 630 | + } |
|---|
| 609 | 631 | } |
|---|
| 610 | 632 | } |
|---|
| 611 | 633 | kfree(buf); |
|---|
| .. | .. |
|---|
| 704 | 726 | type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) |
|---|
| 705 | 727 | components += type_ptr[1]; |
|---|
| 706 | 728 | } |
|---|
| 729 | + |
|---|
| 707 | 730 | ses_dev->page1 = buf; |
|---|
| 708 | 731 | ses_dev->page1_len = len; |
|---|
| 709 | 732 | buf = NULL; |
|---|
| .. | .. |
|---|
| 745 | 768 | buf = NULL; |
|---|
| 746 | 769 | } |
|---|
| 747 | 770 | page2_not_supported: |
|---|
| 748 | | - scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); |
|---|
| 749 | | - if (!scomp) |
|---|
| 750 | | - goto err_free; |
|---|
| 771 | + if (components > 0) { |
|---|
| 772 | + scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); |
|---|
| 773 | + if (!scomp) |
|---|
| 774 | + goto err_free; |
|---|
| 775 | + } |
|---|
| 751 | 776 | |
|---|
| 752 | 777 | edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), |
|---|
| 753 | 778 | components, &ses_enclosure_callbacks); |
|---|
| .. | .. |
|---|
| 827 | 852 | kfree(ses_dev->page2); |
|---|
| 828 | 853 | kfree(ses_dev); |
|---|
| 829 | 854 | |
|---|
| 830 | | - kfree(edev->component[0].scratch); |
|---|
| 855 | + if (edev->components) |
|---|
| 856 | + kfree(edev->component[0].scratch); |
|---|
| 831 | 857 | |
|---|
| 832 | 858 | put_device(&edev->edev); |
|---|
| 833 | 859 | enclosure_unregister(edev); |
|---|