Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: wwan: t7xx: validate port_count against message length in t7xx_port_enum_msg_handler

t7xx_port_enum_msg_handler() uses the modem-supplied port_count field as
a loop bound over port_msg->data[] without checking that the message buffer
contains sufficient data. A modem sending port_count=65535 in a 12-byte
buffer triggers a slab-out-of-bounds read of up to 262140 bytes.

Add a sizeof(*port_msg) check before accessing the port message header
fields to guard against undersized messages.

Add a struct_size() check after extracting port_count and before the loop.

In t7xx_parse_host_rt_data(), guard the rt_feature header read with a
remaining-buffer check before accessing data_len, validate feat_data_len
against the actual remaining buffer to prevent OOB reads and signed
integer overflow on offset.

Pass msg_len from both call sites: skb->len at the DPMAIF path after
skb_pull(), and the validated feat_data_len at the handshake path.

Fixes: da45d2566a1d ("net: wwan: t7xx: Add control port")
Cc: stable@vger.kernel.org
Signed-off-by: Pavitra Jha <jhapavitra98@gmail.com>
Link: https://patch.msgid.link/20260501110713.145563-1-jhapavitra98@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Pavitra Jha and committed by
Jakub Kicinski
0e7c074c f83e07b2

+34 -6
+17 -3
drivers/net/wwan/t7xx/t7xx_modem_ops.c
··· 457 457 458 458 offset = sizeof(struct feature_query); 459 459 for (i = 0; i < FEATURE_COUNT && offset < data_length; i++) { 460 + size_t remaining = data_length - offset; 461 + size_t feat_data_len, feat_total; 462 + 463 + if (remaining < sizeof(*rt_feature)) 464 + break; 465 + 460 466 rt_feature = data + offset; 461 - offset += sizeof(*rt_feature) + le32_to_cpu(rt_feature->data_len); 467 + feat_data_len = le32_to_cpu(rt_feature->data_len); 468 + 469 + if (feat_data_len > remaining - sizeof(*rt_feature)) 470 + break; 471 + 472 + feat_total = sizeof(*rt_feature) + feat_data_len; 473 + offset += feat_total; 462 474 463 475 ft_spt_cfg = FIELD_GET(FEATURE_MSK, core->feature_set[i]); 464 476 if (ft_spt_cfg != MTK_FEATURE_MUST_BE_SUPPORTED) ··· 480 468 if (ft_spt_st != MTK_FEATURE_MUST_BE_SUPPORTED) 481 469 return -EINVAL; 482 470 483 - if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM) 484 - t7xx_port_enum_msg_handler(ctl->md, rt_feature->data); 471 + if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM) { 472 + t7xx_port_enum_msg_handler(ctl->md, rt_feature->data, 473 + feat_data_len); 474 + } 485 475 } 486 476 487 477 return 0;
+16 -2
drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
··· 117 117 * t7xx_port_enum_msg_handler() - Parse the port enumeration message to create/remove nodes. 118 118 * @md: Modem context. 119 119 * @msg: Message. 120 + * @msg_len: Length of @msg in bytes. 120 121 * 121 122 * Used to control create/remove device node. 122 123 * ··· 125 124 * * 0 - Success. 126 125 * * -EFAULT - Message check failure. 127 126 */ 128 - int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg) 127 + int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len) 129 128 { 130 129 struct device *dev = &md->t7xx_dev->pdev->dev; 131 130 unsigned int version, port_count, i; 132 131 struct port_msg *port_msg = msg; 132 + 133 + if (msg_len < sizeof(*port_msg)) { 134 + dev_err(dev, "Port enum msg too short for header: need %zu, have %zu\n", 135 + sizeof(*port_msg), msg_len); 136 + return -EINVAL; 137 + } 133 138 134 139 version = FIELD_GET(PORT_MSG_VERSION, le32_to_cpu(port_msg->info)); 135 140 if (version != PORT_ENUM_VER || ··· 148 141 } 149 142 150 143 port_count = FIELD_GET(PORT_MSG_PRT_CNT, le32_to_cpu(port_msg->info)); 144 + 145 + if (msg_len < struct_size(port_msg, data, port_count)) { 146 + dev_err(dev, "Port enum msg too short: need %zu, have %zu\n", 147 + struct_size(port_msg, data, port_count), msg_len); 148 + return -EINVAL; 149 + } 150 + 151 151 for (i = 0; i < port_count; i++) { 152 152 u32 port_info = le32_to_cpu(port_msg->data[i]); 153 153 unsigned int ch_id; ··· 205 191 206 192 case CTL_ID_PORT_ENUM: 207 193 skb_pull(skb, sizeof(*ctrl_msg_h)); 208 - ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data); 194 + ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data, skb->len); 209 195 if (!ret) 210 196 ret = port_ctl_send_msg_to_md(port, CTL_ID_PORT_ENUM, 0); 211 197 else
+1 -1
drivers/net/wwan/t7xx/t7xx_port_proxy.h
··· 103 103 void t7xx_port_proxy_uninit(struct port_proxy *port_prox); 104 104 int t7xx_port_proxy_init(struct t7xx_modem *md); 105 105 void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state); 106 - int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg); 106 + int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len); 107 107 int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id, 108 108 bool en_flag); 109 109 void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id);