.. | .. |
---|
| 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); |
---|