From 8cf079dbed1b8b3432cd98cf601601e68c179d59 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 24 Feb 2019 17:53:27 +0000 Subject: [PATCH] scst: Avoid that excessive data lengths cause COMPARE AND WRITE to crash Avoid that running the libiscsi conformance tests triggers the following crash: ================================================================== BUG: KASAN: wild-memory-access in sg_cmp_elem+0x1b6/0x490 [scst] Read of size 8 at addr 0002000100000000 by task disk021_5/1231 CPU: 0 PID: 1231 Comm: disk021_5 Tainted: G O 5.0.0-rc6-dbg+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Call Trace: dump_stack+0x86/0xca kasan_report.cold.3+0x5/0x3b __asan_load8+0x54/0x90 sg_cmp_elem+0x1b6/0x490 [scst] sg_cmp.constprop.41+0x185/0x380 [scst] scst_cwr_read_cmd_finished+0x214/0x6d0 [scst] scst_finish_internal_cmd+0x109/0x1d0 [scst] scst_process_active_cmd+0x193/0x570 [scst] scst_process_redirect_cmd+0x214/0x300 [scst] scst_cmd_done_local+0xec/0x1f0 [scst] fileio_async_complete+0x98/0x1b0 [scst_vdisk] fileio_exec_async+0x3ac/0x430 [scst_vdisk] fileio_exec_read+0x34f/0x560 [scst_vdisk] vdev_do_job+0xf5/0x260 [scst_vdisk] fileio_exec+0x66/0x70 [scst_vdisk] scst_do_real_exec+0x11f/0x540 [scst] scst_exec_check_blocking+0x14c/0x270 [scst] scst_exec_check_sn+0x2ef/0x650 [scst] scst_process_active_cmd+0x2d2/0x570 [scst] scst_cmd_thread+0x1e3/0x6b0 [scst] kthread+0x1d2/0x1f0 ret_from_fork+0x3a/0x50 ================================================================== git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7992 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/backport.h | 13 +++++++++++++ scst/src/scst_mem.c | 2 ++ 2 files changed, 15 insertions(+) diff --git a/scst/include/backport.h b/scst/include/backport.h index de48788f9..3b94bb87b 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -868,6 +868,10 @@ static inline void sg_mark_end(struct scatterlist *sg) { } +static inline void sg_unmark_end(struct scatterlist *sg) +{ +} + #ifndef __BACKPORT_LINUX_SCATTERLIST_H_TO_2_6_23__ static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) @@ -895,6 +899,15 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page, #endif /* for_each_sg */ #endif /* __BACKPORT_LINUX_SCATTERLIST_H_TO_2_6_23__ */ +#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) +/* + * See also commit c8164d8931fd ("scatterlist: introduce sg_unmark_end"; + * v3.10). + */ +static inline void sg_unmark_end(struct scatterlist *sg) +{ + sg->page_link &= ~0x02; +} #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ /* */ diff --git a/scst/src/scst_mem.c b/scst/src/scst_mem.c index 7c1139519..53dc11476 100644 --- a/scst/src/scst_mem.c +++ b/scst/src/scst_mem.c @@ -1099,6 +1099,7 @@ success: *sgv = obj; obj->sg_entries[cnt-1].length -= PAGE_ALIGN(size) - size; + sg_mark_end(&obj->sg_entries[cnt-1]); TRACE_MEM("obj=%p, sg_entries %p (size=%d, pages=%d, sg_count=%d, " "count=%d, last_len=%d)", obj, obj->sg_entries, size, pages, @@ -1224,6 +1225,7 @@ void sgv_pool_free(struct sgv_pool_obj *obj, struct scst_mem_lim *mem_lim) if (obj->cache_num >= 0) { obj->sg_entries[obj->orig_sg].length = obj->orig_length; + sg_unmark_end(&obj->sg_entries[obj->orig_sg]); sgv_put_obj(obj); } else { obj->owner_pool->alloc_fns.free_pages_fn(obj->sg_entries,