Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp4404765imu; Tue, 18 Dec 2018 14:20:35 -0800 (PST) X-Google-Smtp-Source: AFSGD/XIsMPfxw454LYJvq102cb76wT8MCOjO8PAANG0XHfuU+/NxEfbAZrK1BMP6Vx+MJZBO3OQ X-Received: by 2002:a63:5518:: with SMTP id j24mr17007626pgb.208.1545171635542; Tue, 18 Dec 2018 14:20:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1545171635; cv=none; d=google.com; s=arc-20160816; b=OvGe1y1QCqdjH1gxcB+2B0qTjhXoofAKr8sbilbJg+7/K/HryvhZtIQAQkrVW6wTQN XFe2MX24fwBwnf6s5+rsNeSAmxwIWXa8DJl7NGzth34Tf0hVUyNQgCf5SpBJ2wNHWZrF WCL1RQFZVIXAYNrxuv+9zRcJ28CpGoNCU8d9Oq8CbblUBcj432xzWugzfJsnbK9D2sev CJjfWODe8fLMTNcqTzHu3/KpUtEtkP7f+ZTaaIwagshvSqpvBYo5Z8gtdQt2LaU7AgDK j0UwR48H8o9DHHZMkGbPgeREhmj/U0UNmKXzyGYqMqZAQaiU9lnWq13xZi1v/7vv9oVI Hohw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-disposition :content-transfer-encoding:mime-version:robot-unsubscribe:robot-id :git-commit-id:subject:to:references:in-reply-to:reply-to:cc :message-id:from:date; bh=CgWQqYu3SxPYv2mVjfpEzm3ezHE5nfEjW6Dzm5qX3F0=; b=VEGAIAorlOz/5sR8FKxMhX9rPQvD6aN/Ix5S1IyGu65via6exl4bgZ4qdhMZEq8WPU 77J8t6ipE6WeQuVfRS9sP5iTmsTdpSu+pbdgvO9BHlVCJS2SA0G6Bo+cGdtckQTvqLtI XoFzrvplCOe1mNKC084I88aT6PXiAgWcfCpOxTUtzWGVSSLT5PwNIaGsZ83TMMI8JyjR tlNZaBCi+uOh7bk1NGvw+EdwemwXQWCmlTKrB5bcN55cUgw4DtxCCyL7wZbD5cMJ4L5Y DNZq7XWDhz/GbEy3DyajVwNLG5ntWs/6uT7cyfDOrRHkkDezraXNe5k5tik67Bx7Esfw uwFA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g21si14103985pgl.114.2018.12.18.14.20.20; Tue, 18 Dec 2018 14:20:35 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727294AbeLRWTb (ORCPT + 99 others); Tue, 18 Dec 2018 17:19:31 -0500 Received: from terminus.zytor.com ([198.137.202.136]:33511 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726570AbeLRWTb (ORCPT ); Tue, 18 Dec 2018 17:19:31 -0500 Received: from terminus.zytor.com (localhost [127.0.0.1]) by terminus.zytor.com (8.15.2/8.15.2) with ESMTPS id wBIMIre22990413 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Tue, 18 Dec 2018 14:18:53 -0800 Received: (from tipbot@localhost) by terminus.zytor.com (8.15.2/8.15.2/Submit) id wBIMIqBH2990410; Tue, 18 Dec 2018 14:18:52 -0800 Date: Tue, 18 Dec 2018 14:18:52 -0800 X-Authentication-Warning: terminus.zytor.com: tipbot set sender to tipbot@zytor.com using -f From: tip-bot for Thomas Gleixner Message-ID: Cc: peterz@infradead.org, stli@linux.ibm.com, mingo@kernel.org, linux-kernel@vger.kernel.org, heiko.carstens@de.ibm.com, hpa@zytor.com, sashal@kernel.org, dvhart@infradead.org, tglx@linutronix.de Reply-To: mingo@kernel.org, stli@linux.ibm.com, peterz@infradead.org, heiko.carstens@de.ibm.com, linux-kernel@vger.kernel.org, tglx@linutronix.de, dvhart@infradead.org, sashal@kernel.org, hpa@zytor.com In-Reply-To: <20181210152311.986181245@linutronix.de> References: <20181210152311.986181245@linutronix.de> To: linux-tip-commits@vger.kernel.org Subject: [tip:locking/urgent] futex: Cure exit race Git-Commit-ID: da791a667536bf8322042e38ca85d55a78d3c273 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00, T_DATE_IN_FUTURE_96_Q autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on terminus.zytor.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: da791a667536bf8322042e38ca85d55a78d3c273 Gitweb: https://git.kernel.org/tip/da791a667536bf8322042e38ca85d55a78d3c273 Author: Thomas Gleixner AuthorDate: Mon, 10 Dec 2018 14:35:14 +0100 Committer: Thomas Gleixner CommitDate: Tue, 18 Dec 2018 23:13:15 +0100 futex: Cure exit race Stefan reported, that the glibc tst-robustpi4 test case fails occasionally. That case creates the following race between sys_exit() and sys_futex_lock_pi(): CPU0 CPU1 sys_exit() sys_futex() do_exit() futex_lock_pi() exit_signals(tsk) No waiters: tsk->flags |= PF_EXITING; *uaddr == 0x00000PID mm_release(tsk) Set waiter bit exit_robust_list(tsk) { *uaddr = 0x80000PID; Set owner died attach_to_pi_owner() { *uaddr = 0xC0000000; tsk = get_task(PID); } if (!tsk->flags & PF_EXITING) { ... attach(); tsk->flags |= PF_EXITPIDONE; } else { if (!(tsk->flags & PF_EXITPIDONE)) return -EAGAIN; return -ESRCH; <--- FAIL } ESRCH is returned all the way to user space, which triggers the glibc test case assert. Returning ESRCH unconditionally is wrong here because the user space value has been changed by the exiting task to 0xC0000000, i.e. the FUTEX_OWNER_DIED bit is set and the futex PID value has been cleared. This is a valid state and the kernel has to handle it, i.e. taking the futex. Cure it by rereading the user space value when PF_EXITING and PF_EXITPIDONE is set in the task which 'owns' the futex. If the value has changed, let the kernel retry the operation, which includes all regular sanity checks and correctly handles the FUTEX_OWNER_DIED case. If it hasn't changed, then return ESRCH as there is no way to distinguish this case from malfunctioning user space. This happens when the exiting task did not have a robust list, the robust list was corrupted or the user space value in the futex was simply bogus. Reported-by: Stefan Liebler Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Cc: Heiko Carstens Cc: Darren Hart Cc: Ingo Molnar Cc: Sasha Levin Cc: stable@vger.kernel.org Link: https://bugzilla.kernel.org/show_bug.cgi?id=200467 Link: https://lkml.kernel.org/r/20181210152311.986181245@linutronix.de --- kernel/futex.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index f423f9b6577e..5cc8083a4c89 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1148,11 +1148,65 @@ out_error: return ret; } +static int handle_exit_race(u32 __user *uaddr, u32 uval, + struct task_struct *tsk) +{ + u32 uval2; + + /* + * If PF_EXITPIDONE is not yet set, then try again. + */ + if (tsk && !(tsk->flags & PF_EXITPIDONE)) + return -EAGAIN; + + /* + * Reread the user space value to handle the following situation: + * + * CPU0 CPU1 + * + * sys_exit() sys_futex() + * do_exit() futex_lock_pi() + * futex_lock_pi_atomic() + * exit_signals(tsk) No waiters: + * tsk->flags |= PF_EXITING; *uaddr == 0x00000PID + * mm_release(tsk) Set waiter bit + * exit_robust_list(tsk) { *uaddr = 0x80000PID; + * Set owner died attach_to_pi_owner() { + * *uaddr = 0xC0000000; tsk = get_task(PID); + * } if (!tsk->flags & PF_EXITING) { + * ... attach(); + * tsk->flags |= PF_EXITPIDONE; } else { + * if (!(tsk->flags & PF_EXITPIDONE)) + * return -EAGAIN; + * return -ESRCH; <--- FAIL + * } + * + * Returning ESRCH unconditionally is wrong here because the + * user space value has been changed by the exiting task. + * + * The same logic applies to the case where the exiting task is + * already gone. + */ + if (get_futex_value_locked(&uval2, uaddr)) + return -EFAULT; + + /* If the user space value has changed, try again. */ + if (uval2 != uval) + return -EAGAIN; + + /* + * The exiting task did not have a robust list, the robust list was + * corrupted or the user space value in *uaddr is simply bogus. + * Give up and tell user space. + */ + return -ESRCH; +} + /* * Lookup the task for the TID provided from user space and attach to * it after doing proper sanity checks. */ -static int attach_to_pi_owner(u32 uval, union futex_key *key, +static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key, struct futex_pi_state **ps) { pid_t pid = uval & FUTEX_TID_MASK; @@ -1162,12 +1216,15 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key, /* * We are the first waiter - try to look up the real owner and attach * the new pi_state to it, but bail out when TID = 0 [1] + * + * The !pid check is paranoid. None of the call sites should end up + * with pid == 0, but better safe than sorry. Let the caller retry */ if (!pid) - return -ESRCH; + return -EAGAIN; p = find_get_task_by_vpid(pid); if (!p) - return -ESRCH; + return handle_exit_race(uaddr, uval, NULL); if (unlikely(p->flags & PF_KTHREAD)) { put_task_struct(p); @@ -1187,7 +1244,7 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key, * set, we know that the task has finished the * cleanup: */ - int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN; + int ret = handle_exit_race(uaddr, uval, p); raw_spin_unlock_irq(&p->pi_lock); put_task_struct(p); @@ -1244,7 +1301,7 @@ static int lookup_pi_state(u32 __user *uaddr, u32 uval, * We are the first waiter - try to look up the owner based on * @uval and attach to it. */ - return attach_to_pi_owner(uval, key, ps); + return attach_to_pi_owner(uaddr, uval, key, ps); } static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) @@ -1352,7 +1409,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, * attach to the owner. If that fails, no harm done, we only * set the FUTEX_WAITERS bit in the user space variable. */ - return attach_to_pi_owner(uval, key, ps); + return attach_to_pi_owner(uaddr, newval, key, ps); } /**