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
|
static
|
||||||
int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
||||||
struct rtw89_fw_suit *fw_suit, bool nowarn)
|
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;
|
u32 mfw_len = firmware->size;
|
||||||
const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw;
|
const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw;
|
||||||
const struct rtw89_mfw_info *mfw_info = NULL, *tmp;
|
const struct rtw89_mfw_info *mfw_info = NULL, *tmp;
|
||||||
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (mfw_hdr->sig != RTW89_MFW_SIG) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = rtw89_mfw_validate_hdr(rtwdev, firmware, mfw_hdr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
for (i = 0; i < mfw_hdr->fw_nr; i++) {
|
for (i = 0; i < mfw_hdr->fw_nr; i++) {
|
||||||
tmp = &mfw_hdr->info[i];
|
tmp = &mfw_hdr->info[i];
|
||||||
if (tmp->type != type)
|
if (tmp->type != type)
|
||||||
@@ -552,6 +581,12 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
|
|||||||
found:
|
found:
|
||||||
fw_suit->data = mfw + le32_to_cpu(mfw_info->shift);
|
fw_suit->data = mfw + le32_to_cpu(mfw_info->shift);
|
||||||
fw_suit->size = le32_to_cpu(mfw_info->size);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user