Thread (7 messages) flat view 7 messages, 3 authors, 2021-11-12

Re: [PATCH] rtw89: Fix crash by loading compressed firmware file

From: Pkshih <pkshih@realtek.com>
Date: 2021-11-05 14:28:57
Also in: lkml

On Fri, 2021-11-05 at 11:03 +0200, Kalle Valo wrote:
Takashi Iwai [off-list ref] writes:
quoted
On Fri, 05 Nov 2021 09:25:13 +0100,
Kalle Valo wrote:
quoted
Takashi Iwai [off-list ref] writes:
quoted
On Fri, 05 Nov 2021 08:17:25 +0100,
Takashi Iwai wrote:
quoted
When a firmware is loaded in the compressed format or via user-mode
helper, it's mapped in read-only, and the rtw89 driver crashes at
rtw89_fw_download() when it tries to modify some data.

This patch is an attemp to avoid the crash by re-allocating the data
via vmalloc() for the data modification.
Alternatively, we may drop the code that modifies the loaded firmware
data?  At least SET_FW_HDR_PART_SIZE() in rtw89_fw_hdr_parser() looks
writing it, and I have no idea why this overwrite is needed.
Strange, isn't the firmware data marked as const just to avoid this kind
of problem? Does rtw89 have wrong casts somewhere which removes the
const?
Yes.  SET_FW_HDR_PART_SIZE() does the cast, dropping the const.
Oh man, all of GET and SET macros in fw.h have those casts:

#define GET_FW_HDR_MAJOR_VERSION(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(7, 0))
#define GET_FW_HDR_MINOR_VERSION(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(15, 8))
#define GET_FW_HDR_SUBVERSION(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(23, 16))

I don't know how I missed those during my review :( But this is exactly
why I prefer having a proper struct for commands and events, instead of
u8 buf used with these macros.

I can use a struct to access firmware header, becuase their fields
are multiple of 8 bits.

But, the "firmware section header" that is additional header followed
by firmware header, and it contains bit fields, likes:

#define GET_FWSECTION_HDR_SEC_SIZE(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(23, 0))
#define GET_FWSECTION_HDR_CHECKSUM(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr) + 1), BIT(28))
#define GET_FWSECTION_HDR_REDL(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr) + 1), BIT(29))
#define GET_FWSECTION_HDR_DL_ADDR(fwhdr)	\
	le32_get_bits(*((__le32 *)(fwhdr)), GENMASK(31, 0))

If we use a struct, it needs big-/little- endians parts.

Then, we will access firmware header with two methods; is
it reasonable?


The macro SET_FW_HDR_PART_SIZE() is used to set the firmware
partition size we are going to download, and it is only used
by rtw89_fw_download_hdr(). So, I will set the partition size
after copying constant firmware header into skb->data.

--
Ping-Ke
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help