|
Varad Gautam |
a8331c |
From a11ddb37bf367e6b5239b95ca759e5389bb46048 Mon Sep 17 00:00:00 2001
|
|
Varad Gautam |
5e2321 |
From: Varad Gautam <varad.gautam@suse.com>
|
|
Varad Gautam |
5e2321 |
Date: Fri, 14 May 2021 10:39:22 +1000
|
|
Varad Gautam |
5e2321 |
Subject: ipc/mqueue, msg, sem: Avoid relying on a stack reference past its
|
|
Varad Gautam |
5e2321 |
expiry
|
|
Varad Gautam |
5e2321 |
References: bsc#1185988
|
|
Varad Gautam |
a8331c |
Git-commit: a11ddb37bf367e6b5239b95ca759e5389bb46048
|
|
Varad Gautam |
a8331c |
Patch-mainline: v5.13-rc3
|
|
Varad Gautam |
a8331c |
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
do_mq_timedreceive calls wq_sleep with a stack local address. The sender
|
|
Varad Gautam |
5e2321 |
(do_mq_timedsend) uses this address to later call pipelined_send.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
This leads to a very hard to trigger race where a do_mq_timedreceive call
|
|
Varad Gautam |
5e2321 |
might return and leave do_mq_timedsend to rely on an invalid address,
|
|
Varad Gautam |
5e2321 |
causing the following crash:
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
[ 240.739977] RIP: 0010:wake_q_add_safe+0x13/0x60
|
|
Varad Gautam |
5e2321 |
[ 240.739991] Call Trace:
|
|
Varad Gautam |
5e2321 |
[ 240.739999] __x64_sys_mq_timedsend+0x2a9/0x490
|
|
Varad Gautam |
5e2321 |
[ 240.740003] ? auditd_test_task+0x38/0x40
|
|
Varad Gautam |
5e2321 |
[ 240.740007] ? auditd_test_task+0x38/0x40
|
|
Varad Gautam |
5e2321 |
[ 240.740011] do_syscall_64+0x80/0x680
|
|
Varad Gautam |
5e2321 |
[ 240.740017] entry_SYSCALL_64_after_hwframe+0x44/0xa9
|
|
Varad Gautam |
5e2321 |
[ 240.740019] RIP: 0033:0x7f5928e40343
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
The race occurs as:
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
1. do_mq_timedreceive calls wq_sleep with the address of `struct
|
|
Varad Gautam |
5e2321 |
ext_wait_queue` on function stack (aliased as `ewq_addr` here) - it
|
|
Varad Gautam |
5e2321 |
holds a valid `struct ext_wait_queue *` as long as the stack has not
|
|
Varad Gautam |
5e2321 |
been overwritten.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
2. `ewq_addr` gets added to info->e_wait_q[RECV].list in wq_add, and
|
|
Varad Gautam |
5e2321 |
do_mq_timedsend receives it via wq_get_first_waiter(info, RECV) to call
|
|
Varad Gautam |
5e2321 |
__pipelined_op.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
3. Sender calls __pipelined_op::smp_store_release(&this->state,
|
|
Varad Gautam |
5e2321 |
STATE_READY). Here is where the race window begins. (`this` is
|
|
Varad Gautam |
5e2321 |
`ewq_addr`.)
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
4. If the receiver wakes up now in do_mq_timedreceive::wq_sleep, it
|
|
Varad Gautam |
5e2321 |
will see `state == STATE_READY` and break.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
5. do_mq_timedreceive returns, and `ewq_addr` is no longer guaranteed
|
|
Varad Gautam |
5e2321 |
to be a `struct ext_wait_queue *` since it was on do_mq_timedreceive's
|
|
Varad Gautam |
5e2321 |
stack. (Although the address may not get overwritten until another
|
|
Varad Gautam |
5e2321 |
function happens to touch it, which means it can persist around for an
|
|
Varad Gautam |
5e2321 |
indefinite time.)
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
6. do_mq_timedsend::__pipelined_op() still believes `ewq_addr` is a
|
|
Varad Gautam |
5e2321 |
`struct ext_wait_queue *`, and uses it to find a task_struct to pass to
|
|
Varad Gautam |
5e2321 |
the wake_q_add_safe call. In the lucky case where nothing has
|
|
Varad Gautam |
5e2321 |
overwritten `ewq_addr` yet, `ewq_addr->task` is the right task_struct.
|
|
Varad Gautam |
5e2321 |
In the unlucky case, __pipelined_op::wake_q_add_safe gets handed a
|
|
Varad Gautam |
5e2321 |
bogus address as the receiver's task_struct causing the crash.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
do_mq_timedsend::__pipelined_op() should not dereference `this` after
|
|
Varad Gautam |
5e2321 |
setting STATE_READY, as the receiver counterpart is now free to return.
|
|
Varad Gautam |
5e2321 |
Change __pipelined_op to call wake_q_add_safe on the receiver's
|
|
Varad Gautam |
5e2321 |
task_struct returned by get_task_struct, instead of dereferencing `this`
|
|
Varad Gautam |
5e2321 |
which sits on the receiver's stack.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
As Manfred pointed out, the race potentially also exists in
|
|
Varad Gautam |
5e2321 |
ipc/msg.c::expunge_all and ipc/sem.c::wake_up_sem_queue_prepare. Fix
|
|
Varad Gautam |
5e2321 |
those in the same way.
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
Link: https://lkml.kernel.org/r/20210510102950.12551-1-varad.gautam@suse.com
|
|
Varad Gautam |
5e2321 |
Fixes: c5b2cbdbdac563 ("ipc/mqueue.c: update/document memory barriers")
|
|
Varad Gautam |
5e2321 |
Fixes: 8116b54e7e23ef ("ipc/sem.c: document and update memory barriers")
|
|
Varad Gautam |
5e2321 |
Fixes: 0d97a82ba830d8 ("ipc/msg.c: update and document memory barriers")
|
|
Varad Gautam |
5e2321 |
Signed-off-by: Varad Gautam <varad.gautam@suse.com>
|
|
Varad Gautam |
5e2321 |
Reported-by: Matthias von Faber <matthias.vonfaber@aox-tech.de>
|
|
Varad Gautam |
5e2321 |
Acked-by: Davidlohr Bueso <dbueso@suse.de>
|
|
Varad Gautam |
5e2321 |
Acked-by: Manfred Spraul <manfred@colorfullife.com>
|
|
Varad Gautam |
5e2321 |
Cc: Christian Brauner <christian.brauner@ubuntu.com>
|
|
Varad Gautam |
5e2321 |
Cc: Oleg Nesterov <oleg@redhat.com>
|
|
Varad Gautam |
5e2321 |
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
|
|
Varad Gautam |
5e2321 |
Cc: <stable@vger.kernel.org>
|
|
Varad Gautam |
5e2321 |
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
|
Varad Gautam |
5e2321 |
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
---
|
|
Varad Gautam |
5e2321 |
ipc/mqueue.c | 6 ++++--
|
|
Varad Gautam |
5e2321 |
ipc/msg.c | 6 ++++--
|
|
Varad Gautam |
5e2321 |
ipc/sem.c | 6 ++++--
|
|
Varad Gautam |
5e2321 |
3 files changed, 12 insertions(+), 6 deletions(-)
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
|
|
Varad Gautam |
5e2321 |
index 8031464ed4ae2..4e4e61111500c 100644
|
|
Varad Gautam |
5e2321 |
--- a/ipc/mqueue.c
|
|
Varad Gautam |
5e2321 |
+++ b/ipc/mqueue.c
|
|
Varad Gautam |
5e2321 |
@@ -1004,12 +1004,14 @@ static inline void __pipelined_op(struct wake_q_head *wake_q,
|
|
Varad Gautam |
5e2321 |
struct mqueue_inode_info *info,
|
|
Varad Gautam |
5e2321 |
struct ext_wait_queue *this)
|
|
Varad Gautam |
5e2321 |
{
|
|
Varad Gautam |
5e2321 |
+ struct task_struct *task;
|
|
Varad Gautam |
5e2321 |
+
|
|
Varad Gautam |
5e2321 |
list_del(&this->list);
|
|
Varad Gautam |
5e2321 |
- get_task_struct(this->task);
|
|
Varad Gautam |
5e2321 |
+ task = get_task_struct(this->task);
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
/* see MQ_BARRIER for purpose/pairing */
|
|
Varad Gautam |
5e2321 |
smp_store_release(&this->state, STATE_READY);
|
|
Varad Gautam |
5e2321 |
- wake_q_add_safe(wake_q, this->task);
|
|
Varad Gautam |
5e2321 |
+ wake_q_add_safe(wake_q, task);
|
|
Varad Gautam |
5e2321 |
}
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
/* pipelined_send() - send a message directly to the task waiting in
|
|
Varad Gautam |
5e2321 |
diff --git a/ipc/msg.c b/ipc/msg.c
|
|
Varad Gautam |
5e2321 |
index acd1bc7af55a2..6e6c8e0c9380e 100644
|
|
Varad Gautam |
5e2321 |
--- a/ipc/msg.c
|
|
Varad Gautam |
5e2321 |
+++ b/ipc/msg.c
|
|
Varad Gautam |
5e2321 |
@@ -251,11 +251,13 @@ static void expunge_all(struct msg_queue *msq, int res,
|
|
Varad Gautam |
5e2321 |
struct msg_receiver *msr, *t;
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
|
|
Varad Gautam |
5e2321 |
- get_task_struct(msr->r_tsk);
|
|
Varad Gautam |
5e2321 |
+ struct task_struct *r_tsk;
|
|
Varad Gautam |
5e2321 |
+
|
|
Varad Gautam |
5e2321 |
+ r_tsk = get_task_struct(msr->r_tsk);
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
/* see MSG_BARRIER for purpose/pairing */
|
|
Varad Gautam |
5e2321 |
smp_store_release(&msr->r_msg, ERR_PTR(res));
|
|
Varad Gautam |
5e2321 |
- wake_q_add_safe(wake_q, msr->r_tsk);
|
|
Varad Gautam |
5e2321 |
+ wake_q_add_safe(wake_q, r_tsk);
|
|
Varad Gautam |
5e2321 |
}
|
|
Varad Gautam |
5e2321 |
}
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
diff --git a/ipc/sem.c b/ipc/sem.c
|
|
Varad Gautam |
5e2321 |
index e0ec239680cbd..bf534c74293e1 100644
|
|
Varad Gautam |
5e2321 |
--- a/ipc/sem.c
|
|
Varad Gautam |
5e2321 |
+++ b/ipc/sem.c
|
|
Varad Gautam |
5e2321 |
@@ -784,12 +784,14 @@ would_block:
|
|
Varad Gautam |
5e2321 |
static inline void wake_up_sem_queue_prepare(struct sem_queue *q, int error,
|
|
Varad Gautam |
5e2321 |
struct wake_q_head *wake_q)
|
|
Varad Gautam |
5e2321 |
{
|
|
Varad Gautam |
5e2321 |
- get_task_struct(q->sleeper);
|
|
Varad Gautam |
5e2321 |
+ struct task_struct *sleeper;
|
|
Varad Gautam |
5e2321 |
+
|
|
Varad Gautam |
5e2321 |
+ sleeper = get_task_struct(q->sleeper);
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
/* see SEM_BARRIER_2 for purpuse/pairing */
|
|
Varad Gautam |
5e2321 |
smp_store_release(&q->status, error);
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
- wake_q_add_safe(wake_q, q->sleeper);
|
|
Varad Gautam |
5e2321 |
+ wake_q_add_safe(wake_q, sleeper);
|
|
Varad Gautam |
5e2321 |
}
|
|
Varad Gautam |
5e2321 |
|
|
Varad Gautam |
5e2321 |
static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
|
|
Varad Gautam |
5e2321 |
--
|
|
Varad Gautam |
5e2321 |
cgit 1.2.3-1.el7
|
|
Varad Gautam |
5e2321 |
|