Skip to content

Commit 475aaf8

Browse files
dvdgomezPlaidCat
authored andcommitted
scsi: iscsi_tcp: Fix UAF during logout when accessing the shost ipaddress
jira LE-868 cve CVE-2023-2162 commit 6f1d64b upstream-diff Upstream has input arg difference; iscsi_host_remove(shost, false) upstream we still have iscsi_host_remove(shost). Bug report and analysis from Ding Hui. During iSCSI session logout, if another task accesses the shost ipaddress attr, we can get a KASAN UAF report like this: [ 276.942144] BUG: KASAN: use-after-free in _raw_spin_lock_bh+0x78/0xe0 [ 276.942535] Write of size 4 at addr ffff8881053b45b8 by task cat/4088 [ 276.943511] CPU: 2 PID: 4088 Comm: cat Tainted: G E 6.1.0-rc8+ #3 [ 276.943997] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 [ 276.944470] Call Trace: [ 276.944943] <TASK> [ 276.945397] dump_stack_lvl+0x34/0x48 [ 276.945887] print_address_description.constprop.0+0x86/0x1e7 [ 276.946421] print_report+0x36/0x4f [ 276.947358] kasan_report+0xad/0x130 [ 276.948234] kasan_check_range+0x35/0x1c0 [ 276.948674] _raw_spin_lock_bh+0x78/0xe0 [ 276.949989] iscsi_sw_tcp_host_get_param+0xad/0x2e0 [iscsi_tcp] [ 276.951765] show_host_param_ISCSI_HOST_PARAM_IPADDRESS+0xe9/0x130 [scsi_transport_iscsi] [ 276.952185] dev_attr_show+0x3f/0x80 [ 276.953005] sysfs_kf_seq_show+0x1fb/0x3e0 [ 276.953401] seq_read_iter+0x402/0x1020 [ 276.954260] vfs_read+0x532/0x7b0 [ 276.955113] ksys_read+0xed/0x1c0 [ 276.955952] do_syscall_64+0x38/0x90 [ 276.956347] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 276.956769] RIP: 0033:0x7f5d3a679222 [ 276.957161] Code: c0 e9 b2 fe ff ff 50 48 8d 3d 32 c0 0b 00 e8 a5 fe 01 00 0f 1f 44 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 0f 05 <48> 3d 00 f0 ff ff 77 56 c3 0f 1f 44 00 00 48 83 ec 28 48 89 54 24 [ 276.958009] RSP: 002b:00007ffc864d16a8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [ 276.958431] RAX: ffffffffffffffda RBX: 0000000000020000 RCX: 00007f5d3a679222 [ 276.958857] RDX: 0000000000020000 RSI: 00007f5d3a4fe000 RDI: 0000000000000003 [ 276.959281] RBP: 00007f5d3a4fe000 R08: 00000000ffffffff R09: 0000000000000000 [ 276.959682] R10: 0000000000000022 R11: 0000000000000246 R12: 0000000000020000 [ 276.960126] R13: 0000000000000003 R14: 0000000000000000 R15: 0000557a26dada58 [ 276.960536] </TASK> [ 276.961357] Allocated by task 2209: [ 276.961756] kasan_save_stack+0x1e/0x40 [ 276.962170] kasan_set_track+0x21/0x30 [ 276.962557] __kasan_kmalloc+0x7e/0x90 [ 276.962923] __kmalloc+0x5b/0x140 [ 276.963308] iscsi_alloc_session+0x28/0x840 [scsi_transport_iscsi] [ 276.963712] iscsi_session_setup+0xda/0xba0 [libiscsi] [ 276.964078] iscsi_sw_tcp_session_create+0x1fd/0x330 [iscsi_tcp] [ 276.964431] iscsi_if_create_session.isra.0+0x50/0x260 [scsi_transport_iscsi] [ 276.964793] iscsi_if_recv_msg+0xc5a/0x2660 [scsi_transport_iscsi] [ 276.965153] iscsi_if_rx+0x198/0x4b0 [scsi_transport_iscsi] [ 276.965546] netlink_unicast+0x4d5/0x7b0 [ 276.965905] netlink_sendmsg+0x78d/0xc30 [ 276.966236] sock_sendmsg+0xe5/0x120 [ 276.966576] ____sys_sendmsg+0x5fe/0x860 [ 276.966923] ___sys_sendmsg+0xe0/0x170 [ 276.967300] __sys_sendmsg+0xc8/0x170 [ 276.967666] do_syscall_64+0x38/0x90 [ 276.968028] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 276.968773] Freed by task 2209: [ 276.969111] kasan_save_stack+0x1e/0x40 [ 276.969449] kasan_set_track+0x21/0x30 [ 276.969789] kasan_save_free_info+0x2a/0x50 [ 276.970146] __kasan_slab_free+0x106/0x190 [ 276.970470] __kmem_cache_free+0x133/0x270 [ 276.970816] device_release+0x98/0x210 [ 276.971145] kobject_cleanup+0x101/0x360 [ 276.971462] iscsi_session_teardown+0x3fb/0x530 [libiscsi] [ 276.971775] iscsi_sw_tcp_session_destroy+0xd8/0x130 [iscsi_tcp] [ 276.972143] iscsi_if_recv_msg+0x1bf1/0x2660 [scsi_transport_iscsi] [ 276.972485] iscsi_if_rx+0x198/0x4b0 [scsi_transport_iscsi] [ 276.972808] netlink_unicast+0x4d5/0x7b0 [ 276.973201] netlink_sendmsg+0x78d/0xc30 [ 276.973544] sock_sendmsg+0xe5/0x120 [ 276.973864] ____sys_sendmsg+0x5fe/0x860 [ 276.974248] ___sys_sendmsg+0xe0/0x170 [ 276.974583] __sys_sendmsg+0xc8/0x170 [ 276.974891] do_syscall_64+0x38/0x90 [ 276.975216] entry_SYSCALL_64_after_hwframe+0x63/0xcd We can easily reproduce by two tasks: 1. while :; do iscsiadm -m node --login; iscsiadm -m node --logout; done 2. while :; do cat \ /sys/devices/platform/host*/iscsi_host/host*/ipaddress; done iscsid | cat --------------------------------+--------------------------------------- |- iscsi_sw_tcp_session_destroy | |- iscsi_session_teardown | |- device_release | |- iscsi_session_release ||- dev_attr_show |- kfree | |- show_host_param_ | ISCSI_HOST_PARAM_IPADDRESS | |- iscsi_sw_tcp_host_get_param | |- r/w tcp_sw_host->session (UAF) |- iscsi_host_remove | |- iscsi_host_free | Fix the above bug by splitting the session removal into 2 parts: 1. removal from iSCSI class which includes sysfs and removal from host tracking. 2. freeing of session. During iscsi_tcp host and session removal we can remove the session from sysfs then remove the host from sysfs. At this point we know userspace is not accessing the kernel via sysfs so we can free the session and host. Link: https://lore.kernel.org/r/20230117193937.21244-2-michael.christie@oracle.com Signed-off-by: Mike Christie <michael.christie@oracle.com> Reviewed-by: Lee Duncan <lduncan@suse.com> Acked-by: Ding Hui <dinghui@sangfor.com.cn> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> (cherry picked from commit 6f1d64b) Signed-off-by: David Gomez <dgomez@ciq.com>
1 parent 91f5a9d commit 475aaf8

