blob: 92be504ee2adc095e5b01493c379adc487f03a26 [file] [log] [blame]
Victor Hsiehb0f5fc82021-10-15 17:24:19 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use anyhow::Result;
18use log::error;
Victor Hsieh45636232021-10-15 17:52:51 -070019use nix::{
20 dir::Dir, errno::Errno, fcntl::openat, fcntl::OFlag, sys::stat::mkdirat, sys::stat::Mode,
Victor Hsiehf7fc3d32021-11-22 10:20:33 -080021 sys::statvfs::statvfs, sys::statvfs::Statvfs,
Victor Hsieh45636232021-10-15 17:52:51 -070022};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070023use std::cmp::min;
Victor Hsieh45636232021-10-15 17:52:51 -070024use std::collections::{btree_map, BTreeMap};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070025use std::convert::TryInto;
26use std::fs::File;
27use std::io;
28use std::os::unix::fs::FileExt;
Victor Hsieh559b9272021-11-08 15:15:14 -080029use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
30use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
Victor Hsieh45636232021-10-15 17:52:51 -070031use std::sync::{Arc, Mutex};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070032
33use crate::fsverity;
34use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::{
Victor Hsiehf7fc3d32021-11-22 10:20:33 -080035 BnVirtFdService, FsStat::FsStat, IVirtFdService, MAX_REQUESTING_DATA,
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070036};
37use authfs_aidl_interface::binder::{
Victor Hsieh45636232021-10-15 17:52:51 -070038 BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, StatusCode, Strong,
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070039};
Victor Hsieh45636232021-10-15 17:52:51 -070040use binder_common::{new_binder_exception, new_binder_service_specific_error};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070041
42fn validate_and_cast_offset(offset: i64) -> Result<u64, Status> {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070043 offset.try_into().map_err(|_| new_errno_error(Errno::EINVAL))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070044}
45
46fn validate_and_cast_size(size: i32) -> Result<usize, Status> {
47 if size > MAX_REQUESTING_DATA {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070048 Err(new_errno_error(Errno::EFBIG))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070049 } else {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070050 size.try_into().map_err(|_| new_errno_error(Errno::EINVAL))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070051 }
52}
53
54/// Configuration of a file descriptor to be served/exposed/shared.
55pub enum FdConfig {
56 /// A read-only file to serve by this server. The file is supposed to be verifiable with the
57 /// associated fs-verity metadata.
58 Readonly {
59 /// The file to read from. fs-verity metadata can be retrieved from this file's FD.
60 file: File,
61
62 /// Alternative Merkle tree stored in another file.
Victor Hsieh559b9272021-11-08 15:15:14 -080063 /// TODO(205987437): Replace with .fsv_meta file.
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070064 alt_merkle_tree: Option<File>,
65
66 /// Alternative signature stored in another file.
Victor Hsieh559b9272021-11-08 15:15:14 -080067 /// TODO(205987437): Replace with .fsv_meta file.
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070068 alt_signature: Option<File>,
69 },
70
71 /// A readable/writable file to serve by this server. This backing file should just be a
72 /// regular file and does not have any specific property.
73 ReadWrite(File),
Victor Hsieh45636232021-10-15 17:52:51 -070074
Victor Hsieh559b9272021-11-08 15:15:14 -080075 /// A read-only directory to serve by this server.
76 InputDir(Dir),
77
Victor Hsieh45636232021-10-15 17:52:51 -070078 /// A writable directory to serve by this server.
79 OutputDir(Dir),
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070080}
81
82pub struct FdService {
Victor Hsieh45636232021-10-15 17:52:51 -070083 /// A pool of opened files and directories, which can be looked up by the FD number.
84 fd_pool: Arc<Mutex<BTreeMap<i32, FdConfig>>>,
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070085}
86
87impl FdService {
88 pub fn new_binder(fd_pool: BTreeMap<i32, FdConfig>) -> Strong<dyn IVirtFdService> {
Victor Hsieh45636232021-10-15 17:52:51 -070089 BnVirtFdService::new_binder(
90 FdService { fd_pool: Arc::new(Mutex::new(fd_pool)) },
91 BinderFeatures::default(),
92 )
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070093 }
94
Victor Hsieh45636232021-10-15 17:52:51 -070095 /// Handles the requesting file `id` with `handle_fn` if it is in the FD pool. This function
96 /// returns whatever `handle_fn` returns.
97 fn handle_fd<F, R>(&self, id: i32, handle_fn: F) -> BinderResult<R>
Victor Hsiehc85e4ef2021-10-18 15:28:53 -070098 where
99 F: FnOnce(&FdConfig) -> BinderResult<R>,
100 {
Victor Hsieh45636232021-10-15 17:52:51 -0700101 let fd_pool = self.fd_pool.lock().unwrap();
102 let fd_config = fd_pool.get(&id).ok_or_else(|| new_errno_error(Errno::EBADF))?;
103 handle_fn(fd_config)
104 }
105
106 /// Inserts a new FD and corresponding `FdConfig` created by `create_fn` to the FD pool, then
107 /// returns the new FD number.
108 fn insert_new_fd<F>(&self, fd: i32, create_fn: F) -> BinderResult<i32>
109 where
110 F: FnOnce(&mut FdConfig) -> BinderResult<(i32, FdConfig)>,
111 {
112 let mut fd_pool = self.fd_pool.lock().unwrap();
113 let mut fd_config = fd_pool.get_mut(&fd).ok_or_else(|| new_errno_error(Errno::EBADF))?;
114 let (new_fd, new_fd_config) = create_fn(&mut fd_config)?;
115 if let btree_map::Entry::Vacant(entry) = fd_pool.entry(new_fd) {
116 entry.insert(new_fd_config);
117 Ok(new_fd)
118 } else {
119 Err(new_binder_exception(
120 ExceptionCode::ILLEGAL_STATE,
121 format!("The newly created FD {} is already in the pool unexpectedly", new_fd),
122 ))
123 }
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700124 }
125}
126
127impl Interface for FdService {}
128
129impl IVirtFdService for FdService {
130 fn readFile(&self, id: i32, offset: i64, size: i32) -> BinderResult<Vec<u8>> {
131 let size: usize = validate_and_cast_size(size)?;
132 let offset: u64 = validate_and_cast_offset(offset)?;
133
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700134 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700135 FdConfig::Readonly { file, .. } | FdConfig::ReadWrite(file) => {
136 read_into_buf(file, size, offset).map_err(|e| {
137 error!("readFile: read error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700138 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700139 })
140 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800141 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700142 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700143 }
144
145 fn readFsverityMerkleTree(&self, id: i32, offset: i64, size: i32) -> BinderResult<Vec<u8>> {
146 let size: usize = validate_and_cast_size(size)?;
147 let offset: u64 = validate_and_cast_offset(offset)?;
148
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700149 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700150 FdConfig::Readonly { file, alt_merkle_tree, .. } => {
151 if let Some(tree_file) = &alt_merkle_tree {
152 read_into_buf(tree_file, size, offset).map_err(|e| {
153 error!("readFsverityMerkleTree: read error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700154 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700155 })
156 } else {
157 let mut buf = vec![0; size];
158 let s = fsverity::read_merkle_tree(file.as_raw_fd(), offset, &mut buf)
159 .map_err(|e| {
160 error!("readFsverityMerkleTree: failed to retrieve merkle tree: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700161 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700162 })?;
163 debug_assert!(s <= buf.len(), "Shouldn't return more bytes than asked");
164 buf.truncate(s);
165 Ok(buf)
166 }
167 }
168 FdConfig::ReadWrite(_file) => {
169 // For a writable file, Merkle tree is not expected to be served since Auth FS
170 // doesn't trust it anyway. Auth FS may keep the Merkle tree privately for its own
171 // use.
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700172 Err(new_errno_error(Errno::ENOSYS))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700173 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800174 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700175 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700176 }
177
178 fn readFsveritySignature(&self, id: i32) -> BinderResult<Vec<u8>> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700179 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700180 FdConfig::Readonly { file, alt_signature, .. } => {
181 if let Some(sig_file) = &alt_signature {
182 // Supposedly big enough buffer size to store signature.
183 let size = MAX_REQUESTING_DATA as usize;
184 let offset = 0;
185 read_into_buf(sig_file, size, offset).map_err(|e| {
186 error!("readFsveritySignature: read error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700187 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700188 })
189 } else {
190 let mut buf = vec![0; MAX_REQUESTING_DATA as usize];
191 let s = fsverity::read_signature(file.as_raw_fd(), &mut buf).map_err(|e| {
192 error!("readFsverityMerkleTree: failed to retrieve merkle tree: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700193 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700194 })?;
195 debug_assert!(s <= buf.len(), "Shouldn't return more bytes than asked");
196 buf.truncate(s);
197 Ok(buf)
198 }
199 }
200 FdConfig::ReadWrite(_file) => {
201 // There is no signature for a writable file.
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700202 Err(new_errno_error(Errno::ENOSYS))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700203 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800204 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700205 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700206 }
207
208 fn writeFile(&self, id: i32, buf: &[u8], offset: i64) -> BinderResult<i32> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700209 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700210 FdConfig::Readonly { .. } => Err(StatusCode::INVALID_OPERATION.into()),
211 FdConfig::ReadWrite(file) => {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700212 let offset: u64 = offset.try_into().map_err(|_| new_errno_error(Errno::EINVAL))?;
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700213 // Check buffer size just to make `as i32` safe below.
214 if buf.len() > i32::MAX as usize {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700215 return Err(new_errno_error(Errno::EOVERFLOW));
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700216 }
217 Ok(file.write_at(buf, offset).map_err(|e| {
218 error!("writeFile: write error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700219 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700220 })? as i32)
221 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800222 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700223 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700224 }
225
226 fn resize(&self, id: i32, size: i64) -> BinderResult<()> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700227 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700228 FdConfig::Readonly { .. } => Err(StatusCode::INVALID_OPERATION.into()),
229 FdConfig::ReadWrite(file) => {
230 if size < 0 {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700231 return Err(new_errno_error(Errno::EINVAL));
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700232 }
233 file.set_len(size as u64).map_err(|e| {
234 error!("resize: set_len error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700235 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700236 })
237 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800238 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700239 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700240 }
241
242 fn getFileSize(&self, id: i32) -> BinderResult<i64> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700243 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700244 FdConfig::Readonly { file, .. } => {
245 let size = file
246 .metadata()
247 .map_err(|e| {
248 error!("getFileSize error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700249 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700250 })?
251 .len();
252 Ok(size.try_into().map_err(|e| {
253 error!("getFileSize: File too large: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700254 new_errno_error(Errno::EFBIG)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700255 })?)
256 }
257 FdConfig::ReadWrite(_file) => {
258 // Content and metadata of a writable file needs to be tracked by authfs, since
259 // fd_server isn't considered trusted. So there is no point to support getFileSize
260 // for a writable file.
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700261 Err(new_errno_error(Errno::ENOSYS))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700262 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800263 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
264 })
265 }
266
267 fn openFileInDirectory(&self, fd: i32, file_path: &str) -> BinderResult<i32> {
268 let path_buf = PathBuf::from(file_path);
269 // Checks if the path is a simple, related path.
270 if path_buf.components().any(|c| !matches!(c, Component::Normal(_))) {
271 return Err(new_errno_error(Errno::EINVAL));
272 }
273
274 self.insert_new_fd(fd, |config| match config {
275 FdConfig::InputDir(dir) => {
276 let file = open_readonly_at(dir.as_raw_fd(), &path_buf).map_err(new_errno_error)?;
277
278 // TODO(205987437): Provide the corresponding ".fsv_meta" file when it's created.
279 Ok((
280 file.as_raw_fd(),
281 FdConfig::Readonly { file, alt_merkle_tree: None, alt_signature: None },
282 ))
283 }
284 FdConfig::OutputDir(_) => {
285 Err(new_errno_error(Errno::ENOSYS)) // TODO: Implement when needed
286 }
287 _ => Err(new_errno_error(Errno::ENOTDIR)),
Victor Hsieh45636232021-10-15 17:52:51 -0700288 })
289 }
290
291 fn createFileInDirectory(&self, fd: i32, basename: &str) -> BinderResult<i32> {
292 if basename.contains(MAIN_SEPARATOR) {
293 return Err(new_errno_error(Errno::EINVAL));
294 }
295 self.insert_new_fd(fd, |config| match config {
Victor Hsieh559b9272021-11-08 15:15:14 -0800296 FdConfig::InputDir(_) => Err(new_errno_error(Errno::EACCES)),
Victor Hsieh45636232021-10-15 17:52:51 -0700297 FdConfig::OutputDir(dir) => {
298 let new_fd = openat(
299 dir.as_raw_fd(),
300 basename,
301 // TODO(205172873): handle the case when the file already exist, e.g. truncate
302 // or fail, and possibly allow the client to specify. For now, always truncate.
303 OFlag::O_CREAT | OFlag::O_RDWR | OFlag::O_TRUNC,
304 Mode::S_IRUSR | Mode::S_IWUSR,
305 )
306 .map_err(new_errno_error)?;
307 // SAFETY: new_fd is just created and not an error.
308 let new_file = unsafe { File::from_raw_fd(new_fd) };
309 Ok((new_fd, FdConfig::ReadWrite(new_file)))
310 }
311 _ => Err(new_errno_error(Errno::ENOTDIR)),
312 })
313 }
314
315 fn createDirectoryInDirectory(&self, dir_fd: i32, basename: &str) -> BinderResult<i32> {
316 if basename.contains(MAIN_SEPARATOR) {
317 return Err(new_errno_error(Errno::EINVAL));
318 }
319 self.insert_new_fd(dir_fd, |config| match config {
Victor Hsieh559b9272021-11-08 15:15:14 -0800320 FdConfig::InputDir(_) => Err(new_errno_error(Errno::EACCES)),
Victor Hsieh45636232021-10-15 17:52:51 -0700321 FdConfig::OutputDir(_) => {
322 mkdirat(dir_fd, basename, Mode::S_IRWXU).map_err(new_errno_error)?;
323 let new_dir = Dir::openat(
324 dir_fd,
325 basename,
326 OFlag::O_DIRECTORY | OFlag::O_RDONLY,
327 Mode::empty(),
328 )
329 .map_err(new_errno_error)?;
330 Ok((new_dir.as_raw_fd(), FdConfig::OutputDir(new_dir)))
331 }
332 _ => Err(new_errno_error(Errno::ENOTDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700333 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700334 }
Victor Hsiehf7fc3d32021-11-22 10:20:33 -0800335
336 fn statfs(&self) -> BinderResult<FsStat> {
337 let st = statvfs("/data").map_err(new_errno_error)?;
338 try_into_fs_stat(st).map_err(|_e| new_errno_error(Errno::EINVAL))
339 }
340}
341
342fn try_into_fs_stat(st: Statvfs) -> Result<FsStat, std::num::TryFromIntError> {
343 Ok(FsStat {
344 blockSize: st.block_size().try_into()?,
345 fragmentSize: st.fragment_size().try_into()?,
346 blockNumbers: st.blocks().try_into()?,
347 blockAvailable: st.blocks_available().try_into()?,
348 inodesAvailable: st.files_available().try_into()?,
349 maxFilename: st.name_max().try_into()?,
350 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700351}
352
353fn read_into_buf(file: &File, max_size: usize, offset: u64) -> io::Result<Vec<u8>> {
354 let remaining = file.metadata()?.len().saturating_sub(offset);
355 let buf_size = min(remaining, max_size as u64) as usize;
356 let mut buf = vec![0; buf_size];
357 file.read_exact_at(&mut buf, offset)?;
358 Ok(buf)
359}
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700360
361fn new_errno_error(errno: Errno) -> Status {
362 new_binder_service_specific_error(errno as i32, errno.desc())
363}
Victor Hsieh559b9272021-11-08 15:15:14 -0800364
365fn open_readonly_at(dir_fd: RawFd, path: &Path) -> nix::Result<File> {
366 let new_fd = openat(dir_fd, path, OFlag::O_RDONLY, Mode::empty())?;
367 // SAFETY: new_fd is just created successfully and not owned.
368 let new_file = unsafe { File::from_raw_fd(new_fd) };
369 Ok(new_file)
370}