[PATCH] scsi: arcmsr: catch bounds error earlier and dont panic

From: Tong Zhang
Date: Thu Feb 18 2021 - 23:16:23 EST


pARCMSR_CDB is calculated from a base address + a value read from
controller with some bit shifting, the value is not checked and could possibly
overflow the buffer and cause panic. The buffer is allocated using
dma_alloc_coherent and the size is acb->uncache_size.
Instead of crashing the system, we can try to catch the bounds error
earlier and return an error.

[ 25.820995] BUG: unable to handle page fault for address: ffffed1010383dd3
[ 25.821451] #PF: supervisor read access in kernel mode
[ 25.821737] #PF: error_code(0x0000) - not-present page
[ 25.822023] PGD 17fff1067 P4D 17fff1067 PUD 17fff0067 PMD 0
[ 25.822342] Oops: 0000 [#1] SMP KASAN NOPTI
[ 25.822578] CPU: 0 PID: 66 Comm: kworker/u2:2 Not tainted 5.11.0 #27
[ 25.822931] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-48-gd9c812dda519-4
[ 25.823553] Workqueue: scsi_tmf_6 scmd_eh_abort_handler
[ 25.823853] RIP: 0010:__asan_load8+0x3c/0xa0
[ 25.824097] Code: 00 00 00 00 00 00 ff 48 39 f8 77 57 48 8d 47 07 48 89 c2 83 e2 07 48 83 fa 07 78
[ 25.825123] RSP: 0018:ffff888101ea7d10 EFLAGS: 00010a03
[ 25.825417] RAX: 1ffff11010383dd3 RBX: ffff888102a2a8c8 RCX: ffffffffc000ac23
[ 25.825813] RDX: dffffc0000000000 RSI: ffffc90004000030 RDI: ffff888081c1ee98
[ 25.826210] RBP: ffff888081c1eec0 R08: ffffffffc000a5ea R09: ffffed102054551a
[ 25.826606] R10: ffff888102a2a8cb R11: ffffed1020545519 R12: ffff888081c1ee80
[ 25.827004] R13: 0000000081c1ee00 R14: ffff888102a28000 R15: ffffc90004000030
[ 25.827400] FS: 0000000000000000(0000) GS:ffff88815b400000(0000) knlGS:0000000000000000
[ 25.827853] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 25.828174] CR2: ffffed1010383dd3 CR3: 00000001029ca000 CR4: 00000000000006f0
[ 25.828570] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 25.828966] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 25.829362] Call Trace:
[ 25.829503] arcmsr_abort.cold+0xd41/0xf40 [arcmsr]
[ 25.829788] ? __schedule+0x5ae/0xd40
[ 25.829999] scmd_eh_abort_handler+0xbd/0x1a0
[ 25.830247] process_one_work+0x470/0x750
[ 25.830476] worker_thread+0x73/0x690
[ 25.830685] ? process_one_work+0x750/0x750
[ 25.830922] kthread+0x199/0x1f0
[ 25.831108] ? kthread_create_on_node+0xd0/0xd0
[ 25.831363] ret_from_fork+0x1f/0x30
[ 25.831571] Modules linked in: arcmsr(+)
[ 25.831796] CR2: ffffed1010383dd3
[ 25.831984] ---[ end trace 4a558ca3660a5f82 ]---
[ 25.832243] RIP: 0010:__asan_load8+0x3c/0xa0
[ 25.832485] Code: 00 00 00 00 00 00 ff 48 39 f8 77 57 48 8d 47 07 48 89 c2 83 e2 07 48 83 fa 07 78
[ 25.833512] RSP: 0018:ffff888101ea7d10 EFLAGS: 00010a03
[ 25.833805] RAX: 1ffff11010383dd3 RBX: ffff888102a2a8c8 RCX: ffffffffc000ac23
[ 25.834201] RDX: dffffc0000000000 RSI: ffffc90004000030 RDI: ffff888081c1ee98
[ 25.834596] RBP: ffff888081c1eec0 R08: ffffffffc000a5ea R09: ffffed102054551a
[ 25.834992] R10: ffff888102a2a8cb R11: ffffed1020545519 R12: ffff888081c1ee80
[ 25.835388] R13: 0000000081c1ee00 R14: ffff888102a28000 R15: ffffc90004000030
[ 25.835784] FS: 0000000000000000(0000) GS:ffff88815b400000(0000) knlGS:0000000000000000
[ 25.836229] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 25.836547] CR2: ffffed1010383dd3 CR3: 00000001029ca000 CR4: 00000000000006f0
[ 25.836940] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 25.837333] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400

Signed-off-by: Tong Zhang <ztong0001@xxxxxxxxx>
---
drivers/scsi/arcmsr/arcmsr_hba.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 4b79661275c9..e0227bf12ab2 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1482,6 +1482,11 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
while(((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
&& (i++ < acb->maxOutstanding)) {
ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff;
+ if (ccb_cdb_phy>=acb->uncache_size) {
+ printk(KERN_WARNING "arcmsr%d: ccb_cdb_phy bounds error detected",
+ acb->host->host_no);
+ break;
+ }
if (acb->cdb_phyadd_hipart)
ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
@@ -2451,6 +2456,11 @@ static void arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb)

while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
cdb_phy_addr = (flag_ccb << 5) & 0xffffffff;
+ if (cdb_phy_addr>=acb->uncache_size) {
+ printk(KERN_WARNING "arcmsr%d: cdb_phy_addr bounds error detected",
+ acb->host->host_no);
+ break;
+ }
if (acb->cdb_phyadd_hipart)
cdb_phy_addr = cdb_phy_addr | acb->cdb_phyadd_hipart;
pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + cdb_phy_addr);
@@ -3503,6 +3513,11 @@ static int arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb,
}
}
ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff;
+ if (ccb_cdb_phy>=acb->uncache_size) {
+ printk(KERN_WARNING "arcmsr%d: ccb_cdb_phy bounds error detected",
+ acb->host->host_no);
+ return FAILED;
+ }
if (acb->cdb_phyadd_hipart)
ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
--
2.25.1