* [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs
@ 2026-09-01 6:58 Arka Mondal
2026-09-01 6:58 ` [PATCH 1/3] usb-storage: alauda: do not do DMA from the stack Arka Mondal
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Arka Mondal @ 2026-09-01 6:58 UTC (permalink / raw)
To: Alan Stern, Greg Kroah-Hartman
Cc: Matthew Dharm, Daniel Drake, linux-usb, usb-storage,
linux-kernel, arkamondalofficial, Arka Mondal
The alauda subdriver builds its commands in stack arrays and passes them
to usb_stor_bulk_transfer_buf(). usb_hcd_map_urb_for_dma() rejects a
buffer on the stack, so on a host controller that uses DMA every alauda
command fails. Patch 1 moves the buffers to us->iobuf.
The first command to fail is the one that builds the block map, and
alauda_ensure_map_for_zone() ignores that failure, so the next access
dereferences a NULL map. Patch 2 checks it.
Separately, the zone index used to reach those maps can be num_zones,
one element past the end of both arrays, because max_lba counts physical
blocks while the index is computed from usable ones. Patch 3 bounds it.
Alan Stern <stern@rowland.harvard.edu> wrote an equivalent fix for
patch 1 in 2023, attachment 305027 on the bug below, and offered to let
me post it. Patch 1 here uses us->iobuf directly, as the other
usb-storage subdrivers do, rather than the memcpy that attachment uses.
Alan also diagnosed the NULL dereference in comment 11 of that bug, and
suggested the reordering that is half of patch 3.
None of this makes the card reader work. Alan has said it may be better
to mark the driver BROKEN; that is a separate decision, and these are
bugs in the code either way.
Compile tested only; no relevant hardware available.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=217862
Link: https://lore.kernel.org/linux-usb/20260821080951.39905-1-arkamondalofficial@gmail.com/
Arka Mondal (3):
usb-storage: alauda: do not do DMA from the stack
usb-storage: alauda: check the return value of alauda_read_map()
usb-storage: alauda: fix out-of-bounds zone index
drivers/usb/storage/alauda.c | 95 +++++++++++++++++++++++++-----------
1 file changed, 67 insertions(+), 28 deletions(-)
base-commit: 2709dd5ae32f0828f386327c76bba9f39f63a1c6
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] usb-storage: alauda: do not do DMA from the stack
2026-09-01 6:58 [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Arka Mondal
@ 2026-09-01 6:58 ` Arka Mondal
2026-09-01 6:58 ` [PATCH 2/3] usb-storage: alauda: check the return value of alauda_read_map() Arka Mondal
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Arka Mondal @ 2026-09-01 6:58 UTC (permalink / raw)
To: Alan Stern, Greg Kroah-Hartman
Cc: Matthew Dharm, Daniel Drake, linux-usb, usb-storage,
linux-kernel, arkamondalofficial, Arka Mondal
alauda_check_status2(), alauda_get_redu_data(), alauda_erase_block(),
alauda_read_block_raw() and alauda_write_block() build their commands in
stack arrays and pass them to usb_stor_bulk_transfer_buf().
alauda_check_status2() and alauda_erase_block() also read the reply back
into a stack array.
usb_stor_msg_common() sets URB_NO_TRANSFER_DMA_MAP only when the buffer
is us->iobuf. Every other buffer reaches usb_hcd_map_urb_for_dma(),
which has warned and returned -EAGAIN for a buffer on the stack since
commit 4568136620c6 ("usb: core: Check URB setup_packet and
transfer_buffer sanity"). On a host controller that uses DMA, all of
these commands fail.
Use us->iobuf, as alauda_reset_media() in this driver and the other
usb-storage subdrivers already do. The command is sent before the reply
is read, so both can use it; sddr09_read_status() does the same.
Fixes: e80b0fade09e ("[PATCH] USB Storage: add alauda support")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=217862
Signed-off-by: Arka Mondal <arka@arkamondal.net>
---
drivers/usb/storage/alauda.c | 70 ++++++++++++++++++++++++------------
1 file changed, 48 insertions(+), 22 deletions(-)
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 691fe47009cf..878c404106c5 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -500,11 +500,14 @@ static int alauda_check_media(struct us_data *us)
static int alauda_check_status2(struct us_data *us)
{
int rc;
- unsigned char command[] = {
- ALAUDA_BULK_CMD, ALAUDA_BULK_GET_STATUS2,
- 0, 0, 0, 0, 3, 0, MEDIA_PORT(us)
- };
- unsigned char data[3];
+ unsigned char *command = us->iobuf;
+ unsigned char *data = us->iobuf;
+
+ memset(command, 0, 9);
+ command[0] = ALAUDA_BULK_CMD;
+ command[1] = ALAUDA_BULK_GET_STATUS2;
+ command[6] = 3;
+ command[8] = MEDIA_PORT(us);
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
@@ -530,10 +533,15 @@ static int alauda_check_status2(struct us_data *us)
static int alauda_get_redu_data(struct us_data *us, u16 pba, unsigned char *data)
{
int rc;
- unsigned char command[] = {
- ALAUDA_BULK_CMD, ALAUDA_BULK_GET_REDU_DATA,
- PBA_HI(pba), PBA_ZONE(pba), 0, PBA_LO(pba), 0, 0, MEDIA_PORT(us)
- };
+ unsigned char *command = us->iobuf;
+
+ memset(command, 0, 9);
+ command[0] = ALAUDA_BULK_CMD;
+ command[1] = ALAUDA_BULK_GET_REDU_DATA;
+ command[2] = PBA_HI(pba);
+ command[3] = PBA_ZONE(pba);
+ command[5] = PBA_LO(pba);
+ command[8] = MEDIA_PORT(us);
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
@@ -702,14 +710,20 @@ static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone)
static int alauda_erase_block(struct us_data *us, u16 pba)
{
int rc;
- unsigned char command[] = {
- ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
- PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, MEDIA_PORT(us)
- };
- unsigned char buf[2];
+ unsigned char *command = us->iobuf;
+ unsigned char *buf = us->iobuf;
usb_stor_dbg(us, "Erasing PBA %d\n", pba);
+ memset(command, 0, 9);
+ command[0] = ALAUDA_BULK_CMD;
+ command[1] = ALAUDA_BULK_ERASE_BLOCK;
+ command[2] = PBA_HI(pba);
+ command[3] = PBA_ZONE(pba);
+ command[5] = PBA_LO(pba);
+ command[6] = 0x02;
+ command[8] = MEDIA_PORT(us);
+
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
if (rc != USB_STOR_XFER_GOOD)
@@ -732,13 +746,19 @@ static int alauda_read_block_raw(struct us_data *us, u16 pba,
unsigned int page, unsigned int pages, unsigned char *data)
{
int rc;
- unsigned char command[] = {
- ALAUDA_BULK_CMD, ALAUDA_BULK_READ_BLOCK, PBA_HI(pba),
- PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us)
- };
+ unsigned char *command = us->iobuf;
usb_stor_dbg(us, "pba %d page %d count %d\n", pba, page, pages);
+ memset(command, 0, 9);
+ command[0] = ALAUDA_BULK_CMD;
+ command[1] = ALAUDA_BULK_READ_BLOCK;
+ command[2] = PBA_HI(pba);
+ command[3] = PBA_ZONE(pba);
+ command[5] = PBA_LO(pba) + page;
+ command[6] = pages;
+ command[8] = MEDIA_PORT(us);
+
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
if (rc != USB_STOR_XFER_GOOD)
@@ -783,13 +803,19 @@ static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data)
{
int rc;
struct alauda_info *info = (struct alauda_info *) us->extra;
- unsigned char command[] = {
- ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_BLOCK, PBA_HI(pba),
- PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us)
- };
+ unsigned char *command = us->iobuf;
usb_stor_dbg(us, "pba %d\n", pba);
+ memset(command, 0, 9);
+ command[0] = ALAUDA_BULK_CMD;
+ command[1] = ALAUDA_BULK_WRITE_BLOCK;
+ command[2] = PBA_HI(pba);
+ command[3] = PBA_ZONE(pba);
+ command[5] = PBA_LO(pba);
+ command[6] = 32;
+ command[8] = MEDIA_PORT(us);
+
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
if (rc != USB_STOR_XFER_GOOD)
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/3] usb-storage: alauda: check the return value of alauda_read_map()
2026-09-01 6:58 [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Arka Mondal
2026-09-01 6:58 ` [PATCH 1/3] usb-storage: alauda: do not do DMA from the stack Arka Mondal
@ 2026-09-01 6:58 ` Arka Mondal
2026-09-01 6:58 ` [PATCH 3/3] usb-storage: alauda: fix out-of-bounds zone index Arka Mondal
2026-09-05 2:37 ` [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Alan Stern
3 siblings, 0 replies; 5+ messages in thread
From: Arka Mondal @ 2026-09-01 6:58 UTC (permalink / raw)
To: Alan Stern, Greg Kroah-Hartman
Cc: Matthew Dharm, Daniel Drake, linux-usb, usb-storage,
linux-kernel, arkamondalofficial, Arka Mondal
alauda_ensure_map_for_zone() ignores the value alauda_read_map()
returns. On failure lba_to_pba[zone] and pba_to_lba[zone] are left NULL,
and both callers dereference them immediately:
pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
alauda_read_map() returns USB_STOR_TRANSPORT_ERROR when either kcalloc()
fails or an alauda_get_redu_data() transfer fails, so one failed bulk
transfer is enough to reach the NULL dereference.
Return that value from alauda_ensure_map_for_zone() and check it in
alauda_read_data() and alauda_write_lba().
Fixes: e80b0fade09e ("[PATCH] USB Storage: add alauda support")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=217862
Signed-off-by: Arka Mondal <arka@arkamondal.net>
---
drivers/usb/storage/alauda.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 878c404106c5..d47ce01d519a 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -697,11 +697,13 @@ static int alauda_read_map(struct us_data *us, unsigned int zone)
* Checks to see whether we have already mapped a certain zone
* If we haven't, the map is generated
*/
-static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone)
+static int alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone)
{
if (MEDIA_INFO(us).lba_to_pba[zone] == NULL
|| MEDIA_INFO(us).pba_to_lba[zone] == NULL)
- alauda_read_map(us, zone);
+ return alauda_read_map(us, zone);
+
+ return 0;
}
/*
@@ -849,7 +851,9 @@ static int alauda_write_lba(struct us_data *us, u16 lba,
unsigned int new_pba_offset;
unsigned int zone = lba / uzonesize;
- alauda_ensure_map_for_zone(us, zone);
+ result = alauda_ensure_map_for_zone(us, zone);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
if (pba == 1) {
@@ -980,7 +984,10 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
unsigned int lba_offset = lba - (zone * uzonesize);
unsigned int pages;
u16 pba;
- alauda_ensure_map_for_zone(us, zone);
+
+ result = alauda_ensure_map_for_zone(us, zone);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ break;
/* Not overflowing capacity? */
if (lba >= max_lba) {
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/3] usb-storage: alauda: fix out-of-bounds zone index
2026-09-01 6:58 [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Arka Mondal
2026-09-01 6:58 ` [PATCH 1/3] usb-storage: alauda: do not do DMA from the stack Arka Mondal
2026-09-01 6:58 ` [PATCH 2/3] usb-storage: alauda: check the return value of alauda_read_map() Arka Mondal
@ 2026-09-01 6:58 ` Arka Mondal
2026-09-05 2:37 ` [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Alan Stern
3 siblings, 0 replies; 5+ messages in thread
From: Arka Mondal @ 2026-09-01 6:58 UTC (permalink / raw)
To: Alan Stern, Greg Kroah-Hartman
Cc: Matthew Dharm, Daniel Drake, linux-usb, usb-storage,
linux-kernel, arkamondalofficial, Arka Mondal
MEDIA_INFO(us).lba_to_pba and .pba_to_lba are arrays of num_zones
pointers, allocated by kcalloc() in alauda_init_media().
alauda_ensure_map_for_zone() reads lba_to_pba[zone] and
pba_to_lba[zone], and when either is NULL alauda_read_map() writes a
pointer back to both. Two separate errors let zone reach num_zones, one
element past the end.
max_lba is capacity >> (blockshift + pageshift), which counts physical
blocks, but zone is lba / uzonesize and uzonesize is 125/128 of
zonesize. On a 16 MB card (alauda_card_ids id 0x73) num_zones is 1 and
uzonesize is 1000, so lba 1000 to 1023 pass the bounds check and index
element 1 of a one-element array.
alauda_read_data() also calls alauda_ensure_map_for_zone() before it
compares lba against max_lba, so any larger lba is used as an index
before the check rejects it. alauda_write_data() already checks first.
Bound lba by num_zones * uzonesize on both paths and move the read
side's call below the check. alauda_transport() reports
num_zones * uzonesize * blocksize for READ_CAPACITY, so the new bound is
exactly the range the device advertises and no block becomes
unreachable.
sd never issues an lba past the reported capacity; an SG_IO READ_10 can.
Fixes: e80b0fade09e ("[PATCH] USB Storage: add alauda support")
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Arka Mondal <arka@arkamondal.net>
---
drivers/usb/storage/alauda.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index d47ce01d519a..5e7f99ba8ac0 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -949,6 +949,7 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
unsigned char *buffer;
u16 lba, max_lba;
unsigned int page, len, offset;
+ unsigned int num_zones;
unsigned int blockshift = MEDIA_INFO(us).blockshift;
unsigned int pageshift = MEDIA_INFO(us).pageshift;
unsigned int blocksize = MEDIA_INFO(us).blocksize;
@@ -973,7 +974,9 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
/* Figure out the initial LBA and page */
lba = address >> blockshift;
page = (address & MEDIA_INFO(us).blockmask);
- max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift);
+ num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+ + blockshift + pageshift);
+ max_lba = num_zones * uzonesize;
result = USB_STOR_TRANSPORT_GOOD;
offset = 0;
@@ -985,10 +988,6 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
unsigned int pages;
u16 pba;
- result = alauda_ensure_map_for_zone(us, zone);
- if (result != USB_STOR_TRANSPORT_GOOD)
- break;
-
/* Not overflowing capacity? */
if (lba >= max_lba) {
usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
@@ -997,6 +996,10 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
break;
}
+ result = alauda_ensure_map_for_zone(us, zone);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ break;
+
/* Find number of pages we can read in this block */
pages = min(sectors, blocksize - page);
len = pages << pageshift;
@@ -1052,6 +1055,7 @@ static int alauda_write_data(struct us_data *us, unsigned long address,
unsigned int pagesize = MEDIA_INFO(us).pagesize;
struct scatterlist *sg;
u16 lba, max_lba;
+ unsigned int num_zones;
int result;
/*
@@ -1078,7 +1082,9 @@ static int alauda_write_data(struct us_data *us, unsigned long address,
/* Figure out the initial LBA and page */
lba = address >> blockshift;
page = (address & MEDIA_INFO(us).blockmask);
- max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift);
+ num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+ + blockshift + pageshift);
+ max_lba = num_zones * MEDIA_INFO(us).uzonesize;
result = USB_STOR_TRANSPORT_GOOD;
offset = 0;
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs
2026-09-01 6:58 [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Arka Mondal
` (2 preceding siblings ...)
2026-09-01 6:58 ` [PATCH 3/3] usb-storage: alauda: fix out-of-bounds zone index Arka Mondal
@ 2026-09-05 2:37 ` Alan Stern
3 siblings, 0 replies; 5+ messages in thread
From: Alan Stern @ 2026-09-05 2:37 UTC (permalink / raw)
To: Arka Mondal
Cc: Greg Kroah-Hartman, Matthew Dharm, Daniel Drake, linux-usb,
usb-storage, linux-kernel, arkamondalofficial
On Tue, Sep 01, 2026 at 03:58:28PM +0900, Arka Mondal wrote:
> The alauda subdriver builds its commands in stack arrays and passes them
> to usb_stor_bulk_transfer_buf(). usb_hcd_map_urb_for_dma() rejects a
> buffer on the stack, so on a host controller that uses DMA every alauda
> command fails. Patch 1 moves the buffers to us->iobuf.
>
> The first command to fail is the one that builds the block map, and
> alauda_ensure_map_for_zone() ignores that failure, so the next access
> dereferences a NULL map. Patch 2 checks it.
>
> Separately, the zone index used to reach those maps can be num_zones,
> one element past the end of both arrays, because max_lba counts physical
> blocks while the index is computed from usable ones. Patch 3 bounds it.
>
> Alan Stern <stern@rowland.harvard.edu> wrote an equivalent fix for
> patch 1 in 2023, attachment 305027 on the bug below, and offered to let
> me post it. Patch 1 here uses us->iobuf directly, as the other
> usb-storage subdrivers do, rather than the memcpy that attachment uses.
> Alan also diagnosed the NULL dereference in comment 11 of that bug, and
> suggested the reordering that is half of patch 3.
>
> None of this makes the card reader work. Alan has said it may be better
> to mark the driver BROKEN; that is a separate decision, and these are
> bugs in the code either way.
>
> Compile tested only; no relevant hardware available.
>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=217862
> Link: https://lore.kernel.org/linux-usb/20260821080951.39905-1-arkamondalofficial@gmail.com/
>
> Arka Mondal (3):
> usb-storage: alauda: do not do DMA from the stack
> usb-storage: alauda: check the return value of alauda_read_map()
> usb-storage: alauda: fix out-of-bounds zone index
>
> drivers/usb/storage/alauda.c | 95 +++++++++++++++++++++++++-----------
> 1 file changed, 67 insertions(+), 28 deletions(-)
For all three patches:
Acked-by: Alan Stern <stern@rowland.harvard.edu>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-05 2:37 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-01 6:58 [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Arka Mondal
2026-09-01 6:58 ` [PATCH 1/3] usb-storage: alauda: do not do DMA from the stack Arka Mondal
2026-09-01 6:58 ` [PATCH 2/3] usb-storage: alauda: check the return value of alauda_read_map() Arka Mondal
2026-09-01 6:58 ` [PATCH 3/3] usb-storage: alauda: fix out-of-bounds zone index Arka Mondal
2026-09-05 2:37 ` [PATCH 0/3] usb-storage: alauda: fix DMA from the stack and two block-map bugs Alan Stern
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®