From nobody Sun Feb 8 05:20:03 2026 Received: from mail-yw1-f202.google.com (mail-yw1-f202.google.com [209.85.128.202]) (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 6916E190482 for ; Thu, 8 Aug 2024 16:16:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133794; cv=none; b=Q0Zt8VcSkyvfafPHE6y8E9ex13k6zOItmUHjERZZFvAv5VTp9muyE5rBOnBfv9K6ZsAYXvO3Q5CQGZ07TQZ8SKXsZv87U1CXauoBKTN38dKBf92dKqi7UwhqM5eU9Rs/FEQFA48t1QEp2LI3bza+6ccQ8w1BrTPsAU1b54uAzg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133794; c=relaxed/simple; bh=4PQaFBps8VktqGwrRnYv70CrPEKA5C/LpKWYnG6Le3w=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ZEL3Z2shamG2A91P8KOgFM3Dc2AHIQ0khl1ThsIZMmnPpu7UfIp36Rz6RXD1Aa7f4cES0/bSUk1Nn+PeG6Rn3kTlZWNIu5T/yZf/9wqw99Aad5bY5pGiomfW5pD/xY0ulnV60/gipSKK7FyFy+MxdJDDmvqSHH/NIl4dbraPTP8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=xngOMi15; arc=none smtp.client-ip=209.85.128.202 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="xngOMi15" Received: by mail-yw1-f202.google.com with SMTP id 00721157ae682-64c3f08ca52so22980557b3.3 for ; Thu, 08 Aug 2024 09:16:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133791; x=1723738591; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=D6Q99M30pfVow/VZrp0OXErUk9qZ3L/8/fDluo5OZ/Y=; b=xngOMi157CPmp9o4UJ88t5aUiLJO3bU4faiKUVD+zbVk8fJ91XED3ToLB3G+Lr5DXt iQPLrX5+DWSV9VJy5nWLt6e/CSO6GmLGKElt+BLZ4RS7gj7UJ5fkq8NV6d9XvzyzYY/+ 1HwxK3gdRe9nEtH9UPARXMeo+nxMrmrFV65xccteYOhbdVvbIPUoQhV2bcdaKQMgir8g QGvwmNod+bsBEWesN5O73hR159wwPxtiXP2lWzNaYtcemJBdm29/DxymnsztaqFrRsJr XNCKuBa+zOfpEosoIj1nYqyviE8T2/gWfDgy1oaEU6TLIc7l93HTUiL9X1ujRA/vbK+b sMyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133791; x=1723738591; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=D6Q99M30pfVow/VZrp0OXErUk9qZ3L/8/fDluo5OZ/Y=; b=kai7JSPCVXaMrzBXl1OVQcNJg9dyVmVKMlZ6WEfAZXi2ToKakf/c8kjK/6mTbu1prF RCJBTOO3mxlBU2JTeeMjiopVz6rAybBCBn+PwP9LcfK3JwcIGjC5tMfi38BjAcawSpIv A8HjZY18EmuaFJUsaaRKVqD4v3CdsgJ5S1mWIY6PVkXPf43gboWaklX0PgVwKmHVaSoq cQAY6UOhwz62KvLHo6JjSeQQFPCM7ve4DnhVxBA8GJgsj3CgC3NiDXbIfW5AmTjhFq+E Kq7vaKCD8XoiZ1XuLDX/+SHRZytXMlsdtOUyXdvee59NcQWAP3qSm7SByzbVEExekFvM yfGA== X-Forwarded-Encrypted: i=1; AJvYcCXjEsUkbLVEYI4Hg/XPpZJ5Bpt/b178jBnovFGoK8DnfLkbY6gq/m8XMk8c66KTwvkLf63kmEzoBs7Deo77tKGYmNWp8WJwS04npKAk X-Gm-Message-State: AOJu0Yx5yz+YFdmdIYQbHQJpR6vCyNmzeqPx1z858GwDq4STTJrHnrK+ 8BA9TAc3lOBUyiy8/VApqqfn84+Jz6Hvurl+Te8AnWGkOPkvXnX0Yr8cD5FR/omr2Ts0CZGD62q rCm9N66mTKdZW/Q== X-Google-Smtp-Source: AGHT+IHjKhmt3D8bcbLRy83MdOEq8l2jcjlXOpQD3wWuk5ZNpxZjN0ccli1jrWq07BiA2HaEn1LRXqh39g1w4TM= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a81:5b08:0:b0:62c:ff73:83f with SMTP id 00721157ae682-69bfd009861mr992547b3.8.1723133791340; Thu, 08 Aug 2024 09:16:31 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:44 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=5621; i=aliceryhl@google.com; h=from:subject:message-id; bh=O79cAbTLjOkpOxwEF3Z9QrUnv7nzcQMruideT4KM+Fk=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9VxvPC11vAKiPwxCea0/BDfH8/XkTnCPamv zalojrmzeCJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvVQAKCRAEWL7uWMY5 RqpRD/9vzLR6fVIVLVEQp85pk/Z2XQ6E89etE+ffgbDSHdgTLT/KXtLMLTqf1fnLhQgEVfnm02T docSA46GvH4T5g8fiU6sbXk4KACtp6IUAHqPCVi1Vl61gbvx/CK3gN97Tx6n57r5VEegobnCjVN W7mTISf/azV8LOUoFVp5DJh4CeQDJYGjiwGeyT1A6ba1becU4CdctxYu9XEJ43NWWB22yxGiCt7 7ISrlCQ8FHaIqHkyuCfSKP2GD705HrNLTfJxLWfy2htYuoYCs9vDH2VpQTPLduWc039D5JQ3PZm 0T3t9UmvoWaL9d7MtvbgcAfCvN9Vc5NXcTiISCCeyPn632HpnjKe+1rAODW0mPbxt+eRNO0KrLP BQRQZpnzc1NOkTW+v/jgJiUPDoqhPmVxA4BzRl7CCT4/HxoCggL1X3XVB7lzwqEO7OHi1fl7lY1 5daZxIE0aHSD/ob0P3viYeU3vq0E2pBTYfySSVEBbz42CFPU/l/K5BVgR/w5/nYY+6CIhvuz2If npUUIrmmBHbbklZqEazx2GvbzfdnUU8MKQ6PKSRpfj4wCGyFq/TErj5O9iaM1UvC5vwA3EV529v 1EusNG3U0NQaKopGt+n8YSl8UYf1QI7mM+KksuYmtKzMav7Bgy2gQlY72wP1YBNJA8kduZ03elb WJc5gNhABnwFeUw== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-1-2cb7b934e0e1@google.com> Subject: [PATCH v9 1/8] rust: types: add `NotThreadSafe` From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This introduces a new marker type for types that shouldn't be thread safe. By adding a field of this type to a struct, it becomes non-Send and non-Sync, which means that it cannot be accessed in any way from threads other than the one it was created on. This is useful for APIs that require globals such as `current` to remain constant while the value exists. We update two existing users in the Kernel to use this helper: * `Task::current()` - moving the return type of this value to a different thread would not be safe as you can no longer be guaranteed that the `current` pointer remains valid. * Lock guards. Mutexes and spinlocks should be unlocked on the same thread as where they were locked, so we enforce this using the Send trait. There are also additional users in later patches of this patchset. See [1] and [2] for the discussion that led to the introduction of this patch. Link: https://lore.kernel.org/all/nFDPJFnzE9Q5cqY7FwSMByRH2OAn_BpI4H53NQfWI= lN6I2qfmAqnkp2wRqn0XjMO65OyZY4h6P4K2nAGKJpAOSzksYXaiAK_FoH_8QbgBI4=3D@proto= n.me/ [1] Link: https://lore.kernel.org/all/nFDPJFnzE9Q5cqY7FwSMByRH2OAn_BpI4H53NQfWI= lN6I2qfmAqnkp2wRqn0XjMO65OyZY4h6P4K2nAGKJpAOSzksYXaiAK_FoH_8QbgBI4=3D@proto= n.me/ [2] Suggested-by: Benno Lossin Reviewed-by: Benno Lossin Reviewed-by: Trevor Gross Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Bj=C3=B6rn Roy Baron Reviewed-by: Gary Guo Signed-off-by: Alice Ryhl --- rust/kernel/sync/lock.rs | 13 +++++++++---- rust/kernel/task.rs | 10 ++++++---- rust/kernel/types.rs | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index f6c34ca4d819..d6e9bab114b8 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -6,8 +6,13 @@ //! spinlocks, raw spinlocks) to be provided with minimal effort. =20 use super::LockClassKey; -use crate::{init::PinInit, pin_init, str::CStr, types::Opaque, types::Scop= eGuard}; -use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned}; +use crate::{ + init::PinInit, + pin_init, + str::CStr, + types::{NotThreadSafe, Opaque, ScopeGuard}, +}; +use core::{cell::UnsafeCell, marker::PhantomPinned}; use macros::pin_data; =20 pub mod mutex; @@ -139,7 +144,7 @@ pub fn lock(&self) -> Guard<'_, T, B> { pub struct Guard<'a, T: ?Sized, B: Backend> { pub(crate) lock: &'a Lock, pub(crate) state: B::GuardState, - _not_send: PhantomData<*mut ()>, + _not_send: NotThreadSafe, } =20 // SAFETY: `Guard` is sync when the data protected by the lock is also syn= c. @@ -191,7 +196,7 @@ pub(crate) unsafe fn new(lock: &'a Lock, state: B= ::GuardState) -> Self { Self { lock, state, - _not_send: PhantomData, + _not_send: NotThreadSafe, } } } diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 55dff7e088bf..278c623de0c6 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -4,10 +4,12 @@ //! //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h). =20 -use crate::types::Opaque; +use crate::{ + bindings, + types::{NotThreadSafe, Opaque}, +}; use core::{ ffi::{c_int, c_long, c_uint}, - marker::PhantomData, ops::Deref, ptr, }; @@ -106,7 +108,7 @@ impl Task { pub unsafe fn current() -> impl Deref { struct TaskRef<'a> { task: &'a Task, - _not_send: PhantomData<*mut ()>, + _not_send: NotThreadSafe, } =20 impl Deref for TaskRef<'_> { @@ -125,7 +127,7 @@ fn deref(&self) -> &Self::Target { // that `TaskRef` is not `Send`, we know it cannot be transfer= red to another thread // (where it could potentially outlive the caller). task: unsafe { &*ptr.cast() }, - _not_send: PhantomData, + _not_send: NotThreadSafe, } } =20 diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index bd189d646adb..bb115d730ebb 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -473,3 +473,24 @@ unsafe impl AsBytes for str {} // does not have any uninitialized portions either. unsafe impl AsBytes for [T] {} unsafe impl AsBytes for [T; N] {} + +/// Zero-sized type to mark types not [`Send`]. +/// +/// Add this type as a field to your struct if your type should not be sen= t to a different task. +/// Since [`Send`] is an auto trait, adding a single field that is `!Send`= will ensure that the +/// whole type is `!Send`. +/// +/// If a type is `!Send` it is impossible to give control over an instance= of the type to another +/// task. This is useful to include in types that store or reference task-= local information. A file +/// descriptor is an example of such task-local information. +/// +/// This type also makes the type `!Sync`, which prevents immutable access= to the value from +/// several threads in parallel. +pub type NotThreadSafe =3D PhantomData<*mut ()>; + +/// Used to construct instances of type [`NotThreadSafe`] similar to how `= PhantomData` is +/// constructed. +/// +/// [`NotThreadSafe`]: type@NotThreadSafe +#[allow(non_upper_case_globals)] +pub const NotThreadSafe: NotThreadSafe =3D PhantomData; --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-yb1-f201.google.com (mail-yb1-f201.google.com [209.85.219.201]) (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 2718D18FC93 for ; Thu, 8 Aug 2024 16:16:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133796; cv=none; b=RMOnFWBUiqURr0nWCHvIhaFOctpHUt37NjpuvevYSEnm0H5dusxyj5xDKZdGnGnQTH4BmyDHJsy75ibme3vMe2+zwaNl7pfp03OM+D36vuxnnMFOgQ+taFcItDvroow7zHMCR8Qes5yVM0SkMKTz8mUAWqoCfD8N1YYj2px2WVs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133796; c=relaxed/simple; bh=6Ih3i+4Hw1P+6eHIXABlsLLf+5mhyzhRH25qSqltXX4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=JblSP4hSOcu402OHAe8wFwUU+PFaqiOtgiz52d8wqmZzNgu79hSv/f4IJYNZm3V7xp1ezr13+jLnVb4Rv1d9hxX8J2spOqXlSdaqPLrDrNF1OCKe5xe6f6tlP5Q/jCncc/oZEtRXzAvoHqOWcEUGZKjL2hX667pnbc8QhBE0zhM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=WEOMKDNT; arc=none smtp.client-ip=209.85.219.201 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="WEOMKDNT" Received: by mail-yb1-f201.google.com with SMTP id 3f1490d57ef6-e0b3d35ccfbso1746002276.3 for ; Thu, 08 Aug 2024 09:16:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133794; x=1723738594; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=LnrOkpnPCFdbzQn/x9iHS+wX+2l97GUTugL+KcnmTkA=; b=WEOMKDNTc2CnSFdd1+kswUEuLqiC7PtjET+Rb9U9fZzxoPEv/FwIQIdhVyUYgU30D6 UtO0+lqVAeTJJeoWSm892IvQy81mYEAXp/Ymt4cQTGfHvlgDJbqoYt6079RcIGW2537J bAAX27BxQnwYlJBhlBLL9Bm0drBp6PfzscaR5vlrkNihZFHnI9r+SZhSs4N1uTmH2gE8 lQzGivb7yIFjb2IPlbAUvgQBNXVzyVuMdkwOuTSCLeHRHmoOu2/QK0A1nVlooDH1Xw3Q iox9NSAzQXrWXYtD1Qg6G0tfYTipRjzt0K1v6nGMrNeACEVrOB7bzEMW/IcfYp4tKD/n r3pw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133794; x=1723738594; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=LnrOkpnPCFdbzQn/x9iHS+wX+2l97GUTugL+KcnmTkA=; b=Py0EX6XMOI3pNqTbbWZHDmG0os2Xc4nt56Yfkcc40wBSPaYdyiR1CztGo17wWl+QMx r4773mpb3NGzph5Dt0etCzgdEtBQuZeeqZWIR1g5vshdVyL4KvTng6DQLp60NUKcOmlL 151wBFFEel2V5ulUaF2ffYf5QT29Z1CVjBBe5jyHI80DED04i/m58qOFAshA/DqRhQt9 6vr07cz12i0IeEWTKG7OCHEGPQOpVLh3YEi0HRNfli6VvQqYZynXRuU8l0wRu1xCVnNk xt20F99S7Dgrm5WV2oGImi3/C87W6018FVE9f4A8HpYmSu6ohJTja6Exp8LyS+G9eS1M ZlPg== X-Forwarded-Encrypted: i=1; AJvYcCXm/4evoaO2hUR/2RQUBCEL/wKPWRggeUmOwyQNHVPBxAuJLRq4IcewCTAaFBrieILHWW7LuC1Pa/2Kt/ZFr29ldBUJP8MdHgw7Gc8p X-Gm-Message-State: AOJu0Yz/Dw82yVyyLYhixZ944OJdYjy663oqOekW1/lPqFYHjjPC7e2K EVmCOPGFeleVYNrpb9s5fMys/NevY7DZ9vz8wmyUhlxlFow8Ry/5ejhzXOyyhw9vEdJ4LoWmzS/ h8iQIvBP1QGOJbQ== X-Google-Smtp-Source: AGHT+IErYjafy0I8ODbgd/7fZg54LDTDd7vHtt2H8T5U9KTddFirQ5oOi7NGxvr6EQ57PdY69ofn8ahJXQz+vb4= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a25:26d2:0:b0:e03:2217:3c8f with SMTP id 3f1490d57ef6-e0e9da86880mr4196276.2.1723133794036; Thu, 08 Aug 2024 09:16:34 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:45 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=2428; i=aliceryhl@google.com; h=from:subject:message-id; bh=6Ih3i+4Hw1P+6eHIXABlsLLf+5mhyzhRH25qSqltXX4=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9W8ShuSxK2tF6pVinnkGiah1DUVK31iGo3K 2Sc7+2LDPaJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvVgAKCRAEWL7uWMY5 RlTSD/9fuN1pb719WKFq9tEB3IAVCXdxBm3YMiS28NgN2w9S+NkWrO/NDIC6+9Gr3rUYizVGk7B 7PldiVjZG+ONB+GuxvcbumwPjtp4uqGlH4yMuK9yriHZYtJ8mVaqFidxLmskQBvpAtqW8kPX2I3 pQUNHDaCfR5mAWWGD/mG1GNu5LRaZLYV0IBso1axFN3sdkRgvoVxIkax8YQR8/XruZoIvdrMtH7 5ci/7UM5r1EHZ8U+OagwjSVhQu6ZbrYk743ZeAXJ+pdy1Adkeh+bY3FSGWteIzi/T+5Bi0HdGzH zYvyEZ6TNMbOoN4P3ILsvaslshULgAECovmpSJ06bCcLFZNGyoFMvQDKXgraUK/nqqitERXeu/V 6Bh+4+CruxzdT8MJ/WpAZfdGZZo3luGBU5aQcHDLluxVKUrz4v8O0x7rEfu77990evr5XnOpns+ K4IVSzTe0wsV3QhW4CEnC4i1TjOH21aK3kMTsjuDF6uc0fIbt14ZLTHjgTVW8sOrNSzYdnW0kRZ 4M2NrFhtj5SvsJ1eNs7JAY8zP0xzeIcJ2SoTU0p2dSsEYONa8B3NwvdUuldqmUJcT4f7CrPY/uH l6HbLQ0VRV7GV9FFW7vptQlfZzAj1A+VlySWKWKBGmB+gR1lqf0w2Eb3CxqXnmX7ttRfQKBYBDO FYmIRq23yMQwmFw== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-2-2cb7b934e0e1@google.com> Subject: [PATCH v9 2/8] rust: task: add `Task::current_raw` From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Introduces a safe function for getting a raw pointer to the current task. When writing bindings that need to access the current task, it is often more convenient to call a method that directly returns a raw pointer than to use the existing `Task::current` method. However, the only way to do that is `bindings::get_current()` which is unsafe since it calls into C. By introducing `Task::current_raw()`, it becomes possible to obtain a pointer to the current task without using unsafe. Link: https://lore.kernel.org/all/CAH5fLgjT48X-zYtidv31mox3C4_Ogoo_2cBOCmX0= Ang3tAgGHA@mail.gmail.com/ Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Trevor Gross Reviewed-by: Gary Guo Signed-off-by: Alice Ryhl --- rust/kernel/task.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 278c623de0c6..367b4bbddd9f 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -97,6 +97,15 @@ unsafe impl Sync for Task {} type Pid =3D bindings::pid_t; =20 impl Task { + /// Returns a raw pointer to the current task. + /// + /// It is up to the user to use the pointer correctly. + #[inline] + pub fn current_raw() -> *mut bindings::task_struct { + // SAFETY: Getting the current pointer is always safe. + unsafe { bindings::get_current() } + } + /// Returns a task reference for the currently executing task/thread. /// /// The recommended way to get the current task/thread is to use the @@ -119,14 +128,12 @@ fn deref(&self) -> &Self::Target { } } =20 - // SAFETY: Just an FFI call with no additional safety requirements. - let ptr =3D unsafe { bindings::get_current() }; - + let current =3D Task::current_raw(); TaskRef { // SAFETY: If the current thread is still running, the current= task is valid. Given // that `TaskRef` is not `Send`, we know it cannot be transfer= red to another thread // (where it could potentially outlive the caller). - task: unsafe { &*ptr.cast() }, + task: unsafe { &*current.cast() }, _not_send: NotThreadSafe, } } --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (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 97A5A1917D4 for ; Thu, 8 Aug 2024 16:16:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133799; cv=none; b=OuzV12w5y3Ohdcpo4nAaEyl9YC9iLkwwZ1q+LxT7Ple6u6ULJR6Yeerk3E763hvlQRR0HezQhPPMc6PnEeba7dLuVhxtnOFwqd1hreK2OTUPTjesrrhm7VCF5mgq745gloiaBCsKEV8LNqiqpeeyZAEwqUwtUF7ykQkDFKOFVFM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133799; c=relaxed/simple; bh=1vMIdUZrcluEyiRiidfiHirkYBIo8Lix67mHNvOXu6Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Epsd0mpsvnwDMxYV9jMCl8xvlKpgPLg0Sc//AZ98VuT6GVc86bP9LH7wfK4PnVflbY8mvS9ebkx6lGZvmE9m6Y89gtf6bnY7T89EB3xQfzE2cO0+pkajxHN3UCC8KtnGZ2mtIU7PxITZZjQqmQeTBY0Oc0BcgPvJp2OqzEsPkX0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ujKVvFNu; arc=none smtp.client-ip=209.85.128.201 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ujKVvFNu" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-666010fb35cso18508207b3.0 for ; Thu, 08 Aug 2024 09:16:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133797; x=1723738597; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=7XPJz0RvqVtGQ0s1/Et3DXHfI74Fp+uTO4G4SSGMpQc=; b=ujKVvFNucsFwY/zaiuylMgeJgQmOg9GP7rYSliEnavUQVc9bS3s2/mXebT5si1Gcu+ 3nyFKW1O3P4oyRUiT9T1V4weLzt4jkBDRAjscPlMg4PA5F6Bo+Bz8reeLxYUn1XUrf5A 32/BtFbqzHa3FQZBtDoTVkG/dM+1M/NxrepVpzPYePn8jS4srqAIPvsepmKsGbLGx6wi ojTLAYMEBD5Vt7Zev9qJrxgespSrPqOPZiRmlQkGiAt6Hb4175wm0kOmcF/BHeJ0fEkV YZlkKpbuKY/pb+hFrYiavi66yp9MAiJp4eRbRuJtP42lHdsigy2GtWlG81deoN7XOuQ/ +BdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133797; x=1723738597; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=7XPJz0RvqVtGQ0s1/Et3DXHfI74Fp+uTO4G4SSGMpQc=; b=egHZZdxAlKvFkDE+rlKZ54btGP3kb/cLvFSs3kRCQwed/uJGslSmQ0tKogtSzNAdsm tAPpEqZ3MYgVbZN99BUHZMkxBpQdhwmPZ+IPBnicQIf1vkAD6NqURb/0GYtreaRObtjZ cUhJjyFrtKudAomVlzurYJfDHO1815aDPd2JlqBzz3418kPrq8rC/y5Uexv3f4/xuM0v LB4D36mcBqtSGmL5uTZE9XN57RRl7uODYcc3qpZntgUhqzr+ohD9U2kN8YLgOOwYHUiY wOuNuVINgdCqvycDh+kI2SsChIxDdnBxdIae2oasuUHJlOrbP5BW4UtkfyHZqFVvu9PU DlXQ== X-Forwarded-Encrypted: i=1; AJvYcCXXq78JfGvoz+YrIUZtM4QqlIgfGVToIHIURsltrAcpwECYh6C0AZr8IMozO5zn5BueRsp9yz0AMs66URcuYCGTd37qPSYQC2JbB/2Q X-Gm-Message-State: AOJu0YwdEPiQNS5zMi6wofU2QjenPyoZL4Kj/FF3GpyaoZQOthBZhbAR UX/aoo2cof6D7QOxPJzBPaXEoAwh+trkxmm2kVasmYTsyo0A/pC5qqD1sebnSM01ouOoTvZSK0C PjPtDufl9mIpvBQ== X-Google-Smtp-Source: AGHT+IHUz767KQcpBOtZNxtFKAoUTa/PamO0iQ+5xE9bAJ6TM11xSajERyKwyV0jx6oCLFQ7vn/8N3bCocaDsa0= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a0d:ff44:0:b0:68e:edf4:7b42 with SMTP id 00721157ae682-69c0e17e20bmr1269207b3.2.1723133796674; Thu, 08 Aug 2024 09:16:36 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:46 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=22225; i=aliceryhl@google.com; h=from:subject:message-id; bh=XP+THKic0jAdNWiD3Ihji1EQOowajiTB27FHNKM103w=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9WCz89/Vj3rRho3KbMtMZ7mKxWeA2S5aCdT VmTbGSXKBmJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvVgAKCRAEWL7uWMY5 Rh0SEAC1saEvVdZ1ckQD233dl/rjwXS1JeXFjuqGV/QxtxHc2WOxMEAEPuygVEducrgWbcA7J1z fLCHftEcAPJpYPeOaTTl9mLAO5Z7z7QNgxYkGSI1ielfZdZyfPr3XFjrO89DFe+0yGwHqSVk2eJ Q314fLCcNEtV2IahDcVpKWX6SvhXu9s/w2TgcSGrZiHvygC3vBPKigy+DXqVi6WkAT0SWHgsDsp eMSLzqqKaG8hn6wueXaCO0MWg8KRGgL1Y9wkEd5MmJu3s6F1h/1GS9ktld2y74mSWYWvn4A7TPv jfnI63MnBrg15cBByPdZUesQfM2b6AekS2+KspIjTAr7/tm8glVJP1ik0rbhwDf03/CRh9DO34+ tos0EyRf7wbK398a5Xqqh/++RhBidKi+6L+2wuz4PWafdDvaBdge4dBdhsjSVcUef0RZ4MuEeU8 eEi2N+LeORhbr8PtEmeNnhiUMY75aR+9FuF/Zzg83CaIpVe6haaaCaXmvr+sLmCvaXJ97fjRzVF GDIUkfo65BHaVJ/B1tGv5RrEPclpAU2RGMCFUbioKLqQ3mJNMmvCqMAV971NEJ5NazsfYcET9qh HZMu2pocg5jonMqdwV6BU64qvqayAo7Emw5hnXW7CRzxzZG9JA32yErM2Y2isGxk9gDYvkDDRba 7/ejfoU6Zy5hobg== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-3-2cb7b934e0e1@google.com> Subject: [PATCH v9 3/8] rust: file: add Rust abstraction for `struct file` From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Wedson Almeida Filho This abstraction makes it possible to manipulate the open files for a process. The new `File` struct wraps the C `struct file`. When accessing it using the smart pointer `ARef`, the pointer will own a reference count to the file. When accessing it as `&File`, then the reference does not own a refcount, but the borrow checker will ensure that the reference count does not hit zero while the `&File` is live. Since this is intended to manipulate the open files of a process, we introduce an `fget` constructor that corresponds to the C `fget` method. In future patches, it will become possible to create a new fd in a process and bind it to a `File`. Rust Binder will use these to send fds from one process to another. We also provide a method for accessing the file's flags. Rust Binder will use this to access the flags of the Binder fd to check whether the non-blocking flag is set, which affects what the Binder ioctl does. This introduces a struct for the EBADF error type, rather than just using the Error type directly. This has two advantages: * `File::fget` returns a `Result, BadFdError>`, which the compiler will represent as a single pointer, with null being an error. This is possible because the compiler understands that `BadFdError` has only one possible value, and it also understands that the `ARef` smart pointer is guaranteed non-null. * Additionally, we promise to users of the method that the method can only fail with EBADF, which means that they can rely on this promise without having to inspect its implementation. That said, there are also two disadvantages: * Defining additional error types involves boilerplate. * The question mark operator will only utilize the `From` trait once, which prevents you from using the question mark operator on `BadFdError` in methods that return some third error type that the kernel `Error` is convertible into. (However, it works fine in methods that return `Error`.) Signed-off-by: Wedson Almeida Filho Co-developed-by: Daniel Xu Signed-off-by: Daniel Xu Co-developed-by: Alice Ryhl Reviewed-by: Benno Lossin Signed-off-by: Alice Ryhl --- fs/file.c | 7 + rust/bindings/bindings_helper.h | 2 + rust/helpers.c | 7 + rust/kernel/fs.rs | 8 + rust/kernel/fs/file.rs | 375 ++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 1 + rust/kernel/types.rs | 8 + 7 files changed, 408 insertions(+) diff --git a/fs/file.c b/fs/file.c index a11e59b5d602..53df370c4fd4 100644 --- a/fs/file.c +++ b/fs/file.c @@ -1127,6 +1127,13 @@ EXPORT_SYMBOL(task_lookup_next_fdget_rcu); * * The fput_needed flag returned by fget_light should be passed to the * corresponding fput_light. + * + * (As an exception to rule 2, you can call filp_close between fget_light = and + * fput_light provided that you capture a real refcount with get_file befo= re + * the call to filp_close, and ensure that this real refcount is fput *aft= er* + * the fput_light call.) + * + * See also the documentation in rust/kernel/file.rs. */ static unsigned long __fget_light(unsigned int fd, fmode_t mask) { diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index b940a5777330..550a4a46d413 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index 92d3c03ae1bd..80021b0a7c63 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -200,6 +201,12 @@ rust_helper_krealloc(const void *objp, size_t new_size= , gfp_t flags) } EXPORT_SYMBOL_GPL(rust_helper_krealloc); =20 +struct file *rust_helper_get_file(struct file *f) +{ + return get_file(f); +} +EXPORT_SYMBOL_GPL(rust_helper_get_file); + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indi= ces. diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs new file mode 100644 index 000000000000..0121b38c59e6 --- /dev/null +++ b/rust/kernel/fs.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel file systems. +//! +//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) + +pub mod file; +pub use self::file::{File, LocalFile}; diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs new file mode 100644 index 000000000000..6adb7a7199ec --- /dev/null +++ b/rust/kernel/fs/file.rs @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Files and file descriptors. +//! +//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) and +//! [`include/linux/file.h`](srctree/include/linux/file.h) + +use crate::{ + bindings, + error::{code::*, Error, Result}, + types::{ARef, AlwaysRefCounted, Opaque}, +}; +use core::ptr; + +/// Flags associated with a [`File`]. +pub mod flags { + /// File is opened in append mode. + pub const O_APPEND: u32 =3D bindings::O_APPEND; + + /// Signal-driven I/O is enabled. + pub const O_ASYNC: u32 =3D bindings::FASYNC; + + /// Close-on-exec flag is set. + pub const O_CLOEXEC: u32 =3D bindings::O_CLOEXEC; + + /// File was created if it didn't already exist. + pub const O_CREAT: u32 =3D bindings::O_CREAT; + + /// Direct I/O is enabled for this file. + pub const O_DIRECT: u32 =3D bindings::O_DIRECT; + + /// File must be a directory. + pub const O_DIRECTORY: u32 =3D bindings::O_DIRECTORY; + + /// Like [`O_SYNC`] except metadata is not synced. + pub const O_DSYNC: u32 =3D bindings::O_DSYNC; + + /// Ensure that this file is created with the `open(2)` call. + pub const O_EXCL: u32 =3D bindings::O_EXCL; + + /// Large file size enabled (`off64_t` over `off_t`). + pub const O_LARGEFILE: u32 =3D bindings::O_LARGEFILE; + + /// Do not update the file last access time. + pub const O_NOATIME: u32 =3D bindings::O_NOATIME; + + /// File should not be used as process's controlling terminal. + pub const O_NOCTTY: u32 =3D bindings::O_NOCTTY; + + /// If basename of path is a symbolic link, fail open. + pub const O_NOFOLLOW: u32 =3D bindings::O_NOFOLLOW; + + /// File is using nonblocking I/O. + pub const O_NONBLOCK: u32 =3D bindings::O_NONBLOCK; + + /// File is using nonblocking I/O. + /// + /// This is effectively the same flag as [`O_NONBLOCK`] on all archite= ctures + /// except SPARC64. + pub const O_NDELAY: u32 =3D bindings::O_NDELAY; + + /// Used to obtain a path file descriptor. + pub const O_PATH: u32 =3D bindings::O_PATH; + + /// Write operations on this file will flush data and metadata. + pub const O_SYNC: u32 =3D bindings::O_SYNC; + + /// This file is an unnamed temporary regular file. + pub const O_TMPFILE: u32 =3D bindings::O_TMPFILE; + + /// File should be truncated to length 0. + pub const O_TRUNC: u32 =3D bindings::O_TRUNC; + + /// Bitmask for access mode flags. + /// + /// # Examples + /// + /// ``` + /// use kernel::fs::file; + /// # fn do_something() {} + /// # let flags =3D 0; + /// if (flags & file::flags::O_ACCMODE) =3D=3D file::flags::O_RDONLY { + /// do_something(); + /// } + /// ``` + pub const O_ACCMODE: u32 =3D bindings::O_ACCMODE; + + /// File is read only. + pub const O_RDONLY: u32 =3D bindings::O_RDONLY; + + /// File is write only. + pub const O_WRONLY: u32 =3D bindings::O_WRONLY; + + /// File can be both read and written. + pub const O_RDWR: u32 =3D bindings::O_RDWR; +} + +/// Wraps the kernel's `struct file`. Thread safe. +/// +/// This represents an open file rather than a file on a filesystem. Proce= sses generally reference +/// open files using file descriptors. However, file descriptors are not t= he same as files. A file +/// descriptor is just an integer that corresponds to a file, and a single= file may be referenced +/// by multiple file descriptors. +/// +/// # Refcounting +/// +/// Instances of this type are reference-counted. The reference count is i= ncremented by the +/// `fget`/`get_file` functions and decremented by `fput`. The Rust type `= ARef` represents a +/// pointer that owns a reference count on the file. +/// +/// Whenever a process opens a file descriptor (fd), it stores a pointer t= o the file in its fd +/// table (`struct files_struct`). This pointer owns a reference count to = the file, ensuring the +/// file isn't prematurely deleted while the file descriptor is open. In R= ust terminology, the +/// pointers in `struct files_struct` are `ARef` pointers. +/// +/// ## Light refcounts +/// +/// Whenever a process has an fd to a file, it may use something called a = "light refcount" as a +/// performance optimization. Light refcounts are acquired by calling `fdg= et` and released with +/// `fdput`. The idea behind light refcounts is that if the fd is not clos= ed between the calls to +/// `fdget` and `fdput`, then the refcount cannot hit zero during that tim= e, as the `struct +/// files_struct` holds a reference until the fd is closed. This means tha= t it's safe to access the +/// file even if `fdget` does not increment the refcount. +/// +/// The requirement that the fd is not closed during a light refcount appl= ies globally across all +/// threads - not just on the thread using the light refcount. For this re= ason, light refcounts are +/// only used when the `struct files_struct` is not shared with other thre= ads, since this ensures +/// that other unrelated threads cannot suddenly start using the fd and cl= ose it. Therefore, +/// calling `fdget` on a shared `struct files_struct` creates a normal ref= count instead of a light +/// refcount. +/// +/// Light reference counts must be released with `fdput` before the system= call returns to +/// userspace. This means that if you wait until the current system call r= eturns to userspace, then +/// all light refcounts that existed at the time have gone away. +/// +/// ### The file position +/// +/// Each `struct file` has a position integer, which is protected by the `= f_pos_lock` mutex. +/// However, if the `struct file` is not shared, then the kernel may avoid= taking the lock as a +/// performance optimization. +/// +/// The condition for avoiding the `f_pos_lock` mutex is different from th= e condition for using +/// `fdget`. With `fdget`, you may avoid incrementing the refcount as long= as the current fd table +/// is not shared; it is okay if there are other fd tables that also refer= ence the same `struct +/// file`. However, `fdget_pos` can only avoid taking the `f_pos_lock` if = the entire `struct file` +/// is not shared, as different processes with an fd to the same `struct f= ile` share the same +/// position. +/// +/// To represent files that are not thread safe due to this optimization, = the [`LocalFile`] type is +/// used. +/// +/// ## Rust references +/// +/// The reference type `&File` is similar to light refcounts: +/// +/// * `&File` references don't own a reference count. They can only exist = as long as the reference +/// count stays positive, and can only be created when there is some mec= hanism in place to ensure +/// this. +/// +/// * The Rust borrow-checker normally ensures this by enforcing that the = `ARef` from which +/// a `&File` is created outlives the `&File`. +/// +/// * Using the unsafe [`File::from_raw_file`] means that it is up to the = caller to ensure that the +/// `&File` only exists while the reference count is positive. +/// +/// * You can think of `fdget` as using an fd to look up an `ARef` i= n the `struct +/// files_struct` and create an `&File` from it. The "fd cannot be close= d" rule is like the Rust +/// rule "the `ARef` must outlive the `&File`". +/// +/// # Invariants +/// +/// * All instances of this type are refcounted using the `f_count` field. +/// * There must not be any active calls to `fdget_pos` on this file that = did not take the +/// `f_pos_lock` mutex. +#[repr(transparent)] +pub struct File { + inner: Opaque, +} + +// SAFETY: This file is known to not have any active `fdget_pos` calls tha= t did not take the +// `f_pos_lock` mutex, so it is safe to transfer it between threads. +unsafe impl Send for File {} + +// SAFETY: This file is known to not have any active `fdget_pos` calls tha= t did not take the +// `f_pos_lock` mutex, so it is safe to access its methods from several th= reads in parallel. +unsafe impl Sync for File {} + +// SAFETY: The type invariants guarantee that `File` is always ref-counted= . This implementation +// makes `ARef` own a normal refcount. +unsafe impl AlwaysRefCounted for File { + #[inline] + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. + unsafe { bindings::get_file(self.as_ptr()) }; + } + + #[inline] + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: To call this method, the caller passes us ownership of = a normal refcount, so we + // may drop it. The cast is okay since `File` has the same represe= ntation as `struct file`. + unsafe { bindings::fput(obj.cast().as_ptr()) } + } +} + +/// Wraps the kernel's `struct file`. Not thread safe. +/// +/// This type represents a file that is not known to be safe to transfer a= cross thread boundaries. +/// To obtain a thread-safe [`File`], use the [`assume_no_fdget_pos`] conv= ersion. +/// +/// See the documentation for [`File`] for more information. +/// +/// # Invariants +/// +/// * All instances of this type are refcounted using the `f_count` field. +/// * If there is an active call to `fdget_pos` that did not take the `f_p= os_lock` mutex, then it +/// must be on the same thread as this file. +/// +/// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos +pub struct LocalFile { + inner: Opaque, +} + +// SAFETY: The type invariants guarantee that `LocalFile` is always ref-co= unted. This implementation +// makes `ARef` own a normal refcount. +unsafe impl AlwaysRefCounted for LocalFile { + #[inline] + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. + unsafe { bindings::get_file(self.as_ptr()) }; + } + + #[inline] + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: To call this method, the caller passes us ownership of = a normal refcount, so we + // may drop it. The cast is okay since `File` has the same represe= ntation as `struct file`. + unsafe { bindings::fput(obj.cast().as_ptr()) } + } +} + +impl LocalFile { + /// Constructs a new `struct file` wrapper from a file descriptor. + /// + /// The file descriptor belongs to the current process, and there migh= t be active local calls + /// to `fdget_pos` on the same file. + /// + /// To obtain an `ARef`, use the [`assume_no_fdget_pos`] functio= n to convert. + /// + /// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos + #[inline] + pub fn fget(fd: u32) -> Result, BadFdError> { + // SAFETY: FFI call, there are no requirements on `fd`. + let ptr =3D ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or= (BadFdError)?; + + // SAFETY: `bindings::fget` created a refcount, and we pass owners= hip of it to the `ARef`. + // + // INVARIANT: This file is in the fd table on this thread, so eith= er all `fdget_pos` calls + // are on this thread, or the file is shared, in which case `fdget= _pos` calls took the + // `f_pos_lock` mutex. + Ok(unsafe { ARef::from_raw(ptr.cast()) }) + } + + /// Creates a reference to a [`LocalFile`] from a valid pointer. + /// + /// # Safety + /// + /// * The caller must ensure that `ptr` points at a valid file and tha= t the file's refcount is + /// positive for the duration of 'a. + /// * The caller must ensure that if there is an active call to `fdget= _pos` that did not take + /// the `f_pos_lock` mutex, then that call is on the current thread. + #[inline] + pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a Loc= alFile { + // SAFETY: The caller guarantees that the pointer is not dangling = and stays valid for the + // duration of 'a. The cast is okay because `File` is `repr(transp= arent)`. + // + // INVARIANT: The caller guarantees that there are no problematic = `fdget_pos` calls. + unsafe { &*ptr.cast() } + } + + /// Assume that there are no active `fdget_pos` calls that prevent us = from sharing this file. + /// + /// This makes it safe to transfer this file to other threads. No chec= ks are performed, and + /// using it incorrectly may lead to a data race on the file position = if the file is shared + /// with another thread. + /// + /// This method is intended to be used together with [`LocalFile::fget= `] when the caller knows + /// statically that there are no `fdget_pos` calls on the current thre= ad. For example, you + /// might use it when calling `fget` from an ioctl, since ioctls usual= ly do not touch the file + /// position. + /// + /// # Safety + /// + /// There must not be any active `fdget_pos` calls on the current thre= ad. + #[inline] + pub unsafe fn assume_no_fdget_pos(me: ARef) -> ARef { + // INVARIANT: There are no `fdget_pos` calls on the current thread= , and by the type + // invariants, if there is a `fdget_pos` call on another thread, t= hen it took the + // `f_pos_lock` mutex. + // + // SAFETY: `LocalFile` and `File` have the same layout. + unsafe { ARef::from_raw(ARef::into_raw(me).cast()) } + } + + /// Returns a raw pointer to the inner C struct. + #[inline] + pub fn as_ptr(&self) -> *mut bindings::file { + self.inner.get() + } + + /// Returns the flags associated with the file. + /// + /// The flags are a combination of the constants in [`flags`]. + #[inline] + pub fn flags(&self) -> u32 { + // This `read_volatile` is intended to correspond to a READ_ONCE c= all. + // + // SAFETY: The file is valid because the shared reference guarante= es a nonzero refcount. + // + // FIXME(read_once): Replace with `read_once` when available on th= e Rust side. + unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volati= le() } + } +} + +impl File { + /// Creates a reference to a [`File`] from a valid pointer. + /// + /// # Safety + /// + /// * The caller must ensure that `ptr` points at a valid file and tha= t the file's refcount is + /// positive for the duration of 'a. + /// * The caller must ensure that if there are active `fdget_pos` call= s on this file, then they + /// took the `f_pos_lock` mutex. + #[inline] + pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a Fil= e { + // SAFETY: The caller guarantees that the pointer is not dangling = and stays valid for the + // duration of 'a. The cast is okay because `File` is `repr(transp= arent)`. + // + // INVARIANT: The caller guarantees that there are no problematic = `fdget_pos` calls. + unsafe { &*ptr.cast() } + } +} + +// Make LocalFile methods available on File. +impl core::ops::Deref for File { + type Target =3D LocalFile; + #[inline] + fn deref(&self) -> &LocalFile { + // SAFETY: The caller provides a `&File`, and since it is a refere= nce, it must point at a + // valid file for the desired duration. + // + // By the type invariants, there are no `fdget_pos` calls that did= not take the + // `f_pos_lock` mutex. + unsafe { LocalFile::from_raw_file(self as *const File as *const bi= ndings::file) } + } +} + +/// Represents the `EBADF` error code. +/// +/// Used for methods that can only fail with `EBADF`. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct BadFdError; + +impl From for Error { + #[inline] + fn from(_: BadFdError) -> Error { + EBADF + } +} + +impl core::fmt::Debug for BadFdError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.pad("EBADF") + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 274bdc1b0a82..61e0dd4ded78 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -34,6 +34,7 @@ pub mod error; #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] pub mod firmware; +pub mod fs; pub mod init; pub mod ioctl; #[cfg(CONFIG_KUNIT)] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index bb115d730ebb..cb3e178b2000 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -366,6 +366,14 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { _p: PhantomData, } } + + /// Convert this [`ARef`] into a raw pointer. + /// + /// The caller retains ownership of the refcount that this `ARef` used= to own. + pub fn into_raw(me: Self) -> NonNull { + let me =3D core::mem::ManuallyDrop::new(me); + me.ptr + } } =20 impl Clone for ARef { --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 2AE68191F61 for ; Thu, 8 Aug 2024 16:16:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133803; cv=none; b=qE5fOprqPXi6o9dovep/O+KjhE7mf2A+NP/8f/RN8RdzI/CAwQYRMtsCbQ/lCrtL5K3iU5ts/Gz87vBFU+fDiONVd8WKX4pPZr+J6sTsAXmiA64rFeEnfoBE1waz0R+YAijTY5EnqsTADT8UrQUZI6CfK41QIu3Hn0kA/dUDZaU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133803; c=relaxed/simple; bh=kttW6yHl82uT5ekK2jF2YDz8Rlxi4B1EZgxWc/6TqKI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DkbHZDMKueiIibYtmYSDVap/q8KfSsDx24jOm8VKoKBTkyMe8MqAYpCP/K5a7mlvU2lwxgLil/N4vYjPKQDsm3F9IYgs/DnqszexvMPphVL4XcEVZKp3oS/exaV84tGf2PIhGdSyGAUzyuhg4YkAhamBIGQOHuOeN583GUYS/GQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=fubBfQ/8; arc=none smtp.client-ip=209.85.221.73 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="fubBfQ/8" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3685a5a765fso629202f8f.1 for ; Thu, 08 Aug 2024 09:16:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133799; x=1723738599; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=HGyDKpg8dWFcTag4GrpDLhvTdGbzYWU8UjhfeFFZm3Y=; b=fubBfQ/8WT7C4uhWyoupeige9q0zWGn+0ZvESa4L+vLohtErKzjT9wkOzsCobCzY9G coNLyE5kMXm804f/bcInLZY3Z5SESm3GWytE9nVa5V5dAKNimxku0+v6Eg1kT05KhDuB 1h2rou3ckM8kzBIINFYX/sbaJH81qGlprMzuvzsbddVxWYwXL/ddNPqRVSB6IEXas/dO c5behaCKmrQHUhzCGNy02ieIzM8W/q6PGD3lz2e5R8pZ45eBD27PJdsfVatzl7zQy+i6 HKVO0U/cDAfyhz1lxK9ju7RTrnuXFg3Y1HJVqLVB37bLAiSuq/VOg6SHvIZ/55mr49gH Gn9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133799; x=1723738599; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HGyDKpg8dWFcTag4GrpDLhvTdGbzYWU8UjhfeFFZm3Y=; b=w0pZ97Pf3L+l8wnaH9o+tDPeaQPHSels7conG/rAkqvqdEvw7u8tXJj6QjO8GfanZP +cxZLypgRgXinr2F13bNzkCFfz2i4uW2ahksQdHyaKrnKoCzXJRa8UoNyXX0zJDOaDCB Iixkk96p+iJBskm0+au6Jbo6xSBU95YSU9H3plFer6p6hKS2mpkL/y9541vVOJNNBNWw GjA8p7hrSWfy9gQXX4Ma+JYaQGK/fVjHCBstnPzPyjI6P5nptRayc40VN/yKWRr6P8A2 QF4ZzGvpmWNoYB1IUuOLTa7rX+vkB5Omh2lMEdez2PpND3w6Gliz2jLtRs/DGzpBzGWv YECA== X-Forwarded-Encrypted: i=1; AJvYcCVcRMVihXDXK5wOriQjvbOQe3sTiSrXNQ2yWaNV0xRK7l5Z/0GVCIce3QLOpa3PH/JvuPNm1qoGiwt4p7+WdEUnNQraqCAXgC7T+7aO X-Gm-Message-State: AOJu0YxiL0qwTRXPGeALzC+V5I03Poex5WehagAT0B+CGd1IgWaV1FBL 32jxXOCd/e0CmvQ10NxPgZYnTsGC71HK042+mwzG1P5k1oLWxAlmQIlrFvDpacGxVJWBFgatH1P 31q7r2vJIUcK3wg== X-Google-Smtp-Source: AGHT+IFTbpduCzC6100J98UmjYSjMkmd+3oWEiNvbe43MFSzynKfaqqeC0f3JVOpkPQMRdxY7Xws+Gauxia+0QU= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:adf:eed1:0:b0:367:326a:d74 with SMTP id ffacd0b85a97d-36d27581a6fmr3348f8f.12.1723133799093; Thu, 08 Aug 2024 09:16:39 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:47 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7305; i=aliceryhl@google.com; h=from:subject:message-id; bh=LUr04YqufJkZXc462uNrCvjGvd9bTLfFksx5H6DRsjc=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9XJ+/XGpnowA/6HESbnFbLf8XNjj3z4IPwG 852GLKcSRyJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvVwAKCRAEWL7uWMY5 RnfBD/wK2KV0yCbgPozS1Ka4SfARilLOmaMqqgnFbD8qaY8oJufJH4BVMwN/MncTAn8VZNWX4Ig NDKykgJhOuLEkPOlVtyHAa8dsSH9pndmMrEe2uN8IAT6IMXGR3jqro/Hougw3xLTLC1Jwhcdu66 3PmMBYaC9mJrNvBx5MKR63o0yhEwFuSwQcgXTbegheHPTpemh/cr5ziSOyUABrz+ajOR7UT5nJy ILOF3Ftx3n5/DiCmx7Dt5tjuh0tliuaAym4xrYzyO7dl5k13r/547HWe9bRgqSV2ySPYL069D44 o312tiOKOZm7gE4Gh1rfpgNh/lpOa95kfezu1gvZN2AWeEq7Tcl3ijlaosWZgWG07aqivuogEbi Yp1kJjGQt0XTU5k5PcXKKsYjwt/menjwJJWKnIeiLcv/IUHsgWrHlLXwXIXfb2hbDnGeyhCSqf4 Vrik7QzBFaLiMsQCcBcGsoTq5vhWmx5M1qPyNFkbicBLlyCBapAKISYDQ/nGGEvw5AC5sAdy5vP nyR8r0/nJ2L1gocRwsY3ViWvYXGLgiQpb0WZiZdTW/fDUtiTGqI00qHnCRfMZbZTMzCCo09xf0z aO5SLG/zZEbkLkHDYugUACORzSeZCIxN29nsemjs5qmqvM5OSpSlRxkYYG+ltSG1b2VBnSazdtK EM5jrAxBnRT8ZOA== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-4-2cb7b934e0e1@google.com> Subject: [PATCH v9 4/8] rust: cred: add Rust abstraction for `struct cred` From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Wedson Almeida Filho Add a wrapper around `struct cred` called `Credential`, and provide functionality to get the `Credential` associated with a `File`. Rust Binder must check the credentials of processes when they attempt to perform various operations, and these checks usually take a `&Credential` as parameter. The security_binder_set_context_mgr function would be one example. This patch is necessary to access these security_* methods from Rust. Signed-off-by: Wedson Almeida Filho Co-developed-by: Alice Ryhl Reviewed-by: Trevor Gross Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Gary Guo Signed-off-by: Alice Ryhl --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 13 +++++++ rust/kernel/cred.rs | 76 +++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/fs/file.rs | 13 +++++++ rust/kernel/lib.rs | 1 + 5 files changed, 104 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 550a4a46d413..81bd1c2db7c9 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index 80021b0a7c63..a63f6b614725 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -207,6 +208,18 @@ struct file *rust_helper_get_file(struct file *f) } EXPORT_SYMBOL_GPL(rust_helper_get_file); =20 +const struct cred *rust_helper_get_cred(const struct cred *cred) +{ + return get_cred(cred); +} +EXPORT_SYMBOL_GPL(rust_helper_get_cred); + +void rust_helper_put_cred(const struct cred *cred) +{ + put_cred(cred); +} +EXPORT_SYMBOL_GPL(rust_helper_put_cred); + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indi= ces. diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs new file mode 100644 index 000000000000..acee04768927 --- /dev/null +++ b/rust/kernel/cred.rs @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Credentials management. +//! +//! C header: [`include/linux/cred.h`](srctree/include/linux/cred.h). +//! +//! Reference: + +use crate::{ + bindings, + types::{AlwaysRefCounted, Opaque}, +}; + +/// Wraps the kernel's `struct cred`. +/// +/// Credentials are used for various security checks in the kernel. +/// +/// Most fields of credentials are immutable. When things have their crede= ntials changed, that +/// happens by replacing the credential instead of changing an existing cr= edential. See the [kernel +/// documentation][ref] for more info on this. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `get= _cred` ensures that the +/// allocation remains valid at least until the matching call to `put_cred= `. +/// +/// [ref]: https://www.kernel.org/doc/html/latest/security/credentials.html +#[repr(transparent)] +pub struct Credential(Opaque); + +// SAFETY: +// - `Credential::dec_ref` can be called from any thread. +// - It is okay to send ownership of `Credential` across thread boundaries. +unsafe impl Send for Credential {} + +// SAFETY: It's OK to access `Credential` through shared references from o= ther threads because +// we're either accessing properties that don't change or that are properl= y synchronised by C code. +unsafe impl Sync for Credential {} + +impl Credential { + /// Creates a reference to a [`Credential`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for t= he lifetime of the + /// returned [`Credential`] reference. + pub unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Credenti= al { + // SAFETY: The safety requirements guarantee the validity of the d= ereference, while the + // `Credential` type being transparent makes the cast ok. + unsafe { &*ptr.cast() } + } + + /// Returns the effective UID of the given credential. + pub fn euid(&self) -> bindings::kuid_t { + // SAFETY: By the type invariant, we know that `self.0` is valid. = Furthermore, the `euid` + // field of a credential is never changed after initialization, so= there is no potential + // for data races. + unsafe { (*self.0.get()).euid } + } +} + +// SAFETY: The type invariants guarantee that `Credential` is always ref-c= ounted. +unsafe impl AlwaysRefCounted for Credential { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. + unsafe { bindings::get_cred(self.0.get()) }; + } + + unsafe fn dec_ref(obj: core::ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is = nonzero. The cast is okay + // because `Credential` has the same representation as `struct cre= d`. + unsafe { bindings::put_cred(obj.cast().as_ptr()) }; + } +} diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index 6adb7a7199ec..3c1f51719804 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -9,6 +9,7 @@ =20 use crate::{ bindings, + cred::Credential, error::{code::*, Error, Result}, types::{ARef, AlwaysRefCounted, Opaque}, }; @@ -308,6 +309,18 @@ pub fn as_ptr(&self) -> *mut bindings::file { self.inner.get() } =20 + /// Returns the credentials of the task that originally opened the fil= e. + pub fn cred(&self) -> &Credential { + // SAFETY: It's okay to read the `f_cred` field without synchroniz= ation because `f_cred` is + // never changed after initialization of the file. + let ptr =3D unsafe { (*self.as_ptr()).f_cred }; + + // SAFETY: The signature of this function ensures that the caller = will only access the + // returned credential while the file is still valid, and the C si= de ensures that the + // credential stays valid at least as long as the file. + unsafe { Credential::from_ptr(ptr) } + } + /// Returns the flags associated with the file. /// /// The flags are a combination of the constants in [`flags`]. diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 61e0dd4ded78..c9ce44812d21 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -30,6 +30,7 @@ #[cfg(CONFIG_BLOCK)] pub mod block; mod build_assert; +pub mod cred; pub mod device; pub mod error; #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 6C4F4191F71 for ; Thu, 8 Aug 2024 16:16:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133805; cv=none; b=rXxi1CW4BwOaurbtbcSfUDOC3yuTp1UmDZMKb9/0zgz3rqF8f3pJO+se8tPNxC+uVsXjO6aMe36gEng8Vgxhc8qDIDfBSKS5WRHbp+3ATUhTm2W0TrrQtfcircG0SPLhrHVNtPVCOkSMUmFdTGSM7IFT2NH+sUeKquS4kY138cs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133805; c=relaxed/simple; bh=hCsKKVj345+b49Ng5A8TJ2plNvQ/FuOO1K1yN5EOnjc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=eCFXnyBer9Lt5H4NbZivFmC2p9qzg2LpKaMTMWAc5iJIwjuhQKB2ejRQfyKrl2qgmbwi1h42t5aKDEE/qu2eMg5BkK5zGCO5xnuki2sGFEjc2KSqcZkOimFgdaJTtp6PubLbx2pNN9j5Z0kkEeOqdgOg2Fsgm5/SMlABzRyhWAM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=snX+Hw3U; arc=none smtp.client-ip=209.85.128.74 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="snX+Hw3U" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-42816096cb8so14164695e9.0 for ; Thu, 08 Aug 2024 09:16:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133802; x=1723738602; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=FyvEzhf1vrLH4fAWxaYl8oZikM7jgsDn2qSzj+h3cIM=; b=snX+Hw3U4ZXc0XKqCI/dZbFDQrBGdKi9d/rSNk3+7Zmgc9egi+WoC11TCaL87AzWed avsVwJjzgoONVhO2qByOLqD60p1ripEKTBnx5BPW+1E8nJyx2cLJrEva3AdF2BMplnXv pJCZ/Ol8aP8X0bMMzderrp6s9d67BCE6lCGI6h6pm7B0B3qNPASgNiiFmMxFoG5UWAjP XPGN5ZNUGnCb9lq0nC2ZsDwwLonTEFCAiYPSpykXRaU/mpJEvjOK4yyRlXni5Bk9O5Ey bkIuC8Fwm7WSXD+Q6LPP3QkUM48yIHixaRJl1bsFw3uvcFl1QL4Y6gqCJc82rDKQ1LXq rI+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133802; x=1723738602; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=FyvEzhf1vrLH4fAWxaYl8oZikM7jgsDn2qSzj+h3cIM=; b=rdnYFUj/4wBTIidHO0QQ+G1ye8qUzLhgVLd+VeM9IAXthwcfb1e1kDN8XRtLLyUTS8 lwI0J3hyv/RTwwlX+JpswZGpDO4cSNcaKdt6nrt2HixeSx14j+6nbDRpzKyMEeoutYxH oz2ITY2nxHh6tOr8fIJRMxGic8nveC7/Sf75U9aJ8uBhYwKo99wFqI6kKWCRiEC/TPmL H9jR8uJlo6YSqPgr/pgWURbfm9VVsEhxuZ8h3Pm7GaXJffW8OmnkxdDMLC9ewJ+UkwR0 YvtCPw7yvSRwIyfgZ2BS678MI8G4pqBYK/FR8hGf6C5TVMfIEko7TWwYBY6Pkc4dgtRS 8omg== X-Forwarded-Encrypted: i=1; AJvYcCVmB0fmGRH7Ae7jn9OoO8OAFk3jzd25dE4dG0fDazu7JwTf9tSvE5p+AdaDrcf3mbwo5N6Nq2vDs1fGCQAwhcNeOMoK56SoGpO5Zb5U X-Gm-Message-State: AOJu0YwAkUooRoYqeGinHeeRRqpiJYXzzbNMD8p5/fhfVpTGb5nS+i0s YQKwjcY3abu0PpUepZPPthX3krpL0XGdbqP0c4AmBLqT8oYj6a1B5w24Oh+n0iFD+1a/kPEKv8A YNPzdaXAXQBJEvg== X-Google-Smtp-Source: AGHT+IHkmyDuHZogA2p1s2T21TqYXa394KS3rlas/ZBn1g6qzzI+I+OtFLK2oPA+Ii1xwIDwVrxn1wMIG8OJzMg= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a05:600c:3b14:b0:425:671d:cef6 with SMTP id 5b1f17b1804b1-4290af3745cmr481345e9.4.1723133801757; Thu, 08 Aug 2024 09:16:41 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:48 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=6528; i=aliceryhl@google.com; h=from:subject:message-id; bh=hCsKKVj345+b49Ng5A8TJ2plNvQ/FuOO1K1yN5EOnjc=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9YE0zx2d9qsqS/2QjFpfM7xBaU8ZUaC6QTc QnZTjRcoqWJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvWAAKCRAEWL7uWMY5 RkK5EACaHV1Ihz+jXjJgfTlljUVpOW845PnAaiF+8dB2Qzy1uJt8oILSS96rFf9ry/gmxIwrHiw SN2sGEu8i45LQxi8EKKoh+ZDFZh0kk3wZmV0ohJJZoU/MeZOb5su37mPwdxyjnX8a0h/uZehVQW h4rO+rpOGduW+6z69asSsirObCS1UFpcb+L3NSJl60jWBwuvjzbq8eg45rsusgQTK6KOBeGY5uT OPICAZFzVgrVqXuJw9kqfW8KbAjan6f998UhZwgmDzES1g1JMTivRBWE6UKPlrmgnH0Cg0HB5dY z9gkGTXZei0Il2a9opIsQCMrAAILCckGLtsvRY0U77YEeqlXeTJ/Rd+GQLWQwdYiYSSpj+nv54G zh1D7hDL6xVZdM2G/qYK4GU0zp3Evz8H9r8Y9xVf6pU238ekksef7nQhsidiT0ZrqBnnXIYwZ3K A4jzWhR8lAWBfN5Q9i3v/tU8Oyg7gcf0xLv6KXqPfYkHfiBMiBDC2Vtcic8Ln2txSmCLMvlSzz8 uosqpaSqvZ3c2uGS55r08SIBPvtkr8oHtHOmEbQ4fafcEpY9vB+QLmmohui1YBWjfC4jj915UNT hewLHkTQiOQiSBL6DXSu92VjRb6V2c7EfrFvz5Q8v09w1ldxqNDHeQR+SE6w2aGi2AVsXCVIDX6 N9bGwPY7Kv+EJzw== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-5-2cb7b934e0e1@google.com> Subject: [PATCH v9 5/8] rust: security: add abstraction for secctx From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add an abstraction for viewing the string representation of a security context. This is needed by Rust Binder because it has a feature where a process can view the string representation of the security context for incoming transactions. The process can use that to authenticate incoming transactions, and since the feature is provided by the kernel, the process can trust that the security context is legitimate. Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Trevor Gross Reviewed-by: Gary Guo Signed-off-by: Alice Ryhl --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 21 ++++++++++++ rust/kernel/cred.rs | 8 +++++ rust/kernel/lib.rs | 1 + rust/kernel/security.rs | 74 +++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 105 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 81bd1c2db7c9..7db502f5ff5e 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index a63f6b614725..33d12d45e4f6 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,26 @@ void rust_helper_put_cred(const struct cred *cred) } EXPORT_SYMBOL_GPL(rust_helper_put_cred); =20 +#ifndef CONFIG_SECURITY +void rust_helper_security_cred_getsecid(const struct cred *c, u32 *secid) +{ + security_cred_getsecid(c, secid); +} +EXPORT_SYMBOL_GPL(rust_helper_security_cred_getsecid); + +int rust_helper_security_secid_to_secctx(u32 secid, char **secdata, u32 *s= eclen) +{ + return security_secid_to_secctx(secid, secdata, seclen); +} +EXPORT_SYMBOL_GPL(rust_helper_security_secid_to_secctx); + +void rust_helper_security_release_secctx(char *secdata, u32 seclen) +{ + security_release_secctx(secdata, seclen); +} +EXPORT_SYMBOL_GPL(rust_helper_security_release_secctx); +#endif + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indi= ces. diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs index acee04768927..92659649e932 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -52,6 +52,14 @@ pub unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -= > &'a Credential { unsafe { &*ptr.cast() } } =20 + /// Get the id for this security context. + pub fn get_secid(&self) -> u32 { + let mut secid =3D 0; + // SAFETY: The invariants of this type ensures that the pointer is= valid. + unsafe { bindings::security_cred_getsecid(self.0.get(), &mut secid= ) }; + secid + } + /// Returns the effective UID of the given credential. pub fn euid(&self) -> bindings::kuid_t { // SAFETY: By the type invariant, we know that `self.0` is valid. = Furthermore, the `euid` diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index c9ce44812d21..86fc957f61eb 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -45,6 +45,7 @@ pub mod page; pub mod prelude; pub mod print; +pub mod security; mod static_assert; #[doc(hidden)] pub mod std_vendor; diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs new file mode 100644 index 000000000000..2522868862a1 --- /dev/null +++ b/rust/kernel/security.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Linux Security Modules (LSM). +//! +//! C header: [`include/linux/security.h`](srctree/include/linux/security.= h). + +use crate::{ + bindings, + error::{to_result, Result}, +}; + +/// A security context string. +/// +/// # Invariants +/// +/// The `secdata` and `seclen` fields correspond to a valid security conte= xt as returned by a +/// successful call to `security_secid_to_secctx`, that has not yet been d= estroyed by calling +/// `security_release_secctx`. +pub struct SecurityCtx { + secdata: *mut core::ffi::c_char, + seclen: usize, +} + +impl SecurityCtx { + /// Get the security context given its id. + pub fn from_secid(secid: u32) -> Result { + let mut secdata =3D core::ptr::null_mut(); + let mut seclen =3D 0u32; + // SAFETY: Just a C FFI call. The pointers are valid for writes. + to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut = secdata, &mut seclen) })?; + + // INVARIANT: If the above call did not fail, then we have a valid= security context. + Ok(Self { + secdata, + seclen: seclen as usize, + }) + } + + /// Returns whether the security context is empty. + pub fn is_empty(&self) -> bool { + self.seclen =3D=3D 0 + } + + /// Returns the length of this security context. + pub fn len(&self) -> usize { + self.seclen + } + + /// Returns the bytes for this security context. + pub fn as_bytes(&self) -> &[u8] { + let ptr =3D self.secdata; + if ptr.is_null() { + debug_assert_eq!(self.seclen, 0); + // We can't pass a null pointer to `slice::from_raw_parts` eve= n if the length is zero. + return &[]; + } + + // SAFETY: The call to `security_secid_to_secctx` guarantees that = the pointer is valid for + // `seclen` bytes. Furthermore, if the length is zero, then we hav= e ensured that the + // pointer is not null. + unsafe { core::slice::from_raw_parts(ptr.cast(), self.seclen) } + } +} + +impl Drop for SecurityCtx { + fn drop(&mut self) { + // SAFETY: By the invariant of `Self`, this frees a pointer that c= ame from a successful + // call to `security_secid_to_secctx` and has not yet been destroy= ed by + // `security_release_secctx`. + unsafe { bindings::security_release_secctx(self.secdata, self.secl= en as u32) }; + } +} --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 DB4031922CF for ; Thu, 8 Aug 2024 16:16:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133807; cv=none; b=EfDYm+daFM2iDKBjqGJnx2gNvmKtPH6Nz+mMPAvbHJdL3hNSOslOqGPQBSffeXpTR5+9AaR/GtcST9p5emIcGuvyekivE63t8hlkXLPyvFTiWA/ZAyufWahvEmFBj7HXVrxufqhJ3i1Y/7BdWdMx/iPo6kL2FCuvmnJzwKb6u/A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133807; c=relaxed/simple; bh=o4fdN4iiM2NHJu7SVfr6hNJGqcKh3Q2Q/FWBdOzigcQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=QATLMXXtNJGbjFEiKdWTrJA6a83blc94pyKbpCbxmHCmgqVLY6hc2LYdqFGkdH9qrUNNifMHZMrAG7wCki72OlRtMrlMR3FteB236LEmAGH772qSpJ3Be0qLnKUmThpckWirESigimls8Df7+zhZE+KFWTb3yVts9+IzeYu7I0s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ztzTMgdQ; arc=none smtp.client-ip=209.85.128.74 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ztzTMgdQ" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-42809eb7b99so6198705e9.0 for ; Thu, 08 Aug 2024 09:16:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133804; x=1723738604; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=GRdYl09LMpZTMrOYeLLNLi8v/UCPdJZixG/jjg1ujqE=; b=ztzTMgdQfQTlSQvtvL7oEg4ibw4oYkWXhkx59/46tjO7UxbBO4L+R9Jin6GUquCXE2 Cjteo1fhRFsc/zfeWuiu/OPIc2q9Hk1lmTU1cR/+x9y4OCyowVmfvcJrTBfsJmFiNWy5 wLrKE6ShQunk4vaCTMByNyr6ahTv0w4zJLaQeoRtz8zTwwFfPkmsn6MLOgkNm4H3GMti 4//yz5Py5D9aq532OQoK/W/JHWinD21O5PzjkVNJQvuP13JgvCakAkcTt1BUdc3JFQwG vlAsIyVs7BpKNpTt01MFM/feVsJRjcth4AQKnEVoiN9U16eE+rp2H2lp6n+uWJpdF0Kt eOpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133804; x=1723738604; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=GRdYl09LMpZTMrOYeLLNLi8v/UCPdJZixG/jjg1ujqE=; b=Tjmdqc/zsmgFmwPtqPBLiD/qyTd/2r+Tb4w47+Cv/UKhRf4/cSCzhkseb9ymXhjKjc OD7GqXv+VSAcSJ4BBS3CohP7mX9S2okqlGFIsvKee/U6I+QhRkOqF9BqY6udngzWQ0KU P8Wzx4p0MFYNw8tDlmW5ugHgV4JSmDdGjupo+VImp7JXU61bevbfDLIBVIaJq4wa5qBY PAR1L2wzsJ/u8wKSJunWPvbogF/jKCDQNp9/uadqJMd+4S9hi9YucCq75/Mop5KMswH0 rpCE5MkHsr333KhOIqdIKnGuvl4Gd5EQNPMYZr3Sg29bXgVQatUabBItkhmav3+ufH9/ Em4Q== X-Forwarded-Encrypted: i=1; AJvYcCXFNHOWN5ISXGDF1zr4ZqMEtPRAROqqm9gqwQboE/coq+h7941KziDDVJxI22ablVTqc4GE+uLnKfT3XYjvUdOr8EnQYu9u868XaWfV X-Gm-Message-State: AOJu0Yz6ipfgm50dg/iddSkgGLJkCv0oECZq/wRG0LFThrK/oQmpOqIX PzN4sOQFeJTYFe0MnPOTr2TKFISvd2ernLKEWmDrpoRPFNJ+sMFlKaE/YRAYzwsGsvuFtfrpuvC hklZRq41rDxWwpw== X-Google-Smtp-Source: AGHT+IECg/sQRjETdVvzKEP5dRt/k0bA5sulOXJhTYE8v5Pt4bxT7HL2chjqadIa7M8YAoRslvvKWPDU43T2PT0= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a05:600c:3b26:b0:426:6761:2fea with SMTP id 5b1f17b1804b1-4290b8de60amr56835e9.3.1723133804245; Thu, 08 Aug 2024 09:16:44 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:49 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=5416; i=aliceryhl@google.com; h=from:subject:message-id; bh=2l8fk9VFbHJWEQ4c3bFrbmnrmdDQcuL4l7ltM9XZJ/4=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9Y7js5TBN7uMGNGA1y+AXxE8YDhWLMabQJB gkoF2iiQYyJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvWAAKCRAEWL7uWMY5 RvgJEAC6x68XniObP5m76P8gtROP92jacQX4OHz0AK8oD23GdKE5CcVd3eRH8FMjA3E32Mgg/+m wYE1aWPJzMouKGvwfD5DszIWFTxMsapEjSnpbh/upkgMDCOk9BjGE9fSIdi+N07fFUtOyWgjx1g +sv67HLm789OHud9ip7R0sIGoZTIENCWqEA9A5Jj/CtllTPVAh2iF8nJMOIRDLlcPZ3CtMNMZ+O c0WaoVmslGJ0Rql5/4SxSzv1DvHmazUTi0Qtx2bo3Exe7+gx7LIWLgftLNU+jvHNSCsmmpSfZ89 VeaC1LRs2wMFooqRWkIPRq1qJofFAYsWCgbsJM4H4puWuQRYnuakASRAW6ywwZ7MWAweUqNVi3D OZNFRia+7PesbljqkySamJ2s3yZSBwMSUXfg561SnUc1IaCzoVQp+rqzJNedX5kUwV3kYRL/SFF xM2u/nTqrR/5U5RYvDwLSHsCi75rarv7agP3jEvejepFQjHzKl4prf4NdTOP1aInBi9gOsuYcQ/ McNpfsTGBm9XI7+FFJXsleVqsjpyWUw7sHac2tudG7QjwMkBxIsW8abKVEJ+eBzOYX4Zk2HOQpn ogqiuRL3xKbs+O5vdEfrD6GjbBXTDVb5VYajk3LWIl8+jrCUu45C+CIwhD4eLdBvaU+OL4a5JKx zsuFx/eccCKmzTA== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-6-2cb7b934e0e1@google.com> Subject: [PATCH v9 6/8] rust: file: add `FileDescriptorReservation` From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Wedson Almeida Filho Allow for the creation of a file descriptor in two steps: first, we reserve a slot for it, then we commit or drop the reservation. The first step may fail (e.g., the current process ran out of available slots), but commit and drop never fail (and are mutually exclusive). This is needed by Rust Binder when fds are sent from one process to another. It has to be a two-step process to properly handle the case where multiple fds are sent: The operation must fail or succeed atomically, which we achieve by first reserving the fds we need, and only installing the files once we have reserved enough fds to send the files. Fd reservations assume that the value of `current` does not change between the call to get_unused_fd_flags and the call to fd_install (or put_unused_fd). By not implementing the Send trait, this abstraction ensures that the `FileDescriptorReservation` cannot be moved into a different process. Signed-off-by: Wedson Almeida Filho Co-developed-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Trevor Gross Reviewed-by: Gary Guo Signed-off-by: Alice Ryhl --- rust/kernel/fs/file.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index 3c1f51719804..e03dbe14d62a 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -11,7 +11,7 @@ bindings, cred::Credential, error::{code::*, Error, Result}, - types::{ARef, AlwaysRefCounted, Opaque}, + types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque}, }; use core::ptr; =20 @@ -368,6 +368,79 @@ fn deref(&self) -> &LocalFile { } } =20 +/// A file descriptor reservation. +/// +/// This allows the creation of a file descriptor in two steps: first, we = reserve a slot for it, +/// then we commit or drop the reservation. The first step may fail (e.g.,= the current process ran +/// out of available slots), but commit and drop never fail (and are mutua= lly exclusive). +/// +/// Dropping the reservation happens in the destructor of this type. +/// +/// # Invariants +/// +/// The fd stored in this struct must correspond to a reserved file descri= ptor of the current task. +pub struct FileDescriptorReservation { + fd: u32, + /// Prevent values of this type from being moved to a different task. + /// + /// The `fd_install` and `put_unused_fd` functions assume that the val= ue of `current` is + /// unchanged since the call to `get_unused_fd_flags`. By adding this = marker to this type, we + /// prevent it from being moved across task boundaries, which ensures = that `current` does not + /// change while this value exists. + _not_send: NotThreadSafe, +} + +impl FileDescriptorReservation { + /// Creates a new file descriptor reservation. + pub fn get_unused_fd_flags(flags: u32) -> Result { + // SAFETY: FFI call, there are no safety requirements on `flags`. + let fd: i32 =3D unsafe { bindings::get_unused_fd_flags(flags) }; + if fd < 0 { + return Err(Error::from_errno(fd)); + } + Ok(Self { + fd: fd as u32, + _not_send: NotThreadSafe, + }) + } + + /// Returns the file descriptor number that was reserved. + pub fn reserved_fd(&self) -> u32 { + self.fd + } + + /// Commits the reservation. + /// + /// The previously reserved file descriptor is bound to `file`. This m= ethod consumes the + /// [`FileDescriptorReservation`], so it will not be usable after this= call. + pub fn fd_install(self, file: ARef) { + // SAFETY: `self.fd` was previously returned by `get_unused_fd_fla= gs`. We have not yet used + // the fd, so it is still valid, and `current` still refers to the= same task, as this type + // cannot be moved across task boundaries. + // + // Furthermore, the file pointer is guaranteed to own a refcount b= y its type invariants, + // and we take ownership of that refcount by not running the destr= uctor below. + // Additionally, the file is known to not have any non-shared `fdg= et_pos` calls, so even if + // this process starts using the file position, this will not resu= lt in a data race on the + // file position. + unsafe { bindings::fd_install(self.fd, file.as_ptr()) }; + + // `fd_install` consumes both the file descriptor and the file ref= erence, so we cannot run + // the destructors. + core::mem::forget(self); + core::mem::forget(file); + } +} + +impl Drop for FileDescriptorReservation { + fn drop(&mut self) { + // SAFETY: By the type invariants of this type, `self.fd` was prev= iously returned by + // `get_unused_fd_flags`. We have not yet used the fd, so it is st= ill valid, and `current` + // still refers to the same task, as this type cannot be moved acr= oss task boundaries. + unsafe { bindings::put_unused_fd(self.fd) }; + } +} + /// Represents the `EBADF` error code. /// /// Used for methods that can only fail with `EBADF`. --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (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 4A2E7192B62 for ; Thu, 8 Aug 2024 16:16:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133810; cv=none; b=Zm4H6X3Ok4meaAZ7aQJ2BHTnyylaQikwj1BI8rENfHcVcQG/K2hZ0t42kof6WLOKvS+73xcJTVUCDZdvAWwSgcKcUPt9XVhfD9SX7eilIA9xkL0YTLASLqCGvOz/kfCdaPiFsryxHAoiucbHdIqw4JpCA4mrlYZLigT78C5DDm0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133810; c=relaxed/simple; bh=bqzWJChdAg7lHPNiFP0jGirLPKKFpGxKrsuLPYcDmvQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Sqih63TnkxIRwXvM3x5joHoqfdOdzIzDlqI1TlT3kgrqRxMXYSp2WAxCGAvR8jYhqDBd6LqO11O8SAfTufpMWtz8wwmxUvxRt35s4mJiSg9wTM4LWILiyMm8sJfXp3urSX+kFz3y3Q70xQ75ztnMjqItJ3TGQeMY0Rs5/RPJa24= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=snGZgyfd; arc=none smtp.client-ip=209.85.128.201 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="snGZgyfd" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-690404fd34eso26219367b3.1 for ; Thu, 08 Aug 2024 09:16:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133807; x=1723738607; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=mgZOQPECBcPtyO9Tuml8rLU+VtW+J83utu9PE84sJFg=; b=snGZgyfd6CkZ6Ey+FmEXqa66qXrTvBHqHsiqzESsiTuogSP1EXW1ch5KGB+rWKe20J 1+XLoT0of41Lx3POk4t/Pk5Uy+D48HY01/sjY/H4/PZWjjRYUojRd0yDKaHlcW7bNLM9 qryamCKwkzJP1hk158pmSwBryGtmtGb1c+t6oqBRt1BFQarUxDVFoAZD6AiuOk22d5Hk J/sw1Q5ibETECg7sM/eUnHB8Gz+sL5VMSmt2/8co4yICt57dp9HmcvVirolghoJtoMAL wWHaUHJl8zg8VDzTgYxoMV+td3Y2ow4Fk8BFq23CLrok6gLx9eGRVu1vj686zLgvOB5+ L56w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133807; x=1723738607; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mgZOQPECBcPtyO9Tuml8rLU+VtW+J83utu9PE84sJFg=; b=hDLN9pcQVFJWYSq1LW09WG7UaNtBuuWQ5nR4RkKueo9VBJM64tcH8cFLbpPjI/Ranj UQuyPOkEF9ZNExcHigyYknOv5PcdTuKPbYOVAInnwO8sGVCbSRTbh0UH38UGAjDNATAZ dKqGB3fpmJNjxIGNwqh2l4ntM/WnteIMREZSwKHcRxlwENzktvFrL5QcgmuHIzLQ0ad6 2Vt8xqWkyWEphAe3vetxdTJYieK9z1lBuSQ/IP/ppfNPDBd2LdWNtYnmF2VTXG3QI6KH Fq4jtKrwnZNOzaeFsdk4u+rPhYOxNjsW5zzt268iYDwRGjmx7I9681Lani9JMqXxzrEX sm/w== X-Forwarded-Encrypted: i=1; AJvYcCVlV6brlSWd5nXUjGyOxrJAnCjPK8flyN6I8ivvrIbtbVjDvCsZfO0pJzyhdd7t5KYM04lcmfAEVpDmduN8dW22NeeY8MoBrEWbqeXg X-Gm-Message-State: AOJu0YwVGmmuRy8BjmkMhcLPTeiJB0Ki4CyUkMgwd+HA6j4NINR7J4Il arSX+2IoGAjp+yrNtc0JfEsymj6ZECp1+qIauG87+7L6UEFcfRN6Wsyf3fKAA/29zgylvFZlfKU L83GKHnR4zdK1iA== X-Google-Smtp-Source: AGHT+IFqHzUb94bbUZPgKWOUfadLCPmMGJwGpS9/jGmGXpeXlR5ildauu19lk1VnR2GS7JUSQ5tN/Z3wwhHrxpw= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a0d:d087:0:b0:648:3f93:61f2 with SMTP id 00721157ae682-69bfb5f8bc6mr349197b3.6.1723133806987; Thu, 08 Aug 2024 09:16:46 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:50 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7804; i=aliceryhl@google.com; h=from:subject:message-id; bh=bqzWJChdAg7lHPNiFP0jGirLPKKFpGxKrsuLPYcDmvQ=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9ZIM7QOHWa1SVfw/68dk6IXxKDJHOQ3HLUt pGxn/RTB2qJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvWQAKCRAEWL7uWMY5 Rr2bD/92IH9YWW1s1K6XtjBKvnjTHz2EDM1bcVmjxTXZ0r4jvZ+C5N0Q7NFrFLSSeTSe0Xhl1d4 h+qVfnSui3x7DmEhDDnkH8PAb8IML11qENgbMAmT1EqH0jA51B/f8jShdm/Fa+rcDc1zllE1jbx 3Iqe/5JoOPYdywEp5h7UrsP12fzLqB3yN33O0cqfddtT6I5w3Q+gxw6vl9cJZBZ7UUtInErlK2Z cjthH4TkjZsKTjZLSv0jp7fw67p/lvhlHOrwDnqAHcdk4Dkf0NSGEv/i6XMcuFrAo/iwlIW8Dn/ VSUgMj3Wg7kKrZxM6I/y0X8O8XhLx10xyFXgsjtbAxg3oAMHccPb5RFJCLYM2DZcgKw1/xBYxng fLkJq67Hqmm0Kr9Cf/eH5h7eowqAghowuuPcLkQ0o9XvaQOtF0g2gmZnND6fhyoyfCtuLfzN1uU oKXeAxp8TUxUoGrFSsR7FSa6ngZCL00++PMdOyNqMEnHgEYBzj9QAC10p5eGnMd6SBlB1f7os8O sbS3+X5TToLVzoXmMVJwdmOb6wcBP6zDRhwIX3qjseBANui29FQ0oegQ4Xhi7GrlDDuHnWfYJzR 4rpNfj9a38eWYpPSTtbJaDdX/t80u5GRbznpZGZZuRfbrJwpgxP/EMvxGaFJdFS1gCCSzV1MVbc KXIsApw89FSTD5g== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-7-2cb7b934e0e1@google.com> Subject: [PATCH v9 7/8] rust: file: add `Kuid` wrapper From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Adds a wrapper around `kuid_t` called `Kuid`. This allows us to define various operations on kuids such as equality and current_euid. It also lets us provide conversions from kuid into userspace values. Rust Binder needs these operations because it needs to compare kuids for equality, and it needs to tell userspace about the pid and uid of incoming transactions. To read kuids from a `struct task_struct`, you must currently use various #defines that perform the appropriate field access under an RCU read lock. Currently, we do not have a Rust wrapper for rcu_read_lock, which means that for this patch, there are two ways forward: 1. Inline the methods into Rust code, and use __rcu_read_lock directly rather than the rcu_read_lock wrapper. This gives up lockdep for these usages of RCU. 2. Wrap the various #defines in helpers and call the helpers from Rust. This patch uses the second option. One possible disadvantage of the second option is the possible introduction of speculation gadgets, but as discussed in [1], the risk appears to be acceptable. Of course, once a wrapper for rcu_read_lock is available, it is preferable to use that over either of the two above approaches. Link: https://lore.kernel.org/all/202312080947.674CD2DC7@keescook/ [1] Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Trevor Gross Signed-off-by: Alice Ryhl --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 45 ++++++++++++++++++++++++++++ rust/kernel/cred.rs | 5 ++-- rust/kernel/task.rs | 66 +++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 115 insertions(+), 2 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 7db502f5ff5e..73a133b92017 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index 33d12d45e4f6..69ed229c32c3 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -178,6 +178,51 @@ void rust_helper_put_task_struct(struct task_struct *t) } EXPORT_SYMBOL_GPL(rust_helper_put_task_struct); =20 +kuid_t rust_helper_task_uid(struct task_struct *task) +{ + return task_uid(task); +} +EXPORT_SYMBOL_GPL(rust_helper_task_uid); + +kuid_t rust_helper_task_euid(struct task_struct *task) +{ + return task_euid(task); +} +EXPORT_SYMBOL_GPL(rust_helper_task_euid); + +#ifndef CONFIG_USER_NS +uid_t rust_helper_from_kuid(struct user_namespace *to, kuid_t uid) +{ + return from_kuid(to, uid); +} +EXPORT_SYMBOL_GPL(rust_helper_from_kuid); +#endif /* CONFIG_USER_NS */ + +bool rust_helper_uid_eq(kuid_t left, kuid_t right) +{ + return uid_eq(left, right); +} +EXPORT_SYMBOL_GPL(rust_helper_uid_eq); + +kuid_t rust_helper_current_euid(void) +{ + return current_euid(); +} +EXPORT_SYMBOL_GPL(rust_helper_current_euid); + +struct user_namespace *rust_helper_current_user_ns(void) +{ + return current_user_ns(); +} +EXPORT_SYMBOL_GPL(rust_helper_current_user_ns); + +pid_t rust_helper_task_tgid_nr_ns(struct task_struct *tsk, + struct pid_namespace *ns) +{ + return task_tgid_nr_ns(tsk, ns); +} +EXPORT_SYMBOL_GPL(rust_helper_task_tgid_nr_ns); + struct kunit *rust_helper_kunit_get_current_test(void) { return kunit_get_current_test(); diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs index 92659649e932..81d67789b16f 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -10,6 +10,7 @@ =20 use crate::{ bindings, + task::Kuid, types::{AlwaysRefCounted, Opaque}, }; =20 @@ -61,11 +62,11 @@ pub fn get_secid(&self) -> u32 { } =20 /// Returns the effective UID of the given credential. - pub fn euid(&self) -> bindings::kuid_t { + pub fn euid(&self) -> Kuid { // SAFETY: By the type invariant, we know that `self.0` is valid. = Furthermore, the `euid` // field of a credential is never changed after initialization, so= there is no potential // for data races. - unsafe { (*self.0.get()).euid } + Kuid::from_raw(unsafe { (*self.0.get()).euid }) } } =20 diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 367b4bbddd9f..1a36a9f19368 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -9,6 +9,7 @@ types::{NotThreadSafe, Opaque}, }; use core::{ + cmp::{Eq, PartialEq}, ffi::{c_int, c_long, c_uint}, ops::Deref, ptr, @@ -96,6 +97,12 @@ unsafe impl Sync for Task {} /// The type of process identifiers (PIDs). type Pid =3D bindings::pid_t; =20 +/// The type of user identifiers (UIDs). +#[derive(Copy, Clone)] +pub struct Kuid { + kuid: bindings::kuid_t, +} + impl Task { /// Returns a raw pointer to the current task. /// @@ -157,12 +164,31 @@ pub fn pid(&self) -> Pid { unsafe { *ptr::addr_of!((*self.0.get()).pid) } } =20 + /// Returns the UID of the given task. + pub fn uid(&self) -> Kuid { + // SAFETY: By the type invariant, we know that `self.0` is valid. + Kuid::from_raw(unsafe { bindings::task_uid(self.0.get()) }) + } + + /// Returns the effective UID of the given task. + pub fn euid(&self) -> Kuid { + // SAFETY: By the type invariant, we know that `self.0` is valid. + Kuid::from_raw(unsafe { bindings::task_euid(self.0.get()) }) + } + /// Determines whether the given task has pending signals. pub fn signal_pending(&self) -> bool { // SAFETY: By the type invariant, we know that `self.0` is valid. unsafe { bindings::signal_pending(self.0.get()) !=3D 0 } } =20 + /// Returns the given task's pid in the current pid namespace. + pub fn pid_in_current_ns(&self) -> Pid { + // SAFETY: We know that `self.0.get()` is valid by the type invari= ant, and passing a null + // pointer as the namespace is correct for using the current names= pace. + unsafe { bindings::task_tgid_nr_ns(self.0.get(), ptr::null_mut()) } + } + /// Wakes up the task. pub fn wake_up(&self) { // SAFETY: By the type invariant, we know that `self.0.get()` is n= on-null and valid. @@ -184,3 +210,43 @@ unsafe fn dec_ref(obj: ptr::NonNull) { unsafe { bindings::put_task_struct(obj.cast().as_ptr()) } } } + +impl Kuid { + /// Get the current euid. + #[inline] + pub fn current_euid() -> Kuid { + // SAFETY: Just an FFI call. + Self::from_raw(unsafe { bindings::current_euid() }) + } + + /// Create a `Kuid` given the raw C type. + #[inline] + pub fn from_raw(kuid: bindings::kuid_t) -> Self { + Self { kuid } + } + + /// Turn this kuid into the raw C type. + #[inline] + pub fn into_raw(self) -> bindings::kuid_t { + self.kuid + } + + /// Converts this kernel UID into a userspace UID. + /// + /// Uses the namespace of the current task. + #[inline] + pub fn into_uid_in_current_ns(self) -> bindings::uid_t { + // SAFETY: Just an FFI call. + unsafe { bindings::from_kuid(bindings::current_user_ns(), self.kui= d) } + } +} + +impl PartialEq for Kuid { + #[inline] + fn eq(&self, other: &Kuid) -> bool { + // SAFETY: Just an FFI call. + unsafe { bindings::uid_eq(self.kuid, other.kuid) } + } +} + +impl Eq for Kuid {} --=20 2.46.0.rc2.264.g509ed76dc8-goog From nobody Sun Feb 8 05:20:03 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 36333192B93 for ; Thu, 8 Aug 2024 16:16:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133813; cv=none; b=cTXo+Fz7uWRQyLHa/FjWFzwt7ZfjySmfKTo8FaTMFXJ9QydZUHNUF+5yva5Od4kmMPjRn/UMLnozHO7gX0gOXGC69qNjWits6jNDnbxYrQLM1S4EHUcmenLvp41g6PT5+AjHZ4oXRk/F7BTUab8tACYyRodsv6/lqu0imclnmH0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723133813; c=relaxed/simple; bh=v6Li3ohO2P9VOUj0DUKsbg7ywLMTVrJwO8YEJkpqo/0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lMrqNpnhaQd3ZWBw2KM9RzyaDH1zwqLqw59XGyadAZ1TRSkqJ62++Gg5vkO0quMSj/Fnnjz9jX4GmtmZspAb7aD747zsWPVm1qWK9daB6EvXgBot7+DUfYCq/AhL3Rgo9WwqF/PGXay5aR1CMvPlg+Yfv2aZS+RBsR1D0dq3op4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=QsUZ2Bda; arc=none smtp.client-ip=209.85.128.74 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=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="QsUZ2Bda" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-4280a39ecebso10872195e9.0 for ; Thu, 08 Aug 2024 09:16:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723133810; x=1723738610; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=y+ey13UI9SszW+tMd43Q70Tf7NiOEY//3F7sxm3IBtc=; b=QsUZ2Bda26mX0n5V6qpxvXx0D4SuAbXmegggJ36kv61QYe/5hVBC7xOFgdBaVpEQ3b HKDjlBImH22TlKH/6ZW9uVPnqub0Y6yj+EM3AYdJdgb8yMxfEzYEbAac3xOAWuk94M3H eCOOHHAGu/dx4fkdU32F8XRstx7C1OELyLHJgajqMeXZumoi9N8NSImpIrDbkbv9eNx4 EgzWeDBIj/PWVXWpiYza1AHz8tEYzgfcXT7a0bt6oJyVvHjc1C6XMGXtXTJnwf+4YLex wQhtIhhR99HW0+akqcT7nJMG2vUp42xhPQ2eXA+fyN48I1mRF9HHG0P7u4FVBZLG42jC YmyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723133810; x=1723738610; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=y+ey13UI9SszW+tMd43Q70Tf7NiOEY//3F7sxm3IBtc=; b=ce1BGUxYU3YyEoKYajJ1f68Cf+75STZaeTFTGBDWabfWXyN/8VdM292XmdGd9vQuj9 WF8VIB6SFoA9NtefpGhdxYyXSfCv07oRy6b+Ii9CcVCxUrldpPQR7GPaU0Tadv7c+4ox TKaPbwwdf0aW04QNOICLUvopozZMLKU1QnzlQHm8AmsWm7vQCNVHg9gg2cBfbxbL+NSA AXhJb+WHSgvCgdBvshfsx0tGkG67j4c+VNNGYHzUPQdLcOsIl5+ArlKi/HXPDO+Ys258 bV6dxvRtQH5W7x0vNKpTazpJz3D0G046Gacl01ct7+md17nq7jHKdzo3fNcBT/5lIvBF TQ5Q== X-Forwarded-Encrypted: i=1; AJvYcCVzV8oRjd0DwxoxTGUJT6r7eoxb/GNyc5mDXtSbUelllLfFq3IseLTCdnnKYp3FtjIT1wNfhRAYw+AMHkCZrWuXpuvj8AfSlDoLya1H X-Gm-Message-State: AOJu0YyWYfY69RBDm4H9kONt0yEs/SgPQHQQ8ZAKCuClQwrR8omraFkN 93mSWaeK1I8gayZOEwM5tyw3ov/k1GYDQ4k8bNGP21Vi0CrkDQM3+h9myNxv48bjWsuKy0ND4lm fhOZjnNNswCLydA== X-Google-Smtp-Source: AGHT+IG2I4RPbnoStD3MOJX605BuNQcfc/hAKnnRNwDK+vapHNO4hCViNkB7px+DBGtKqt1lQ7RyR4EL9zrFG+4= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a05:600c:35cb:b0:427:d8f1:e55c with SMTP id 5b1f17b1804b1-4290b7c929fmr615195e9.0.1723133809729; Thu, 08 Aug 2024 09:16:49 -0700 (PDT) Date: Thu, 08 Aug 2024 16:15:51 +0000 In-Reply-To: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240808-alice-file-v9-0-2cb7b934e0e1@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7284; i=aliceryhl@google.com; h=from:subject:message-id; bh=v6Li3ohO2P9VOUj0DUKsbg7ywLMTVrJwO8YEJkpqo/0=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmtO9ZEoaGDCW3sRjvgQ7wGSV9sVyQG7u0GIe30 YObCCFtao2JAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrTvWQAKCRAEWL7uWMY5 RpmxD/99GymF544SLDODAA4TSMZgcLCu1gRqElkJfapFS54UKp3EaE35FFBZueI80D0FO9iXE0p 2cBEeLOSKLr3+Cip5ckUTz0ZFzEvnhP0PXWHmyoc39VyG70eMPWKKYXmc6UsY0z8jjAvHx2nqMg dmGOOSefvMKbOxJbRYFIcXv3sWwbpT2+vZ4fyn/WDtuFgxGgZ27keedNV3qlspeNdji9bm8exb7 C60yHS7QIfgf8MriI/qvkHz40eaJvsD8mQV98YubdEessJmhONSxsQ3g4b72KS22CjH9CnAs8MF Ia0e9fSku2bVLfTayQWZcornYxeLkIaM9gapPDr+FVe2ug8BJEXvfqdrVm7rUzhU5IBJgeRK+Iv /KuB9MkgV3ZMsILLONf/Sg6KnJ+mgoTFHNwJH8ak59vl2/tepSVUJC4aGM0LPtyc+Q4OTNQ7Xtf W1HmgESjgxqskjJOEYHPJBGk3DXBdLxRWOX4ZkuSTpwk04e7fcxXvOch8lAVd1sHtvnHxZrkLxd N0qPYtvjV7TTemZWFJz4QlI7E+IQLIVlxuAbvjg7ylbt68qFhwF4FdwHQFXzGzFPOX3CqYMsZGj jNgQs2OsXbIbpilaAzYMpM3zwxD6226GBvH3LI1NwVpISg0lKLlwWU8SRV8OP+xbnvcE/aO0X+c zuE5dHeOasm+3mg== X-Mailer: b4 0.13.0 Message-ID: <20240808-alice-file-v9-8-2cb7b934e0e1@google.com> Subject: [PATCH v9 8/8] rust: file: add abstraction for `poll_table` From: Alice Ryhl To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan Cc: Dan Williams , Matthew Wilcox , Thomas Gleixner , Daniel Xu , Martin Rodriguez Reboredo , Trevor Gross , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The existing `CondVar` abstraction is a wrapper around `wait_queue_head`, but it does not support all use-cases of the C `wait_queue_head` type. To be specific, a `CondVar` cannot be registered with a `struct poll_table`. This limitation has the advantage that you do not need to call `synchronize_rcu` when destroying a `CondVar`. However, we need the ability to register a `poll_table` with a `wait_queue_head` in Rust Binder. To enable this, introduce a type called `PollCondVar`, which is like `CondVar` except that you can register a `poll_table`. We also introduce `PollTable`, which is a safe wrapper around `poll_table` that is intended to be used with `PollCondVar`. The destructor of `PollCondVar` unconditionally calls `synchronize_rcu` to ensure that the removal of epoll waiters has fully completed before the `wait_queue_head` is destroyed. That said, `synchronize_rcu` is rather expensive and is not needed in all cases: If we have never registered a `poll_table` with the `wait_queue_head`, then we don't need to call `synchronize_rcu`. (And this is a common case in Binder - not all processes use Binder with epoll.) The current implementation does not account for this, but if we find that it is necessary to improve this, a future patch could store a boolean next to the `wait_queue_head` to keep track of whether a `poll_table` has ever been registered. Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Trevor Gross Signed-off-by: Alice Ryhl --- rust/bindings/bindings_helper.h | 1 + rust/kernel/sync.rs | 1 + rust/kernel/sync/poll.rs | 121 ++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 123 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 73a133b92017..b5793142904d 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 0ab20975a3b5..bae4a5179c72 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -11,6 +11,7 @@ mod condvar; pub mod lock; mod locked_by; +pub mod poll; =20 pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs new file mode 100644 index 000000000000..d5f17153b424 --- /dev/null +++ b/rust/kernel/sync/poll.rs @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Utilities for working with `struct poll_table`. + +use crate::{ + bindings, + fs::File, + prelude::*, + sync::{CondVar, LockClassKey}, + types::Opaque, +}; +use core::ops::Deref; + +/// Creates a [`PollCondVar`] initialiser with the given name and a newly-= created lock class. +#[macro_export] +macro_rules! new_poll_condvar { + ($($name:literal)?) =3D> { + $crate::sync::poll::PollCondVar::new( + $crate::optional_name!($($name)?), $crate::static_lock_class!() + ) + }; +} + +/// Wraps the kernel's `struct poll_table`. +/// +/// # Invariants +/// +/// This struct contains a valid `struct poll_table`. +/// +/// For a `struct poll_table` to be valid, its `_qproc` function must foll= ow the safety +/// requirements of `_qproc` functions: +/// +/// * The `_qproc` function is given permission to enqueue a waiter to the= provided `poll_table` +/// during the call. Once the waiter is removed and an rcu grace period = has passed, it must no +/// longer access the `wait_queue_head`. +#[repr(transparent)] +pub struct PollTable(Opaque); + +impl PollTable { + /// Creates a reference to a [`PollTable`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that for the duration of 'a, the pointer wi= ll point at a valid poll + /// table (as defined in the type invariants). + /// + /// The caller must also ensure that the `poll_table` is only accessed= via the returned + /// reference for the duration of 'a. + pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut = PollTable { + // SAFETY: The safety requirements guarantee the validity of the d= ereference, while the + // `PollTable` type being transparent makes the cast ok. + unsafe { &mut *ptr.cast() } + } + + fn get_qproc(&self) -> bindings::poll_queue_proc { + let ptr =3D self.0.get(); + // SAFETY: The `ptr` is valid because it originates from a referen= ce, and the `_qproc` + // field is not modified concurrently with this call since we have= an immutable reference. + unsafe { (*ptr)._qproc } + } + + /// Register this [`PollTable`] with the provided [`PollCondVar`], so = that it can be notified + /// using the condition variable. + pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) { + if let Some(qproc) =3D self.get_qproc() { + // SAFETY: The pointers to `file` and `self` need to be valid = for the duration of this + // call to `qproc`, which they are because they are references. + // + // The `cv.wait_queue_head` pointer must be valid until an rcu= grace period after the + // waiter is removed. The `PollCondVar` is pinned, so before `= cv.wait_queue_head` can + // be destroyed, the destructor must run. That destructor firs= t removes all waiters, + // and then waits for an rcu grace period. Therefore, `cv.wait= _queue_head` is valid for + // long enough. + unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), s= elf.0.get()) }; + } + } +} + +/// A wrapper around [`CondVar`] that makes it usable with [`PollTable`]. +/// +/// [`CondVar`]: crate::sync::CondVar +#[pin_data(PinnedDrop)] +pub struct PollCondVar { + #[pin] + inner: CondVar, +} + +impl PollCondVar { + /// Constructs a new condvar initialiser. + pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl Pi= nInit { + pin_init!(Self { + inner <- CondVar::new(name, key), + }) + } +} + +// Make the `CondVar` methods callable on `PollCondVar`. +impl Deref for PollCondVar { + type Target =3D CondVar; + + fn deref(&self) -> &CondVar { + &self.inner + } +} + +#[pinned_drop] +impl PinnedDrop for PollCondVar { + fn drop(self: Pin<&mut Self>) { + // Clear anything registered using `register_wait`. + // + // SAFETY: The pointer points at a valid `wait_queue_head`. + unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.g= et()) }; + + // Wait for epoll items to be properly removed. + // + // SAFETY: Just an FFI call. + unsafe { bindings::synchronize_rcu() }; + } +} --=20 2.46.0.rc2.264.g509ed76dc8-goog