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