All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lu Jialin <lujialin4@huawei.com>
To: Lu Jialin <lujialin4@huawei.com>,
	Johannes Weiner <hannes@cmpxchg.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	Christian Brauner <brauner@kernel.org>,
	Suren Baghdasaryan <surenb@google.com>,
	Oleg Nesterov <oleg@redhat.com>,
	Eric Biggers <ebiggers@google.com>
Cc: <linux-kernel@vger.kernel.org>, <linux-fsdevel@vger.kernel.org>
Subject: [PATCH v2] poll: Fix use-after-free in poll_freewait()
Date: Wed, 14 Jun 2023 15:07:33 +0800	[thread overview]
Message-ID: <20230614070733.113068-1-lujialin4@huawei.com> (raw)

We found a UAF bug in remove_wait_queue as follows:

==================================================================
BUG: KASAN: use-after-free in _raw_spin_lock_irqsave+0x71/0xe0
Write of size 4 at addr ffff8881150d7b28 by task psi_trigger/15306
Call Trace:
 dump_stack+0x9c/0xd3
 print_address_description.constprop.0+0x19/0x170
 __kasan_report.cold+0x6c/0x84
 kasan_report+0x3a/0x50
 check_memory_region+0xfd/0x1f0
 _raw_spin_lock_irqsave+0x71/0xe0
 remove_wait_queue+0x26/0xc0
 poll_freewait+0x6b/0x120
 do_sys_poll+0x305/0x400
 do_syscall_64+0x33/0x40
 entry_SYSCALL_64_after_hwframe+0x61/0xc6

Allocated by task 15306:
 kasan_save_stack+0x1b/0x40
 __kasan_kmalloc.constprop.0+0xb5/0xe0
 psi_trigger_create.part.0+0xfc/0x450
 cgroup_pressure_write+0xfc/0x3b0
 cgroup_file_write+0x1b3/0x390
 kernfs_fop_write_iter+0x224/0x2e0
 new_sync_write+0x2ac/0x3a0
 vfs_write+0x365/0x430
 ksys_write+0xd5/0x1b0
 do_syscall_64+0x33/0x40
 entry_SYSCALL_64_after_hwframe+0x61/0xc6

Freed by task 15850:
 kasan_save_stack+0x1b/0x40
 kasan_set_track+0x1c/0x30
 kasan_set_free_info+0x20/0x40
 __kasan_slab_free+0x151/0x180
 kfree+0xba/0x680
 cgroup_file_release+0x5c/0xe0
 kernfs_drain_open_files+0x122/0x1e0
 kernfs_drain+0xff/0x1e0
 __kernfs_remove.part.0+0x1d1/0x3b0
 kernfs_remove_by_name_ns+0x89/0xf0
 cgroup_addrm_files+0x393/0x3d0
 css_clear_dir+0x8f/0x120
 kill_css+0x41/0xd0
 cgroup_destroy_locked+0x166/0x300
 cgroup_rmdir+0x37/0x140
 kernfs_iop_rmdir+0xbb/0xf0
 vfs_rmdir.part.0+0xa5/0x230
 do_rmdir+0x2e0/0x320
 __x64_sys_unlinkat+0x99/0xc0
 do_syscall_64+0x33/0x40
 entry_SYSCALL_64_after_hwframe+0x61/0xc6
==================================================================

If using epoll(), wake_up_pollfree will empty waitqueue and set
wait_queue_head is NULL before free waitqueue of psi trigger. But is
doesn't work when using poll(), which will lead a UAF problem in
poll_freewait coms as following:

(cgroup_rmdir)                      |
psi_trigger_destroy                 |
  wake_up_pollfree(&t->event_wait)  |
   synchronize_rcu();               |
    kfree(t)                        |
				    |	(poll_freewait)
				    |     free_poll_entry(pwq->inline_entries + i)
				    |	    remove_wait_queue(entry->wait_address)
				    |	      spin_lock_irqsave(&wq_head->lock)

