From nobody Sat Feb 7 18:28:43 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (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 9818A1DE4E5; Fri, 31 Jan 2025 15:08:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738336105; cv=none; b=PZPuOmKE9fYNIwhn8LjvJ1exAlUP4/Ak6zPNoxzij9gbfvb4jgcHLb9tEk4VbFzhH60lbrZsS/QM6CpGN/K4jvcjIH9tK/hnbCDHrMpbCq2ZWsZ4r7+2jcIYMjhrCWO27GvVsGw8Xuz4dh6KHwUcnKfTeY2ZdRBD0fuwvaITlzM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738336105; c=relaxed/simple; bh=xAEnZ7bRI9MGSFtBwP1gsbkfBflvSwAiHaQcFi+NBGQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=L9jVrLhS8phDXSxGGpo4geODNRM31SAbnGJB+X1Pb4XsQHy5xkRW2KzzKzqDMYaNnNg/RFN4ZopZCdWmfEZrcC+g6CA1KjdfymPESU6i4akQM0NSiFt8rHevxndtQ+sQ6hjTramLx5hCW17K2eUuBGRwkOSf7at0CYZ5pVSDgpY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=NP4e+llJ; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NP4e+llJ" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-3862d16b4f5so1323485f8f.0; Fri, 31 Jan 2025 07:08:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738336102; x=1738940902; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=ab7bqlgvZTUAqANn/N2gtXKKfdu+ZO1ULo5xsqJxgDo=; b=NP4e+llJDdxAoojlKGfWkyQR4xm/iTHpVWxMs4dTVehopkf1gSKRiViXmHWuA2doB/ kHFK5QCaDBWVf5/qSL09xH7+4poRiT9PHf89dqN6jXQwbisiNCqDscSWZ89jGs/VE8cy 2PtfN1cMSTgt339cq5Bg6LyZX2VE100sQLlZYl0Tn09E2pfbNGL/T/lCqL8FrI7DlERY CVP+aRY8C/VxXbJsbkJrzleqvdDI/v9fW8DNEYddpJ2dE/lKNf0Mhn9Yb0NIoQvA054d JjtFbxuKOuMyldXxt+2djXnpTXQ3YtiJ9hS+1iOEJ7AiQmjNWbqTEl0+y+g3kVzIbtAp v5dw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738336102; x=1738940902; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ab7bqlgvZTUAqANn/N2gtXKKfdu+ZO1ULo5xsqJxgDo=; b=TrEr6sKNw34R5rg1io6rUZ0JUEMMKCNMxiKXu/FPEBB78WXLpG96q1I7ZPk8r6yMCs sB3W5OIvBtObSI/hJKdD5Tebs96bTdygaBDIjKxfq7+LivKnkG8kY0oHL0QZU1w0U2yL xmePyRuSoaos1M/6Edl9PZPtSxjS/tCjLY8A85e53JHI/LYc30/RNxQ4MlWJYh22Eh+v p7BhCHHwdrVfazK8QOMInRGD8djmaKYhtdBuNsMUZlQ4gbaVP3uP8wKkhSt4vbFmjzL+ gASeCfQnOosHo3rAaclQW7tHKXHQ1uyi2j3+2VW6XKYTiFQAPWZuOe6LKNpZSUnhPsis 5rig== X-Forwarded-Encrypted: i=1; AJvYcCWt/JBwpMxXH/T6/CVvfDFTUe6l4CisRDn4GEPKoYJ1t9COgKWFZoXN2ouoLH2T4+G8MjamA4ql5JXc8sk=@vger.kernel.org X-Gm-Message-State: AOJu0YxfAf1U2wMYXiw1I/uqycNkxw8MWmr2q605Ge/BLdDp5Hw3vSrP GAtK5nRBLs/Bt5Tv5lhAg0c419ec0gR1SGBbu0ISCq7kbFjmIi6N X-Gm-Gg: ASbGncuffxYX6SBC6oUl1J082fxmBhxMbkF0cK0NGHmFAFRIJAuexu6SWf/N61w7QWy n5Z96s7wiVylHvrGF8KidB7TSQ2CkCEHD9uQllnCr27+vgF9HYWJIJh+Sa20q+xlBJDhjrimJfT TJJBETbOohQTjfKi+BYN6WVP7yIjU3evgEil4D6FyOqL59266t5qJZpoF4WHlNNLU/wASsyumpH qycnzhpJAhxrhCGxSVYmk17yu+noPeZ+N4E6lsuCJdIRCxhoVJ43Cq7waEgE0GuPLvlp3R+OxMr SCc= X-Google-Smtp-Source: AGHT+IFotVDiuS2up/NlNR0JeqrFZgLgx8MbTOaY+Dudjm7fdZ37KqMNvT/Ckhixcp4Uc/6SUEsldA== X-Received: by 2002:a05:6000:402b:b0:38b:ee9f:52d5 with SMTP id ffacd0b85a97d-38c5a98e04cmr6319044f8f.16.1738336099844; Fri, 31 Jan 2025 07:08:19 -0800 (PST) Received: from [10.0.1.56] ([2001:871:22a:8634::1ad1]) by smtp.googlemail.com with ESMTPSA id ffacd0b85a97d-38c5c102f7dsm4961479f8f.30.2025.01.31.07.08.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jan 2025 07:08:19 -0800 (PST) From: Christian Schrefl Date: Fri, 31 Jan 2025 16:08:14 +0100 Subject: [PATCH v2 1/3] rust: add UnsafePinned type Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250131-b4-rust_miscdevice_registrationdata-v2-1-588f1e6cfabe@gmail.com> References: <20250131-b4-rust_miscdevice_registrationdata-v2-0-588f1e6cfabe@gmail.com> In-Reply-To: <20250131-b4-rust_miscdevice_registrationdata-v2-0-588f1e6cfabe@gmail.com> To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Arnd Bergmann , Greg Kroah-Hartman , Lee Jones , Daniel Almeida , Danilo Krummrich Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Christian Schrefl X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1738336097; l=4162; i=chrisi.schrefl@gmail.com; s=20250119; h=from:subject:message-id; bh=xAEnZ7bRI9MGSFtBwP1gsbkfBflvSwAiHaQcFi+NBGQ=; b=Rkq/fWnyxtYXZ31MhfCDDBxW5arPynA9KvgMg5+SGYc69NO6bL/XnYqxOrQxgxSFQlRKw35UT nm4do8Rxx17Cvyg2ExeTU9iGDcsaEMPCka5Z54JiybJpJN4vlOEf4zP X-Developer-Key: i=chrisi.schrefl@gmail.com; a=ed25519; pk=EIyitYCrzxWlybrqoGqiL2jyvO7Vp9X40n0dQ6HE4oU= `UnsafePinned` is useful for cases where a value might be shared with C code but not directly used by it. In particular this is added for additional data in the `MiscDeviceRegistration` which will be shared between `fops->open` and the containing struct. Similar to `Opaque` but guarantees that the value is always initialized and that the inner value is dropped when `UnsafePinned` is dropped. This was originally proposed for the IRQ abstractions [0] and is also useful for other where the inner data may be aliased, but is always valid and automatic `Drop` is desired. Link: https://lore.kernel.org/rust-for-linux/CAH5fLgiOASgjoYKFz6kWwzLaH07Dq= P2ph+3YyCDh2+gYqGpABA@mail.gmail.com [0] Suggested-by: Alice Ryhl Signed-off-by: Christian Schrefl --- rust/kernel/types.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 57 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 2bbaab83b9d65da667a07e85b3c89c7fa881b53c..3c2f6ac62d161f1187b5e7ade86= 689eec667ff4d 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -253,6 +253,9 @@ fn drop(&mut self) { /// /// `Opaque` is meant to be used with FFI objects that are never interp= reted by Rust code. /// +/// In cases where the contained data is only used by Rust, is not allowed= to be +/// uninitialized and automatic [`Drop`] is desired [`UnsafePinned`] shoul= d be used instead. +/// /// It is used to wrap structs from the C side, like for example `Opaque`. /// It gets rid of all the usual assumptions that Rust has for a value: /// @@ -573,3 +576,57 @@ pub enum Either { /// [`NotThreadSafe`]: type@NotThreadSafe #[allow(non_upper_case_globals)] pub const NotThreadSafe: NotThreadSafe =3D PhantomData; + +/// Stores a value that may be used from multiple mutable pointers. +/// +/// `UnsafePinned` gets rid of some of the usual assumptions that Rust has= for a value: +/// - The value is allowed to be mutated, when a `&UnsafePinned` exists= on the Rust side. +/// - No uniqueness for mutable references: it is fine to have multiple `&= mut UnsafePinned` +/// point to the same value. +/// +/// To avoid the ability to use [`core::mem::swap`] this still needs to be= used through a +/// [`core::pin::Pin`] reference. +/// +/// This is useful for cases where a value might be shared with C code +/// but not interpreted by it or in cases where it can not always be guara= nteed that the +/// references are unique. +/// +/// This is similar to [`Opaque`] but is guaranteed to always contain v= alid data and will +/// call the [`Drop`] implementation of `T` when dropped. +#[repr(transparent)] +pub struct UnsafePinned { + value: UnsafeCell, + _pin: PhantomPinned, +} + +impl UnsafePinned { + /// Creates a new [`UnsafePinned`] value. + pub const fn new(value: T) -> Self { + Self { + value: UnsafeCell::new(value), + _pin: PhantomPinned, + } + } + + /// Create an [`UnsafePinned`] pin-initializer from the given pin-init= ializer. + pub fn try_pin_init(value: impl PinInit) -> impl PinInit { + // SAFETY: + // - In case of an error in `value` the error is returned, other= wise `slot` is fully + // initialized, since `self.value` is initialized and `_pin` i= s a zero sized type. + // - The `Pin` invariants of `self.value` are upheld, since no m= oving occurs. + unsafe { init::pin_init_from_closure(move |slot| value.__pinned_in= it(Self::raw_get(slot))) } + } + + /// Returns a raw pointer to the contained data. + pub const fn get(&self) -> *mut T { + UnsafeCell::get(&self.value).cast::() + } + + /// Gets the value behind `this`. + /// + /// This function is useful to get access to the value without creatin= g intermediate + /// references. + pub const fn raw_get(this: *const Self) -> *mut T { + UnsafeCell::raw_get(this.cast::>>()).cas= t::() + } +} --=20 2.48.1 From nobody Sat Feb 7 18:28:43 2026 Received: from mail-wm1-f53.google.com (mail-wm1-f53.google.com [209.85.128.53]) (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 E72461CB9E2; Fri, 31 Jan 2025 15:08:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738336105; cv=none; b=ZCnJhpv6cWmoxhY5IJZAkSIfAaMZIikckl4FJS+MrZowJbaB8/O8Sp62gsSnq2RKnY0Sv0ji1fsc8lOQVRu/oQubv1MvtjaJtHxl92mq50sw/LxXtVArtr4iXFMN7jcc0zE0Uabh/WMPXRtoeKKY9bAtQHRhg1euPcxZ3MST1No= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738336105; c=relaxed/simple; bh=W8rdcgHq5/Rf7UBuM1nuiKlm3EHoGb8E5wAEDaYy060=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=i4l9ujxFdrjOvOc7Lxdvwt577o6Mwsh8Vo0BjPCuknHb09pIR05YV+7FQHyo2s7HnssNhjfEH20yWxCsDPO7RXewvBxyhkzssqSoskJnW3crQLy5wF1DjG05zDbsE3GMeHQiQsYRZbkfkUoxoyzkFz0yiXhfkVITLhhqJTQTK1Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Ejwnf5HY; arc=none smtp.client-ip=209.85.128.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Ejwnf5HY" Received: by mail-wm1-f53.google.com with SMTP id 5b1f17b1804b1-436341f575fso24616725e9.1; Fri, 31 Jan 2025 07:08:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738336101; x=1738940901; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=cSI3MPyGhxbJgcp2M7J56C/nAlb1W0KmOXVx629dU8I=; b=Ejwnf5HYSM8SVNZnNqPSSu9ylLWzcGHClDtUn/KMOsYCJbhgE4YqjmxtpkswsfoVDV 4iWjvGIu00X/Ni5PELd/qgBF4lqJUYooASiC5OwfjUymUMU51IlIwjjUyZkU09Iz4GnR DT45csN8wsB0Gq2arlM+azwZ0dZKmCW7syZ5JJRnttQWHaOBnOaPChvr1LgWYcdtMYBZ ypBcusvwDO/RsbrkNFRo71NfHTU2uAHeeRCJR0PHWs+LlT/A6Ahvqkm9Bv534KxXnYQM lJXYMj623p0LwJEMNeQC5loaBGfFtQzpkbsnCnORWmqHsdbXp0j3SdZwYN6JKCPMDFwU uEdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738336101; x=1738940901; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=cSI3MPyGhxbJgcp2M7J56C/nAlb1W0KmOXVx629dU8I=; b=C8NqVOEBWTN7MSzZbjzr3sxOuPeupFyLQcClxVlyMIUosNEbgF7DOH+vrpuI2lOPmw Pr7hCyorSXig/tEI6RFQvHdsBGy0PeuzYI33oYrtuRvDG9NbQXrr/zXWu+wVk8Bu4AWK YEwKB4WsrNBgxRATUoItX7Qd1jd5BxDhkijGED2GziKh+nmqnON4RnyZyxRXKrt+4H30 6SqpNgkjfRJDzp6C04MjeZLdCFH3jq4opvT+N4H738U/Tfs+xiyefV6tXM7vlIaWsbUL 4sV9XS/XBZyVlSspySALdVo/kSUQhBuqCVY8oee3HyxS0TBPFxB4T3NHwEIH0AJ7H2vE IH/w== X-Forwarded-Encrypted: i=1; AJvYcCVeR9SZelI/hsfLBTxWWG/gtJGWDQlo/Ag18iwEoMzwBgYJTnx8DAWufAd2ODLcm8EIezNtze+BG9qPifg=@vger.kernel.org X-Gm-Message-State: AOJu0Yw6GCl1+O44umRR+qxMrcjCiP1van8LgiPGuXltAZqMXuZqWYma 4cE/TEZ9cuzn5d2HE0A7iiWN6SMuG4/srQgfwVW02o+558eha8rg X-Gm-Gg: ASbGncuvqku1AmbpqvNPAP1p2c1+NPxurX8hSzR/N0412fGiEBybfQzIS0FjhWI9TGv BN556Dc+U3Tb5Jq9fwSA/saKGfUvsMoncxo/M2sJrEehX82HzvzWyTOS010nmeRGWDm4aBHKSC7 vBm48Hgmbmu8MiXFiihr9wIEbNCL6YEChhgz60CeUSGmxXBELJriNtaj4jCOY2nAgdqLKutnWnH opPnu+RPwI1d4vR+8Rhpxp/prCWSoiSk62vir9UPRe9nqtWyXUfU0V91DqC696Cq2s2RBovB7Mw Huo= X-Google-Smtp-Source: AGHT+IEaCswwNDE2SOSBhu9ihG4LrOpHUGeefehrkNEftWLqTsrp0tSb1RKUn/hLMQ97D0QAtlw+mQ== X-Received: by 2002:a05:600c:19cc:b0:434:fddf:5c0c with SMTP id 5b1f17b1804b1-438e298fea7mr70953285e9.4.1738336100809; Fri, 31 Jan 2025 07:08:20 -0800 (PST) Received: from [10.0.1.56] ([2001:871:22a:8634::1ad1]) by smtp.googlemail.com with ESMTPSA id ffacd0b85a97d-38c5c102f7dsm4961479f8f.30.2025.01.31.07.08.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jan 2025 07:08:20 -0800 (PST) From: Christian Schrefl Date: Fri, 31 Jan 2025 16:08:15 +0100 Subject: [PATCH v2 2/3] rust: miscdevice: Add additional data to MiscDeviceRegistration Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250131-b4-rust_miscdevice_registrationdata-v2-2-588f1e6cfabe@gmail.com> References: <20250131-b4-rust_miscdevice_registrationdata-v2-0-588f1e6cfabe@gmail.com> In-Reply-To: <20250131-b4-rust_miscdevice_registrationdata-v2-0-588f1e6cfabe@gmail.com> To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Arnd Bergmann , Greg Kroah-Hartman , Lee Jones , Daniel Almeida , Danilo Krummrich Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Christian Schrefl X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1738336097; l=10315; i=chrisi.schrefl@gmail.com; s=20250119; h=from:subject:message-id; bh=W8rdcgHq5/Rf7UBuM1nuiKlm3EHoGb8E5wAEDaYy060=; b=+z7mE0TlK6JU51Avl4PgapoQ3g/LJ+nrDcTZspfyWmhFL5tx2LUgcmgA6oFHv+pdPTVe/G+VE ldXShgxeiHOC8D3HvoamRS6FB6VuJO8eh/J65jBXjG9HRF7+ww+ZwEV X-Developer-Key: i=chrisi.schrefl@gmail.com; a=ed25519; pk=EIyitYCrzxWlybrqoGqiL2jyvO7Vp9X40n0dQ6HE4oU= When using the Rust miscdevice bindings, you generally embed the `MiscDeviceRegistration` within another struct: struct MyDriverData { data: SomeOtherData, misc: MiscDeviceRegistration } In the `fops->open` callback of the miscdevice, you are given a reference to the registration, which allows you to access its fields. For example, as of commit 284ae0be4dca ("rust: miscdevice: Provide accessor to pull out miscdevice::this_device") you can access the internal `struct device`. However, there is still no way to access the `data` field in the above example, because you only have a reference to the registration. Using `container_of` is also not possible to do safely. For example, if the destructor of `MyDriverData` runs, then the destructor of `data` would run before the miscdevice is deregistered, so using `container_of` to access `data` from `fops->open` could result in a UAF. A similar problem can happen on initialization if `misc` is not the last field to be initialized. To provide a safe way to access user-defined data stored next to the `struct miscdevice`, make `MiscDeviceRegistration` into a container that can store a user-provided piece of data. This way, `fops->open` can access that data via the registration, since the data is stored inside the registration. The container enforces that the additional user data is initialized before the miscdevice is registered, and that the miscdevice is deregistered before the user data is destroyed. This ensures that access to the userdata is safe. For the same reasons as in commit 88441d5c6d17 ("rust: miscdevice: access the `struct miscdevice` from fops->open()"), you cannot access the user data in any other fops callback than open. This is because a miscdevice can be deregistered while there are still open files. A situation where this user data might be required is when a platform driver acquires a resource in `probe` and wants to use this resource in the `fops` implementation of a `MiscDevice`. This solution is similar to the approach used by the initial downstream Rust-for-Linux/Rust branch [0]. Link: https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/miscdev= .rs#L108 [0] Suggested-by: Alice Ryhl Signed-off-by: Christian Schrefl --- rust/kernel/miscdevice.rs | 75 +++++++++++++++++++++++++++++-------= ---- samples/rust/rust_misc_device.rs | 4 ++- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index e14433b2ab9d8fa391474b2ad7e3ed55c64b4d91..dea7d8d1a0366cf2243c7a3888e= bfb8a90d6295c 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -9,7 +9,7 @@ //! Reference: =20 use crate::{ - bindings, + bindings, container_of, device::Device, error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, ffi::{c_int, c_long, c_uint, c_ulong}, @@ -17,7 +17,7 @@ prelude::*, seq_file::SeqFile, str::CStr, - types::{ForeignOwnable, Opaque}, + types::{ForeignOwnable, Opaque, UnsafePinned}, }; use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin}; =20 @@ -45,32 +45,46 @@ pub const fn into_raw(self) -> bindings:= :miscdevice { /// # Invariants /// /// `inner` is a registered misc device. -#[repr(transparent)] +#[repr(C)] #[pin_data(PinnedDrop)] -pub struct MiscDeviceRegistration { +pub struct MiscDeviceRegistration { #[pin] inner: Opaque, + #[pin] + data: UnsafePinned, _t: PhantomData, } =20 -// SAFETY: It is allowed to call `misc_deregister` on a different thread f= rom where you called -// `misc_register`. -unsafe impl Send for MiscDeviceRegistration {} -// SAFETY: All `&self` methods on this type are written to ensure that it = is safe to call them in -// parallel. -unsafe impl Sync for MiscDeviceRegistration {} +// SAFETY: +// - It is allowed to call `misc_deregister` on a different thread from wh= ere you called +// `misc_register`. +// - Only implements `Send` if `MiscDevice::RegistrationData` is also `Sen= d`. +unsafe impl Send for MiscDeviceRegistration where T::Reg= istrationData: Send {} + +// SAFETY: +// - All `&self` methods on this type are written to ensure that it is saf= e to call them in +// parallel. +// - `MiscDevice::RegistrationData` is always `Sync`. +unsafe impl Sync for MiscDeviceRegistration {} =20 impl MiscDeviceRegistration { /// Register a misc device. - pub fn register(opts: MiscDeviceOptions) -> impl PinInit { + pub fn register( + opts: MiscDeviceOptions, + data: impl PinInit, + ) -> impl PinInit { try_pin_init!(Self { + data <- UnsafePinned::try_pin_init(data), inner <- Opaque::try_ffi_init(move |slot: *mut bindings::miscd= evice| { // SAFETY: The initializer can write to the provided `slot= `. unsafe { slot.write(opts.into_raw::()) }; =20 - // SAFETY: We just wrote the misc device options to the sl= ot. The miscdevice will - // get unregistered before `slot` is deallocated because t= he memory is pinned and - // the destructor of this type deallocates the memory. + // SAFETY: + // * We just wrote the misc device options to the slot. Th= e miscdevice will + // get unregistered before `slot` is deallocated because= the memory is pinned and + // the destructor of this type deallocates the memory. + // * `data` is Initialized before `misc_register` so no ra= ce with `fops->open()` + // is possible. // INVARIANT: If this returns `Ok(())`, then the `slot` wi= ll contain a registered // misc device. to_result(unsafe { bindings::misc_register(slot) }) @@ -93,10 +107,18 @@ pub fn device(&self) -> &Device { // before the underlying `struct miscdevice` is destroyed. unsafe { Device::as_ref((*self.as_raw()).this_device) } } + + /// Access the additional data stored in this registration. + pub fn data(&self) -> &T::RegistrationData { + // SAFETY: + // * No mutable reference to the value contained by `self.data` ca= n ever be created. + // * The value contained by `self.data` is valid for the entire li= fetime of `&self`. + unsafe { &*self.data.get() } + } } =20 #[pinned_drop] -impl PinnedDrop for MiscDeviceRegistration { +impl PinnedDrop for MiscDeviceRegistration { fn drop(self: Pin<&mut Self>) { // SAFETY: We know that the device is registered by the type invar= iants. unsafe { bindings::misc_deregister(self.inner.get()) }; @@ -109,6 +131,13 @@ pub trait MiscDevice: Sized { /// What kind of pointer should `Self` be wrapped in. type Ptr: ForeignOwnable + Send + Sync; =20 + /// The additional data carried by the [`MiscDeviceRegistration`] for = this [`MiscDevice`]. + /// If no additional data is required than the unit type `()` should b= e used. + /// + /// This data can be accessed in [`MiscDevice::open()`] using + /// [`MiscDeviceRegistration::data()`]. + type RegistrationData: Sync; + /// Called when the misc device is opened. /// /// The returned pointer will be stored as the private data for the fi= le. @@ -211,17 +240,23 @@ impl VtableHelper { // SAFETY: The open call of a file can access the private data. let misc_ptr =3D unsafe { (*raw_file).private_data }; =20 - // SAFETY: This is a miscdevice, so `misc_open()` set the private data= to a pointer to the - // associated `struct miscdevice` before calling into this method. Fur= thermore, `misc_open()` - // ensures that the miscdevice can't be unregistered and freed during = this call to `fops_open`. - let misc =3D unsafe { &*misc_ptr.cast::>() }; + // This is a miscdevice, so `misc_open()` sets the private data to a p= ointer to the + // associated `struct miscdevice` before calling into this method. + let misc_ptr =3D misc_ptr.cast::(); + + // SAFETY: + // * `misc_open()` ensures that the `struct miscdevice` can't be unreg= istered and freed + // during this call to `fops_open`. + // * The `misc_ptr` always points to the `inner` field of a `MiscDevic= eRegistration`. + // * The `MiscDeviceRegistration` is valid until the `struct miscde= vice` was unregistered. + let registration =3D unsafe { &*container_of!(misc_ptr, MiscDeviceRegi= stration, inner) }; =20 // SAFETY: // * This underlying file is valid for (much longer than) the duration= of `T::open`. // * There is no active fdget_pos region on the file on this thread. let file =3D unsafe { File::from_raw_file(raw_file) }; =20 - let ptr =3D match T::open(file, misc) { + let ptr =3D match T::open(file, registration) { Ok(ptr) =3D> ptr, Err(err) =3D> return err.to_errno(), }; diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_devi= ce.rs index 40ad7266c2252e5c0b4e91e501ef9ada2eda3b16..779fcfd64119bdd5b4f8be740f7= e8336c652b4d3 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -136,7 +136,7 @@ fn init(_module: &'static ThisModule) -> impl PinInit { }; =20 try_pin_init!(Self { - _miscdev <- MiscDeviceRegistration::register(options), + _miscdev <- MiscDeviceRegistration::register(options, ()), }) } } @@ -156,6 +156,8 @@ struct RustMiscDevice { impl MiscDevice for RustMiscDevice { type Ptr =3D Pin>; =20 + type RegistrationData =3D (); + fn open(_file: &File, misc: &MiscDeviceRegistration) -> Result>> { let dev =3D ARef::from(misc.device()); =20 --=20 2.48.1 From nobody Sat Feb 7 18:28:43 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (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 8CB5A1E377E; Fri, 31 Jan 2025 15:08:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738336106; cv=none; b=C5ube02Z1kC/JpG1DMGbDkMHKHTCsfwjh+O9w88xdxdL+k88BzJIJweT4osEhUqUJydQw6ed2b+GKsWK/btKVK0oXusrvGIe3dJ9Q+CuJSr9HySagpNTH2yfKrQZj49AxRfLa1jgrUheXQNMVZvoF29WfkXij6TYnQ8EGOjkd94= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738336106; c=relaxed/simple; bh=NltnxPsvyHizFdY1rZDyMFYkrrhOoY/Vq3+44/WgE7E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=P7WqkX1ocCv+jX/PWTFVSGlx8FE0qPHGVAMSTIp7SkciWL12uTc8F14wPuki38U7WC1mwY/SpeM6uGFSJeIpBuUqF4B1jck9TwYVM+RX8TnaL1TgcKFMzXe7HwqENxL1YcApAyQ334gt6pJb+B8wJaMIAbcj4IGdnKRWWZ1YLMQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ZQIfKWMI; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZQIfKWMI" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-438a3216fc2so20955475e9.1; Fri, 31 Jan 2025 07:08:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738336103; x=1738940903; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=sYn0muHYjqjA6UsqqcKnISyo0x1aOKCSWvoO/WsiV2k=; b=ZQIfKWMIL6bzyCXjVCAyiBdiieZXkQJSFA2lUOyO1K2/5kjG6VIiPqKuTrXZdcW0Yo TsyhjzWkGb2zSENjLgyFvNhjFfWV+0xvnbhyQxEWHDmwEfZrxbNVjccq343WKWqAy5ov V7XR5ZQmjoFzzA2q4ZzTA9oVFY+Td7F1AguWafo/ncHlw3j7TVY8+MAUR9zu0/c3JkZA w8NMColD7BMs2+M/t1gV8T3IvdhobNMxY2E7p8VCSDj3jAWtUmPCI/4lWPZD9BtB2dAt n7oy/YfZUPoY1o7yoxektSZqaZsTGPu4o8qM5UUXHFOIrGAx/CEN6OWF3IOlPJhOhoAD PRBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738336103; x=1738940903; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sYn0muHYjqjA6UsqqcKnISyo0x1aOKCSWvoO/WsiV2k=; b=SJj8I4wduP+ww7d9FqDlyY/VoSbMxv7NxqyjbUflHUVDDca9cX7+WbJaEoSr7EPAGH 1kcFjwZYX1Nn/1cV5UuAoDIuA7wIdRiyME5EJBfZxxxojcGMT+SrqRIa+N11dlHjCCnd xCsTAuu5l6h+iTCZZOK3bWIvoRsZAPjh3lSfJZJuyQtbDn4NRgKXa4C3aDF0lJ+AE5+V 0ZFQhl2KUFpiT+yjCLQgJS4QaLrXN8Y3ko5/3yk/mEEVG2kXnYveeU7tFAXtU7a9Sq8v y5UPDPm0vqEmRmoIRnqlYbPSc59/0nikiaVTfx1gPplwj7QgNYePWW7Yu45EixZW0LLV qR4Q== X-Forwarded-Encrypted: i=1; AJvYcCUDaQ6KzVGioTiT/q/VheIOpic8mrHpZtVr2ibRxq2lMbZp7euir0lJwbjK/EvUCLkbFLXox8VwXg1r1lo=@vger.kernel.org X-Gm-Message-State: AOJu0YzjdTU/TcJqOciNJeEHoGJyrR8yC4wnGTL9F6VPphV9/bCeDCqZ W7Cp8GVEXhk9rP0IL6VL0N7C7zOaWfKA4cjSzB1vmSwWk5jJDCMl X-Gm-Gg: ASbGncvG0EUWZ7eELWXCbJbcjjg+LMTHRWfP2dpjYvMhZ1erfQa/7yv6xowONS3Tf69 nawsSVORY5r0EnX1Sqo0jwEZMZv4dIPzcxiWW3YwZuJ6fpiAZVcgisQYytUj7auLcRw907bm9xb csCXbjnKmi49aOJ8IY1yRNqSuF+ho2vqFTCRede24WxN9gaylwFIUPnSAI/8uakFnLYJwnINL3N Me1JEWXTIgPqbwiqNcwynTTXmcQp7L+10thDKoroL8DUirrxmCyB32GkpmzLfPSzDqi7QYRhx/x +Go= X-Google-Smtp-Source: AGHT+IHevu4w6u0n5f/tqugEgYckD6bhxH24TqMUE6w5dM/Z5vQ4B1xT2XlwwjUovVM6qa4WXCltLg== X-Received: by 2002:adf:fbd1:0:b0:386:3835:9fec with SMTP id ffacd0b85a97d-38c520972d6mr8152272f8f.44.1738336102278; Fri, 31 Jan 2025 07:08:22 -0800 (PST) Received: from [10.0.1.56] ([2001:871:22a:8634::1ad1]) by smtp.googlemail.com with ESMTPSA id ffacd0b85a97d-38c5c102f7dsm4961479f8f.30.2025.01.31.07.08.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jan 2025 07:08:21 -0800 (PST) From: Christian Schrefl Date: Fri, 31 Jan 2025 16:08:16 +0100 Subject: [PATCH v2 3/3] rust: miscdevice: adjust the rust_misc_device sample to use RegistrationData. Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250131-b4-rust_miscdevice_registrationdata-v2-3-588f1e6cfabe@gmail.com> References: <20250131-b4-rust_miscdevice_registrationdata-v2-0-588f1e6cfabe@gmail.com> In-Reply-To: <20250131-b4-rust_miscdevice_registrationdata-v2-0-588f1e6cfabe@gmail.com> To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Arnd Bergmann , Greg Kroah-Hartman , Lee Jones , Daniel Almeida , Danilo Krummrich Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Christian Schrefl X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1738336097; l=7574; i=chrisi.schrefl@gmail.com; s=20250119; h=from:subject:message-id; bh=NltnxPsvyHizFdY1rZDyMFYkrrhOoY/Vq3+44/WgE7E=; b=c7LplwSvTqIu+Va75CPu8xjG1TeUKHHCx0G9m7T9YReLx7411MIpgglJ87y5U84yv7Ynq9RMm MsNbDacBPIXDjuOYeuDO7m58r7gWyc4+gB2vJv6enYEJSq2EgoN/3hx X-Developer-Key: i=chrisi.schrefl@gmail.com; a=ed25519; pk=EIyitYCrzxWlybrqoGqiL2jyvO7Vp9X40n0dQ6HE4oU= Add a second mutex to the RustMiscDevice, which is shared between all instances of the device using an Arc and the RegistrationData of MiscDeviceRegistration. This is mostly to demonstrate the capability to share data in this way. Signed-off-by: Christian Schrefl --- samples/rust/rust_misc_device.rs | 117 +++++++++++++++++++++++++++++++++++= +--- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_devi= ce.rs index 779fcfd64119bdd5b4f8be740f7e8336c652b4d3..050910400c6f05024625136a66f= fbeec21d654e8 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -86,6 +86,62 @@ /// return -1; /// } /// +/// value++; +/// +/// // Set shared value to something different +/// printf("Submitting new shared value (%d)\n", value); +/// ret =3D ioctl(fd, RUST_MISC_DEV_SET_SHARED_VALUE, &value); +/// if (ret < 0) { +/// perror("ioctl: Failed to submit new value"); +/// close(fd); +/// return errno; +/// } +/// +/// // Close the device file +/// printf("Closing /dev/rust-misc-device\n"); +/// close(fd); +/// +/// // Open the device file again +/// printf("Opening /dev/rust-misc-device again for reading\n"); +/// fd =3D open("/dev/rust-misc-device", O_RDWR); +/// if (fd < 0) { +/// perror("open"); +/// return errno; +/// } +/// +/// // Ensure new value was applied +/// printf("Fetching new value\n"); +/// ret =3D ioctl(fd, RUST_MISC_DEV_GET_SHARED_VALUE, &new_value); +/// if (ret < 0) { +/// perror("ioctl: Failed to fetch the new value"); +/// close(fd); +/// return errno; +/// } +/// +/// if (value !=3D new_value) { +/// printf("Failed: Committed and retrieved values are different (%d -= %d)\n", +/// value, new_value); +/// close(fd); +/// return -1; +/// } +/// +/// value =3D 0; +/// // Ensure non-shared value is still 0 +/// printf("Fetching new value\n"); +/// ret =3D ioctl(fd, RUST_MISC_DEV_GET_VALUE, &new_value); +/// if (ret < 0) { +/// perror("ioctl: Failed to fetch the new value"); +/// close(fd); +/// return errno; +/// } +/// +/// if (value !=3D new_value) { +/// printf("Failed: Committed and retrieved values are different (%d -= %d)\n", +/// value, new_value); +/// close(fd); +/// return -1; +/// } +/// /// // Close the device file /// printf("Closing /dev/rust-misc-device\n"); /// close(fd); @@ -104,7 +160,7 @@ miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, new_mutex, prelude::*, - sync::Mutex, + sync::{Arc, Mutex}, types::ARef, uaccess::{UserSlice, UserSliceReader, UserSliceWriter}, }; @@ -112,6 +168,8 @@ const RUST_MISC_DEV_HELLO: u32 =3D _IO('|' as u32, 0x80); const RUST_MISC_DEV_GET_VALUE: u32 =3D _IOR::('|' as u32, 0x81); const RUST_MISC_DEV_SET_VALUE: u32 =3D _IOW::('|' as u32, 0x82); +const RUST_MISC_DEV_GET_SHARED_VALUE: u32 =3D _IOR::('|' as u32, 0x83= ); +const RUST_MISC_DEV_SET_SHARED_VALUE: u32 =3D _IOW::('|' as u32, 0x84= ); =20 module! { type: RustMiscDeviceModule, @@ -129,14 +187,17 @@ struct RustMiscDeviceModule { =20 impl kernel::InPlaceModule for RustMiscDeviceModule { fn init(_module: &'static ThisModule) -> impl PinInit { - pr_info!("Initialising Rust Misc Device Sample\n"); + pr_info!("Initializing Rust Misc Device Sample\n"); =20 let options =3D MiscDeviceOptions { name: c_str!("rust-misc-device"), }; =20 try_pin_init!(Self { - _miscdev <- MiscDeviceRegistration::register(options, ()), + _miscdev <- MiscDeviceRegistration::register( + options, + Arc::pin_init(new_mutex!(Inner { value: 0_i32 }), GFP_KERN= EL)? + ), }) } } @@ -147,8 +208,9 @@ struct Inner { =20 #[pin_data(PinnedDrop)] struct RustMiscDevice { + shared: Arc>, #[pin] - inner: Mutex, + unique: Mutex, dev: ARef, } =20 @@ -156,7 +218,7 @@ struct RustMiscDevice { impl MiscDevice for RustMiscDevice { type Ptr =3D Pin>; =20 - type RegistrationData =3D (); + type RegistrationData =3D Arc>; =20 fn open(_file: &File, misc: &MiscDeviceRegistration) -> Result>> { let dev =3D ARef::from(misc.device()); @@ -166,7 +228,8 @@ fn open(_file: &File, misc: &MiscDeviceRegistration) -> Result, _file: &File, cmd: = u32, arg: usize) -> Result match cmd { RUST_MISC_DEV_GET_VALUE =3D> me.get_value(UserSlice::new(arg, = size).writer())?, RUST_MISC_DEV_SET_VALUE =3D> me.set_value(UserSlice::new(arg, = size).reader())?, + RUST_MISC_DEV_GET_SHARED_VALUE =3D> { + me.get_shared_value(UserSlice::new(arg, size).writer())? + } + RUST_MISC_DEV_SET_SHARED_VALUE =3D> { + me.set_shared_value(UserSlice::new(arg, size).reader())? + } RUST_MISC_DEV_HELLO =3D> me.hello()?, _ =3D> { dev_err!(me.dev, "-> IOCTL not recognised: {}\n", cmd); @@ -192,7 +261,6 @@ fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u= 32, arg: usize) -> Result Ok(0) } } - #[pinned_drop] impl PinnedDrop for RustMiscDevice { fn drop(self: Pin<&mut Self>) { @@ -203,7 +271,7 @@ fn drop(self: Pin<&mut Self>) { impl RustMiscDevice { fn set_value(&self, mut reader: UserSliceReader) -> Result { let new_value =3D reader.read::()?; - let mut guard =3D self.inner.lock(); + let mut guard =3D self.unique.lock(); =20 dev_info!( self.dev, @@ -216,7 +284,38 @@ fn set_value(&self, mut reader: UserSliceReader) -> Re= sult { } =20 fn get_value(&self, mut writer: UserSliceWriter) -> Result { - let guard =3D self.inner.lock(); + let guard =3D self.unique.lock(); + let value =3D guard.value; + + // Free-up the lock and use our locally cached instance from here + drop(guard); + + dev_info!( + self.dev, + "-> Copying data to userspace (value: {})\n", + &value + ); + + writer.write::(&value)?; + Ok(0) + } + + fn set_shared_value(&self, mut reader: UserSliceReader) -> Result { + let new_value =3D reader.read::()?; + let mut guard =3D self.shared.lock(); + + dev_info!( + self.dev, + "-> Copying data from userspace (value: {})\n", + new_value + ); + + guard.value =3D new_value; + Ok(0) + } + + fn get_shared_value(&self, mut writer: UserSliceWriter) -> Result { + let guard =3D self.shared.lock(); let value =3D guard.value; =20 // Free-up the lock and use our locally cached instance from here --=20 2.48.1