Re: [PATCH net] net: wwan: iosm: bound device offsets in the MUX downlink decoder
From: Loic Poulain
Date: Fri Jun 19 2026 - 16:48:48 EST
On Fri, Jun 19, 2026 at 11:03 AM Maoyi Xie <maoyixie.tju@xxxxxxxxx> wrote:
>
> mux_dl_adb_decode() walks a chain of aggregated datagram tables using
> offsets and lengths taken from the modem. first_table_index,
> next_table_index, table_length, datagram_index and datagram_length are
> all device supplied le values. Only first_table_index was checked, and
> only for being non zero. The decoder then formed adth = block +
> adth_index and read the table header and the datagram entries with no
> bound against the received skb. A modem that reports an index or a
> length past the downlink buffer makes the decoder read out of bounds.
>
> The buffer is IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE and skb->len is at most
> that, so skb->len is the real limit, but none of these in band offsets
> were checked against it.
>
> Validate every device offset and length against skb->len before use.
> The block header must fit. Each table header, on entry and after every
> next_table_index, must lie inside the skb. The datagram table must fit.
> Each datagram index and length must stay inside the skb. The header
> padding must not exceed the datagram length so the receive length does
> not wrap.
>
> This was reproduced under KASAN as a slab out of bounds read on a normal
> downlink receive once the iosm net device is up.
>
> Fixes: 1f52d7b62285 ("net: wwan: iosm: Enable M.2 7360 WWAN card support")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Maoyi Xie <maoyixie.tju@xxxxxxxxx>
> ---
> drivers/net/wwan/iosm/iosm_ipc_mux_codec.c | 23 ++++++++++++++++++++--
> 1 file changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
> index bff46f7ca59f..1c021bb0aa7a 100644
> --- a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
> +++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
> @@ -557,15 +557,21 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh,
> < sizeof(struct mux_adbh))
> goto dg_error;
>
> - /* Is the packet inside of the ADB */
> + /* Is the packet inside of the ADB and the received skb ? */
> if (le32_to_cpu(dg->datagram_index) >=
> - le32_to_cpu(adbh->block_length)) {
> + le32_to_cpu(adbh->block_length) ||
> + le32_to_cpu(dg->datagram_index) >= skb->len ||
> + le16_to_cpu(dg->datagram_length) >
> + skb->len - le32_to_cpu(dg->datagram_index)) {
The logic is ok, but for readability, I would suggest to convert
dg->datagram_index and dg->datagram_length into intermediate
native-endian local variables (e.g dg_index, dg_len), making the if
condition cleaner and avoiding repeated conversions.
> goto dg_error;
> } else {
> packet_offset =
> le32_to_cpu(dg->datagram_index) +
> dl_head_pad_len;
> dg_len = le16_to_cpu(dg->datagram_length);
> + /* The header padding must not exceed the datagram. */
> + if (dl_head_pad_len >= dg_len)
> + goto dg_error;
> /* Pass the packet to the netif layer. */
> rc = ipc_mux_net_receive(ipc_mux, if_id, ipc_mux->wwan,
> packet_offset,
> @@ -595,6 +601,10 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
> block = skb->data;
> adbh = (struct mux_adbh *)block;
>
> + /* The block header itself must fit in the received skb. */
> + if (skb->len < sizeof(struct mux_adbh))
> + goto adb_decode_err;
> +
> /* Process the aggregated datagram tables. */
> adth_index = le32_to_cpu(adbh->first_table_index);
>
> @@ -606,6 +616,11 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
>
> /* Loop through mixed session tables. */
> while (adth_index) {
> + /* The table header must lie within the received skb. */
> + if (adth_index < sizeof(struct mux_adbh) ||
> + adth_index > skb->len - sizeof(struct mux_adth))
> + goto adb_decode_err;
> +
> /* Get the reference to the table header. */
> adth = (struct mux_adth *)(block + adth_index);
>
> @@ -629,6 +644,10 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
> if (le16_to_cpu(adth->table_length) < sizeof(struct mux_adth))
> goto adb_decode_err;
>
> + /* The whole datagram table must fit in the received skb. */
> + if (le16_to_cpu(adth->table_length) > skb->len - adth_index)
> + goto adb_decode_err;
> +
> /* Calculate the number of datagrams. */
> nr_of_dg = (le16_to_cpu(adth->table_length) -
> sizeof(struct mux_adth)) /
> --
> 2.34.1
>