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