wifi: rtw89: fw: validate multi-firmware header before accessing
[ Upstream commit 1f0efffd597893404aea5c3d4f1bdaa1c61d4434 ]
A firmeware file contains multi-firmware with a header to represent
contents. The mfw_hdr->fw_nr is to define number of firmware in file.
+-----+-------+------+---------+--------------+
| sig | fw_nr | rsvd | version | reserved |
+---------------------------------------------+ --
fw 0 | cv | type | mp | rsvd | shift | size | rsvd | \
+---------------------------------------------+ |
fw 1 | cv | type | mp | rsvd | shift | size | rsvd | | mfw_hdr->fw_nr
+---------------------------------------------+ |
fw N-1 | ... | /
+=============================================+ --
| fw 0 content |
| (pointed by fw0 shift/size) |
+=============================================+
To avoid Coverity warning, validate header is in range of firmware size,
and also validate the range of actual firmware content is in range.
Addresses-Coverity-ID: 1494046 ("Untrusted loop bound")
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250203072911.47313-4-pkshih@realtek.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f4c99c7b71
commit
01edf9255f
@@ -501,6 +501,30 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev,
|
||||
}
|
||||
}
|
||||
|
||||
static int rtw89_mfw_validate_hdr(struct rtw89_dev *rtwdev,
|
||||
const struct firmware *firmware,
|
||||
const struct rtw89_mfw_hdr *mfw_hdr)
|
||||
{
|
||||
const void *mfw = firmware->data;
|
||||
u32 mfw_len = firmware->size;
|
||||
u8 fw_nr = mfw_hdr->fw_nr;
|
||||
const void *ptr;
|
||||
|
||||
if (fw_nr == 0) {
|
||||
rtw89_err(rtwdev, "mfw header has no fw entry\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ptr = &mfw_hdr->info[fw_nr];
|
||||
|
||||
if (ptr > mfw + mfw_len) {
|
||||
rtw89_err(rtwdev, "mfw header out of address\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
||||
struct rtw89_fw_suit *fw_suit, bool nowarn)
|
||||
@@ -511,6 +535,7 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
||||
u32 mfw_len = firmware->size;
|
||||
const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw;
|
||||
const struct rtw89_mfw_info *mfw_info = NULL, *tmp;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (mfw_hdr->sig != RTW89_MFW_SIG) {
|
||||
@@ -523,6 +548,10 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = rtw89_mfw_validate_hdr(rtwdev, firmware, mfw_hdr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < mfw_hdr->fw_nr; i++) {
|
||||
tmp = &mfw_hdr->info[i];
|
||||
if (tmp->type != type)
|
||||
@@ -552,6 +581,12 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
||||
found:
|
||||
fw_suit->data = mfw + le32_to_cpu(mfw_info->shift);
|
||||
fw_suit->size = le32_to_cpu(mfw_info->size);
|
||||
|
||||
if (fw_suit->data + fw_suit->size > mfw + mfw_len) {
|
||||
rtw89_err(rtwdev, "fw_suit %d out of address\n", type);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user