diff options
author | Kulikov Vasiliy <segooon@gmail.com> | 2010-07-23 02:36:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-23 16:05:13 -0400 |
commit | 9c1797808996eef47a7954ec580c6db7de1fff76 (patch) | |
tree | 1a15655cf586c34a0b9d33ff5f591dd15e279107 /drivers/net/s2io.c | |
parent | 50a749c1f2fc8f03232c174c9dbc78a78f9bebfd (diff) |
net: s2io: fix buffer overflow
vpd_data[] is allocated as kmalloc(256, GFP_KERNEL), so if cnt = 255
then (cnt + 3) overflows 256. memset() is executed without checking.
vpd_data[cnt+2] must be less than 256-cnt-2 as the latter is number of
vpd_data[] elements to copy.
Do not fill with zero the beginning of nic->serial_num as it will
be filled with vpd_data[].
String in product_name[] should be terminated by '\0'.
Signed-off-by: Kulikov Vasiliy <segooon@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r-- | drivers/net/s2io.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index b8b85843c614..18bc5b718bbb 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -5796,7 +5796,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) | |||
5796 | { | 5796 | { |
5797 | u8 *vpd_data; | 5797 | u8 *vpd_data; |
5798 | u8 data; | 5798 | u8 data; |
5799 | int i = 0, cnt, fail = 0; | 5799 | int i = 0, cnt, len, fail = 0; |
5800 | int vpd_addr = 0x80; | 5800 | int vpd_addr = 0x80; |
5801 | struct swStat *swstats = &nic->mac_control.stats_info->sw_stat; | 5801 | struct swStat *swstats = &nic->mac_control.stats_info->sw_stat; |
5802 | 5802 | ||
@@ -5837,20 +5837,28 @@ static void s2io_vpd_read(struct s2io_nic *nic) | |||
5837 | 5837 | ||
5838 | if (!fail) { | 5838 | if (!fail) { |
5839 | /* read serial number of adapter */ | 5839 | /* read serial number of adapter */ |
5840 | for (cnt = 0; cnt < 256; cnt++) { | 5840 | for (cnt = 0; cnt < 252; cnt++) { |
5841 | if ((vpd_data[cnt] == 'S') && | 5841 | if ((vpd_data[cnt] == 'S') && |
5842 | (vpd_data[cnt+1] == 'N') && | 5842 | (vpd_data[cnt+1] == 'N')) { |
5843 | (vpd_data[cnt+2] < VPD_STRING_LEN)) { | 5843 | len = vpd_data[cnt+2]; |
5844 | memset(nic->serial_num, 0, VPD_STRING_LEN); | 5844 | if (len < min(VPD_STRING_LEN, 256-cnt-2)) { |
5845 | memcpy(nic->serial_num, &vpd_data[cnt + 3], | 5845 | memcpy(nic->serial_num, |
5846 | vpd_data[cnt+2]); | 5846 | &vpd_data[cnt + 3], |
5847 | break; | 5847 | len); |
5848 | memset(nic->serial_num+len, | ||
5849 | 0, | ||
5850 | VPD_STRING_LEN-len); | ||
5851 | break; | ||
5852 | } | ||
5848 | } | 5853 | } |
5849 | } | 5854 | } |
5850 | } | 5855 | } |
5851 | 5856 | ||
5852 | if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) | 5857 | if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) { |
5853 | memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); | 5858 | len = vpd_data[1]; |
5859 | memcpy(nic->product_name, &vpd_data[3], len); | ||
5860 | nic->product_name[len] = 0; | ||
5861 | } | ||
5854 | kfree(vpd_data); | 5862 | kfree(vpd_data); |
5855 | swstats->mem_freed += 256; | 5863 | swstats->mem_freed += 256; |
5856 | } | 5864 | } |