summaryrefslogtreecommitdiffstats
path: root/rust/syn/restriction.rs
diff options
context:
space:
mode:
authorShivank Garg <shivankg@amd.com>2026-08-22 19:22:05 +0000
committerVinod Koul <vkoul@kernel.org>2026-09-09 17:51:44 +0530
commite873c74132f0c5f1452816cd9bb26208f0bba1e1 (patch)
treecc1ce1567f5b982359331863ebd9da38741f8d2e /rust/syn/restriction.rs
downloadlinux-stable-e873c74132f0c5f1452816cd9bb26208f0bba1e1.tar.gz
linux-stable-e873c74132f0c5f1452816cd9bb26208f0bba1e1.zip
dmaengine: fix use-after-free in dma_chan_put() and dma_release_channel()grafted
When dma_device_put() drops the last reference on chan->device->ref, dma_device_release() runs and may free the dma_device along with its channels. dma_chan_put() then still reads chan->device->owner via dma_chan_to_owner() for the trailing module_put(). KASAN catches it: slab-use-after-free in dma_chan_put+0x3e6/0x4c0 Read of size 8 by task insmod/6319 Freed by task 6319: kfree+0x225/0x470 dma_chan_put+0x395/0x4c0 dmaengine_put+0xf8/0x160 Cache the module owner in dma_chan_put() before the put so the trailing module_put() does not need chan->device. Fixes: 8ad342a86359 ("dmaengine: Add reference counting to dma_device struct") Suggested-by: Sashiko <sashiko-bot@kernel.org> Link: https://sashiko.dev/#/patchset/20260518-dmaengine-kref-fix-v1-1-4d6125048fb7@amd.com Reviewed-by: Frank Li <Frank.Li@nxp.com> Reviewed-by: Logan Gunthorpe <logang@deltatee.com> Signed-off-by: Shivank Garg <shivankg@amd.com> Link: https://patch.msgid.link/20260822-dmaengine-kref-fix-v5-3-d4a4ee47d927@amd.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'rust/syn/restriction.rs')
-rw-r--r--rust/syn/restriction.rs180
1 files changed, 180 insertions, 0 deletions
diff --git a/rust/syn/restriction.rs b/rust/syn/restriction.rs
new file mode 100644
index 000000000..b844f64c3
--- /dev/null
+++ b/rust/syn/restriction.rs
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+use crate::path::Path;
+use crate::token;
+
+ast_enum! {
+ /// The visibility level of an item: inherited or `pub` or
+ /// `pub(restricted)`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+ pub enum Visibility {
+ /// A public visibility level: `pub`.
+ Public(Token![pub]),
+
+ /// A visibility level restricted to some path: `pub(self)` or
+ /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
+ Restricted(VisRestricted),
+
+ /// An inherited visibility, which usually means private.
+ Inherited,
+ }
+}
+
+ast_struct! {
+ /// A visibility level restricted to some path: `pub(self)` or
+ /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+ pub struct VisRestricted {
+ pub pub_token: Token![pub],
+ pub paren_token: token::Paren,
+ pub in_token: Option<Token![in]>,
+ pub path: Box<Path>,
+ }
+}
+
+ast_enum! {
+ /// Unused, but reserved for RFC 3323 restrictions.
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
+ #[non_exhaustive]
+ pub enum FieldMutability {
+ None,
+
+ // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html
+ //
+ // FieldMutability::Restricted(MutRestricted)
+ //
+ // pub struct MutRestricted {
+ // pub mut_token: Token![mut],
+ // pub paren_token: token::Paren,
+ // pub in_token: Option<Token![in]>,
+ // pub path: Box<Path>,
+ // }
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub(crate) mod parsing {
+ use crate::error::Result;
+ use crate::ext::IdentExt as _;
+ use crate::ident::Ident;
+ use crate::parse::discouraged::Speculative as _;
+ use crate::parse::{Parse, ParseStream};
+ use crate::path::Path;
+ use crate::restriction::{VisRestricted, Visibility};
+ use crate::token;
+
+ #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
+ impl Parse for Visibility {
+ fn parse(input: ParseStream) -> Result<Self> {
+ // Recognize an empty None-delimited group, as produced by a $:vis
+ // matcher that matched no tokens.
+ if input.peek(token::Group) {
+ let ahead = input.fork();
+ let group = crate::group::parse_group(&ahead)?;
+ if group.content.is_empty() {
+ input.advance_to(&ahead);
+ return Ok(Visibility::Inherited);
+ }
+ }
+
+ if input.peek(Token![pub]) {
+ Self::parse_pub(input)
+ } else {
+ Ok(Visibility::Inherited)
+ }
+ }
+ }
+
+ impl Visibility {
+ fn parse_pub(input: ParseStream) -> Result<Self> {
+ let pub_token = input.parse::<Token![pub]>()?;
+
+ if input.peek(token::Paren) {
+ let ahead = input.fork();
+
+ let content;
+ let paren_token = parenthesized!(content in ahead);
+ if content.peek(Token![crate])
+ || content.peek(Token![self])
+ || content.peek(Token![super])
+ {
+ let path = content.call(Ident::parse_any)?;
+
+ // Ensure there are no additional tokens within `content`.
+ // Without explicitly checking, we may misinterpret a tuple
+ // field as a restricted visibility, causing a parse error.
+ // e.g. `pub (crate::A, crate::B)` (Issue #720).
+ if content.is_empty() {
+ input.advance_to(&ahead);
+ return Ok(Visibility::Restricted(VisRestricted {
+ pub_token,
+ paren_token,
+ in_token: None,
+ path: Box::new(Path::from(path)),
+ }));
+ }
+ } else if content.peek(Token![in]) {
+ let in_token: Token![in] = content.parse()?;
+ let path = content.call(Path::parse_mod_style)?;
+
+ input.advance_to(&ahead);
+ return Ok(Visibility::Restricted(VisRestricted {
+ pub_token,
+ paren_token,
+ in_token: Some(in_token),
+ path: Box::new(path),
+ }));
+ }
+ }
+
+ Ok(Visibility::Public(pub_token))
+ }
+
+ #[cfg(feature = "full")]
+ pub(crate) fn is_some(&self) -> bool {
+ match self {
+ Visibility::Inherited => false,
+ _ => true,
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use crate::path;
+ use crate::path::printing::PathStyle;
+ use crate::restriction::{VisRestricted, Visibility};
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
+ impl ToTokens for Visibility {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Visibility::Public(pub_token) => pub_token.to_tokens(tokens),
+ Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens),
+ Visibility::Inherited => {}
+ }
+ }
+ }
+
+ #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
+ impl ToTokens for VisRestricted {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pub_token.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ // TODO: If we have a path which is not "self" or "super" or
+ // "crate", automatically add the "in" token.
+ self.in_token.to_tokens(tokens);
+ path::printing::print_path(tokens, &self.path, PathStyle::Mod);
+ });
+ }
+ }
+}