RE: [PATCH] wifi: rtw89: cap firmware section_num before parsing

Ping-Ke Shih <[email protected]>
Newsgroups org.kernel.vger.linux-wireless,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
Laxman Acharya Padhya <[email protected]> wrote:
> rtw89_fw_bin_info.section_info has FWDL_SECTION_MAX_NUM (10) entries.
> The v0/v1 header parsers take section_num from an 8-bit firmware field
> (0..255) and write info->section_info[i] with no cap.
> rtw89_fw_download_suit() keeps that object on the stack, so a crafted
> firmware blob overflows the stack.
> 
> Reject a truncated header and a section table that does not fit in the
> firmware image before reading fw_hdr->sections[i].
> 
> Cc: [email protected]
> Signed-off-by: Laxman Acharya Padhya <[email protected]>

Acked-by: Ping-Ke Shih <[email protected]>

Logic is good to me, but please add empty lines. 

> ---
>  drivers/net/wireless/realtek/rtw89/fw.c | 30 +++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
> index 0099c5c03e7a6..57d4252ee78f0 100644
> --- a/drivers/net/wireless/realtek/rtw89/fw.c
> +++ b/drivers/net/wireless/realtek/rtw89/fw.c
> @@ -156,8 +156,23 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
>         if (!info)
>                 return -EINVAL;
> 
> +       if (len < sizeof(*fw_hdr)) {
> +               rtw89_err(rtwdev, "[ERR]fw header truncated\n");
> +               return -EINVAL;
> +       }
> +
>         info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM);
> +       if (!info->section_num || info->section_num > FWDL_SECTION_MAX_NUM) {
> +               rtw89_err(rtwdev, "[ERR]invalid fw section num %u\n",
> +                         info->section_num);
> +               return -EINVAL;
> +       }
> +
>         base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
> +       if (base_hdr_len > len) {
> +               rtw89_err(rtwdev, "[ERR]fw header truncated\n");
> +               return -EINVAL;
> +       }

an empty line

>         info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR);
>         info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_W7_IDMEM_SHARE_MODE);
> 
> @@ -455,9 +470,24 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
>         int ret;
>         u32 i;
> 
> +       if (len < sizeof(*fw_hdr)) {
> +               rtw89_err(rtwdev, "[ERR]fw header truncated\n");
> +               return -EINVAL;
> +       }
> +
>         info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_SEC_NUM);
> +       if (!info->section_num || info->section_num > FWDL_SECTION_MAX_NUM) {
> +               rtw89_err(rtwdev, "[ERR]invalid fw section num %u\n",
> +                         info->section_num);
> +               return -EINVAL;
> +       }
> +
>         info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM);
>         base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
> +       if (base_hdr_len > len) {
> +               rtw89_err(rtwdev, "[ERR]fw header truncated\n");
> +               return -EINVAL;
> +       }

an empty line

>         info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR);
>         info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_IDMEM_SHARE_MODE);
> 
> --
> 2.51.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.