File tree

3 files changed

+42
-9
lines changed

3 files changed

+42
-9
lines changed

drivers/scsi/iscsi_tcp.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -921,10 +921,17 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
921921
if (WARN_ON_ONCE(session->leadconn))
922922
return;
923923

924+
iscsi_session_remove(cls_session);
925+
/*
926+
* Our get_host_param needs to access the session, so remove the
927+
* host from sysfs before freeing the session to make sure userspace
928+
* is no longer accessing the callout.
929+
*/
930+
iscsi_host_remove(shost);
931+
924932
iscsi_tcp_r2tpool_free(cls_session->dd_data);
925-
iscsi_session_teardown(cls_session);
926933

927-
iscsi_host_remove(shost);
934+
iscsi_session_free(cls_session);
928935
iscsi_host_free(shost);
929936
}
930937

drivers/scsi/libiscsi.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2997,17 +2997,32 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
29972997
}
29982998
EXPORT_SYMBOL_GPL(iscsi_session_setup);
29992999

3000-
/**
3001-
* iscsi_session_teardown - destroy session, host, and cls_session
3002-
* @cls_session: iscsi session
3000+
/*
3001+
* issi_session_remove - Remove session from iSCSI class.
30033002
*/
3004-
void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
3003+
void iscsi_session_remove(struct iscsi_cls_session *cls_session)
30053004
{
30063005
struct iscsi_session *session = cls_session->dd_data;
3007-
struct module *owner = cls_session->transport->owner;
30083006
struct Scsi_Host *shost = session->host;
30093007

30103008
iscsi_remove_session(cls_session);
3009+
/*
3010+
* host removal only has to wait for its children to be removed from
3011+
* sysfs, and iscsi_tcp needs to do iscsi_host_remove before freeing
3012+
* the session, so drop the session count here.
3013+
*/
3014+
iscsi_host_dec_session_cnt(shost);
3015+
}
3016+
EXPORT_SYMBOL_GPL(iscsi_session_remove);
3017+
3018+
/**
3019+
* iscsi_session_free - Free iscsi session and it's resources
3020+
* @cls_session: iscsi session
3021+
*/
3022+
void iscsi_session_free(struct iscsi_cls_session *cls_session)
3023+
{
3024+
struct iscsi_session *session = cls_session->dd_data;
3025+
struct module *owner = cls_session->transport->owner;
30113026

30123027
iscsi_pool_free(&session->cmdpool);
30133028
kfree(session->password);
@@ -3025,10 +3040,19 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
30253040
kfree(session->discovery_parent_type);
30263041

30273042
iscsi_free_session(cls_session);
3028-
3029-
iscsi_host_dec_session_cnt(shost);
30303043
module_put(owner);
30313044
}
3045+
EXPORT_SYMBOL_GPL(iscsi_session_free);
3046+
3047+
/**
3048+
* iscsi_session_teardown - destroy session and cls_session
3049+
* @cls_session: iscsi session
3050+
*/
3051+
void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
3052+
{
3053+
iscsi_session_remove(cls_session);
3054+
iscsi_session_free(cls_session);
3055+
}
30323056
EXPORT_SYMBOL_GPL(iscsi_session_teardown);
30333057

30343058
/**

include/scsi/libiscsi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
412412
extern struct iscsi_cls_session *
413413
iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
414414
uint16_t, int, int, uint32_t, unsigned int);
415+
void iscsi_session_remove(struct iscsi_cls_session *cls_session);
416+
void iscsi_session_free(struct iscsi_cls_session *cls_session);
415417
extern void iscsi_session_teardown(struct iscsi_cls_session *);
416418
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
417419
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,

0 commit comments

Comments
 (0)