Commit 5cfc9125 authored by Jiansong Chen's avatar Jiansong Chen Committed by Alex Deucher

drm/amdgpu: refine amdgpu_fru_get_product_info

1. eliminate potential array index out of bounds.
2. return meaningful value for failure.
Signed-off-by: default avatarJiansong Chen <Jiansong.Chen@amd.com>
Reviewed-by: default avatarJack Gui <Jack.Gui@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 147feb00
...@@ -101,7 +101,8 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, ...@@ -101,7 +101,8 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr,
int amdgpu_fru_get_product_info(struct amdgpu_device *adev) int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
{ {
unsigned char buff[34]; unsigned char buff[34];
int addrptr = 0, size = 0; int addrptr, size;
int len;
if (!is_fru_eeprom_supported(adev)) if (!is_fru_eeprom_supported(adev))
return 0; return 0;
...@@ -109,7 +110,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) ...@@ -109,7 +110,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
/* If algo exists, it means that the i2c_adapter's initialized */ /* If algo exists, it means that the i2c_adapter's initialized */
if (!adev->pm.smu_i2c.algo) { if (!adev->pm.smu_i2c.algo) {
DRM_WARN("Cannot access FRU, EEPROM accessor not initialized"); DRM_WARN("Cannot access FRU, EEPROM accessor not initialized");
return 0; return -ENODEV;
} }
/* There's a lot of repetition here. This is due to the FRU having /* There's a lot of repetition here. This is due to the FRU having
...@@ -128,7 +129,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) ...@@ -128,7 +129,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
size = amdgpu_fru_read_eeprom(adev, addrptr, buff); size = amdgpu_fru_read_eeprom(adev, addrptr, buff);
if (size < 1) { if (size < 1) {
DRM_ERROR("Failed to read FRU Manufacturer, ret:%d", size); DRM_ERROR("Failed to read FRU Manufacturer, ret:%d", size);
return size; return -EINVAL;
} }
/* Increment the addrptr by the size of the field, and 1 due to the /* Increment the addrptr by the size of the field, and 1 due to the
...@@ -138,43 +139,45 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) ...@@ -138,43 +139,45 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
size = amdgpu_fru_read_eeprom(adev, addrptr, buff); size = amdgpu_fru_read_eeprom(adev, addrptr, buff);
if (size < 1) { if (size < 1) {
DRM_ERROR("Failed to read FRU product name, ret:%d", size); DRM_ERROR("Failed to read FRU product name, ret:%d", size);
return size; return -EINVAL;
} }
len = size;
/* Product name should only be 32 characters. Any more, /* Product name should only be 32 characters. Any more,
* and something could be wrong. Cap it at 32 to be safe * and something could be wrong. Cap it at 32 to be safe
*/ */
if (size > 32) { if (len >= sizeof(adev->product_name)) {
DRM_WARN("FRU Product Number is larger than 32 characters. This is likely a mistake"); DRM_WARN("FRU Product Number is larger than 32 characters. This is likely a mistake");
size = 32; len = sizeof(adev->product_name) - 1;
} }
/* Start at 2 due to buff using fields 0 and 1 for the address */ /* Start at 2 due to buff using fields 0 and 1 for the address */
memcpy(adev->product_name, &buff[2], size); memcpy(adev->product_name, &buff[2], len);
adev->product_name[size] = '\0'; adev->product_name[len] = '\0';
addrptr += size + 1; addrptr += size + 1;
size = amdgpu_fru_read_eeprom(adev, addrptr, buff); size = amdgpu_fru_read_eeprom(adev, addrptr, buff);
if (size < 1) { if (size < 1) {
DRM_ERROR("Failed to read FRU product number, ret:%d", size); DRM_ERROR("Failed to read FRU product number, ret:%d", size);
return size; return -EINVAL;
} }
len = size;
/* Product number should only be 16 characters. Any more, /* Product number should only be 16 characters. Any more,
* and something could be wrong. Cap it at 16 to be safe * and something could be wrong. Cap it at 16 to be safe
*/ */
if (size > 16) { if (len >= sizeof(adev->product_number)) {
DRM_WARN("FRU Product Number is larger than 16 characters. This is likely a mistake"); DRM_WARN("FRU Product Number is larger than 16 characters. This is likely a mistake");
size = 16; len = sizeof(adev->product_number) - 1;
} }
memcpy(adev->product_number, &buff[2], size); memcpy(adev->product_number, &buff[2], len);
adev->product_number[size] = '\0'; adev->product_number[len] = '\0';
addrptr += size + 1; addrptr += size + 1;
size = amdgpu_fru_read_eeprom(adev, addrptr, buff); size = amdgpu_fru_read_eeprom(adev, addrptr, buff);
if (size < 1) { if (size < 1) {
DRM_ERROR("Failed to read FRU product version, ret:%d", size); DRM_ERROR("Failed to read FRU product version, ret:%d", size);
return size; return -EINVAL;
} }
addrptr += size + 1; addrptr += size + 1;
...@@ -182,18 +185,19 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) ...@@ -182,18 +185,19 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
if (size < 1) { if (size < 1) {
DRM_ERROR("Failed to read FRU serial number, ret:%d", size); DRM_ERROR("Failed to read FRU serial number, ret:%d", size);
return size; return -EINVAL;
} }
len = size;
/* Serial number should only be 16 characters. Any more, /* Serial number should only be 16 characters. Any more,
* and something could be wrong. Cap it at 16 to be safe * and something could be wrong. Cap it at 16 to be safe
*/ */
if (size > 16) { if (len >= sizeof(adev->serial)) {
DRM_WARN("FRU Serial Number is larger than 16 characters. This is likely a mistake"); DRM_WARN("FRU Serial Number is larger than 16 characters. This is likely a mistake");
size = 16; len = sizeof(adev->serial) - 1;
} }
memcpy(adev->serial, &buff[2], size); memcpy(adev->serial, &buff[2], len);
adev->serial[size] = '\0'; adev->serial[len] = '\0';
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment