Skip to content

Commit f94450c

Browse files
pavitrajhagregkh
authored andcommitted
net: wwan: t7xx: validate port_count against message length in t7xx_port_enum_msg_handler
commit 0e7c074 upstream. 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: da45d25 ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 21d7074 commit f94450c

3 files changed

Lines changed: 34 additions & 6 deletions

File tree

drivers/net/wwan/t7xx/t7xx_modem_ops.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,8 +417,20 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
417417

418418
offset = sizeof(struct feature_query);
419419
for (i = 0; i < FEATURE_COUNT && offset < data_length; i++) {
420+
size_t remaining = data_length - offset;
421+
size_t feat_data_len, feat_total;
422+
423+
if (remaining < sizeof(*rt_feature))
424+
break;
425+
420426
rt_feature = data + offset;
421-
offset += sizeof(*rt_feature) + le32_to_cpu(rt_feature->data_len);
427+
feat_data_len = le32_to_cpu(rt_feature->data_len);
428+
429+
if (feat_data_len > remaining - sizeof(*rt_feature))
430+
break;
431+
432+
feat_total = sizeof(*rt_feature) + feat_data_len;
433+
offset += feat_total;
422434

423435
ft_spt_cfg = FIELD_GET(FEATURE_MSK, core->feature_set[i]);
424436
if (ft_spt_cfg != MTK_FEATURE_MUST_BE_SUPPORTED)
@@ -428,8 +440,10 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
428440
if (ft_spt_st != MTK_FEATURE_MUST_BE_SUPPORTED)
429441
return -EINVAL;
430442

431-
if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM)
432-
t7xx_port_enum_msg_handler(ctl->md, rt_feature->data);
443+
if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM) {
444+
t7xx_port_enum_msg_handler(ctl->md, rt_feature->data,
445+
feat_data_len);
446+
}
433447
}
434448

435449
return 0;

drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,26 @@ static int fsm_ee_message_handler(struct t7xx_port *port, struct t7xx_fsm_ctl *c
117117
* t7xx_port_enum_msg_handler() - Parse the port enumeration message to create/remove nodes.
118118
* @md: Modem context.
119119
* @msg: Message.
120+
* @msg_len: Length of @msg in bytes.
120121
*
121122
* Used to control create/remove device node.
122123
*
123124
* Return:
124125
* * 0 - Success.
125126
* * -EFAULT - Message check failure.
126127
*/
127-
int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg)
128+
int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len)
128129
{
129130
struct device *dev = &md->t7xx_dev->pdev->dev;
130131
unsigned int version, port_count, i;
131132
struct port_msg *port_msg = msg;
132133

134+
if (msg_len < sizeof(*port_msg)) {
135+
dev_err(dev, "Port enum msg too short for header: need %zu, have %zu\n",
136+
sizeof(*port_msg), msg_len);
137+
return -EINVAL;
138+
}
139+
133140
version = FIELD_GET(PORT_MSG_VERSION, le32_to_cpu(port_msg->info));
134141
if (version != PORT_ENUM_VER ||
135142
le32_to_cpu(port_msg->head_pattern) != PORT_ENUM_HEAD_PATTERN ||
@@ -141,6 +148,13 @@ int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg)
141148
}
142149

143150
port_count = FIELD_GET(PORT_MSG_PRT_CNT, le32_to_cpu(port_msg->info));
151+
152+
if (msg_len < struct_size(port_msg, data, port_count)) {
153+
dev_err(dev, "Port enum msg too short: need %zu, have %zu\n",
154+
struct_size(port_msg, data, port_count), msg_len);
155+
return -EINVAL;
156+
}
157+
144158
for (i = 0; i < port_count; i++) {
145159
u32 port_info = le32_to_cpu(port_msg->data[i]);
146160
unsigned int ch_id;
@@ -191,7 +205,7 @@ static int control_msg_handler(struct t7xx_port *port, struct sk_buff *skb)
191205

192206
case CTL_ID_PORT_ENUM:
193207
skb_pull(skb, sizeof(*ctrl_msg_h));
194-
ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data);
208+
ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data, skb->len);
195209
if (!ret)
196210
ret = port_ctl_send_msg_to_md(port, CTL_ID_PORT_ENUM, 0);
197211
else

drivers/net/wwan/t7xx/t7xx_port_proxy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ void t7xx_port_proxy_reset(struct port_proxy *port_prox);
9595
void t7xx_port_proxy_uninit(struct port_proxy *port_prox);
9696
int t7xx_port_proxy_init(struct t7xx_modem *md);
9797
void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state);
98-
int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg);
98+
int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len);
9999
int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
100100
bool en_flag);
101101

0 commit comments

Comments
 (0)