starnix_modules_binderfs/
fs.rs1use crate::binder::BinderDevice;
6use crate::remote_binder::RemoteBinderDevice;
7use starnix_core::device::DeviceOps;
8use starnix_core::mm::MemoryAccessorExt;
9use starnix_core::task::{CurrentTask, Kernel};
10use starnix_core::vfs::pseudo::simple_file::BytesFile;
11use starnix_core::vfs::pseudo::vec_directory::{VecDirectory, VecDirectoryEntry};
12use starnix_core::vfs::{
13 CacheMode, DirEntry, DirectoryEntryType, FileObject, FileOps, FileSystem, FileSystemHandle,
14 FileSystemOps, FileSystemOptions, FsNode, FsNodeHandle, FsNodeInfo, FsNodeOps, FsStr, FsString,
15 NamespaceNode, SpecialNode, fileops_impl_dataless, fileops_impl_nonseekable,
16 fileops_impl_noop_sync, fs_node_impl_dir_readonly,
17};
18use starnix_sync::{BinderFsDevicesLevel, LockDepMutex};
19use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
20use starnix_types::vfs::default_statfs;
21use starnix_uapi::auth::FsCred;
22use starnix_uapi::device_id::DeviceId;
23use starnix_uapi::errors::{Errno, error};
24use starnix_uapi::file_mode::mode;
25use starnix_uapi::open_flags::OpenFlags;
26use starnix_uapi::user_address::{UserAddress, UserRef};
27use starnix_uapi::{BINDERFS_SUPER_MAGIC, statfs, uapi};
28use std::collections::BTreeMap;
29use std::collections::btree_map::Entry;
30use std::sync::Arc;
31
32pub struct BinderFs;
33impl FileSystemOps for BinderFs {
34 fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
35 Ok(default_statfs(BINDERFS_SUPER_MAGIC))
36 }
37 fn name(&self) -> &'static FsStr {
38 "binder".into()
39 }
40}
41
42const DEFAULT_BINDERS: [&str; 3] = ["binder", "hwbinder", "vndbinder"];
43const FEATURES_DIR: &str = "features";
44const BINDER_CONTROL_DEVICE: &str = "binder-control";
45const RESERVED_NAMES: [&str; 2] = [FEATURES_DIR, BINDER_CONTROL_DEVICE];
47
48#[derive(Debug)]
49pub struct BinderFsDir {
50 control_device: DeviceId,
51 state: Arc<BinderFsState>,
52}
53
54#[derive(Debug)]
55pub struct BinderFsState {
56 devices: LockDepMutex<BTreeMap<FsString, DeviceId>, BinderFsDevicesLevel>,
57}
58
59impl BinderFsDir {
60 pub fn new(kernel: &Kernel) -> Result<Self, Errno> {
61 let registry = &kernel.device_registry;
62 let mut devices = BTreeMap::<FsString, DeviceId>::default();
63 let remote_device =
64 registry.register_silent_dyn_device("remote-binder".into(), RemoteBinderDevice {})?;
65 devices.insert("remote".into(), remote_device.devt);
66
67 for name in DEFAULT_BINDERS {
68 let device_metadata =
69 registry.register_silent_dyn_device(name.into(), BinderDevice::default())?;
70 devices.insert(name.into(), device_metadata.devt);
71 }
72 let state = Arc::new(BinderFsState { devices: devices.into() });
73
74 let control_device = registry
75 .register_silent_dyn_device(
76 BINDER_CONTROL_DEVICE.into(),
77 BinderControlDevice { state: state.clone() },
78 )?
79 .devt;
80
81 Ok(Self { control_device, state })
82 }
83}
84
85impl FsNodeOps for BinderFsDir {
86 fs_node_impl_dir_readonly!();
87
88 fn create_file_ops(
89 &self,
90 _node: &FsNode,
91 _current_task: &CurrentTask,
92 _flags: OpenFlags,
93 ) -> Result<Box<dyn FileOps>, Errno> {
94 let mut entries = self
95 .state
96 .devices
97 .lock()
98 .keys()
99 .map(|name| VecDirectoryEntry {
100 entry_type: DirectoryEntryType::CHR,
101 name: name.clone(),
102 inode: None,
103 })
104 .collect::<Vec<_>>();
105 entries.push(VecDirectoryEntry {
106 entry_type: DirectoryEntryType::DIR,
107 name: FEATURES_DIR.into(),
108 inode: None,
109 });
110 entries.push(VecDirectoryEntry {
111 entry_type: DirectoryEntryType::CHR,
112 name: BINDER_CONTROL_DEVICE.into(),
113 inode: None,
114 });
115 Ok(VecDirectory::new_file(entries))
116 }
117
118 fn lookup(
119 &self,
120 node: &FsNode,
121 _current_task: &CurrentTask,
122 name: &FsStr,
123 ) -> Result<FsNodeHandle, Errno> {
124 if name == FEATURES_DIR {
125 Ok(node.fs().create_node_and_allocate_node_id(
126 BinderFeaturesDir::new(),
127 FsNodeInfo::new(mode!(IFDIR, 0o755), FsCred::root()),
128 ))
129 } else if name == BINDER_CONTROL_DEVICE {
130 let mut info = FsNodeInfo::new(mode!(IFCHR, 0o600), FsCred::root());
131 info.rdev = self.control_device;
132 Ok(node.fs().create_node_and_allocate_node_id(SpecialNode, info))
133 } else if let Some(dev) = self.state.devices.lock().get(name) {
134 let mode = if name == "remote" { mode!(IFCHR, 0o444) } else { mode!(IFCHR, 0o600) };
135 let mut info = FsNodeInfo::new(mode, FsCred::root());
136 info.rdev = *dev;
137 Ok(node.fs().create_node_and_allocate_node_id(SpecialNode, info))
138 } else {
139 error!(ENOENT, format!("looking for {name}"))
140 }
141 }
142}
143
144impl BinderFs {
145 pub fn new_fs(
146 current_task: &CurrentTask,
147 options: FileSystemOptions,
148 ) -> Result<FileSystemHandle, Errno> {
149 let kernel = current_task.kernel();
150 let fs = FileSystem::new(kernel, CacheMode::Permanent, BinderFs, options)?;
151 let ops = BinderFsDir::new(kernel)?;
152 let root_ino = fs.allocate_ino();
153 fs.create_root(root_ino, ops);
154 Ok(fs)
155 }
156}
157
158#[derive(Clone)]
159struct BinderControlDevice {
160 state: Arc<BinderFsState>,
161}
162
163impl DeviceOps for BinderControlDevice {
164 fn open(
165 &self,
166 _current_task: &CurrentTask,
167 _devt: DeviceId,
168 _node: &NamespaceNode,
169 _flags: OpenFlags,
170 ) -> Result<Box<dyn FileOps>, Errno> {
171 Ok(Box::new(self.clone()))
172 }
173}
174
175impl FileOps for BinderControlDevice {
176 fileops_impl_dataless!();
177 fileops_impl_nonseekable!();
178 fileops_impl_noop_sync!();
179
180 fn ioctl(
181 &self,
182 _file: &FileObject,
183 current_task: &CurrentTask,
184 request: u32,
185 arg: SyscallArg,
186 ) -> Result<SyscallResult, Errno> {
187 if request == uapi::BINDER_CTL_ADD {
188 let user_arg = UserAddress::from(arg);
189 if user_arg.is_null() {
190 return error!(EINVAL);
191 }
192 let user_ref = UserRef::<uapi::binderfs_device>::new(user_arg);
193 let mut request = current_task.read_object(user_ref)?;
194 let name: Vec<u8> =
195 request.name.iter().copied().map(|x| x as u8).take_while(|x| *x != 0).collect();
196 if DirEntry::is_reserved_name((*name).into()) {
198 return error!(EACCES);
199 }
200 if name.contains(&('/' as u8)) {
201 return error!(EACCES);
202 }
203 for reserved_name in RESERVED_NAMES {
205 if *name == *reserved_name.as_bytes() {
206 return error!(EEXIST);
207 }
208 }
209 let mut devices = self.state.devices.lock();
210 match devices.entry(FsString::from(name.clone())) {
211 Entry::Occupied(_) => error!(EEXIST),
212 Entry::Vacant(entry) => {
213 let kernel = current_task.kernel();
214 let device_metadata = kernel
215 .device_registry
216 .register_silent_dyn_device((*name).into(), BinderDevice::default())?;
217 entry.insert(device_metadata.devt);
218 request.major = device_metadata.devt.major();
219 request.minor = device_metadata.devt.minor();
220 current_task.write_object(user_ref, &request)?;
221 Ok(SUCCESS)
222 }
223 }
224 } else {
225 error!(EINVAL)
226 }
227 }
228}
229
230struct BinderFeaturesDir {
231 features: BTreeMap<FsString, bool>,
232}
233
234impl BinderFeaturesDir {
235 fn new() -> Self {
236 Self { features: BTreeMap::from([("freeze_notification".into(), true)]) }
237 }
238}
239
240impl FsNodeOps for BinderFeaturesDir {
241 fs_node_impl_dir_readonly!();
242
243 fn create_file_ops(
244 &self,
245 _node: &FsNode,
246 _current_task: &CurrentTask,
247 _flags: OpenFlags,
248 ) -> Result<Box<dyn FileOps>, Errno> {
249 let entries = self
250 .features
251 .keys()
252 .map(|name| VecDirectoryEntry {
253 entry_type: DirectoryEntryType::REG,
254 name: name.clone(),
255 inode: None,
256 })
257 .collect::<Vec<_>>();
258 Ok(VecDirectory::new_file(entries))
259 }
260
261 fn lookup(
262 &self,
263 node: &FsNode,
264 _current_task: &CurrentTask,
265 name: &FsStr,
266 ) -> Result<FsNodeHandle, Errno> {
267 if let Some(enable) = self.features.get(name) {
268 return Ok(node.fs().create_node_and_allocate_node_id(
269 BytesFile::new_node(if *enable { b"1\n" } else { b"0\n" }.to_vec()),
270 FsNodeInfo::new(mode!(IFREG, 0o444), FsCred::root()),
271 ));
272 }
273 error!(ENOENT, format!("looking for {name}"))
274 }
275}