mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
drm/amdgpu: harden FRU PIA parsing with bounded helpers
Replace the open-coded TLV walk with fru_pia_advance() and fru_pia_copy_field() helpers that bound every read by the actual EEPROM data length, preventing out-of-bounds reads on truncated or malformed FRU data. Signed-off-by: Stanley.Yang <Stanley.Yang@amd.com> Reviewed-by: Tao Zhou <tao.zhou1@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
7822e87bb7
commit
c990c05eb6
|
|
@ -115,6 +115,43 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IPMI FRU Product Info Area fields are TLV: one type/length byte
|
||||
* (low 6 bits = data length) followed by that many data bytes. These
|
||||
* helpers walk the cursor and copy a single field while bounding all
|
||||
* accesses to the actual buffer length read from the EEPROM.
|
||||
*/
|
||||
#define FRU_FIELD_LEN(p, a) ((p)[a] & 0x3F)
|
||||
|
||||
/* Advance cursor past the current TLV. Returns false if no more data. */
|
||||
static bool fru_pia_advance(u32 *addr, const unsigned char *pia, int len)
|
||||
{
|
||||
if (*addr >= (u32)len)
|
||||
return false;
|
||||
*addr += 1 + FRU_FIELD_LEN(pia, *addr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the current TLV's data into dst (NUL-terminated). Returns false if
|
||||
* the TLV header or data would read past the end of pia.
|
||||
*/
|
||||
static bool fru_pia_copy_field(char *dst, size_t dst_size,
|
||||
const unsigned char *pia, u32 addr, int len)
|
||||
{
|
||||
size_t fl;
|
||||
|
||||
if (addr + 1 >= (u32)len)
|
||||
return false;
|
||||
|
||||
fl = min3((size_t)FRU_FIELD_LEN(pia, addr),
|
||||
dst_size - 1,
|
||||
(size_t)(len - addr - 1));
|
||||
memcpy(dst, pia + addr + 1, fl);
|
||||
dst[fl] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_fru_info *fru_info;
|
||||
|
|
@ -223,52 +260,46 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
|
|||
* Read Manufacturer Name field whose length is [3].
|
||||
*/
|
||||
addr = 3;
|
||||
if (addr + 1 >= len)
|
||||
if (!fru_pia_copy_field(fru_info->manufacturer_name,
|
||||
sizeof(fru_info->manufacturer_name),
|
||||
pia, addr, len))
|
||||
goto Out;
|
||||
memcpy(fru_info->manufacturer_name, pia + addr + 1,
|
||||
min_t(size_t, sizeof(fru_info->manufacturer_name),
|
||||
pia[addr] & 0x3F));
|
||||
fru_info->manufacturer_name[sizeof(fru_info->manufacturer_name) - 1] =
|
||||
'\0';
|
||||
|
||||
/* Read Product Name field. */
|
||||
addr += 1 + (pia[addr] & 0x3F);
|
||||
if (addr + 1 >= len)
|
||||
if (!fru_pia_advance(&addr, pia, len) ||
|
||||
!fru_pia_copy_field(fru_info->product_name,
|
||||
sizeof(fru_info->product_name),
|
||||
pia, addr, len))
|
||||
goto Out;
|
||||
memcpy(fru_info->product_name, pia + addr + 1,
|
||||
min_t(size_t, sizeof(fru_info->product_name), pia[addr] & 0x3F));
|
||||
fru_info->product_name[sizeof(fru_info->product_name) - 1] = '\0';
|
||||
|
||||
/* Go to the Product Part/Model Number field. */
|
||||
addr += 1 + (pia[addr] & 0x3F);
|
||||
if (addr + 1 >= len)
|
||||
if (!fru_pia_advance(&addr, pia, len) ||
|
||||
!fru_pia_copy_field(fru_info->product_number,
|
||||
sizeof(fru_info->product_number),
|
||||
pia, addr, len))
|
||||
goto Out;
|
||||
memcpy(fru_info->product_number, pia + addr + 1,
|
||||
min_t(size_t, sizeof(fru_info->product_number),
|
||||
pia[addr] & 0x3F));
|
||||
fru_info->product_number[sizeof(fru_info->product_number) - 1] = '\0';
|
||||
|
||||
/* Go to the Product Version field. */
|
||||
addr += 1 + (pia[addr] & 0x3F);
|
||||
|
||||
/* Go to the Product Serial Number field. */
|
||||
addr += 1 + (pia[addr] & 0x3F);
|
||||
if (addr + 1 >= len)
|
||||
/* Skip the Product Version field. */
|
||||
if (!fru_pia_advance(&addr, pia, len))
|
||||
goto Out;
|
||||
memcpy(fru_info->serial, pia + addr + 1,
|
||||
min_t(size_t, sizeof(fru_info->serial), pia[addr] & 0x3F));
|
||||
fru_info->serial[sizeof(fru_info->serial) - 1] = '\0';
|
||||
|
||||
/* Asset Tag field */
|
||||
addr += 1 + (pia[addr] & 0x3F);
|
||||
/* Read the Product Serial Number field. */
|
||||
if (!fru_pia_advance(&addr, pia, len) ||
|
||||
!fru_pia_copy_field(fru_info->serial,
|
||||
sizeof(fru_info->serial),
|
||||
pia, addr, len))
|
||||
goto Out;
|
||||
|
||||
/* Skip the Asset Tag field. */
|
||||
if (!fru_pia_advance(&addr, pia, len))
|
||||
goto Out;
|
||||
|
||||
/* FRU File Id field. This could be 'null'. */
|
||||
addr += 1 + (pia[addr] & 0x3F);
|
||||
if ((addr + 1 >= len) || !(pia[addr] & 0x3F))
|
||||
if (!fru_pia_advance(&addr, pia, len) ||
|
||||
!fru_pia_copy_field(fru_info->fru_id,
|
||||
sizeof(fru_info->fru_id),
|
||||
pia, addr, len))
|
||||
goto Out;
|
||||
memcpy(fru_info->fru_id, pia + addr + 1,
|
||||
min_t(size_t, sizeof(fru_info->fru_id), pia[addr] & 0x3F));
|
||||
fru_info->fru_id[sizeof(fru_info->fru_id) - 1] = '\0';
|
||||
|
||||
Out:
|
||||
kfree(pia);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user