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        let fs = anon_fs(current_task.kernel());
54        let node = fs.create_node_with_flags(None, Anon {}, info, FsNodeFlags::empty());
55        security::fs_node_init_anon(current_task, &node, name)?;
56        let name = NamespaceNode::new_anonymous(DirEntry::new(node, None, name.into()));
57        FileObject::new(current_task, ops, name, flags)
58    }
59
60    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
61    pub fn new_file(
62        current_task: &CurrentTask,
63        ops: Box<dyn FileOps>,
64        flags: OpenFlags,
65        name: &'static str,
66    ) -> Result<FileHandle, Errno> {
67        Self::new_file_extended(
68            current_task,
69            ops,
70            flags,
71            name,
72            FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred()),
73        )
74    }
75
76    /// Returns a new anonymous file backed by a single "private" `FsNode`, to which no security
77    /// labeling nor access-checks will be applied.
78    pub fn new_private_file(
79        current_task: &CurrentTask,
80        ops: Box<dyn FileOps>,
81        flags: OpenFlags,
82        name: &'static str,
83    ) -> FileHandle {
84        let node = shared_private_node(current_task);
85        security::fs_node_init_anon(current_task, &node, name)
86            .expect("Private anon_inode creation cannot fail");
87        let name = NamespaceNode::new_anonymous(DirEntry::new(node, None, name.into()));
88        FileObject::new(current_task, ops, name, flags).unwrap()
89    }
90}
91
92struct AnonFs;
93impl FileSystemOps for AnonFs {
94    fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
95        Ok(default_statfs(ANON_INODE_FS_MAGIC))
96    }
97    fn name(&self) -> &'static FsStr {
98        "anon_inodefs".into()
99    }
100}
101
102pub fn anon_fs(kernel: &Kernel) -> FileSystemHandle {
103    struct AnonFsHandle(FileSystemHandle);
104
105    kernel
106        .expando
107        .get_or_init(|| {
108            let fs =
109                FileSystem::new(kernel, CacheMode::Uncached, AnonFs, FileSystemOptions::default())
110                    .expect("anonfs constructed with valid options");
111            AnonFsHandle(fs)
112        })
113        .0
114        .clone()
115}
116
117fn shared_private_node(current_task: &CurrentTask) -> FsNodeHandle {
118    struct CommonAnonFsNodeHandle(FsNodeHandle);
119
120    let fs = anon_fs(current_task.kernel());
121
122    current_task
123        .kernel()
124        .expando
125        .get_or_init(|| {
126            let info = FsNodeInfo::new(FileMode::from_bits(0o600), FsCred::root());
127            let node = fs.create_node_with_flags(None, Anon {}, info, FsNodeFlags::IS_PRIVATE);
128            CommonAnonFsNodeHandle(node)
129        })
130        .0
131        .clone()
132}