starnix_core/vfs/
anon_node.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::security;
6use crate::task::{CurrentTask, Kernel};
7use crate::vfs::{
8    CacheMode, FileHandle, FileObject, FileOps, FileSystem, FileSystemHandle, FileSystemOps,
9    FileSystemOptions, FsNode, FsNodeInfo, FsNodeOps, FsStr, FsString, fs_node_impl_not_dir,
10};
11use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked};
12use starnix_types::vfs::default_statfs;
13use starnix_uapi::errors::Errno;
14use starnix_uapi::file_mode::FileMode;
15use starnix_uapi::open_flags::OpenFlags;
16use starnix_uapi::{ANON_INODE_FS_MAGIC, error, statfs};
17
18pub struct Anon {
19    /// If this instance represents an `anon_inode` then `name` holds the type-name of the node,
20    /// e.g. "inotify", "sync_file", "[usereventfd]", etc.
21    name: Option<&'static str>,
22
23    is_private: bool,
24}
25
26impl FsNodeOps for Anon {
27    fs_node_impl_not_dir!();
28
29    fn create_file_ops(
30        &self,
31        _locked: &mut Locked<FileOpsCore>,
32        _node: &FsNode,
33        _current_task: &CurrentTask,
34        _flags: OpenFlags,
35    ) -> Result<Box<dyn FileOps>, Errno> {
36        error!(ENOSYS)
37    }
38
39    fn internal_name(&self, _node: &FsNode) -> Option<FsString> {
40        self.name.map(|name| format!("anon_inode:{}", name).into())
41    }
42}
43
44impl Anon {
45    /// Returns a new `Anon` instance for use in a binder device FD.
46    pub fn new_for_binder_device() -> Self {
47        Self { name: None, is_private: false }
48    }
49
50    /// Returns a new `Anon` instance for use as the `FsNodeOps` of a socket.
51    pub fn new_for_socket(kernel_private: bool) -> Self {
52        Self { name: None, is_private: kernel_private }
53    }
54
55    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
56    pub fn new_file_extended<L>(
57        locked: &mut Locked<L>,
58        current_task: &CurrentTask,
59        ops: Box<dyn FileOps>,
60        flags: OpenFlags,
61        name: &'static str,
62        info: FsNodeInfo,
63    ) -> Result<FileHandle, Errno>
64    where
65        L: LockEqualOrBefore<FileOpsCore>,
66    {
67        let fs = anon_fs(locked, current_task.kernel());
68        let node =
69            fs.create_node_and_allocate_node_id(Anon { name: Some(name), is_private: false }, info);
70        security::fs_node_init_anon(current_task, &node, name)?;
71        Ok(FileObject::new_anonymous(locked, current_task, ops, node, flags))
72    }
73
74    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
75    pub fn new_file<L>(
76        locked: &mut Locked<L>,
77        current_task: &CurrentTask,
78        ops: Box<dyn FileOps>,
79        flags: OpenFlags,
80        name: &'static str,
81    ) -> Result<FileHandle, Errno>
82    where
83        L: LockEqualOrBefore<FileOpsCore>,
84    {
85        Self::new_file_extended(
86            locked,
87            current_task,
88            ops,
89            flags,
90            name,
91            FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred()),
92        )
93    }
94
95    /// Returns a new anonymous file backed by a single "private" `FsNode`, to which no security
96    /// labeling nor access-checks will be applied.
97    pub fn new_private_file<L>(
98        locked: &mut Locked<L>,
99        current_task: &CurrentTask,
100        ops: Box<dyn FileOps>,
101        flags: OpenFlags,
102        name: &'static str,
103    ) -> FileHandle
104    where
105        L: LockEqualOrBefore<FileOpsCore>,
106    {
107        Self::new_private_file_extended(
108            locked,
109            current_task,
110            ops,
111            flags,
112            name,
113            FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred()),
114        )
115    }
116
117    /// Returns a new private anonymous file, applying caller-supplied `info`.
118    pub fn new_private_file_extended<L>(
119        locked: &mut Locked<L>,
120        current_task: &CurrentTask,
121        ops: Box<dyn FileOps>,
122        flags: OpenFlags,
123        name: &'static str,
124        info: FsNodeInfo,
125    ) -> FileHandle
126    where
127        L: LockEqualOrBefore<FileOpsCore>,
128    {
129        let fs = anon_fs(locked, current_task.kernel());
130        let node =
131            fs.create_node_and_allocate_node_id(Anon { name: Some(name), is_private: true }, info);
132        security::fs_node_init_anon(current_task, &node, name)
133            .expect("Private anon_inode creation cannot fail");
134        FileObject::new_anonymous(locked, current_task, ops, node, flags)
135    }
136
137    /// Returns true if the `fs_node` is `Anon` and private to the `Kernel`/`FileSystem`, in which
138    /// case it should not have access checks applied by the LSM layer.
139    /// This may become part of `FsNodeOps` in future, if other private node use-cases are found.
140    pub fn is_private(fs_node: &FsNode) -> bool {
141        fs_node.downcast_ops::<Anon>().map(|anon| anon.is_private).unwrap_or(false)
142    }
143}
144
145struct AnonFs;
146impl FileSystemOps for AnonFs {
147    fn statfs(
148        &self,
149        _locked: &mut Locked<FileOpsCore>,
150        _fs: &FileSystem,
151        _current_task: &CurrentTask,
152    ) -> Result<statfs, Errno> {
153        Ok(default_statfs(ANON_INODE_FS_MAGIC))
154    }
155    fn name(&self) -> &'static FsStr {
156        "anon_inodefs".into()
157    }
158}
159pub fn anon_fs<L>(locked: &mut Locked<L>, kernel: &Kernel) -> FileSystemHandle
160where
161    L: LockEqualOrBefore<FileOpsCore>,
162{
163    struct AnonFsHandle(FileSystemHandle);
164
165    kernel
166        .expando
167        .get_or_init(|| {
168            let fs = FileSystem::new(
169                locked,
170                kernel,
171                CacheMode::Uncached,
172                AnonFs,
173                FileSystemOptions::default(),
174            )
175            .expect("anonfs constructed with valid options");
176            AnonFsHandle(fs)
177        })
178        .0
179        .clone()
180}