1 /* 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 17 use crate::serialization::Serializer; 18 use crate::sys::*; 19 use crate::{Deserialize, Serialize, TipcError}; 20 use core::convert::TryInto; 21 use core::ffi::CStr; 22 use core::mem::MaybeUninit; 23 use log::{error, warn}; 24 use trusty_sys::{c_int, c_long}; 25 26 /// An open IPC connection or shared memory reference. 27 /// 28 /// A `Handle` can either represent an open IPC connection or a shared memory 29 /// reference. Which one a given handle represents generally must be determined 30 /// from context, i.e. the handle returned by [`Handle::connect`] will always 31 /// represent an IPC connection. A given incoming or outgoing message will 32 /// generally have specific semantics regarding what kind of handles are sent 33 /// along with it. 34 /// 35 /// # IPC Connections 36 /// 37 /// This handle knows how to send and receive messages which implement 38 /// [`Serialize`] and [`Deserialize`] respectively. Serialization and parsing 39 /// are handled by the message itself. 40 /// 41 /// The handle owns its connection, which is closed when this struct is dropped. 42 /// Do not rely on the connection being closed for protocol correctness, as the 43 /// drop method may not always be called. 44 /// 45 /// # Shared Memory References 46 /// 47 /// An incoming TIPC message may include one or more handles representing a 48 /// shared memory buffer. These can be mapped into process memory using 49 /// [`Handle::mmap`]. The returned [`UnsafeSharedBuf`] object provides access to 50 /// the shared memory buffer and will unmap the buffer automatically on drop. 51 #[repr(transparent)] 52 #[derive(Eq, PartialEq, Debug)] 53 pub struct Handle(handle_t); 54 55 /// Maximum number of handles that can be transferred in an IPC message at once. 56 pub const MAX_MSG_HANDLES: usize = 8; 57 /// Maximum numbers of iovecs that can be sent or received over IPC at once. 58 pub const MAX_MSG_IOVECS: usize = 32; 59 /// Maximum number of segments that can be serialized by BorrowingSerializer. 60 pub const MAX_SERIALIZED_SEGMENTS: usize = 32; 61 62 impl Handle { 63 /// Open a client connection to the given service. 64 /// 65 /// The service `port` can be either a Trusty TA or kernel port name. This 66 /// call is synchronous and will block until the specified port exists. 67 /// 68 /// # Examples 69 /// 70 /// Open a TIPC connection to `com.android.trusty.test_port`: 71 /// 72 /// ``` 73 /// use core::ffi::CStr; 74 /// use tipc::Handle; 75 /// 76 /// let port = CStr::from_bytes_with_nul(b"com.android.trusty.test_port\0") 77 /// .unwrap(); 78 /// 79 /// if let Ok(handle) = Handle::connect(port) { 80 /// println!("Connection successful"); 81 /// } else { 82 /// println!("Connection attempt failed"); 83 /// } 84 /// ``` connect(port: &CStr) -> crate::Result<Self>85 pub fn connect(port: &CStr) -> crate::Result<Self> { 86 // SAFETY: external syscall. port is guaranteed to be a well-formed, 87 // null-terminated C string. 88 let rc = unsafe { trusty_sys::connect(port.as_ptr(), IPC_CONNECT_WAIT_FOR_PORT as u32) }; 89 if rc < 0 { 90 Err(TipcError::from_uapi(rc)) 91 } else { 92 rc.try_into().map(Handle).or(Err(TipcError::InvalidHandle)) 93 } 94 } 95 try_clone(&self) -> crate::Result<Self>96 pub fn try_clone(&self) -> crate::Result<Self> { 97 // SAFETY: external syscall, handle descriptor is valid for the lifetime 98 // of self. Return value is either an error or a new valid handle 99 // descriptor that we can take ownership of. 100 let rc = unsafe { trusty_sys::dup(self.0) }; 101 Self::from_raw(rc.try_into().or(Err(TipcError::InvalidHandle))?) 102 } 103 104 /// Construct a Handle from a raw file descriptor 105 /// 106 /// Conditionally creates a Handle from the return value of a C FFI function. 107 /// If the integer value is < 0, then we will refuse to create the Handle. from_raw(fd: i32) -> crate::Result<Self>108 pub fn from_raw(fd: i32) -> crate::Result<Self> { 109 if fd < 0 { 110 Err(TipcError::from_uapi(fd as c_long)) 111 } else { 112 Ok(Self(fd)) 113 } 114 } 115 116 /// Send an IPC message. 117 /// 118 /// Serializes `msg` using its [`Serialize`] implementation and send it 119 /// across this IPC connection. Attempts to serialize the message in-place 120 /// without new allocations. send<'s, T: Serialize<'s>>(&self, msg: &'s T) -> crate::Result<()>121 pub fn send<'s, T: Serialize<'s>>(&self, msg: &'s T) -> crate::Result<()> { 122 let mut serializer = BorrowingSerializer::default(); 123 msg.serialize(&mut serializer)?; 124 self.send_vectored(&serializer.buffers[..], &serializer.handles[..]) 125 } 126 127 /// Receive an IPC message. 128 /// 129 /// Receives a message into the given temporary `buffer`, and deserializes 130 /// the received message into a `T` using `T::Deserialize`. If the received 131 /// message does not fit into `buffer` this method will return error value 132 /// [`TipcError::NotEnoughBuffer`]. In the case of insufficient buffer 133 /// space, the message data will be lost and must be resent to recover. 134 /// 135 /// TODO: Support a timeout for the wait. recv<T: Deserialize>(&self, buffer: &mut [u8]) -> Result<T, T::Error>136 pub fn recv<T: Deserialize>(&self, buffer: &mut [u8]) -> Result<T, T::Error> { 137 let mut handles: [Option<Handle>; MAX_MSG_HANDLES] = Default::default(); 138 let (byte_count, handle_count) = self.recv_vectored(&mut [buffer], &mut handles)?; 139 140 T::deserialize(&buffer[..byte_count], &mut handles[..handle_count]) 141 } 142 143 /// Receive raw bytes and handles into slices of buffers and handles. 144 /// 145 /// Returns a tuple of the number of bytes written into the buffer and the 146 /// number of handles received. `handles` should have space for at least 147 /// [`MAX_MSG_HANDLES`]. recv_vectored( &self, buffers: &mut [&mut [u8]], handles: &mut [Option<Handle>], ) -> crate::Result<(usize, usize)>148 pub fn recv_vectored( 149 &self, 150 buffers: &mut [&mut [u8]], 151 handles: &mut [Option<Handle>], 152 ) -> crate::Result<(usize, usize)> { 153 let _ = self.wait(None)?; 154 155 let mut raw_handles = [-1; MAX_MSG_HANDLES]; 156 157 let (buf_len, handles_len) = self.get_msg(|msg_info| { 158 if msg_info.len > buffers.iter().map(|b| b.len()).sum() { 159 return Err(TipcError::NotEnoughBuffer); 160 } 161 162 let mut iovs = arrayvec::ArrayVec::<_, MAX_MSG_IOVECS>::new(); 163 assert!(buffers.len() <= MAX_MSG_IOVECS); 164 iovs.extend(buffers.iter_mut().map(|buf| trusty_sys::iovec { 165 iov_base: buf.as_mut_ptr().cast(), 166 iov_len: buf.len(), 167 })); 168 169 let mut msg = trusty_sys::ipc_msg { 170 num_iov: iovs.len().try_into()?, 171 iov: iovs.as_mut_ptr(), 172 173 num_handles: raw_handles.len().try_into()?, 174 handles: raw_handles.as_mut_ptr() as *mut i32, 175 }; 176 177 // SAFETY: syscall, pointer is initialized with valid data and 178 // mutably borrowed. The buffers that the msg refers to are valid 179 // and writable across this call. `Handle` is a transparent wrapper 180 // around `handle_t`, i.e. `i32` so we can safely cast the handles 181 // slice to an `i32` pointer. Although the syscall requires a 182 // mutable handle pointer, it does not mutate these handles, so we 183 // can safely cast the immutable slice to mutable pointer. 184 let rc = unsafe { trusty_sys::read_msg(self.as_raw_fd(), msg_info.id, 0, &mut msg) }; 185 186 if rc < 0 { 187 Err(TipcError::from_uapi(rc)) 188 } else { 189 Ok((rc.try_into()?, msg_info.num_handles.try_into()?)) 190 } 191 })?; 192 193 // Convert the raw handles list into a list of `Option<Handle>`. 194 for (index, raw_handle) in raw_handles[..handles_len].into_iter().enumerate() { 195 handles[index] = Some(Handle(*raw_handle)); 196 } 197 198 Ok((buf_len, handles_len)) 199 } 200 201 /// Send a set of buffers and file/memref handles. 202 /// 203 /// Sends a set of buffers and set of handles at once. `buf` must fit in the 204 /// message queue and `handles` must contain no more than 205 /// [`MAX_MSG_HANDLES`]. 206 /// 207 /// If the message fails to fit in the server's message queue, the send will 208 /// block and retry when the kernel indicates that the queue is unblocked. send_vectored(&self, buffers: &[&[u8]], handles: &[Handle]) -> crate::Result<()>209 pub fn send_vectored(&self, buffers: &[&[u8]], handles: &[Handle]) -> crate::Result<()> { 210 let mut iovs = arrayvec::ArrayVec::<_, MAX_MSG_IOVECS>::new(); 211 assert!(buffers.len() <= MAX_MSG_IOVECS); 212 iovs.extend( 213 buffers.iter().map(|buf| trusty_sys::iovec { 214 iov_base: buf.as_ptr() as *mut _, 215 iov_len: buf.len(), 216 }), 217 ); 218 let total_num_bytes = buffers.iter().map(|b| b.len()).sum(); 219 220 let mut msg = trusty_sys::ipc_msg { 221 num_iov: iovs.len().try_into()?, 222 iov: iovs.as_mut_ptr(), 223 224 num_handles: handles.len().try_into()?, 225 handles: handles.as_ptr() as *mut i32, 226 }; 227 // SAFETY: syscall, pointer is initialized with valid data and mutably 228 // borrowed. The buffers that the msg refers to are valid and writable 229 // across this call. `Handle` is a transparent wrapper around 230 // `handle_t`, i.e. `i32` so we can safely cast the handles slice to an 231 // `i32` pointer. Although the syscall requires a mutable handle 232 // pointer, it does not mutate these handles, so we can safely cast the 233 // immutable slice to mutable pointer. 234 let mut rc = unsafe { trusty_sys::send_msg(self.as_raw_fd(), &mut msg) }; 235 236 // If there's not enough space in the buffer to send the message, wait until we 237 // get a `SEND_UNBLOCKED` event or another error occurs. 238 if rc == trusty_sys::Error::NotEnoughBuffer as c_long { 239 loop { 240 let event = self.wait(None)?; 241 if event.event & IPC_HANDLE_POLL_SEND_UNBLOCKED as u32 != 0 { 242 break; 243 } else if event.event & IPC_HANDLE_POLL_MSG as u32 != 0 { 244 warn!("Received a message while waiting for send to be unblocked, abandoning send attempt"); 245 return Err(TipcError::Busy); 246 } else if event.event & IPC_HANDLE_POLL_HUP as u32 != 0 { 247 return Err(TipcError::ChannelClosed); 248 } else { 249 error!( 250 "Unexpected event while waiting for send to be unblocked: {}", 251 event.event, 252 ); 253 } 254 } 255 256 // Retry the send. It should go through this time because sending is now 257 // unblocked. 258 rc = unsafe { trusty_sys::send_msg(self.as_raw_fd(), &mut msg) }; 259 } 260 261 if rc < 0 { 262 Err(TipcError::from_uapi(rc)) 263 } else if rc as usize != total_num_bytes { 264 Err(TipcError::IncompleteWrite { num_bytes_written: rc as usize }) 265 } else { 266 Ok(()) 267 } 268 } 269 270 /// Get the raw file descriptor of this handle. 271 /// 272 /// Returns the raw integer OS file descriptor(fd) associated with this handle. This is 273 /// primarily useful for interacting with FFI interfaces. The programmer must ensure that any 274 /// interactions with the raw fd do not cause it to close or otherwise become invalid. This 275 /// handle must outlive all uses of the returned fd. Otherwise, the behavior is undefined. as_raw_fd(&self) -> i32276 pub fn as_raw_fd(&self) -> i32 { 277 self.0 278 } 279 280 /// Wait for an event on this handle for `timeout` milliseconds, or 281 /// indefinitely if `None`. wait(&self, timeout: Option<u32>) -> crate::Result<trusty_sys::uevent>282 pub(crate) fn wait(&self, timeout: Option<u32>) -> crate::Result<trusty_sys::uevent> { 283 let timeout = timeout.unwrap_or(INFINITE_TIME); 284 let mut uevent = MaybeUninit::zeroed(); 285 // SAFETY: syscall, uevent is borrowed mutably and outlives the call 286 let rc = unsafe { trusty_sys::wait(self.as_raw_fd(), uevent.as_mut_ptr(), timeout) }; 287 if rc != 0 { 288 Err(TipcError::from_uapi(rc)) 289 } else { 290 // SAFETY: If the wait call succeeded, the uevent structure has been 291 // fully initialized. 292 let uevent = unsafe { uevent.assume_init() }; 293 Ok(uevent) 294 } 295 } 296 297 /// Receive an IPC message. 298 /// 299 /// The `func` callback must call `trusty_sys::read_msg()` with the provided 300 /// message id from `ipc_msg_info` to read the message bytes. A message is 301 /// only valid for the lifetime of this callback and the message bytes 302 /// should be copied into the return value, if needed. get_msg<F, R>(&self, mut func: F) -> crate::Result<R> where F: FnMut(&trusty_sys::ipc_msg_info) -> crate::Result<R>,303 fn get_msg<F, R>(&self, mut func: F) -> crate::Result<R> 304 where 305 F: FnMut(&trusty_sys::ipc_msg_info) -> crate::Result<R>, 306 { 307 let mut msg_info: MaybeUninit<trusty_sys::ipc_msg_info> = MaybeUninit::uninit(); 308 309 // SAFETY: syscall, msg_info pointer is mutably borrowed and will be 310 // correctly initialized if the syscall returns 0. 311 let msg_info = unsafe { 312 let rc = trusty_sys::get_msg(self.as_raw_fd(), msg_info.as_mut_ptr()); 313 if rc != 0 { 314 return Err(TipcError::from_uapi(rc)); 315 } 316 msg_info.assume_init() 317 }; 318 319 let ret = func(&msg_info); 320 321 // SAFETY: syscall with safe arguments 322 let put_msg_rc = unsafe { trusty_sys::put_msg(self.as_raw_fd(), msg_info.id) }; 323 324 // prefer returning the callback error to the put_msg error, if any 325 if put_msg_rc != 0 { 326 Err(ret.err().unwrap_or_else(|| TipcError::from_uapi(put_msg_rc))) 327 } else { 328 ret 329 } 330 } 331 332 /// Maps the shared memory buffer represented by this handle. 333 /// 334 /// If `size` is not already a multiple of the page size it will be rounded up 335 /// to the nearest multiple of the page size. Use the 336 /// [`len`][UnsafeSharedBuf::len] method on the returned [`UnsafeSharedBuf`] to 337 /// determine the final size of the mapped buffer. mmap(&self, size: usize, flags: MMapFlags) -> crate::Result<UnsafeSharedBuf>338 pub fn mmap(&self, size: usize, flags: MMapFlags) -> crate::Result<UnsafeSharedBuf> { 339 let prot = match flags { 340 MMapFlags::Read => trusty_sys::MMAP_FLAG_PROT_READ as c_int, 341 MMapFlags::Write => trusty_sys::MMAP_FLAG_PROT_WRITE as c_int, 342 MMapFlags::ReadWrite => { 343 (trusty_sys::MMAP_FLAG_PROT_READ | trusty_sys::MMAP_FLAG_PROT_WRITE) as c_int 344 } 345 }; 346 347 // SAFETY: FFI call with all safe arguments. 348 let page_size = unsafe { libc::getauxval(libc::AT_PAGESZ) }; 349 350 // Round `size` up to the nearest multiple of the page size. 351 let page_size: usize = page_size.try_into().unwrap(); 352 let size = (size + (page_size - 1)) & !(page_size - 1); 353 354 // SAFETY: FFI call with all safe arguments. 355 let buf_ptr = 356 unsafe { libc::mmap(core::ptr::null_mut(), size, prot, 0, self.as_raw_fd(), 0) }; 357 358 if buf_ptr == libc::MAP_FAILED { 359 Err(TipcError::InvalidHandle) 360 } else { 361 Ok(UnsafeSharedBuf { buf: buf_ptr as *mut u8, len: size }) 362 } 363 } 364 } 365 366 impl Drop for Handle { drop(&mut self)367 fn drop(&mut self) { 368 // SAFETY syscall with safe arguments 369 unsafe { 370 let _ = trusty_sys::close(self.as_raw_fd()); 371 } 372 } 373 } 374 375 /// A serializer that borrows its input bytes and does not allocate. 376 #[derive(Default)] 377 struct BorrowingSerializer<'a> { 378 buffers: arrayvec::ArrayVec<&'a [u8], MAX_SERIALIZED_SEGMENTS>, 379 handles: arrayvec::ArrayVec<Handle, MAX_MSG_HANDLES>, 380 } 381 382 impl<'a> Serializer<'a> for BorrowingSerializer<'a> { 383 type Ok = (); 384 type Error = TipcError; 385 serialize_bytes(&mut self, bytes: &'a [u8]) -> Result<Self::Ok, Self::Error>386 fn serialize_bytes(&mut self, bytes: &'a [u8]) -> Result<Self::Ok, Self::Error> { 387 self.buffers.try_push(bytes).or(Err(TipcError::AllocError)) 388 } 389 serialize_handle(&mut self, handle: &'a Handle) -> Result<Self::Ok, Self::Error>390 fn serialize_handle(&mut self, handle: &'a Handle) -> Result<Self::Ok, Self::Error> { 391 self.handles.try_push(Handle(handle.as_raw_fd())).or(Err(TipcError::AllocError)) 392 } 393 } 394 395 /// Memory protection flags for [`Handle::mmap`]. 396 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 397 pub enum MMapFlags { 398 /// The shared buffer can be read from. 399 Read, 400 401 /// The shared buffer can be written to. 402 Write, 403 404 /// The shared buffer can be read from and written to. 405 ReadWrite, 406 } 407 408 /// A shared buffer that has been mapped into memory 409 /// 410 /// # Safety 411 /// 412 /// Note that all operations performed on the shared buffer must be performed 413 /// through a raw pointer, accessible via the [`ptr`][Self::ptr] method. Rust's 414 /// ownership semantics do not align with how shared buffers work, and so it 415 /// cannot be represented as a normal Rust slice or reference. Extra care must 416 /// be taken on the part of the user to ensure that all reads and writes 417 /// performed on the buffer are done safely. 418 /// 419 /// Most notably, it is **never** safe to take a reference to data in the shared 420 /// buffer. All read operations must copy data from the buffer via the raw 421 /// pointer APIs in order to safely read shared memory. 422 /// 423 /// # Unmapping 424 /// 425 /// Call [`unmap`][Self::unmap] once the shared memory is no longer needed to 426 /// unmap the buffer. Doing this invalidates any existing pointers to the 427 /// buffer, so care must be taken to ensure that any such pointers are not used 428 /// after unmapping. 429 /// 430 /// Note that the buffer is not automatically unmapped on drop. Failing to unmap 431 /// the buffer will leak memory until the process exits. 432 #[derive(Debug)] 433 pub struct UnsafeSharedBuf { 434 buf: *mut u8, 435 len: usize, 436 } 437 438 impl UnsafeSharedBuf { 439 /// Gets the pointer to the start of the buffer. 440 /// 441 /// Any pointers returned by this method are invalidated once 442 /// [`unmap`][Self::unmap] is called. ptr(&self) -> *mut u8443 pub fn ptr(&self) -> *mut u8 { 444 self.buf 445 } 446 447 /// Gets the length of the buffer. 448 /// 449 /// Guaranteed to always be a multiple of the page size. len(&self) -> usize450 pub fn len(&self) -> usize { 451 self.len 452 } 453 454 /// Unmaps the shared memory buffer. 455 /// 456 /// Invalidates any pointers to the shared memory that were previously returned 457 /// by calls to [`ptr`][Self::ptr]. unmap(self)458 pub fn unmap(self) { 459 let rc = unsafe { libc::munmap(self.buf as *mut _, self.len) }; 460 if rc != 0 { 461 panic!("Failed to unmap shared buf"); 462 } 463 } 464 } 465 466 #[cfg(test)] 467 pub(crate) mod test { 468 use super::Handle; 469 use crate::sys; 470 use crate::TipcError; 471 use std::sync::Once; 472 use test::expect_eq; 473 use trusty_sys::Error; 474 475 // Expected limits: should be in sync with kernel settings 476 477 /// First user handle ID 478 pub const USER_BASE_HANDLE: i32 = sys::USER_BASE_HANDLE as i32; 479 480 /// Maximum number of user handles 481 pub const MAX_USER_HANDLES: i32 = sys::MAX_USER_HANDLES as i32; 482 483 const INVALID_IPC_HANDLE: Handle = Handle(-1); 484 485 static mut FIRST_FREE_HANDLE_INDEX: i32 = -1; 486 static FIRST_FREE_HANDLE_INDEX_INIT: Once = Once::new(); 487 488 // We don't know ahead of time what the first free handle will be, so we have to 489 // check and save the result the first time we need it. first_free_handle_index() -> i32490 pub fn first_free_handle_index() -> i32 { 491 type Channel = crate::service::Channel<crate::service::SingleDispatcher<()>>; 492 493 FIRST_FREE_HANDLE_INDEX_INIT.call_once(|| { 494 let chan = Channel::try_new_port( 495 &crate::PortCfg::new("com.android.tipc.handle_probe").unwrap(), 496 ) 497 .unwrap(); 498 499 // SAFETY: Write access is guarded by Once 500 unsafe { 501 FIRST_FREE_HANDLE_INDEX = chan.handle().0 - USER_BASE_HANDLE; 502 } 503 }); 504 505 // SAFETY: Once call above gates write access, so we know that the 506 // static has been initialized at this point and will be read-only from 507 // now on. Read-only access to a static i32 is safe. 508 unsafe { FIRST_FREE_HANDLE_INDEX } 509 } 510 511 #[test] wait_negative()512 fn wait_negative() { 513 let timeout = Some(1000); // 1 sec 514 515 expect_eq!( 516 INVALID_IPC_HANDLE.wait(timeout).err(), 517 Some(TipcError::InvalidHandle), 518 "wait on invalid handle" 519 ); 520 521 // call wait on an invalid (out of range) handle 522 // 523 // check handling of the following cases: 524 // - handle is on the upper boundary of valid handle range 525 // - handle is above of the upper boundary of valid handle range 526 // - handle is below of valid handle range 527 // 528 // in all cases, the expected result is ERR_BAD_HANDLE error. 529 expect_eq!( 530 Handle(USER_BASE_HANDLE + MAX_USER_HANDLES).wait(timeout).err(), 531 Some(TipcError::InvalidHandle), 532 "wait on invalid handle" 533 ); 534 535 expect_eq!( 536 Handle(USER_BASE_HANDLE + MAX_USER_HANDLES + 1).wait(timeout).err(), 537 Some(TipcError::InvalidHandle), 538 "wait on invalid handle" 539 ); 540 541 expect_eq!( 542 Handle(USER_BASE_HANDLE - 1).wait(timeout).err(), 543 Some(TipcError::InvalidHandle), 544 "wait on invalid handle" 545 ); 546 547 // wait on non-existent handle in valid range 548 for i in first_free_handle_index()..MAX_USER_HANDLES { 549 expect_eq!( 550 Handle(USER_BASE_HANDLE + i).wait(timeout).err(), 551 Some(TipcError::SystemError(Error::NotFound)), 552 "wait on invalid handle" 553 ); 554 } 555 } 556 } 557