Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp3549657pxj; Mon, 24 May 2021 09:09:28 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyiD0tGUdE5+3yT50WR1pJsPuPspuylyXYHiNt4+pFKGwSrygZ6QDGBmVaz0tCBMlSxnAkV X-Received: by 2002:a92:da8b:: with SMTP id u11mr16909855iln.135.1621872568572; Mon, 24 May 2021 09:09:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1621872568; cv=none; d=google.com; s=arc-20160816; b=tooBCMEVhw6glr/84MoINm56Jdw6nWHtyu07yAmjiupYIKFwt898J6LN+3+Gz3WtRC U2nYuV0zD1yUujSfPX5hB4Du5Wz+NLiFuUaLoEeLBEpFa/gXm05LZGcip0h2SuHJkjux eiOCcaqBpgTETZ+uNkO3Z2wTkL7wdvCzCwWc61IOvhpZ4SDM7vGgouu+4XVm/l5CajMv lXjXzAeP5kqEzkLzEX0nomuEYwdyxp1scPxApRF0jjTqZ1iGn7daqJZtfadNk0RHLY1Q yGMDY/NLBYHNubV+ZmAlizsySzGjWDO+TiOELuDl7kfEWt6Ft1BXfEhQGydH0J9jsvwk +0lw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=r77KSe22B61jBT8TioEtdd4YjDzW/hs7rkTr7ywUIxY=; b=amQ0oXWu6RSuYMgaJZTVd9wH+RWLczp9TgNLDrg8m5BRqCqmCcaF/3aybUfG/f2hJ6 uHriTPPwGTDifUTDQT1fz8kUqsh5xIkGH8ukreOK91loTS74ViFeolZiGH5DrAKbupBK 5DxId1Jg9PSwIaPhAYd27lPupPtjcR/Sj4CI92CxBEzx+J3AhkGakprgVRL+LnRizHw6 /+2XBUgkBvIAmJjOgJdar0TPCxs3DgXl1oE7AyKqO5PDA4I/KBDPK9/PIaqqDyM2sRUU H4xNxlRUw5xqqMjKdKn3tYvoDd7/gzJ74eNyJkxF+fbJlRiP2iD+jaZgVzUgTp0hM0SS kdbA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="rEGGtW/T"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d8si14254018iob.68.2021.05.24.09.09.14; Mon, 24 May 2021 09:09:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="rEGGtW/T"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236766AbhEXQH0 (ORCPT + 99 others); Mon, 24 May 2021 12:07:26 -0400 Received: from mail.kernel.org ([198.145.29.99]:41358 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235878AbhEXP75 (ORCPT ); Mon, 24 May 2021 11:59:57 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 387C36197E; Mon, 24 May 2021 15:45:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1621871139; bh=VdguUL2ONoSrznA65U7v2bOlxIKqqdf0jx9up5brb+U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rEGGtW/TqYNO+4u5m1tY+HDWhc+S/lRKC17vDDkA0e8ipfJSvoThufhaJo8WtDz0M CFsu95uNqfE3FLNdOIHSTbQ8eK6CybKaHA83gDetJLtiF0Wf3D727EgVhnD8e+oppw 0jDkN2JdqKKcTcQ2O0eKlsbowFqvKIdAqcId3tX4= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Varad Gautam , Matthias von Faber , Davidlohr Bueso , Manfred Spraul , Christian Brauner , Oleg Nesterov , "Eric W. Biederman" , Andrew Morton , Linus Torvalds Subject: [PATCH 5.12 090/127] ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry Date: Mon, 24 May 2021 17:26:47 +0200 Message-Id: <20210524152337.896787744@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210524152334.857620285@linuxfoundation.org> References: <20210524152334.857620285@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Varad Gautam commit a11ddb37bf367e6b5239b95ca759e5389bb46048 upstream. do_mq_timedreceive calls wq_sleep with a stack local address. The sender (do_mq_timedsend) uses this address to later call pipelined_send. This leads to a very hard to trigger race where a do_mq_timedreceive call might return and leave do_mq_timedsend to rely on an invalid address, causing the following crash: RIP: 0010:wake_q_add_safe+0x13/0x60 Call Trace: __x64_sys_mq_timedsend+0x2a9/0x490 do_syscall_64+0x80/0x680 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7f5928e40343 The race occurs as: 1. do_mq_timedreceive calls wq_sleep with the address of `struct ext_wait_queue` on function stack (aliased as `ewq_addr` here) - it holds a valid `struct ext_wait_queue *` as long as the stack has not been overwritten. 2. `ewq_addr` gets added to info->e_wait_q[RECV].list in wq_add, and do_mq_timedsend receives it via wq_get_first_waiter(info, RECV) to call __pipelined_op. 3. Sender calls __pipelined_op::smp_store_release(&this->state, STATE_READY). Here is where the race window begins. (`this` is `ewq_addr`.) 4. If the receiver wakes up now in do_mq_timedreceive::wq_sleep, it will see `state == STATE_READY` and break. 5. do_mq_timedreceive returns, and `ewq_addr` is no longer guaranteed to be a `struct ext_wait_queue *` since it was on do_mq_timedreceive's stack. (Although the address may not get overwritten until another function happens to touch it, which means it can persist around for an indefinite time.) 6. do_mq_timedsend::__pipelined_op() still believes `ewq_addr` is a `struct ext_wait_queue *`, and uses it to find a task_struct to pass to the wake_q_add_safe call. In the lucky case where nothing has overwritten `ewq_addr` yet, `ewq_addr->task` is the right task_struct. In the unlucky case, __pipelined_op::wake_q_add_safe gets handed a bogus address as the receiver's task_struct causing the crash. do_mq_timedsend::__pipelined_op() should not dereference `this` after setting STATE_READY, as the receiver counterpart is now free to return. Change __pipelined_op to call wake_q_add_safe on the receiver's task_struct returned by get_task_struct, instead of dereferencing `this` which sits on the receiver's stack. As Manfred pointed out, the race potentially also exists in ipc/msg.c::expunge_all and ipc/sem.c::wake_up_sem_queue_prepare. Fix those in the same way. Link: https://lkml.kernel.org/r/20210510102950.12551-1-varad.gautam@suse.com Fixes: c5b2cbdbdac563 ("ipc/mqueue.c: update/document memory barriers") Fixes: 8116b54e7e23ef ("ipc/sem.c: document and update memory barriers") Fixes: 0d97a82ba830d8 ("ipc/msg.c: update and document memory barriers") Signed-off-by: Varad Gautam Reported-by: Matthias von Faber Acked-by: Davidlohr Bueso Acked-by: Manfred Spraul Cc: Christian Brauner Cc: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- ipc/mqueue.c | 6 ++++-- ipc/msg.c | 6 ++++-- ipc/sem.c | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1004,12 +1004,14 @@ static inline void __pipelined_op(struct struct mqueue_inode_info *info, struct ext_wait_queue *this) { + struct task_struct *task; + list_del(&this->list); - get_task_struct(this->task); + task = get_task_struct(this->task); /* see MQ_BARRIER for purpose/pairing */ smp_store_release(&this->state, STATE_READY); - wake_q_add_safe(wake_q, this->task); + wake_q_add_safe(wake_q, task); } /* pipelined_send() - send a message directly to the task waiting in --- a/ipc/msg.c +++ b/ipc/msg.c @@ -251,11 +251,13 @@ static void expunge_all(struct msg_queue struct msg_receiver *msr, *t; list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { - get_task_struct(msr->r_tsk); + struct task_struct *r_tsk; + + r_tsk = get_task_struct(msr->r_tsk); /* see MSG_BARRIER for purpose/pairing */ smp_store_release(&msr->r_msg, ERR_PTR(res)); - wake_q_add_safe(wake_q, msr->r_tsk); + wake_q_add_safe(wake_q, r_tsk); } } --- a/ipc/sem.c +++ b/ipc/sem.c @@ -784,12 +784,14 @@ would_block: static inline void wake_up_sem_queue_prepare(struct sem_queue *q, int error, struct wake_q_head *wake_q) { - get_task_struct(q->sleeper); + struct task_struct *sleeper; + + sleeper = get_task_struct(q->sleeper); /* see SEM_BARRIER_2 for purpuse/pairing */ smp_store_release(&q->status, error); - wake_q_add_safe(wake_q, q->sleeper); + wake_q_add_safe(wake_q, sleeper); } static void unlink_queue(struct sem_array *sma, struct sem_queue *q)