From nobody Thu Apr 2 18:46:22 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (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 F33F635D611 for ; Thu, 12 Feb 2026 16:44:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770914676; cv=none; b=pfJck3PGl1k2jnT+P5dMjlyQmBEumIft/RKIfLeL7Jub5B7L4cnacMScCHsG0T7sUeLQZlyohteCZJpyvHY4N6Zp1VKDubBYeyfKa7l3Tuhem3sY0n1zndE5dMwdUamA92IwFap36C5opxotaxELXh+MNZCOG8RPwfOqnl0xFIs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770914676; c=relaxed/simple; bh=fnLASdRdlmo9w5vmeFfi3RRSbxD+NZH2u+fYKknSXzM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=U7rLRQr3GGFVMhscK8KtjMhPIlKeQFXyptTTs7XfbNwLE/qPTsC/xhaoy1DFWh7H7dxDyshN2xoorgj2zLtvqB+fZ/BYSnR8Ip3MjLtN9pkdwJnoaL7v06Vjlk+gyF5/KuU/wzv8+HaDrbADyjQojLwau4iJa9UlONWxxK8KYlg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=FQHK651e; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="FQHK651e" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-48318d08ec2so68145e9.1 for ; Thu, 12 Feb 2026 08:44:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1770914666; x=1771519466; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=Nn7HRp9kZ1ePRvS2UgqTH5jOXAnJnoqPXBxFpVwue5g=; b=FQHK651eFG5AnKq/18Xnt9x6FEOZJeA/rIqnBND1kkxmLLwMHG7csvSkWA6J+kEo1g 0SwJC7tOMQ5TX91AqIDdABzxFSbpGWIOLL/4ifb411DHbqX1C1JwQZ9ir8nGwCDHUuXg sMXcvzu80x/zQMgvYX270KG85VTXvRPTxvfzrmgrF2vUUGoKuY2zzj8TO96FZ7hEAU3c F+fmaFNGk0pWVSA0IayxTs8EjJ9303eTEbTo/XnyKEI59P39zhhWB5cwcqdxHNdTATbC lve8MCG8M0F9kAv0wHKAeaShVicMJ07u5edq5gDQAeOVX9KgFps45YvFlzlBXxeXBIM+ q2Bg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770914666; x=1771519466; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Nn7HRp9kZ1ePRvS2UgqTH5jOXAnJnoqPXBxFpVwue5g=; b=wX0kL0aPPngKF8db/0ZQrfwNLbHvfuZqHTIu7L7cYx+Zx/F9jtwLo8viCIGECUgPYE 9lOyudEQh0GAEZ7A6otMBTNVLCxDBeCFA/mCywwuwRvMOXTWW8LNFMKguLnyZ33pk+ch E1+LDcBw6sadtPMDK4lMNVaE9A/70b5PzJBxLNbHV9FAy+Mq4T/vGmYzz8zpaRSdxlCG lmkxbRfA7hM45sEyZ0O+tIICcaPyZ3lfqRSTFRsZZQUGSftahTZm6GE2akW/0Ntwfglk X/hyKFqA+uAvAzYKqfUrwXWKAjJII/V+yXDdvEQ1u9nK8bT5axm4ZMKkS8657Ro2qd66 Jfcg== X-Forwarded-Encrypted: i=1; AJvYcCUhNW0By+ggjyxQFHqaEFk4GudjUTP7MGodJ7jzdoDzJfL4U7uP8TMd9/jUWWPgsi/4AJRiGEZKHMxyTBE=@vger.kernel.org X-Gm-Message-State: AOJu0Yx5Jb63aQXRqEazD7ySBJui3XNPlfSDPLxWTpCHwT/fo5pbyICa DIt7Gm5CRdjNBtqcUKrjFEpiJc5G5XdwevnrUi2ux3lPfGr2OUipu+GY5nHeVdKBT6ky/mxKpRp PF/UJjlU5 X-Gm-Gg: AZuq6aLn2hWzheRryBtJCpApViofedDoH9W7wKH+p3FQTolJYLPfFuRmzS1FDb6c6qE e6GYvSplnGFzGO9MDLTAPHejDbAqEn7uqU0319Il6ExNYnEPKrqyjB2vCwyH7nNZ7hY0dgRbQJR 6i49LexmCKljXcDKI8q5vXzsaLs/r/A6MsoQp6IYYvv7mC2B1p7LBV8up9FNZ6EHa20N3Net/cj FxDzCAOH6979Ise8W7PyR9qrEEK2/AmB8OoxM+SW977Rt1M2nOF18VRZXNJfZJt+PfBw5fbLtZm Ixf20xj7HGKIhH6TdtTVS9cxLAMU3H65R0dJ8iuwdelTo42KrjfyhCKmIJFyIxR1Q6PFxjcB0lt wf/dYmoKiF3XfKxoWtTyOzl3i71HPzoCpgYxhwsUZUmnPXBVAJD+zqvoO0ndTqKzWlhuUM645+I ZCr26SBK1QXyLX7jGecAH2IM3v6uRxeiO+SuJbCsAaw20Y5/g/nrM= X-Received: by 2002:a05:600c:8a0a:20b0:477:95a8:3803 with SMTP id 5b1f17b1804b1-48366d58fecmr568465e9.13.1770914665961; Thu, 12 Feb 2026 08:44:25 -0800 (PST) Received: from localhost ([2a00:79e0:288a:8:11ea:f041:437e:7de8]) by smtp.gmail.com with UTF8SMTPSA id ffacd0b85a97d-43783e0196bsm14208731f8f.23.2026.02.12.08.44.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Feb 2026 08:44:25 -0800 (PST) From: Jann Horn Date: Thu, 12 Feb 2026 17:44:15 +0100 Subject: [PATCH] rust: task: clean up safety issues wrt de_thread() 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="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260212-rust-de_thread-v1-1-948f5b992624@google.com> X-B4-Tracking: v=1; b=H4sIAF4DjmkC/x3MMQqAMAxA0auUzBbaoIJeRUSqiZpFJa0iiHe3O L7h/wciq3CE1jygfEmUfcvwhYFpDdvCVigb0GHt0KPVMyZLPKRVOZB1gRpflYFpdJCjQ3mW+x9 2/ft+QDGN+mAAAAA= X-Change-ID: 20260212-rust-de_thread-0ad9154aedb0 To: Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Wedson Almeida Filho , Martin Rodriguez Reboredo , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Jann Horn X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=ed25519-sha256; t=1770914662; l=4141; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=fnLASdRdlmo9w5vmeFfi3RRSbxD+NZH2u+fYKknSXzM=; b=bHU6ABu01nN//km96QLGFubDoobsaaIXah5mXJKYiL5NIDOi9+t7JtUsQcseKhOxncbDLFoSF E1oOsakHPGiAONZWR9xD5QAEKXzcjGvKD9XYWuRwEmrMGYCXpKfuFDS X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= (Note: This is not a bugfix, it just cleans up incorrect assumptions.) Task::pid() and Task::group_leader() assume that task::pid and task::group_leader remain constant until the task refcount drops to zero. However, Linux has a special quirk where, when execve() is called by a thread other than the thread group leader (the main thread), the thread calling execve() swaps its identity with the thread group leader's, becoming the new thread group leader. This means task::pid and task::group_leader can't be assumed to be immutable for non-current tasks. (The actual swapping of PIDs is implemented in exchange_tids(); the change of leadership is in de_thread().) For reference, you can see that accessing the ->group_leader of some random task requires extra caution in the prlimit64() syscall, which grabs the tasklist_lock and has a comment explaining that this is done to prevent races with de_thread(). Signed-off-by: Jann Horn --- rust/kernel/task.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 49fad6de0674..989165116278 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -103,7 +103,7 @@ macro_rules! current { unsafe impl Send for Task {} =20 // SAFETY: It's OK to access `Task` through shared references from other t= hreads because we're -// either accessing properties that don't change (e.g., `pid`, `group_lead= er`) or that are properly +// either accessing properties that don't change or that are properly // synchronised by C code (e.g., `signal_pending`). unsafe impl Sync for Task {} =20 @@ -204,23 +204,13 @@ pub fn as_ptr(&self) -> *mut bindings::task_struct { self.0.get() } =20 - /// Returns the group leader of the given task. - pub fn group_leader(&self) -> &Task { - // SAFETY: The group leader of a task never changes after initiali= zation, so reading this - // field is not a data race. - let ptr =3D unsafe { *ptr::addr_of!((*self.as_ptr()).group_leader)= }; - - // SAFETY: The lifetime of the returned task reference is tied to = the lifetime of `self`, - // and given that a task has a reference to its group leader, we k= now it must be valid for - // the lifetime of the returned task reference. - unsafe { &*ptr.cast() } - } - /// Returns the PID of the given task. pub fn pid(&self) -> Pid { - // SAFETY: The pid of a task never changes after initialization, s= o reading this field is - // not a data race. - unsafe { *ptr::addr_of!((*self.as_ptr()).pid) } + // SAFETY: The pid of a task almost never changes after initializa= tion, + // so reading this field is usually not a data race. + // The exception is a race where the task is part of a process that + // goes through execve(), see exchange_tids(). + unsafe { ptr::addr_of!((*self.as_ptr()).pid).read_volatile() } } =20 /// Returns the UID of the given task. @@ -345,6 +335,18 @@ pub fn active_pid_ns(&self) -> Option<&PidNamespace> { // `release_task()` call. Some(unsafe { PidNamespace::from_ptr(active_ns) }) } + + /// Returns the group leader of the current task. + pub fn group_leader(&self) -> &Task { + // SAFETY: The group leader of the current task never changes in s= yscall + // context (except in the implementation of execve()). + let ptr =3D unsafe { *ptr::addr_of!((*self.as_ptr()).group_leader)= }; + + // SAFETY: The lifetime of the returned task reference is tied to = the lifetime of `self`, + // and given that a task has a reference to its group leader, we k= now it must be valid for + // the lifetime of the returned task reference. + unsafe { &*ptr.cast() } + } } =20 // SAFETY: The type invariants guarantee that `Task` is always refcounted. --- base-commit: 192c0159402e6bfbe13de6f8379546943297783d change-id: 20260212-rust-de_thread-0ad9154aedb0 -- =20 Jann Horn