diff options
author | Rajesh K Borundia <rajesh.borundia@qlogic.com> | 2010-03-28 22:43:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-29 16:18:37 -0400 |
commit | 10c0f2a852a529eacf2f223bbaef47832224a521 (patch) | |
tree | d2f2c6cca67ad3a8c8526d2bb707b99639cf93f5 | |
parent | 6b50ea1516fab30ce5843e5b11e43488f38c776d (diff) |
netxen: validate unified romimage
Signed-off-by: Rajesh K Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Validate all sections of unified romimage, before accessing them,
to avoid seg fault.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/netxen/netxen_nic.h | 1 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 154 |
2 files changed, 140 insertions, 15 deletions
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 144d2e880422..33ae5e13b608 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h | |||
@@ -420,7 +420,6 @@ struct status_desc { | |||
420 | } __attribute__ ((aligned(16))); | 420 | } __attribute__ ((aligned(16))); |
421 | 421 | ||
422 | /* UNIFIED ROMIMAGE *************************/ | 422 | /* UNIFIED ROMIMAGE *************************/ |
423 | #define NX_UNI_FW_MIN_SIZE 0xc8000 | ||
424 | #define NX_UNI_DIR_SECT_PRODUCT_TBL 0x0 | 423 | #define NX_UNI_DIR_SECT_PRODUCT_TBL 0x0 |
425 | #define NX_UNI_DIR_SECT_BOOTLD 0x6 | 424 | #define NX_UNI_DIR_SECT_BOOTLD 0x6 |
426 | #define NX_UNI_DIR_SECT_FW 0x7 | 425 | #define NX_UNI_DIR_SECT_FW 0x7 |
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1c63610ead42..141bc4389fec 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c | |||
@@ -613,22 +613,123 @@ static struct uni_table_desc *nx_get_table_desc(const u8 *unirom, int section) | |||
613 | return NULL; | 613 | return NULL; |
614 | } | 614 | } |
615 | 615 | ||
616 | #define QLCNIC_FILEHEADER_SIZE (14 * 4) | ||
617 | |||
616 | static int | 618 | static int |
617 | nx_set_product_offs(struct netxen_adapter *adapter) | 619 | netxen_nic_validate_header(struct netxen_adapter *adapter) |
618 | { | 620 | { |
619 | struct uni_table_desc *ptab_descr; | ||
620 | const u8 *unirom = adapter->fw->data; | 621 | const u8 *unirom = adapter->fw->data; |
621 | uint32_t i; | 622 | struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; |
623 | u32 fw_file_size = adapter->fw->size; | ||
624 | u32 tab_size; | ||
622 | __le32 entries; | 625 | __le32 entries; |
626 | __le32 entry_size; | ||
627 | |||
628 | if (fw_file_size < QLCNIC_FILEHEADER_SIZE) | ||
629 | return -EINVAL; | ||
630 | |||
631 | entries = cpu_to_le32(directory->num_entries); | ||
632 | entry_size = cpu_to_le32(directory->entry_size); | ||
633 | tab_size = cpu_to_le32(directory->findex) + (entries * entry_size); | ||
634 | |||
635 | if (fw_file_size < tab_size) | ||
636 | return -EINVAL; | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static int | ||
642 | netxen_nic_validate_bootld(struct netxen_adapter *adapter) | ||
643 | { | ||
644 | struct uni_table_desc *tab_desc; | ||
645 | struct uni_data_desc *descr; | ||
646 | const u8 *unirom = adapter->fw->data; | ||
647 | __le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + | ||
648 | NX_UNI_BOOTLD_IDX_OFF)); | ||
649 | u32 offs; | ||
650 | u32 tab_size; | ||
651 | u32 data_size; | ||
652 | |||
653 | tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_BOOTLD); | ||
654 | |||
655 | if (!tab_desc) | ||
656 | return -EINVAL; | ||
623 | 657 | ||
658 | tab_size = cpu_to_le32(tab_desc->findex) + | ||
659 | (cpu_to_le32(tab_desc->entry_size) * (idx + 1)); | ||
660 | |||
661 | if (adapter->fw->size < tab_size) | ||
662 | return -EINVAL; | ||
663 | |||
664 | offs = cpu_to_le32(tab_desc->findex) + | ||
665 | (cpu_to_le32(tab_desc->entry_size) * (idx)); | ||
666 | descr = (struct uni_data_desc *)&unirom[offs]; | ||
667 | |||
668 | data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size); | ||
669 | |||
670 | if (adapter->fw->size < data_size) | ||
671 | return -EINVAL; | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static int | ||
677 | netxen_nic_validate_fw(struct netxen_adapter *adapter) | ||
678 | { | ||
679 | struct uni_table_desc *tab_desc; | ||
680 | struct uni_data_desc *descr; | ||
681 | const u8 *unirom = adapter->fw->data; | ||
682 | __le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + | ||
683 | NX_UNI_FIRMWARE_IDX_OFF)); | ||
684 | u32 offs; | ||
685 | u32 tab_size; | ||
686 | u32 data_size; | ||
687 | |||
688 | tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_FW); | ||
689 | |||
690 | if (!tab_desc) | ||
691 | return -EINVAL; | ||
692 | |||
693 | tab_size = cpu_to_le32(tab_desc->findex) + | ||
694 | (cpu_to_le32(tab_desc->entry_size) * (idx + 1)); | ||
695 | |||
696 | if (adapter->fw->size < tab_size) | ||
697 | return -EINVAL; | ||
698 | |||
699 | offs = cpu_to_le32(tab_desc->findex) + | ||
700 | (cpu_to_le32(tab_desc->entry_size) * (idx)); | ||
701 | descr = (struct uni_data_desc *)&unirom[offs]; | ||
702 | data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size); | ||
703 | |||
704 | if (adapter->fw->size < data_size) | ||
705 | return -EINVAL; | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | |||
711 | static int | ||
712 | netxen_nic_validate_product_offs(struct netxen_adapter *adapter) | ||
713 | { | ||
714 | struct uni_table_desc *ptab_descr; | ||
715 | const u8 *unirom = adapter->fw->data; | ||
624 | int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ? | 716 | int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ? |
625 | 1 : netxen_p3_has_mn(adapter); | 717 | 1 : netxen_p3_has_mn(adapter); |
718 | __le32 entries; | ||
719 | __le32 entry_size; | ||
720 | u32 tab_size; | ||
721 | u32 i; | ||
626 | 722 | ||
627 | ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL); | 723 | ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL); |
628 | if (ptab_descr == NULL) | 724 | if (ptab_descr == NULL) |
629 | return -1; | 725 | return -EINVAL; |
630 | 726 | ||
631 | entries = cpu_to_le32(ptab_descr->num_entries); | 727 | entries = cpu_to_le32(ptab_descr->num_entries); |
728 | entry_size = cpu_to_le32(ptab_descr->entry_size); | ||
729 | tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size); | ||
730 | |||
731 | if (adapter->fw->size < tab_size) | ||
732 | return -EINVAL; | ||
632 | 733 | ||
633 | nomn: | 734 | nomn: |
634 | for (i = 0; i < entries; i++) { | 735 | for (i = 0; i < entries; i++) { |
@@ -657,9 +758,38 @@ nomn: | |||
657 | goto nomn; | 758 | goto nomn; |
658 | } | 759 | } |
659 | 760 | ||
660 | return -1; | 761 | return -EINVAL; |
661 | } | 762 | } |
662 | 763 | ||
764 | static int | ||
765 | netxen_nic_validate_unified_romimage(struct netxen_adapter *adapter) | ||
766 | { | ||
767 | if (netxen_nic_validate_header(adapter)) { | ||
768 | dev_err(&adapter->pdev->dev, | ||
769 | "unified image: header validation failed\n"); | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | |||
773 | if (netxen_nic_validate_product_offs(adapter)) { | ||
774 | dev_err(&adapter->pdev->dev, | ||
775 | "unified image: product validation failed\n"); | ||
776 | return -EINVAL; | ||
777 | } | ||
778 | |||
779 | if (netxen_nic_validate_bootld(adapter)) { | ||
780 | dev_err(&adapter->pdev->dev, | ||
781 | "unified image: bootld validation failed\n"); | ||
782 | return -EINVAL; | ||
783 | } | ||
784 | |||
785 | if (netxen_nic_validate_fw(adapter)) { | ||
786 | dev_err(&adapter->pdev->dev, | ||
787 | "unified image: firmware validation failed\n"); | ||
788 | return -EINVAL; | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
663 | 793 | ||
664 | static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter, | 794 | static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter, |
665 | u32 section, u32 idx_offset) | 795 | u32 section, u32 idx_offset) |
@@ -933,27 +1063,23 @@ static int | |||
933 | netxen_validate_firmware(struct netxen_adapter *adapter) | 1063 | netxen_validate_firmware(struct netxen_adapter *adapter) |
934 | { | 1064 | { |
935 | __le32 val; | 1065 | __le32 val; |
936 | u32 ver, min_ver, bios, min_size; | 1066 | u32 ver, min_ver, bios; |
937 | struct pci_dev *pdev = adapter->pdev; | 1067 | struct pci_dev *pdev = adapter->pdev; |
938 | const struct firmware *fw = adapter->fw; | 1068 | const struct firmware *fw = adapter->fw; |
939 | u8 fw_type = adapter->fw_type; | 1069 | u8 fw_type = adapter->fw_type; |
940 | 1070 | ||
941 | if (fw_type == NX_UNIFIED_ROMIMAGE) { | 1071 | if (fw_type == NX_UNIFIED_ROMIMAGE) { |
942 | if (nx_set_product_offs(adapter)) | 1072 | if (netxen_nic_validate_unified_romimage(adapter)) |
943 | return -EINVAL; | 1073 | return -EINVAL; |
944 | |||
945 | min_size = NX_UNI_FW_MIN_SIZE; | ||
946 | } else { | 1074 | } else { |
947 | val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); | 1075 | val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); |
948 | if ((__force u32)val != NETXEN_BDINFO_MAGIC) | 1076 | if ((__force u32)val != NETXEN_BDINFO_MAGIC) |
949 | return -EINVAL; | 1077 | return -EINVAL; |
950 | 1078 | ||
951 | min_size = NX_FW_MIN_SIZE; | 1079 | if (fw->size < NX_FW_MIN_SIZE) |
1080 | return -EINVAL; | ||
952 | } | 1081 | } |
953 | 1082 | ||
954 | if (fw->size < min_size) | ||
955 | return -EINVAL; | ||
956 | |||
957 | val = nx_get_fw_version(adapter); | 1083 | val = nx_get_fw_version(adapter); |
958 | 1084 | ||
959 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) | 1085 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) |