blob: fa1914a170f5901b813cef2614b625f8db278acc [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,
21};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070022use std::cmp::min;
Victor Hsieh45636232021-10-15 17:52:51 -070023use std::collections::{btree_map, BTreeMap};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070024use std::convert::TryInto;
25use std::fs::File;
26use std::io;
27use std::os::unix::fs::FileExt;
Victor Hsieh559b9272021-11-08 15:15:14 -080028use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
29use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
Victor Hsieh45636232021-10-15 17:52:51 -070030use std::sync::{Arc, Mutex};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070031
32use crate::fsverity;
33use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::{
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070034 BnVirtFdService, IVirtFdService, MAX_REQUESTING_DATA,
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070035};
36use authfs_aidl_interface::binder::{
Victor Hsieh45636232021-10-15 17:52:51 -070037 BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, StatusCode, Strong,
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070038};
Victor Hsieh45636232021-10-15 17:52:51 -070039use binder_common::{new_binder_exception, new_binder_service_specific_error};
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070040
41fn validate_and_cast_offset(offset: i64) -> Result<u64, Status> {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070042 offset.try_into().map_err(|_| new_errno_error(Errno::EINVAL))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070043}
44
45fn validate_and_cast_size(size: i32) -> Result<usize, Status> {
46 if size > MAX_REQUESTING_DATA {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070047 Err(new_errno_error(Errno::EFBIG))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070048 } else {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -070049 size.try_into().map_err(|_| new_errno_error(Errno::EINVAL))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070050 }
51}
52
53/// Configuration of a file descriptor to be served/exposed/shared.
54pub enum FdConfig {
55 /// A read-only file to serve by this server. The file is supposed to be verifiable with the
56 /// associated fs-verity metadata.
57 Readonly {
58 /// The file to read from. fs-verity metadata can be retrieved from this file's FD.
59 file: File,
60
61 /// Alternative Merkle tree stored in another file.
Victor Hsieh559b9272021-11-08 15:15:14 -080062 /// TODO(205987437): Replace with .fsv_meta file.
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070063 alt_merkle_tree: Option<File>,
64
65 /// Alternative signature stored in another file.
Victor Hsieh559b9272021-11-08 15:15:14 -080066 /// TODO(205987437): Replace with .fsv_meta file.
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070067 alt_signature: Option<File>,
68 },
69
70 /// A readable/writable file to serve by this server. This backing file should just be a
71 /// regular file and does not have any specific property.
72 ReadWrite(File),
Victor Hsieh45636232021-10-15 17:52:51 -070073
Victor Hsieh559b9272021-11-08 15:15:14 -080074 /// A read-only directory to serve by this server.
75 InputDir(Dir),
76
Victor Hsieh45636232021-10-15 17:52:51 -070077 /// A writable directory to serve by this server.
78 OutputDir(Dir),
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070079}
80
81pub struct FdService {
Victor Hsieh45636232021-10-15 17:52:51 -070082 /// A pool of opened files and directories, which can be looked up by the FD number.
83 fd_pool: Arc<Mutex<BTreeMap<i32, FdConfig>>>,
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070084}
85
86impl FdService {
87 pub fn new_binder(fd_pool: BTreeMap<i32, FdConfig>) -> Strong<dyn IVirtFdService> {
Victor Hsieh45636232021-10-15 17:52:51 -070088 BnVirtFdService::new_binder(
89 FdService { fd_pool: Arc::new(Mutex::new(fd_pool)) },
90 BinderFeatures::default(),
91 )
Victor Hsiehb0f5fc82021-10-15 17:24:19 -070092 }
93
Victor Hsieh45636232021-10-15 17:52:51 -070094 /// Handles the requesting file `id` with `handle_fn` if it is in the FD pool. This function
95 /// returns whatever `handle_fn` returns.
96 fn handle_fd<F, R>(&self, id: i32, handle_fn: F) -> BinderResult<R>
Victor Hsiehc85e4ef2021-10-18 15:28:53 -070097 where
98 F: FnOnce(&FdConfig) -> BinderResult<R>,
99 {
Victor Hsieh45636232021-10-15 17:52:51 -0700100 let fd_pool = self.fd_pool.lock().unwrap();
101 let fd_config = fd_pool.get(&id).ok_or_else(|| new_errno_error(Errno::EBADF))?;
102 handle_fn(fd_config)
103 }
104
105 /// Inserts a new FD and corresponding `FdConfig` created by `create_fn` to the FD pool, then
106 /// returns the new FD number.
107 fn insert_new_fd<F>(&self, fd: i32, create_fn: F) -> BinderResult<i32>
108 where
109 F: FnOnce(&mut FdConfig) -> BinderResult<(i32, FdConfig)>,
110 {
111 let mut fd_pool = self.fd_pool.lock().unwrap();
112 let mut fd_config = fd_pool.get_mut(&fd).ok_or_else(|| new_errno_error(Errno::EBADF))?;
113 let (new_fd, new_fd_config) = create_fn(&mut fd_config)?;
114 if let btree_map::Entry::Vacant(entry) = fd_pool.entry(new_fd) {
115 entry.insert(new_fd_config);
116 Ok(new_fd)
117 } else {
118 Err(new_binder_exception(
119 ExceptionCode::ILLEGAL_STATE,
120 format!("The newly created FD {} is already in the pool unexpectedly", new_fd),
121 ))
122 }
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700123 }
124}
125
126impl Interface for FdService {}
127
128impl IVirtFdService for FdService {
129 fn readFile(&self, id: i32, offset: i64, size: i32) -> BinderResult<Vec<u8>> {
130 let size: usize = validate_and_cast_size(size)?;
131 let offset: u64 = validate_and_cast_offset(offset)?;
132
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700133 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700134 FdConfig::Readonly { file, .. } | FdConfig::ReadWrite(file) => {
135 read_into_buf(file, size, offset).map_err(|e| {
136 error!("readFile: read error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700137 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700138 })
139 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800140 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700141 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700142 }
143
144 fn readFsverityMerkleTree(&self, id: i32, offset: i64, size: i32) -> BinderResult<Vec<u8>> {
145 let size: usize = validate_and_cast_size(size)?;
146 let offset: u64 = validate_and_cast_offset(offset)?;
147
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700148 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700149 FdConfig::Readonly { file, alt_merkle_tree, .. } => {
150 if let Some(tree_file) = &alt_merkle_tree {
151 read_into_buf(tree_file, size, offset).map_err(|e| {
152 error!("readFsverityMerkleTree: read error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700153 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700154 })
155 } else {
156 let mut buf = vec![0; size];
157 let s = fsverity::read_merkle_tree(file.as_raw_fd(), offset, &mut buf)
158 .map_err(|e| {
159 error!("readFsverityMerkleTree: failed to retrieve merkle tree: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700160 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700161 })?;
162 debug_assert!(s <= buf.len(), "Shouldn't return more bytes than asked");
163 buf.truncate(s);
164 Ok(buf)
165 }
166 }
167 FdConfig::ReadWrite(_file) => {
168 // For a writable file, Merkle tree is not expected to be served since Auth FS
169 // doesn't trust it anyway. Auth FS may keep the Merkle tree privately for its own
170 // use.
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700171 Err(new_errno_error(Errno::ENOSYS))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700172 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800173 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700174 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700175 }
176
177 fn readFsveritySignature(&self, id: i32) -> BinderResult<Vec<u8>> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700178 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700179 FdConfig::Readonly { file, alt_signature, .. } => {
180 if let Some(sig_file) = &alt_signature {
181 // Supposedly big enough buffer size to store signature.
182 let size = MAX_REQUESTING_DATA as usize;
183 let offset = 0;
184 read_into_buf(sig_file, size, offset).map_err(|e| {
185 error!("readFsveritySignature: read error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700186 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700187 })
188 } else {
189 let mut buf = vec![0; MAX_REQUESTING_DATA as usize];
190 let s = fsverity::read_signature(file.as_raw_fd(), &mut buf).map_err(|e| {
191 error!("readFsverityMerkleTree: failed to retrieve merkle tree: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700192 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700193 })?;
194 debug_assert!(s <= buf.len(), "Shouldn't return more bytes than asked");
195 buf.truncate(s);
196 Ok(buf)
197 }
198 }
199 FdConfig::ReadWrite(_file) => {
200 // There is no signature for a writable file.
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700201 Err(new_errno_error(Errno::ENOSYS))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700202 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800203 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700204 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700205 }
206
207 fn writeFile(&self, id: i32, buf: &[u8], offset: i64) -> BinderResult<i32> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700208 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700209 FdConfig::Readonly { .. } => Err(StatusCode::INVALID_OPERATION.into()),
210 FdConfig::ReadWrite(file) => {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700211 let offset: u64 = offset.try_into().map_err(|_| new_errno_error(Errno::EINVAL))?;
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700212 // Check buffer size just to make `as i32` safe below.
213 if buf.len() > i32::MAX as usize {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700214 return Err(new_errno_error(Errno::EOVERFLOW));
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700215 }
216 Ok(file.write_at(buf, offset).map_err(|e| {
217 error!("writeFile: write error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700218 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700219 })? as i32)
220 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800221 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700222 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700223 }
224
225 fn resize(&self, id: i32, size: i64) -> BinderResult<()> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700226 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700227 FdConfig::Readonly { .. } => Err(StatusCode::INVALID_OPERATION.into()),
228 FdConfig::ReadWrite(file) => {
229 if size < 0 {
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700230 return Err(new_errno_error(Errno::EINVAL));
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700231 }
232 file.set_len(size as u64).map_err(|e| {
233 error!("resize: set_len error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700234 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700235 })
236 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800237 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700238 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700239 }
240
241 fn getFileSize(&self, id: i32) -> BinderResult<i64> {
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700242 self.handle_fd(id, |config| match config {
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700243 FdConfig::Readonly { file, .. } => {
244 let size = file
245 .metadata()
246 .map_err(|e| {
247 error!("getFileSize error: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700248 new_errno_error(Errno::EIO)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700249 })?
250 .len();
251 Ok(size.try_into().map_err(|e| {
252 error!("getFileSize: File too large: {}", e);
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700253 new_errno_error(Errno::EFBIG)
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700254 })?)
255 }
256 FdConfig::ReadWrite(_file) => {
257 // Content and metadata of a writable file needs to be tracked by authfs, since
258 // fd_server isn't considered trusted. So there is no point to support getFileSize
259 // for a writable file.
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700260 Err(new_errno_error(Errno::ENOSYS))
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700261 }
Victor Hsieh559b9272021-11-08 15:15:14 -0800262 FdConfig::InputDir(_) | FdConfig::OutputDir(_) => Err(new_errno_error(Errno::EISDIR)),
263 })
264 }
265
266 fn openFileInDirectory(&self, fd: i32, file_path: &str) -> BinderResult<i32> {
267 let path_buf = PathBuf::from(file_path);
268 // Checks if the path is a simple, related path.
269 if path_buf.components().any(|c| !matches!(c, Component::Normal(_))) {
270 return Err(new_errno_error(Errno::EINVAL));
271 }
272
273 self.insert_new_fd(fd, |config| match config {
274 FdConfig::InputDir(dir) => {
275 let file = open_readonly_at(dir.as_raw_fd(), &path_buf).map_err(new_errno_error)?;
276
277 // TODO(205987437): Provide the corresponding ".fsv_meta" file when it's created.
278 Ok((
279 file.as_raw_fd(),
280 FdConfig::Readonly { file, alt_merkle_tree: None, alt_signature: None },
281 ))
282 }
283 FdConfig::OutputDir(_) => {
284 Err(new_errno_error(Errno::ENOSYS)) // TODO: Implement when needed
285 }
286 _ => Err(new_errno_error(Errno::ENOTDIR)),
Victor Hsieh45636232021-10-15 17:52:51 -0700287 })
288 }
289
290 fn createFileInDirectory(&self, fd: i32, basename: &str) -> BinderResult<i32> {
291 if basename.contains(MAIN_SEPARATOR) {
292 return Err(new_errno_error(Errno::EINVAL));
293 }
294 self.insert_new_fd(fd, |config| match config {
Victor Hsieh559b9272021-11-08 15:15:14 -0800295 FdConfig::InputDir(_) => Err(new_errno_error(Errno::EACCES)),
Victor Hsieh45636232021-10-15 17:52:51 -0700296 FdConfig::OutputDir(dir) => {
297 let new_fd = openat(
298 dir.as_raw_fd(),
299 basename,
300 // TODO(205172873): handle the case when the file already exist, e.g. truncate
301 // or fail, and possibly allow the client to specify. For now, always truncate.
302 OFlag::O_CREAT | OFlag::O_RDWR | OFlag::O_TRUNC,
303 Mode::S_IRUSR | Mode::S_IWUSR,
304 )
305 .map_err(new_errno_error)?;
306 // SAFETY: new_fd is just created and not an error.
307 let new_file = unsafe { File::from_raw_fd(new_fd) };
308 Ok((new_fd, FdConfig::ReadWrite(new_file)))
309 }
310 _ => Err(new_errno_error(Errno::ENOTDIR)),
311 })
312 }
313
314 fn createDirectoryInDirectory(&self, dir_fd: i32, basename: &str) -> BinderResult<i32> {
315 if basename.contains(MAIN_SEPARATOR) {
316 return Err(new_errno_error(Errno::EINVAL));
317 }
318 self.insert_new_fd(dir_fd, |config| match config {
Victor Hsieh559b9272021-11-08 15:15:14 -0800319 FdConfig::InputDir(_) => Err(new_errno_error(Errno::EACCES)),
Victor Hsieh45636232021-10-15 17:52:51 -0700320 FdConfig::OutputDir(_) => {
321 mkdirat(dir_fd, basename, Mode::S_IRWXU).map_err(new_errno_error)?;
322 let new_dir = Dir::openat(
323 dir_fd,
324 basename,
325 OFlag::O_DIRECTORY | OFlag::O_RDONLY,
326 Mode::empty(),
327 )
328 .map_err(new_errno_error)?;
329 Ok((new_dir.as_raw_fd(), FdConfig::OutputDir(new_dir)))
330 }
331 _ => Err(new_errno_error(Errno::ENOTDIR)),
Victor Hsiehc85e4ef2021-10-18 15:28:53 -0700332 })
Victor Hsiehb0f5fc82021-10-15 17:24:19 -0700333 }
334}
335
336fn read_into_buf(file: &File, max_size: usize, offset: u64) -> io::Result<Vec<u8>> {
337 let remaining = file.metadata()?.len().saturating_sub(offset);
338 let buf_size = min(remaining, max_size as u64) as usize;
339 let mut buf = vec![0; buf_size];
340 file.read_exact_at(&mut buf, offset)?;
341 Ok(buf)
342}
Victor Hsiehbe8b08d2021-10-29 16:31:24 -0700343
344fn new_errno_error(errno: Errno) -> Status {
345 new_binder_service_specific_error(errno as i32, errno.desc())
346}
Victor Hsieh559b9272021-11-08 15:15:14 -0800347
348fn open_readonly_at(dir_fd: RawFd, path: &Path) -> nix::Result<File> {
349 let new_fd = openat(dir_fd, path, OFlag::O_RDONLY, Mode::empty())?;
350 // SAFETY: new_fd is just created successfully and not owned.
351 let new_file = unsafe { File::from_raw_fd(new_fd) };
352 Ok(new_file)
353}