atsamd: Fix possible buffer overflow in usbserial.c

The USB buffer size register PCKSIZE.SIZE was not being assigned
correctly.  As a result, it was possible for an incoming USB
transmission to write past the allocated buffer space, which could
corrupt memory of other storage.  In particular, in some cases gcc may
layout ram in such a way that the trailing bytes of an incoming
message might overlap the buffer for an outgoing message.  This could
cause sporadic transmit errors and unstable connections.

Fix by correctly configuring the PCKSIZE.SIZE register.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2025-12-12 23:03:01 -05:00
parent d92dda439e
commit 3f72e519ed

View file

@ -25,27 +25,30 @@ static uint8_t __aligned(4) acmin[USB_CDC_EP_ACM_SIZE];
static uint8_t __aligned(4) bulkout[USB_CDC_EP_BULK_OUT_SIZE];
static uint8_t __aligned(4) bulkin[USB_CDC_EP_BULK_IN_SIZE];
// Convert 64, 32, 16, 8 sized buffer to 3, 2, 1, 0 for PCKSIZE.SIZE register
#define BSIZE(bufname) (__builtin_ctz(sizeof(bufname)) - 3)
static UsbDeviceDescriptor usb_desc[] = {
[0] = { {
{
.ADDR.reg = (uint32_t)ep0out,
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(ep0out) >> 4),
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(BSIZE(ep0out)),
}, {
.ADDR.reg = (uint32_t)ep0in,
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(ep0in) >> 4),
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(BSIZE(ep0in)),
},
} },
[USB_CDC_EP_ACM] = { {
{
}, {
.ADDR.reg = (uint32_t)acmin,
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(acmin) >> 4),
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(BSIZE(acmin)),
},
} },
[USB_CDC_EP_BULK_OUT] = { {
{
.ADDR.reg = (uint32_t)bulkout,
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(bulkout) >> 4),
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(BSIZE(bulkout)),
}, {
},
} },
@ -53,7 +56,7 @@ static UsbDeviceDescriptor usb_desc[] = {
{
}, {
.ADDR.reg = (uint32_t)bulkin,
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(bulkin) >> 4),
.PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(BSIZE(bulkin)),
},
} },
};