| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * SCSI Enclosure Services |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> |
|---|
| 5 | | - * |
|---|
| 6 | | -**----------------------------------------------------------------------------- |
|---|
| 7 | | -** |
|---|
| 8 | | -** This program is free software; you can redistribute it and/or |
|---|
| 9 | | -** modify it under the terms of the GNU General Public License |
|---|
| 10 | | -** version 2 as published by the Free Software Foundation. |
|---|
| 11 | | -** |
|---|
| 12 | | -** This program is distributed in the hope that it will be useful, |
|---|
| 13 | | -** but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | -** GNU General Public License for more details. |
|---|
| 16 | | -** |
|---|
| 17 | | -** You should have received a copy of the GNU General Public License |
|---|
| 18 | | -** along with this program; if not, write to the Free Software |
|---|
| 19 | | -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 20 | | -** |
|---|
| 21 | | -**----------------------------------------------------------------------------- |
|---|
| 22 | | -*/ |
|---|
| 6 | + */ |
|---|
| 23 | 7 | |
|---|
| 24 | 8 | #include <linux/slab.h> |
|---|
| 25 | 9 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 449 | 433 | } |
|---|
| 450 | 434 | #endif /* 0 */ |
|---|
| 451 | 435 | |
|---|
| 452 | | -static void ses_process_descriptor(struct enclosure_component *ecomp, |
|---|
| 453 | | - unsigned char *desc) |
|---|
| 436 | +static int ses_process_descriptor(struct enclosure_component *ecomp, |
|---|
| 437 | + unsigned char *desc, int max_desc_len) |
|---|
| 454 | 438 | { |
|---|
| 455 | 439 | int eip = desc[0] & 0x10; |
|---|
| 456 | 440 | int invalid = desc[0] & 0x80; |
|---|
| .. | .. |
|---|
| 461 | 445 | unsigned char *d; |
|---|
| 462 | 446 | |
|---|
| 463 | 447 | if (invalid) |
|---|
| 464 | | - return; |
|---|
| 448 | + return 0; |
|---|
| 465 | 449 | |
|---|
| 466 | 450 | switch (proto) { |
|---|
| 467 | 451 | case SCSI_PROTOCOL_FCP: |
|---|
| 468 | 452 | if (eip) { |
|---|
| 453 | + if (max_desc_len <= 7) |
|---|
| 454 | + return 1; |
|---|
| 469 | 455 | d = desc + 4; |
|---|
| 470 | 456 | slot = d[3]; |
|---|
| 471 | 457 | } |
|---|
| 472 | 458 | break; |
|---|
| 473 | 459 | case SCSI_PROTOCOL_SAS: |
|---|
| 460 | + |
|---|
| 474 | 461 | if (eip) { |
|---|
| 462 | + if (max_desc_len <= 27) |
|---|
| 463 | + return 1; |
|---|
| 475 | 464 | d = desc + 4; |
|---|
| 476 | 465 | slot = d[3]; |
|---|
| 477 | 466 | d = desc + 8; |
|---|
| 478 | | - } else |
|---|
| 467 | + } else { |
|---|
| 468 | + if (max_desc_len <= 23) |
|---|
| 469 | + return 1; |
|---|
| 479 | 470 | d = desc + 4; |
|---|
| 471 | + } |
|---|
| 472 | + |
|---|
| 473 | + |
|---|
| 480 | 474 | /* only take the phy0 addr */ |
|---|
| 481 | 475 | addr = (u64)d[12] << 56 | |
|---|
| 482 | 476 | (u64)d[13] << 48 | |
|---|
| .. | .. |
|---|
| 493 | 487 | } |
|---|
| 494 | 488 | ecomp->slot = slot; |
|---|
| 495 | 489 | scomp->addr = addr; |
|---|
| 490 | + |
|---|
| 491 | + return 0; |
|---|
| 496 | 492 | } |
|---|
| 497 | 493 | |
|---|
| 498 | 494 | struct efd { |
|---|
| .. | .. |
|---|
| 506 | 502 | struct efd *efd = data; |
|---|
| 507 | 503 | int i; |
|---|
| 508 | 504 | struct ses_component *scomp; |
|---|
| 509 | | - |
|---|
| 510 | | - if (!edev->component[0].scratch) |
|---|
| 511 | | - return 0; |
|---|
| 512 | 505 | |
|---|
| 513 | 506 | for (i = 0; i < edev->components; i++) { |
|---|
| 514 | 507 | scomp = edev->component[i].scratch; |
|---|
| .. | .. |
|---|
| 565 | 558 | /* skip past overall descriptor */ |
|---|
| 566 | 559 | desc_ptr += len + 4; |
|---|
| 567 | 560 | } |
|---|
| 568 | | - if (ses_dev->page10) |
|---|
| 561 | + if (ses_dev->page10 && ses_dev->page10_len > 9) |
|---|
| 569 | 562 | addl_desc_ptr = ses_dev->page10 + 8; |
|---|
| 570 | 563 | type_ptr = ses_dev->page1_types; |
|---|
| 571 | 564 | components = 0; |
|---|
| .. | .. |
|---|
| 573 | 566 | for (j = 0; j < type_ptr[1]; j++) { |
|---|
| 574 | 567 | char *name = NULL; |
|---|
| 575 | 568 | struct enclosure_component *ecomp; |
|---|
| 569 | + int max_desc_len; |
|---|
| 576 | 570 | |
|---|
| 577 | 571 | if (desc_ptr) { |
|---|
| 578 | | - if (desc_ptr >= buf + page7_len) { |
|---|
| 572 | + if (desc_ptr + 3 >= buf + page7_len) { |
|---|
| 579 | 573 | desc_ptr = NULL; |
|---|
| 580 | 574 | } else { |
|---|
| 581 | 575 | len = (desc_ptr[2] << 8) + desc_ptr[3]; |
|---|
| 582 | 576 | desc_ptr += 4; |
|---|
| 583 | | - /* Add trailing zero - pushes into |
|---|
| 584 | | - * reserved space */ |
|---|
| 585 | | - desc_ptr[len] = '\0'; |
|---|
| 586 | | - 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 | + } |
|---|
| 587 | 585 | } |
|---|
| 588 | 586 | } |
|---|
| 589 | 587 | if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || |
|---|
| .. | .. |
|---|
| 595 | 593 | components++, |
|---|
| 596 | 594 | type_ptr[0], |
|---|
| 597 | 595 | name); |
|---|
| 598 | | - else |
|---|
| 596 | + else if (components < edev->components) |
|---|
| 599 | 597 | ecomp = &edev->component[components++]; |
|---|
| 598 | + else |
|---|
| 599 | + ecomp = ERR_PTR(-EINVAL); |
|---|
| 600 | 600 | |
|---|
| 601 | 601 | if (!IS_ERR(ecomp)) { |
|---|
| 602 | | - if (addl_desc_ptr) |
|---|
| 603 | | - ses_process_descriptor( |
|---|
| 604 | | - ecomp, |
|---|
| 605 | | - 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 | + } |
|---|
| 606 | 610 | if (create) |
|---|
| 607 | 611 | enclosure_component_register( |
|---|
| 608 | 612 | ecomp); |
|---|
| .. | .. |
|---|
| 619 | 623 | /* these elements are optional */ |
|---|
| 620 | 624 | type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT || |
|---|
| 621 | 625 | type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT || |
|---|
| 622 | | - type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) |
|---|
| 626 | + type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) { |
|---|
| 623 | 627 | addl_desc_ptr += addl_desc_ptr[1] + 2; |
|---|
| 624 | | - |
|---|
| 628 | + if (addl_desc_ptr + 1 >= ses_dev->page10 + ses_dev->page10_len) |
|---|
| 629 | + addl_desc_ptr = NULL; |
|---|
| 630 | + } |
|---|
| 625 | 631 | } |
|---|
| 626 | 632 | } |
|---|
| 627 | 633 | kfree(buf); |
|---|
| .. | .. |
|---|
| 720 | 726 | type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) |
|---|
| 721 | 727 | components += type_ptr[1]; |
|---|
| 722 | 728 | } |
|---|
| 729 | + |
|---|
| 723 | 730 | ses_dev->page1 = buf; |
|---|
| 724 | 731 | ses_dev->page1_len = len; |
|---|
| 725 | 732 | buf = NULL; |
|---|
| .. | .. |
|---|
| 761 | 768 | buf = NULL; |
|---|
| 762 | 769 | } |
|---|
| 763 | 770 | page2_not_supported: |
|---|
| 764 | | - scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); |
|---|
| 765 | | - if (!scomp) |
|---|
| 766 | | - 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 | + } |
|---|
| 767 | 776 | |
|---|
| 768 | 777 | edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), |
|---|
| 769 | 778 | components, &ses_enclosure_callbacks); |
|---|
| .. | .. |
|---|
| 843 | 852 | kfree(ses_dev->page2); |
|---|
| 844 | 853 | kfree(ses_dev); |
|---|
| 845 | 854 | |
|---|
| 846 | | - kfree(edev->component[0].scratch); |
|---|
| 855 | + if (edev->components) |
|---|
| 856 | + kfree(edev->component[0].scratch); |
|---|
| 847 | 857 | |
|---|
| 848 | 858 | put_device(&edev->edev); |
|---|
| 849 | 859 | enclosure_unregister(edev); |
|---|