Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp3541436pxj; Mon, 24 May 2021 09:00:52 -0700 (PDT) X-Google-Smtp-Source: ABdhPJysJhUR9qdsI2Q8SJeChwg6XbestfrBbm0M2gte3KkogPhJBmT5K+ZGrVz5rCm4UxhkHyib X-Received: by 2002:a05:6638:13cc:: with SMTP id i12mr25317493jaj.20.1621872052354; Mon, 24 May 2021 09:00:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1621872052; cv=none; d=google.com; s=arc-20160816; b=RBr9afmwa6OyFVU8jJYI6cw//MYhUzJp3Iff3iZeY6GwCx9U53pRpEOUSrxvsJpgfx cHrFC5W0rIo9TpveaG2Gwf10c0R6cbDN2c9Ky0zhhuwLD94FUlE5yMUsaUGXC2oydgY9 VpOJjYloZ0Aoax0Tv6mw6caTsl1jzVWZcLWc416CfEoWidoGUAxLAwK47L1AXG7IA423 Y/juzk6oS5M7mmLzJ+sQgU3GRdrUt4zKifaUdjqyLVdkPYznxUfas/xU5G9jlOCM/K14 6uY+szrxzuXj4yAPjHE2LbKECvTyeIyiqsMwp2bdS0jynxYpT1N0gsMcg0JMFAjTm2pD yUvA== 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=IgZJPIjfNmMZHtVnRRFMF+5QMUJ2CMJyqeElGBtQTIo=; b=IH+RBLOf1Fz2biygrTXGXmNT9HAup+QpZ+9VV2wo3DIdGl8KC5z9WUm6oevRyLU1T2 i1YP2hcBoknTShrbDBJpk0qr85BnTxAXKz0WlC8glziYi/eYJJyk0KOrPiUzxiUlV6pN MHj8dkSDyYItkfuKUSJcPVBnWXGW1n4ui1y3dAMorD3FVO67kiyAkwroiWLigQaP/6AC b5RRZ/8fkguBIjLcZZ5l3LHmya0OW6Qhc2XAXN+eS/Gbxk0og3kZHwsgY++DX0+i1Sbd HyQA8NVuyod562mNQC6sZQf3hmw5xYJhvEvRTzFMZOMUWbnkM5MKuruVHnXoGfkv71Vq Q6Gw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=yDZOt8bM; 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 138si12556379iob.20.2021.05.24.09.00.38; Mon, 24 May 2021 09:00:52 -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=yDZOt8bM; 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 S235034AbhEXQAY (ORCPT + 99 others); Mon, 24 May 2021 12:00:24 -0400 Received: from mail.kernel.org ([198.145.29.99]:38696 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235317AbhEXPzF (ORCPT ); Mon, 24 May 2021 11:55:05 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id D77EB61930; Mon, 24 May 2021 15:41:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1621870864; bh=ltbbYEFhgO6/+YnQDbpBLYbBtqKENujx/ng6urUI7jo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=yDZOt8bMR6ZoQEYoIYrDneWD4cuSWYVP1pkJihZSXd014d2lTeuz1Y5KsnWvUFzFx qCdCaQ+5ICPZD1Cj2qQeKL3C56C3iPKLn0XFH9LcXLzMlBmuW2oOlQhOqjgsceXqJa o5L0uSTh6GO8pw7SYjoB9KtQpq08CGbH8f+gRZi0= 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.10 069/104] ipc/mqueue, msg, sem: avoid relying on a stack reference past its expiry Date: Mon, 24 May 2021 17:26:04 +0200 Message-Id: <20210524152335.144408381@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210524152332.844251980@linuxfoundation.org> References: <20210524152332.844251980@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 @@ -1003,12 +1003,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)