From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81A66313E38 for ; Sun, 9 Aug 2026 05:08:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786252140; cv=none; b=JQAT5Z08KI50WNoBlYfeZfDip8lj76+TTTKjq0lzNKFPV1lYQDGpTIeIqafWd0pTnQ4t7P9q/5rzd+v+ggm+kqz2ytRePEr5zeFuScDDRWtpRdUbLthfno/ifHzgj65Ob6W7xrvRsmW+B0YH8GXGeBL1alcp9ik0xj9y1EsIk3M= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786252140; c=relaxed/simple; bh=a2fdKboBcWAqQHPJKJKB4rOWMBtPUGvltOZ6yhiVXg8=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type: Content-Disposition; b=LAgEmClApd6ECG+n/rCQOVRcYrn8zMAKP0M4XLy52LYMa2PbOzezJLyz3NXzI0njhmb8itOdQI0felz1PHxQoJSrE13z7m3Cfa6DO2Iwxnn/GW3od0OIM634cwi+bkjqrqSV0F0CF0ngY4sJa1dmcoVXdNlxjWq+L11t++Hn6zc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QpZZVRjd; arc=none smtp.client-ip=209.85.214.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QpZZVRjd" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2d004f135b1so9661115ad.3 for ; Sat, 08 Aug 2026 22:08:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786252139; x=1786856939; darn=vger.kernel.org; h=content-disposition:content-type:mime-version:message-id:subject:cc :to:from:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Nk2+FkpQTilRE8OBvaT+5PGW/tZ3nM9sQGvr8ZWb4+E=; b=QpZZVRjdbk50JHv8IQcZHr2qq0VhCV+gyu367Y0XjoeXQwObHblKzm3cOD40WtgTYd GDxxO7XroQWdVaqcj4GD/jG0qnSMrKlaP65FTMMtB2ztBRE2fdCK95Mst4FPEwvFAAvg HFLpMdyW8eB0oBxIeKj6atZcIV0zJGy7f7HdCd08wDBYPYZwx6U2i+6SlqijR/zhfdwf 2hIcEtH6k/eNJR7sJTTZhp/76izKhDVFoMB7gADre1p98uJqaeAIbBv9NWsAoDoJrsGp 1LPgI3lsEK+WkhPGc//0/tfzwP8VlXqgWBXmSIvHeUB3jnqDNqlICZ1ppjW2XDgH9tYz AQ6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786252139; x=1786856939; h=content-disposition:content-type:mime-version:message-id:subject:cc :to:from:date:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Nk2+FkpQTilRE8OBvaT+5PGW/tZ3nM9sQGvr8ZWb4+E=; b=EYcI7Cwcl4LJjRM1t9KSKFgnjmnjdXBWF+ICLeby1bL/khQPU16U5QT7mzAqyhJrEF nEyHL/J84/x+Pfb0IOvUKgB8my5laOIIfQapu487n4ngFXMHducUImadabp/S7devBjx 9y0lPmKmUWqY2Ro/xbw8LG3NqAUWS7TcOC5iqI4OWw/O/MX55bXHZAanUM85svchPQU8 NA7TWLclFYXE3tkRXnBlP0F5LAuICZmP1AeDf6N3OrKoMGPyVYTb04tYmW0ZcfLTKG2v RDe7dYvuP0De/lAWsx+tkFFkzdsgDqx15yMG3GjKivnmw3/iNOL9x8XfSH9iWkAitwJo Wsvw== X-Gm-Message-State: AOJu0Yz/TvyMq+5MOQ6oSAjESKNzHvgdu6GK8AIIym48Bpa36lgFKadL tcoPP/fCVFjzVymyvmGKHgwPbM/j2YB8SRdwmGRlor2+368mpRNaz3nhT2WFzQ== X-Gm-Gg: AR+sD11X7o5QmRdn5m1nOn4szFfRvSbHo755bdhId2tcgEofNL7vZv5YBzHZIGZ61mu BW3v5o5ZOfAWes5LwTj9botCC1vG0WPmDV9Bbxkr42RdVcGBhl+FsZzyV1E7fjlAin4ZdukFEF7 IxRMiaBj2OuCZzJGUmCy5qstPUT1am7VDcKiVTt7Awfk/LdBZYxh4gndFuRw2kCmrotqmNC10hE sbPDa6JJNZrA/ZCoKma6OL3kSrBG6MbJ4wlfDn6i2I2OaOJtyRjmN1ZMNwuIjYr6biUwRlH5PCD Cz1zqZ0z1zjSgde2XJfNncwtTaDeoKQrqx3RAS3SuNJRxT1KJC1rO4uyumBtD0x1IsGfMooWRys NiLyxcIfiT8H/8NMqj54ONlLik+n1n14ldnMx4PdXJiIBAIiemJu7i4EW7F5qFO/a98bNyRrN4t hNgaA304tM3o9zquZyzhiHNGIL+1OLhZvkzLOZwnXuGoTYZjTuUC/Ef78pSWhQ7jUA8wL1yfS4X aXZXZkA X-Received: by 2002:a17:90b:4f91:b0:37c:6910:5758 with SMTP id 98e67ed59e1d1-3903c542f55mr28335136a91.1.1786252138635; Sat, 08 Aug 2026 22:08:58 -0700 (PDT) Received: from v4bel ([58.123.110.97]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-39085f2b2fdsm10679982a91.12.2026.08.08.22.08.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 08 Aug 2026 22:08:58 -0700 (PDT) Date: Sun, 9 Aug 2026 14:08:54 +0900 From: Hyunwoo Kim To: tglx@kernel.org, mingo@redhat.com, peterz@infradead.org, dvhart@infradead.org, dave@stgolabs.net, andrealmeid@igalia.com Cc: linux-kernel@vger.kernel.org, imv4bel@gmail.com Subject: [PATCH] futex: Require the PI owner of a private futex to share the key's mm Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline The futex word read by the FUTEX_LOCK_PI operations can hold an arbitrary TID. attach_to_pi_owner() only checks whether the task looked up by that TID is a kernel thread and whether it is already exiting. It does not verify that the task belongs to the address space the futex key was taken from. A private futex key is the pair (mm, address), and the mm is stored as a plain pointer without taking a reference. __attach_to_pi_owner() copies that key into the pi_state by value and links the pi_state onto the owner's futex.pi_state_list, so a key scoped to the waiter's mm ends up on a task in a different mm. When the owner exits, exit_pi_state_list() pins the private hash of the owner's mm with guard(private_hash)(current->mm), but resolves the hash bucket from the key stored in the pi_state, which points at the waiter's mm (M below). Nothing holds a reference that keeps that mm alive. T1 (waiter, mm = M) T2 (owner, mm != M) prctl(PR_FUTEX_HASH, SET_SLOTS, 2) /* creates M's private hash */ futex_lock_pi() attach_to_pi_owner() pi_state->key = *key /* {M, addr} */ list_add(&pi_state->list, &T2->futex.pi_state_list) do_exit() exit_pi_state_list() guard(private_hash)(current->mm) /* T2's mm, not M */ raw_spin_lock_irq(&curr->pi_lock) key = pi_state->key // M CLASS(hbr, hbr)(&key) hb = hbr.hb raw_spin_unlock_irq(&curr->pi_lock) do_exit() exit_mm() mmput(M) -> __mmput(M) futex_hash_free(M) kvfree(fph) spin_lock(&hb->lock) // UAF Once M loses its last mm_users reference, futex_hash_free() in __mmput() frees the private hash with kvfree() unconditionally, ignoring the fph references that are still outstanding. When the owner then reaches spin_lock() with the stale hb, it writes into the freed queues[0].lock. A private futex only has meaning inside the mm its key was taken from, so a task that does not share that mm cannot be its owner. Verify in attach_to_pi_owner() that the candidate owner belongs to the mm of the private key and return -ESRCH otherwise, as the TID is then simply a bogus user space value. p->mm is not protected by p->pi_lock, so it is read with READ_ONCE(). The check is placed after the exit state check. Placing it before would return -ESRCH for a task whose current->mm has already been cleared by exit_mm(), instead of letting handle_exit_race() decide. Fixes: 80367ad01d93 ("futex: Add basic infrastructure for local task local hash") Cc: stable@kernel.org Signed-off-by: Hyunwoo Kim --- kernel/futex/pi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c index 795011ea1202f1..d97611196b34ac 100644 --- a/kernel/futex/pi.c +++ b/kernel/futex/pi.c @@ -465,6 +465,13 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key, return ret; } + if (IS_ENABLED(CONFIG_MMU) && futex_key_is_private(key) && + READ_ONCE(p->mm) != key->private.mm) { + raw_spin_unlock_irq(&p->pi_lock); + put_task_struct(p); + return -ESRCH; + } + __attach_to_pi_owner(p, key, ps); raw_spin_unlock_irq(&p->pi_lock); -- 2.43.0