]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: wwan: t7xx: validate port_count against message length in t7xx_port_enum_msg_handler
authorPavitra Jha <jhapavitra98@gmail.com>
Fri, 1 May 2026 11:07:12 +0000 (07:07 -0400)
committerJakub Kicinski <kuba@kernel.org>
Wed, 6 May 2026 02:05:11 +0000 (19:05 -0700)
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>
drivers/net/wwan/t7xx/t7xx_modem_ops.c
drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
drivers/net/wwan/t7xx/t7xx_port_proxy.h

index 7968e208dd37c1cc1931ed722b2772d23acfe031..adb29d30c63fe7588e940ed5c8af74609256c238 100644 (file)
@@ -457,8 +457,20 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
 
        offset = sizeof(struct feature_query);
        for (i = 0; i < FEATURE_COUNT && offset < data_length; i++) {
+               size_t remaining = data_length - offset;
+               size_t feat_data_len, feat_total;
+
+               if (remaining < sizeof(*rt_feature))
+                       break;
+
                rt_feature = data + offset;
-               offset += sizeof(*rt_feature) + le32_to_cpu(rt_feature->data_len);
+               feat_data_len = le32_to_cpu(rt_feature->data_len);
+
+               if (feat_data_len > remaining - sizeof(*rt_feature))
+                       break;
+
+               feat_total = sizeof(*rt_feature) + feat_data_len;
+               offset += feat_total;
 
                ft_spt_cfg = FIELD_GET(FEATURE_MSK, core->feature_set[i]);
                if (ft_spt_cfg != MTK_FEATURE_MUST_BE_SUPPORTED)
@@ -468,8 +480,10 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
                if (ft_spt_st != MTK_FEATURE_MUST_BE_SUPPORTED)
                        return -EINVAL;
 
-               if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM)
-                       t7xx_port_enum_msg_handler(ctl->md, rt_feature->data);
+               if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM) {
+                       t7xx_port_enum_msg_handler(ctl->md, rt_feature->data,
+                                                  feat_data_len);
+               }
        }
 
        return 0;
index ae632ef966983eefd8c7f4854c42b5fea62e1da2..f869e4ed9ee9a9b5c596edc49b14f296599a1e65 100644 (file)
@@ -117,6 +117,7 @@ static int fsm_ee_message_handler(struct t7xx_port *port, struct t7xx_fsm_ctl *c
  * t7xx_port_enum_msg_handler() - Parse the port enumeration message to create/remove nodes.
  * @md: Modem context.
  * @msg: Message.
+ * @msg_len:   Length of @msg in bytes.
  *
  * Used to control create/remove device node.
  *
@@ -124,12 +125,18 @@ static int fsm_ee_message_handler(struct t7xx_port *port, struct t7xx_fsm_ctl *c
  * * 0         - Success.
  * * -EFAULT   - Message check failure.
  */
-int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg)
+int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len)
 {
        struct device *dev = &md->t7xx_dev->pdev->dev;
        unsigned int version, port_count, i;
        struct port_msg *port_msg = msg;
 
+       if (msg_len < sizeof(*port_msg)) {
+               dev_err(dev, "Port enum msg too short for header: need %zu, have %zu\n",
+                       sizeof(*port_msg), msg_len);
+               return -EINVAL;
+       }
+
        version = FIELD_GET(PORT_MSG_VERSION, le32_to_cpu(port_msg->info));
        if (version != PORT_ENUM_VER ||
            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)
        }
 
        port_count = FIELD_GET(PORT_MSG_PRT_CNT, le32_to_cpu(port_msg->info));
+
+       if (msg_len < struct_size(port_msg, data, port_count)) {
+               dev_err(dev, "Port enum msg too short: need %zu, have %zu\n",
+                       struct_size(port_msg, data, port_count), msg_len);
+               return -EINVAL;
+       }
+
        for (i = 0; i < port_count; i++) {
                u32 port_info = le32_to_cpu(port_msg->data[i]);
                unsigned int ch_id;
@@ -191,7 +205,7 @@ static int control_msg_handler(struct t7xx_port *port, struct sk_buff *skb)
 
        case CTL_ID_PORT_ENUM:
                skb_pull(skb, sizeof(*ctrl_msg_h));
-               ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data);
+               ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data, skb->len);
                if (!ret)
                        ret = port_ctl_send_msg_to_md(port, CTL_ID_PORT_ENUM, 0);
                else
index f0918b36e899bd4bc2cb1b971b929589c8b1aed6..7c3190bf0fcf391438001a946178af6590aa0290 100644 (file)
@@ -103,7 +103,7 @@ void t7xx_port_proxy_reset(struct port_proxy *port_prox);
 void t7xx_port_proxy_uninit(struct port_proxy *port_prox);
 int t7xx_port_proxy_init(struct t7xx_modem *md);
 void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state);
-int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg);
+int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len);
 int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
                                       bool en_flag);
 void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id);