Skip to contentSkip to conversation

USB: serial: keyspan: fix missing indat transfer sanity check

PATCH In review Johan Hovold 3 participants 5 messages May 20

Subsystems (3)
lore
Share & tools
lore

Johan Hovold

author maintainer
#0 lore raw

PATCH 1/1 USB: serial: keyspan: fix missing indat transfer sanity check

Add the missing sanity check on the size of usa49wg indat transfers to avoid parsing stale or uninitialised slab data.

Fixes 0ca1268e109a ("USB Serial Keyspan: add support for USA-49WG & USA-28XG")
Cc [email protected] # 2.6.23
---
 drivers/usb/serial/keyspan.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/usb/serial/keyspan.c +4 -0
index 46448843541a..a267bc51afc1 100644
@@ -1187,6 +1187,10 @@ static void usa49wg_indat_callback(struct urb *urb)
 	len = 0;
 
 	while (i < urb->actual_length) {
+		if (urb->actual_length - i < 3) {
+			dev_warn_ratelimited(&serial->dev, "malformed indat packet\n");
+			break;
+		}
 
 		/* Check port number from message */
 		if (data[i] >= serial->num_ports) {
Signature · 1 line
2.53.0
author maintainer
#2 lore raw
In reply to Johan Hovold
Quoted 15 lines · Johan Hovold

Add the missing sanity check on the size of usa49wg indat transfers to avoid parsing stale or uninitialised slab data.

Fixes 0ca1268e109a ("USB Serial Keyspan: add support for USA-49WG & USA-28XG")
Cc [email protected] # 2.6.23
---
 drivers/usb/serial/keyspan.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/usb/serial/keyspan.c +0 -0
index 46448843541a..a267bc51afc1 100644

drivers/usb/serial/keyspan.c static void usa49wg_indat_callback(struct urb *urb) · line 1191

Quoted 5 lines
drivers/usb/serial/keyspan.c +2 -0
@@ -1187,6 +1187,10 @@ static void usa49wg_indat_callback(struct urb *urb)
 	len = 0;
 
 	while (i < urb->actual_length) {
+		if (urb->actual_length - i < 3) {
+			dev_warn_ratelimited(&serial->dev, "malformed indat packet\n");

This dev_printk was a last minute addition before submitting which I apparently failed to compile test. This should have been &serial->interface->dev (or &urb->dev->dev).

Will fix up when applying.

drivers/usb/serial/keyspan.c static void usa49wg_indat_callback(struct urb *urb) · line 1196

Quoted 5 lines
drivers/usb/serial/keyspan.c +2 -0
+			break;
+		}
 
 		/* Check port number from message */
 		if (data[i] >= serial->num_ports) {

Johan

#3 lore raw
In reply to Johan Hovold
kernel test robot noticed the following build errors:

Hi Johan,

kernel test robot noticed the following build errors:

[auto build test ERROR on johan-usb-serial/usb-next]
[also build test ERROR on usb/usb-testing usb/usb-next usb/usb-linus tty/tty-testing tty/tty-next tty/tty-linus linus/master v7.1-rc4 next-20260520] [cannot apply to johan-usb-serial/usb-linus]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Johan-Hovold/USB-serial-keyspan-fix-missing-indat-transfer-sanity-check/20260520-181924
base:   https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git usb-next
patch link:    https://lore.kernel.org/r/20260520101230.657426-1-johan%40kernel.org
patch subject: [PATCH] USB: serial: keyspan: fix missing indat transfer sanity check
config: i386-buildonly-randconfig-006-20260520 (https://download.01.org/0day-ci/archive/20260521/[email protected]/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260521/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/usb/serial/keyspan.c:1189:25: error: incompatible pointer types passing 'struct usb_device **' to parameter of type 'const struct device *' [-Werror,-Wincompatible-pointer-types]
    1189 |                         dev_warn_ratelimited(&serial->dev, "malformed indat packet\n");
         |                                              ^~~~~~~~~~~~
   include/linux/dev_printk.h:227:34: note: expanded from macro 'dev_warn_ratelimited'
     227 |         dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
         |                                         ^~~
   include/linux/dev_printk.h:215:13: note: expanded from macro 'dev_level_ratelimited'
     215 |                 dev_level(dev, fmt, ##__VA_ARGS__);                     \
         |                           ^~~
   include/linux/dev_printk.h:156:49: note: expanded from macro 'dev_warn'
     156 |         dev_printk_index_wrap(_dev_warn, KERN_WARNING, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~
   include/linux/dev_printk.h:110:11: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~

include/linux/dev_printk.h:89:37: note: passing argument to parameter 'dev' here
89 | void _dev_warn(const struct device *dev, const char *fmt, ...)
| ^
1 error generated.

vim +1189 drivers/usb/serial/keyspan.c

1166
1167 static void usa49wg_indat_callback(struct urb *urb)
1168 {
1169 int i, len, x, err;
1170 struct usb_serial *serial;
1171 struct usb_serial_port *port;
1172 unsigned char *data = urb->transfer_buffer;
1173 int status = urb->status;
1174
1175 serial = urb->context;
1176
1177 if (status) {
1178 dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
1179 __func__, status);
1180 return;
1181 }
1182
1183 /* inbound data is in the form P#, len, status, data */
1184 i = 0;
1185 len = 0;
1186
1187 while (i < urb->actual_length) {
1188 if (urb->actual_length - i < 3) {

> 1189				dev_warn_ratelimited(&serial->dev, "malformed indat packet\n");

1190 break;
1191 }
1192
1193 /* Check port number from message */
1194 if (data[i] >= serial->num_ports) {
1195 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
1196 __func__, data[i]);
1197 return;
1198 }
1199 port = serial->port[data[i++]];
1200 len = data[i++];
1201
1202 /* 0x80 bit is error flag */
1203 if ((data[i] & 0x80) == 0) {
1204 /* no error on any byte */
1205 i++;
1206 for (x = 1; x < len && i < urb->actual_length; ++x)
1207 tty_insert_flip_char(&port->port,
1208 data[i++], 0);
1209 } else {
1210 /*
1211 * some bytes had errors, every byte has status
1212 */
1213 for (x = 0; x + 1 < len &&
1214 i + 1 < urb->actual_length; x += 2) {
1215 int stat = data[i];
1216 int flag = TTY_NORMAL;
1217
1218 if (stat & RXERROR_OVERRUN) {
1219 tty_insert_flip_char(&port->port, 0,
1220 TTY_OVERRUN);
1221 }
1222 /* XXX should handle break (0x10) */
1223 if (stat & RXERROR_PARITY)
1224 flag = TTY_PARITY;
1225 else if (stat & RXERROR_FRAMING)
1226 flag = TTY_FRAME;
1227
1228 tty_insert_flip_char(&port->port, data[i+1],
1229 flag);
1230 i += 2;
1231 }
1232 }
1233 tty_flip_buffer_push(&port->port);
1234 }
1235
1236 /* Resubmit urb so we continue receiving */
1237 err = usb_submit_urb(urb, GFP_ATOMIC);
1238 if (err != 0)
1239 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
1240 }
1241

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

#4 lore raw
In reply to Johan Hovold
kernel test robot noticed the following build errors:

Hi Johan,

kernel test robot noticed the following build errors:

[auto build test ERROR on johan-usb-serial/usb-next]
[also build test ERROR on usb/usb-testing usb/usb-next usb/usb-linus tty/tty-testing tty/tty-next tty/tty-linus linus/master v7.1-rc4 next-20260520] [cannot apply to johan-usb-serial/usb-linus]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Johan-Hovold/USB-serial-keyspan-fix-missing-indat-transfer-sanity-check/20260520-181924
base:   https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git usb-next
patch link:    https://lore.kernel.org/r/20260520101230.657426-1-johan%40kernel.org
patch subject: [PATCH] USB: serial: keyspan: fix missing indat transfer sanity check
config: arm-randconfig-002-20260520 (https://download.01.org/0day-ci/archive/20260521/[email protected]/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 5bac06718f502014fade905512f1d26d578a18f3)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260521/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/usb/serial/keyspan.c:1189:25: error: incompatible pointer types passing 'struct usb_device **' to parameter of type 'const struct device *' [-Wincompatible-pointer-types]
    1189 |                         dev_warn_ratelimited(&serial->dev, "malformed indat packet\n");
         |                                              ^~~~~~~~~~~~
   include/linux/dev_printk.h:227:34: note: expanded from macro 'dev_warn_ratelimited'
     227 |         dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
         |                                         ^~~
   include/linux/dev_printk.h:215:13: note: expanded from macro 'dev_level_ratelimited'
     215 |                 dev_level(dev, fmt, ##__VA_ARGS__);                     \
         |                           ^~~
   include/linux/dev_printk.h:156:49: note: expanded from macro 'dev_warn'
     156 |         dev_printk_index_wrap(_dev_warn, KERN_WARNING, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~
   include/linux/dev_printk.h:110:11: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   include/linux/dev_printk.h:52:37: note: passing argument to parameter 'dev' here
      52 | void _dev_warn(const struct device *dev, const char *fmt, ...);
         |                                     ^

1 error generated.

vim +1189 drivers/usb/serial/keyspan.c

1166
1167 static void usa49wg_indat_callback(struct urb *urb)
1168 {
1169 int i, len, x, err;
1170 struct usb_serial *serial;
1171 struct usb_serial_port *port;
1172 unsigned char *data = urb->transfer_buffer;
1173 int status = urb->status;
1174
1175 serial = urb->context;
1176
1177 if (status) {
1178 dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
1179 __func__, status);
1180 return;
1181 }
1182
1183 /* inbound data is in the form P#, len, status, data */
1184 i = 0;
1185 len = 0;
1186
1187 while (i < urb->actual_length) {
1188 if (urb->actual_length - i < 3) {

> 1189				dev_warn_ratelimited(&serial->dev, "malformed indat packet\n");

1190 break;
1191 }
1192
1193 /* Check port number from message */
1194 if (data[i] >= serial->num_ports) {
1195 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
1196 __func__, data[i]);
1197 return;
1198 }
1199 port = serial->port[data[i++]];
1200 len = data[i++];
1201
1202 /* 0x80 bit is error flag */
1203 if ((data[i] & 0x80) == 0) {
1204 /* no error on any byte */
1205 i++;
1206 for (x = 1; x < len && i < urb->actual_length; ++x)
1207 tty_insert_flip_char(&port->port,
1208 data[i++], 0);
1209 } else {
1210 /*
1211 * some bytes had errors, every byte has status
1212 */
1213 for (x = 0; x + 1 < len &&
1214 i + 1 < urb->actual_length; x += 2) {
1215 int stat = data[i];
1216 int flag = TTY_NORMAL;
1217
1218 if (stat & RXERROR_OVERRUN) {
1219 tty_insert_flip_char(&port->port, 0,
1220 TTY_OVERRUN);
1221 }
1222 /* XXX should handle break (0x10) */
1223 if (stat & RXERROR_PARITY)
1224 flag = TTY_PARITY;
1225 else if (stat & RXERROR_FRAMING)
1226 flag = TTY_FRAME;
1227
1228 tty_insert_flip_char(&port->port, data[i+1],
1229 flag);
1230 i += 2;
1231 }
1232 }
1233 tty_flip_buffer_push(&port->port);
1234 }
1235
1236 /* Resubmit urb so we continue receiving */
1237 err = usb_submit_urb(urb, GFP_ATOMIC);
1238 if (err != 0)
1239 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
1240 }
1241

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki