From mboxrd@z Thu Jan 1 00:00:00 1970 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 B8E6919E810 for ; Thu, 25 Jul 2024 14:28:00 +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=1721917683; cv=none; b=NIdT8/e+beNmsR0Izat94yjwyDEuIMfMN7ijwA1yX06IEJGdB1hpFEXb+idiMYQBm/zyMU9c703OvT1yRExl6+bxBzNSKw8+KqfFfeup9NPpFG31eNmqM3RXB5RRh/AeNUADpceDqKN8wZXz/9e7A9Sh8qLmrNuaymO5Kbndd/U= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721917683; c=relaxed/simple; bh=J91Gx6MIvC8NeTYkxxFTLjHgsB7/VaJDgCuCqcQNtJs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=V3dh7v69MdLS6egLDglf7qoqCrJBqoOh2fb+AAvyHa+S7BROEns2zcL5FdMVEbbhiXONsoibKthUuTwvuYJhEa59uk3MMk9lEFI6wDNldlfpoY8MCC6hz7MsYsDxE0Ljv17xAvuFOXuBDJlRdn7/J6nYEtpx4EroagSY4rlAPOs= 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=bPrXwkLJ; 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="bPrXwkLJ" Received: by mail-yb1-f201.google.com with SMTP id 3f1490d57ef6-e0b2af9de57so1417035276.3 for ; Thu, 25 Jul 2024 07:28:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1721917680; x=1722522480; 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=WCadNj0kmUPw3EC6sSlLJ1QlRyEDEjrL02Pe/kDxaDs=; b=bPrXwkLJoIrLh1rvK/CCkiLssEQ/o9ItzZnJwwNt5wZWM479fSyWibRYVZBP0RNIoJ 2cJFiD3JZDtEjYRvls0wlyoCe3Y2oJbx4Hj1yTp5pMWgePb+YwjZBP5ZopFG/UaUR0qp nlIkHA6xVlGtftOGl136E04WF3WfGJGlmU67kd/j/OYg1EUTeI3C/wfSmTi1KRIekyI2 I/ev7QN+gc/drD7Cr25YhwfcCoTf0XULYY6b+bj3VzgYoMr6wW5Vnv7xdRYTgupFlfy8 FUe1A6QxPFCTOCqrvcVU/j8oJW7x656filQiBtob6RYKGUXlsgLtjkHM/UrydXq1SO61 qEIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721917680; x=1722522480; 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=WCadNj0kmUPw3EC6sSlLJ1QlRyEDEjrL02Pe/kDxaDs=; b=m1wucXT5BYt/UQy1MpmR5aZdiaJ7lzhSJDOQsbEtqFEciwA9G8xR7YbQn3TFpYizRQ nVazqCytGbXchDdhkET7+WEOKQlLeQo9I0d2IJ45SM3XFxErH3fXhM7WAik+yCKp0SUx //oaYKpsdF9PkxWjRMZgWwnUrLpDHzSaOJk6XT+pvhEf1+eXItdCRDxBpM7CSqTAhDNm C8m38YByEEoB15mwaGoCnIC3sOlo95sk6MeUy8fGdnggwZY3wLWqzhbuvEmINtucMUS8 fhSAghjFNKbu83zHVpDuKu0F138kvAzk0CkKPW3Y1wkUbeLLWBVJlYs/94Lx41c1JHmF UPFA== X-Forwarded-Encrypted: i=1; AJvYcCUFLsKVyBFXpZa1odaaCf6RJ6ISKnXec5POt50LX10H0CVoYnOMjubbIY66AvK27zj8Jic1x9bfC5FvIKtB2PVa/nr8STy8zKJ8HTEaC+k= X-Gm-Message-State: AOJu0YzToNJ5LTMTBy88IwdtrUF60g8Zkjmc3nIBR7C7JXBVL97+mh0A ymkbdqQ8zwCGgaDw679mxvP3dQ7AZDtM/xfZxenenjSrLMZ4JiXh1O8cyDf560/31gD5t0e1TZE mVmh+G+7TKgpfxA== X-Google-Smtp-Source: AGHT+IFKYihlbOoX4iJsmGs9EfswZcG8G7huPM/Kp+v9+uVgvno5FkEt+tRzpYzNQMus2OCOcCPmt1f5OwY66Ig= X-Received: from aliceryhl2.c.googlers.com ([fda3:e722:ac3:cc00:68:949d:c0a8:572]) (user=aliceryhl job=sendgmr) by 2002:a05:6902:2b0f:b0:e05:65b7:32d9 with SMTP id 3f1490d57ef6-e0b2ca7734cmr22335276.6.1721917679919; Thu, 25 Jul 2024 07:27:59 -0700 (PDT) Date: Thu, 25 Jul 2024 14:27:39 +0000 In-Reply-To: <20240725-alice-file-v8-0-55a2e80deaa8@google.com> Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240725-alice-file-v8-0-55a2e80deaa8@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=5384; i=aliceryhl@google.com; h=from:subject:message-id; bh=Dwps4ysAMwtCKIr0qbQaLdxg6EG+tQNeQs65V1osc9I=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmomDa+P7LzNE+jmX+/kQHXyXhbz5uo1UajGv8c 3SDDziX8GaJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZqJg2gAKCRAEWL7uWMY5 Rv1wD/9yIpYyp+1FzfVlXK5fro/+UN5sDKFyuVNC75IP8CLT6XcV3QknwbTAR23Jh05FQpF7+Pf jrz1iMF6MGxEu7dHpd+Cl+DYCvXcj0lLCya+ACthV9pGo7t8njodU8iIWPX5iWBDv8LqTNX+kft mKhg5iHuvAmi8RwVkEUQfiS1OspLzSSX6D3sO86RygZNpbKq8GhAd7b3J341plPPzDRq1N0mE9a ZK80uLJEYIdmdQisnranp/36sHgVvxreXbZyUx0DDVQktnaPU70yRHqgylgJcTQ25YpfvGPSdIw 68XWOIct7/yqFDfkFO9IbqWMZjWjRIyZkwmDrQ+J1aJ2gty5eHQfCSDjzsVy2xpdvMJZMBXqyoh zcOm7ohj2DqwATIzS82N0tXEYt5X5egNQ49Oy9uiWFrmdw6NEXNBXwCC0JzHQ1O+RrRPpbEHAfc UFrD9y4QhyV4axUSVWfyFEmShVg4naOomjnaZKHj9WoTqxroCvhPtXbMpIEoZL1RtXXx3s28m5g TQGTrj68xvKhQERJ0mrtk9mzDlV/K4v1m7FrikEh3Ltr8MkyfBdTaBcKcwIz29uNVG262QRQHfr FKq9qPioWU5Kx+f5qgLUrHkipdtPhEiGiOO1awCA6Q/9vdRSIhrHPft8exKcqcJdHqMHKaZoGNU pj6yiYSwGLvsqtA== X-Mailer: b4 0.13-dev-26615 Message-ID: <20240725-alice-file-v8-6-55a2e80deaa8@google.com> Subject: [PATCH v8 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" 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 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 8bed7bebcc43..af98513bb2ee 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; @@ -368,6 +368,79 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } +/// 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 mutually exclusive). +/// +/// Dropping the reservation happens in the destructor of this type. +/// +/// # Invariants +/// +/// The fd stored in this struct must correspond to a reserved file descriptor 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 value 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 = 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 method 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_flags`. 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 by its type invariants, + // and we take ownership of that refcount by not running the destructor below. + // Additionally, the file is known to not have any non-shared `fdget_pos` calls, so even if + // this process starts using the file position, this will not result 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 reference, 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 previously returned by + // `get_unused_fd_flags`. 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. + unsafe { bindings::put_unused_fd(self.fd) }; + } +} + /// Represents the `EBADF` error code. /// /// Used for methods that can only fail with `EBADF`. -- 2.45.2.1089.g2a221341d9-goog