entry->wait_address in poll_freewait() is t->event_wait in cgroup_rmdir().
t->event_wait is free in psi_trigger_destroy before call poll_freewait(),
therefore wq_head in poll_freewait() has been already freed, which would
lead to a UAF.

similar problem for epoll() has been fixed commit c2dbe32d5db5
("sched/psi: Fix use-after-free in ep_remove_wait_queue()").
epoll wakeup function ep_poll_callback() will empty waitqueue and set
wait_queue_head is NULL when pollflags is POLLFREE and judge pwq->whead
is NULL or not before remove_wait_queue in ep_remove_wait_queue(),
which will fix the UAF bug in ep_remove_wait_queue.

But poll wakeup function pollwake() doesn't do that. To fix the
problem, we empty waitqueue and set wait_address is NULL in pollwake() when
key is POLLFREE. otherwise in remove_wait_queue, which is similar to
epoll().

Fixes: 0e94682b73bf ("psi: introduce psi monitor")
Suggested-by: Suren Baghdasaryan <surenb@google.com>
Link: https://lore.kernel.org/all/CAJuCfpEoCRHkJF-=1Go9E94wchB4BzwQ1E3vHGWxNe+tEmSJoA@mail.gmail.com/#t
Signed-off-by: Lu Jialin <lujialin4@huawei.com>
---
v2: correct commit msg and title suggested by Suren Baghdasaryan
---
 fs/select.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/fs/select.c b/fs/select.c
index 0ee55af1a55c..e64c7b4e9959 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -132,7 +132,17 @@ EXPORT_SYMBOL(poll_initwait);
 
 static void free_poll_entry(struct poll_table_entry *entry)
 {
-	remove_wait_queue(entry->wait_address, &entry->wait);
+	wait_queue_head_t *whead;
+
+	rcu_read_lock();
+	/* If it is cleared by POLLFREE, it should be rcu-safe.
+	 * If we read NULL we need a barrier paired with smp_store_release()
+	 * in pollwake().
+	 */
+	whead = smp_load_acquire(&entry->wait_address);
+	if (whead)
+		remove_wait_queue(whead, &entry->wait);
+	rcu_read_unlock();
 	fput(entry->filp);
 }
 
@@ -215,6 +225,14 @@ static int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key
 	entry = container_of(wait, struct poll_table_entry, wait);
 	if (key && !(key_to_poll(key) & entry->key))
 		return 0;
+	if (key_to_poll(key) & POLLFREE) {
+		list_del_init(&wait->entry);
+		/* wait_address !=NULL protects us from the race with
+		 * poll_freewait().
+		 */
+		smp_store_release(&entry->wait_address, NULL);
+		return 0;
+	}
 	return __pollwake(wait, mode, sync, key);
 }
 
-- 
2.17.1


             reply	other threads:[~2023-06-14  7:09 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-14  7:07 Lu Jialin [this message]
2023-06-14  7:57 ` [PATCH v2] poll: Fix use-after-free in poll_freewait() Christian Brauner
2023-06-14 17:40 ` Eric Biggers
2023-06-14 18:19   ` Suren Baghdasaryan
2023-06-15 23:13     ` Suren Baghdasaryan
2023-06-18 13:28       ` lujialin (A)
2023-06-21  0:09         ` Suren Baghdasaryan
2023-06-24  1:58           ` Suren Baghdasaryan
2023-06-26 20:22             ` Suren Baghdasaryan

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=20230614070733.113068-1-lujialin4@huawei.com \
    --to=lujialin4@huawei.com \
    --cc=akpm@linux-foundation.org \
    --cc=brauner@kernel.org \
    --cc=ebiggers@google.com \
    --cc=hannes@cmpxchg.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oleg@redhat.com \
    --cc=surenb@google.com \
    --cc=viro@zeniv.linux.org.uk \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.