From: Steve French <smfrench@gmail.com>
To: "Paulo Alcantara (SUSE)" <pc@cjr.nz>
Cc: CIFS <linux-cifs@vger.kernel.org>
Subject: Re: [PATCH 1/7] cifs: Fix use-after-free bug in cifs_reconnect()
Date: Mon, 25 Nov 2019 01:34:14 -0600 [thread overview]
Message-ID: <CAH2r5mt0ZQyq=x_65y0sTH9k-3wA+QJp_bZdBHoqA079GdyKfA@mail.gmail.com> (raw)
In-Reply-To: <20191122153057.6608-2-pc@cjr.nz>
merged into cifs-2.6.git for-next pending testing and more reviews
On Fri, Nov 22, 2019 at 9:31 AM Paulo Alcantara (SUSE) <pc@cjr.nz> wrote:
>
> Ensure we grab an active reference in cifs superblock while doing
> failover to prevent automounts (DFS links) of expiring and then
> destroying the superblock pointer.
>
> This patch fixes the following KASAN report:
>
> [ 464.301462] BUG: KASAN: use-after-free in
> cifs_reconnect+0x6ab/0x1350
> [ 464.303052] Read of size 8 at addr ffff888155e580d0 by task
> cifsd/1107
>
> [ 464.304682] CPU: 3 PID: 1107 Comm: cifsd Not tainted 5.4.0-rc4+ #13
> [ 464.305552] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009),
> BIOS rel-1.12.1-0-ga5cab58-rebuilt.opensuse.org 04/01/2014
> [ 464.307146] Call Trace:
> [ 464.307875] dump_stack+0x5b/0x90
> [ 464.308631] print_address_description.constprop.0+0x16/0x200
> [ 464.309478] ? cifs_reconnect+0x6ab/0x1350
> [ 464.310253] ? cifs_reconnect+0x6ab/0x1350
> [ 464.311040] __kasan_report.cold+0x1a/0x41
> [ 464.311811] ? cifs_reconnect+0x6ab/0x1350
> [ 464.312563] kasan_report+0xe/0x20
> [ 464.313300] cifs_reconnect+0x6ab/0x1350
> [ 464.314062] ? extract_hostname.part.0+0x90/0x90
> [ 464.314829] ? printk+0xad/0xde
> [ 464.315525] ? _raw_spin_lock+0x7c/0xd0
> [ 464.316252] ? _raw_read_lock_irq+0x40/0x40
> [ 464.316961] ? ___ratelimit+0xed/0x182
> [ 464.317655] cifs_readv_from_socket+0x289/0x3b0
> [ 464.318386] cifs_read_from_socket+0x98/0xd0
> [ 464.319078] ? cifs_readv_from_socket+0x3b0/0x3b0
> [ 464.319782] ? try_to_wake_up+0x43c/0xa90
> [ 464.320463] ? cifs_small_buf_get+0x4b/0x60
> [ 464.321173] ? allocate_buffers+0x98/0x1a0
> [ 464.321856] cifs_demultiplex_thread+0x218/0x14a0
> [ 464.322558] ? cifs_handle_standard+0x270/0x270
> [ 464.323237] ? __switch_to_asm+0x40/0x70
> [ 464.323893] ? __switch_to_asm+0x34/0x70
> [ 464.324554] ? __switch_to_asm+0x40/0x70
> [ 464.325226] ? __switch_to_asm+0x40/0x70
> [ 464.325863] ? __switch_to_asm+0x34/0x70
> [ 464.326505] ? __switch_to_asm+0x40/0x70
> [ 464.327161] ? __switch_to_asm+0x34/0x70
> [ 464.327784] ? finish_task_switch+0xa1/0x330
> [ 464.328414] ? __switch_to+0x363/0x640
> [ 464.329044] ? __schedule+0x575/0xaf0
> [ 464.329655] ? _raw_spin_lock_irqsave+0x82/0xe0
> [ 464.330301] kthread+0x1a3/0x1f0
> [ 464.330884] ? cifs_handle_standard+0x270/0x270
> [ 464.331624] ? kthread_create_on_node+0xd0/0xd0
> [ 464.332347] ret_from_fork+0x35/0x40
>
> [ 464.333577] Allocated by task 1110:
> [ 464.334381] save_stack+0x1b/0x80
> [ 464.335123] __kasan_kmalloc.constprop.0+0xc2/0xd0
> [ 464.335848] cifs_smb3_do_mount+0xd4/0xb00
> [ 464.336619] legacy_get_tree+0x6b/0xa0
> [ 464.337235] vfs_get_tree+0x41/0x110
> [ 464.337975] fc_mount+0xa/0x40
> [ 464.338557] vfs_kern_mount.part.0+0x6c/0x80
> [ 464.339227] cifs_dfs_d_automount+0x336/0xd29
> [ 464.339846] follow_managed+0x1b1/0x450
> [ 464.340449] lookup_fast+0x231/0x4a0
> [ 464.341039] path_openat+0x240/0x1fd0
> [ 464.341634] do_filp_open+0x126/0x1c0
> [ 464.342277] do_sys_open+0x1eb/0x2c0
> [ 464.342957] do_syscall_64+0x5e/0x190
> [ 464.343555] entry_SYSCALL_64_after_hwframe+0x44/0xa9
>
> [ 464.344772] Freed by task 0:
> [ 464.345347] save_stack+0x1b/0x80
> [ 464.345966] __kasan_slab_free+0x12c/0x170
> [ 464.346576] kfree+0xa6/0x270
> [ 464.347211] rcu_core+0x39c/0xc80
> [ 464.347800] __do_softirq+0x10d/0x3da
>
> [ 464.348919] The buggy address belongs to the object at
> ffff888155e58000
> which belongs to the cache kmalloc-256 of size 256
> [ 464.350222] The buggy address is located 208 bytes inside of
> 256-byte region [ffff888155e58000, ffff888155e58100)
> [ 464.351575] The buggy address belongs to the page:
> [ 464.352333] page:ffffea0005579600 refcount:1 mapcount:0
> mapping:ffff88815a803400 index:0x0 compound_mapcount: 0
> [ 464.353583] flags: 0x200000000010200(slab|head)
> [ 464.354209] raw: 0200000000010200 ffffea0005576200 0000000400000004
> ffff88815a803400
> [ 464.355353] raw: 0000000000000000 0000000080100010 00000001ffffffff
> 0000000000000000
> [ 464.356458] page dumped because: kasan: bad access detected
>
> [ 464.367005] Memory state around the buggy address:
> [ 464.367787] ffff888155e57f80: fc fc fc fc fc fc fc fc fc fc fc fc
> fc fc fc fc
> [ 464.368877] ffff888155e58000: fb fb fb fb fb fb fb fb fb fb fb fb
> fb fb fb fb
> [ 464.369967] >ffff888155e58080: fb fb fb fb fb fb fb fb fb fb fb fb
> fb fb fb fb
> [ 464.371111] ^
> [ 464.371775] ffff888155e58100: fc fc fc fc fc fc fc fc fc fc fc fc
> fc fc fc fc
> [ 464.372893] ffff888155e58180: fc fc fc fc fc fc fc fc fc fc fc fc
> fc fc fc fc
> [ 464.373983] ==================================================================
>
> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
> ---
> fs/cifs/connect.c | 46 +++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 35 insertions(+), 11 deletions(-)
>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index fce71a6cc3f4..668d477cc9c7 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -391,7 +391,7 @@ static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
> #ifdef CONFIG_CIFS_DFS_UPCALL
> struct super_cb_data {
> struct TCP_Server_Info *server;
> - struct cifs_sb_info *cifs_sb;
> + struct super_block *sb;
> };
>
> /* These functions must be called with server->srv_mutex held */
> @@ -402,25 +402,39 @@ static void super_cb(struct super_block *sb, void *arg)
> struct cifs_sb_info *cifs_sb;
> struct cifs_tcon *tcon;
>
> - if (d->cifs_sb)
> + if (d->sb)
> return;
>
> cifs_sb = CIFS_SB(sb);
> tcon = cifs_sb_master_tcon(cifs_sb);
> if (tcon->ses->server == d->server)
> - d->cifs_sb = cifs_sb;
> + d->sb = sb;
> }
>
> -static inline struct cifs_sb_info *
> -find_super_by_tcp(struct TCP_Server_Info *server)
> +static struct super_block *get_tcp_super(struct TCP_Server_Info *server)
> {
> struct super_cb_data d = {
> .server = server,
> - .cifs_sb = NULL,
> + .sb = NULL,
> };
>
> iterate_supers_type(&cifs_fs_type, super_cb, &d);
> - return d.cifs_sb ? d.cifs_sb : ERR_PTR(-ENOENT);
> +
> + if (unlikely(!d.sb))
> + return ERR_PTR(-ENOENT);
> + /*
> + * Grab an active reference in order to prevent automounts (DFS links)
> + * of expiring and then freeing up our cifs superblock pointer while
> + * we're doing failover.
> + */
> + cifs_sb_active(d.sb);
> + return d.sb;
> +}
> +
> +static inline void put_tcp_super(struct super_block *sb)
> +{
> + if (!IS_ERR_OR_NULL(sb))
> + cifs_sb_deactive(sb);
> }
>
> static void reconn_inval_dfs_target(struct TCP_Server_Info *server,
> @@ -484,6 +498,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
> struct mid_q_entry *mid_entry;
> struct list_head retry_list;
> #ifdef CONFIG_CIFS_DFS_UPCALL
> + struct super_block *sb = NULL;
> struct cifs_sb_info *cifs_sb = NULL;
> struct dfs_cache_tgt_list tgt_list = {0};
> struct dfs_cache_tgt_iterator *tgt_it = NULL;
> @@ -493,13 +508,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
> server->nr_targets = 1;
> #ifdef CONFIG_CIFS_DFS_UPCALL
> spin_unlock(&GlobalMid_Lock);
> - cifs_sb = find_super_by_tcp(server);
> - if (IS_ERR(cifs_sb)) {
> - rc = PTR_ERR(cifs_sb);
> + sb = get_tcp_super(server);
> + if (IS_ERR(sb)) {
> + rc = PTR_ERR(sb);
> cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
> __func__, rc);
> - cifs_sb = NULL;
> + sb = NULL;
> } else {
> + cifs_sb = CIFS_SB(sb);
> +
> rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list, &tgt_it);
> if (rc && (rc != -EOPNOTSUPP)) {
> cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n",
> @@ -516,6 +533,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
> /* the demux thread will exit normally
> next time through the loop */
> spin_unlock(&GlobalMid_Lock);
> +#ifdef CONFIG_CIFS_DFS_UPCALL
> + dfs_cache_free_tgts(&tgt_list);
> + put_tcp_super(sb);
> +#endif
> return rc;
> } else
> server->tcpStatus = CifsNeedReconnect;
> @@ -642,7 +663,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
> __func__, rc);
> }
> dfs_cache_free_tgts(&tgt_list);
> +
> }
> +
> + put_tcp_super(sb);
> #endif
> if (server->tcpStatus == CifsNeedNegotiate)
> mod_delayed_work(cifsiod_wq, &server->echo, 0);
> --
> 2.24.0
>
--
Thanks,
Steve
next prev parent reply other threads:[~2019-11-25 7:34 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-22 15:30 [PATCH 0/7] DFS fixes Paulo Alcantara (SUSE)
2019-11-22 15:30 ` [PATCH 1/7] cifs: Fix use-after-free bug in cifs_reconnect() Paulo Alcantara (SUSE)
2019-11-25 7:34 ` Steve French [this message]
2019-11-25 11:36 ` Aurélien Aptel
2019-11-22 15:30 ` [PATCH 2/7] cifs: Fix lookup of root ses in DFS referral cache Paulo Alcantara (SUSE)
2019-11-25 7:33 ` Steve French
2019-11-25 11:37 ` Aurélien Aptel
2019-11-22 15:30 ` [PATCH 3/7] cifs: Fix potential softlockups while refreshing DFS cache Paulo Alcantara (SUSE)
2019-11-25 11:41 ` Aurélien Aptel
2019-11-25 15:35 ` Steve French
2019-11-25 19:53 ` Pavel Shilovsky
2019-11-22 15:30 ` [PATCH 4/7] cifs: Clean up DFS referral cache Paulo Alcantara (SUSE)
2019-11-25 11:54 ` Aurélien Aptel
2019-11-22 15:30 ` [PATCH 5/7] cifs: Fix potential deadlock when updating vol in cifs_reconnect() Paulo Alcantara (SUSE)
2019-11-25 12:01 ` Aurélien Aptel
2019-11-22 15:30 ` [PATCH 6/7] cifs: Fix retrieval of DFS referrals in cifs_mount() Paulo Alcantara (SUSE)
2019-11-25 7:38 ` Steve French
2019-11-22 15:30 ` [PATCH 7/7] cifs: Always update signing key of first channel Paulo Alcantara (SUSE)
2019-11-25 15:48 ` Aurélien Aptel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAH2r5mt0ZQyq=x_65y0sTH9k-3wA+QJp_bZdBHoqA079GdyKfA@mail.gmail.com' \
--to=smfrench@gmail.com \
--cc=linux-cifs@vger.kernel.org \
--cc=pc@cjr.nz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).