Skip to main content

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, DirEntry, FileHandle, FileObject, FileOps, FileSystem, FileSystemHandle,
9    FileSystemOps, FileSystemOptions, FsNode, FsNodeFlags, FsNodeHandle, FsNodeInfo, FsNodeOps,
10    FsStr, NamespaceNode, fs_node_impl_not_dir,
11};
12use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked};
13use starnix_types::vfs::default_statfs;
14use starnix_uapi::auth::FsCred;
15use starnix_uapi::errors::Errno;
16use starnix_uapi::file_mode::FileMode;
17use starnix_uapi::open_flags::OpenFlags;
18use starnix_uapi::{ANON_INODE_FS_MAGIC, error, statfs};
19
20pub struct Anon {}
21
22impl FsNodeOps for Anon {
23    fs_node_impl_not_dir!();
24
25    fn create_file_ops(
26        &self,
27        _locked: &mut Locked<FileOpsCore>,
28        _node: &FsNode,
29        _current_task: &CurrentTask,
30        _flags: OpenFlags,
31    ) -> Result<Box<dyn FileOps>, Errno> {
32        error!(ENOSYS)
33    }
34}
35
36impl Anon {
37    /// Returns a new `Anon` instance for use in a binder device FD.
38    pub fn new_for_binder_device() -> Self {
39        Self {}
40    }
41
42    /// Returns a new `Anon` instance for use as the `FsNodeOps` of a socket.
43    pub fn new_for_socket() -> Self {
44        Self {}
45    }
46
47    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
48    pub fn new_file_extended<L>(
49        locked: &mut Locked<L>,
50        current_task: &CurrentTask,
51        ops: Box<dyn FileOps>,
52        flags: OpenFlags,
53        name: &'static str,
54        info: FsNodeInfo,
55    ) -> Result<FileHandle, Errno>
56    where
57        L: LockEqualOrBefore<FileOpsCore>,
58    {
59        Self::new_file_internal(locked, current_task, ops, flags, name, info, FsNodeFlags::empty())
60    }
61
62    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
63    pub fn new_file<L>(
64        locked: &mut Locked<L>,
65        current_task: &CurrentTask,
66        ops: Box<dyn FileOps>,
67        flags: OpenFlags,
68        name: &'static str,
69    ) -> Result<FileHandle, Errno>
70    where
71        L: LockEqualOrBefore<FileOpsCore>,
72    {
73        Self::new_file_extended(
74            locked,
75            current_task,
76            ops,
77            flags,
78            name,
79            FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred()),
80        )
81    }
82
83    /// Returns a new anonymous file backed by a single "private" `FsNode`, to which no security
84    /// labeling nor access-checks will be applied.
85    pub fn new_private_file<L>(
86        locked: &mut Locked<L>,
87        current_task: &CurrentTask,
88        ops: Box<dyn FileOps>,
89        flags: OpenFlags,
90        name: &'static str,
91    ) -> FileHandle
92    where
93        L: LockEqualOrBefore<FileOpsCore>,
94    {
95        let node = shared_private_node(locked, current_task);
96        security::fs_node_init_anon(current_task, &node, name)
97            .expect("Private anon_inode creation cannot fail");
98        let name = NamespaceNode::new_anonymous(DirEntry::new(node, None, name.into()));
99        FileObject::new(locked, current_task, ops, name, flags).unwrap()
100    }
101
102    /// Returns a new private anonymous file, applying caller-supplied `info`.
103    // TODO: https://fxbug.dev/407611229 - Migrate callers off this and remove it.
104    pub fn new_private_file_extended<L>(
105        locked: &mut Locked<L>,
106        current_task: &CurrentTask,
107        ops: Box<dyn FileOps>,
108        flags: OpenFlags,
109        name: &'static str,
110        info: FsNodeInfo,
111    ) -> FileHandle
112    where
113        L: LockEqualOrBefore<FileOpsCore>,
114    {
115        Self::new_file_internal(
116            locked,
117            current_task,
118            ops,
119            flags,
120            name,
121            info,
122            FsNodeFlags::IS_PRIVATE,
123        )
124        .expect("Private anon_inode creation cannot fail")
125    }
126
127    fn new_file_internal<L>(
128        locked: &mut Locked<L>,
129        current_task: &CurrentTask,
130        ops: Box<dyn FileOps>,
131        flags: OpenFlags,
132        name: &'static str,
133        info: FsNodeInfo,
134        node_flags: FsNodeFlags,
135    ) -> Result<FileHandle, Errno>
136    where
137        L: LockEqualOrBefore<FileOpsCore>,
138    {
139        let fs = anon_fs(locked, current_task.kernel());
140        let node = fs.create_node_with_flags(None, Anon {}, info, node_flags);
141        security::fs_node_init_anon(current_task, &node, name)?;
142        let name = NamespaceNode::new_anonymous(DirEntry::new(node, None, name.into()));
143        FileObject::new(locked, current_task, ops, name, flags)
144    }
145}
146
147struct AnonFs;
148impl FileSystemOps for AnonFs {
149    fn statfs(
150        &self,
151        _locked: &mut Locked<FileOpsCore>,
152        _fs: &FileSystem,
153        _current_task: &CurrentTask,
154    ) -> Result<statfs, Errno> {
155        Ok(default_statfs(ANON_INODE_FS_MAGIC))
156    }
157    fn name(&self) -> &'static FsStr {
158        "anon_inodefs".into()
159    }
160}
161
162pub fn anon_fs<L>(locked: &mut Locked<L>, kernel: &Kernel) -> FileSystemHandle
163where
164    L: LockEqualOrBefore<FileOpsCore>,
165{
166    struct AnonFsHandle(FileSystemHandle);
167
168    kernel
169        .expando
170        .get_or_init(|| {
171            let fs = FileSystem::new(
172                locked,
173                kernel,
174                CacheMode::Uncached,
175                AnonFs,
176                FileSystemOptions::default(),
177            )
178            .expect("anonfs constructed with valid options");
179            AnonFsHandle(fs)
180        })
181        .0
182        .clone()
183}
184
185fn shared_private_node<L>(locked: &mut Locked<L>, current_task: &CurrentTask) -> FsNodeHandle
186where
187    L: LockEqualOrBefore<FileOpsCore>,
188{
189    struct CommonAnonFsNodeHandle(FsNodeHandle);
190
191    let fs = anon_fs(locked, current_task.kernel());
192
193    current_task
194        .kernel()
195        .expando
196        .get_or_init(|| {
197            let info = FsNodeInfo::new(FileMode::from_bits(0o600), FsCred::root());
198            let node = fs.create_node_with_flags(None, Anon {}, info, FsNodeFlags::IS_PRIVATE);
199            CommonAnonFsNodeHandle(node)
200        })
201        .0
202        .clone()
203}