1 // Copyright (C) 2024 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use android_hardware_common::{ 16 aidl::android::hardware::common::NativeHandle::NativeHandle as AidlNativeHandle, 17 binder::ParcelFileDescriptor, 18 }; 19 use std::{ 20 ffi::c_int, 21 mem::forget, 22 os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}, 23 ptr::NonNull, 24 }; 25 26 /// Rust wrapper around `native_handle_t`. 27 /// 28 /// This owns the `native_handle_t` and its file descriptors, and will close them and free it when 29 /// it is dropped. 30 #[derive(Debug)] 31 pub struct NativeHandle(NonNull<ffi::native_handle_t>); 32 33 impl NativeHandle { 34 /// Creates a new `NativeHandle` with the given file descriptors and integer values. 35 /// 36 /// The `NativeHandle` will take ownership of the file descriptors and close them when it is 37 /// dropped. new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self>38 pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> { 39 let fd_count = fds.len(); 40 // SAFETY: native_handle_create doesn't have any safety requirements. 41 let handle = unsafe { 42 ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap()) 43 }; 44 let handle = NonNull::new(handle)?; 45 for (i, fd) in fds.into_iter().enumerate() { 46 // SAFETY: `handle` must be valid because it was just created, and the array offset is 47 // within the bounds of what we allocated above. 48 unsafe { 49 *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd(); 50 } 51 } 52 for (i, value) in ints.iter().enumerate() { 53 // SAFETY: `handle` must be valid because it was just created, and the array offset is 54 // within the bounds of what we allocated above. Note that `data` is uninitialized 55 // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a 56 // reference to it so we use raw pointers arithmetic instead. 57 unsafe { 58 *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value; 59 } 60 } 61 // SAFETY: `handle` must be valid because it was just created. 62 unsafe { 63 ffi::native_handle_set_fdsan_tag(handle.as_ptr()); 64 } 65 Some(Self(handle)) 66 } 67 68 /// Returns a borrowed view of all the file descriptors in this native handle. fds(&self) -> Vec<BorrowedFd>69 pub fn fds(&self) -> Vec<BorrowedFd> { 70 self.data()[..self.fd_count()] 71 .iter() 72 .map(|fd| { 73 // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it 74 // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will 75 // have a lifetime constrained to that of `&self`, so it can't outlive it. 76 unsafe { BorrowedFd::borrow_raw(*fd) } 77 }) 78 .collect() 79 } 80 81 /// Returns the integer values in this native handle. ints(&self) -> &[c_int]82 pub fn ints(&self) -> &[c_int] { 83 &self.data()[self.fd_count()..] 84 } 85 86 /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained. into_fds(self) -> Vec<OwnedFd>87 pub fn into_fds(self) -> Vec<OwnedFd> { 88 // Unset FDSan tag since this `native_handle_t` is no longer the owner of the file 89 // descriptors after this function. 90 // SAFETY: Our wrapped `native_handle_t` pointer is always valid. 91 unsafe { 92 ffi::native_handle_unset_fdsan_tag(self.as_ref()); 93 } 94 let fds = self.data()[..self.fd_count()] 95 .iter() 96 .map(|fd| { 97 // SAFETY: The `native_handle_t` has ownership of the file descriptor, and 98 // after this we destroy it without closing the file descriptor so we can take over 99 // ownership of it. 100 unsafe { OwnedFd::from_raw_fd(*fd) } 101 }) 102 .collect(); 103 104 // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed 105 // after this because we own it and forget it. 106 unsafe { 107 assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0); 108 } 109 // Don't drop self, as that would cause `native_handle_close` to be called and close the 110 // file descriptors. 111 forget(self); 112 fds 113 } 114 115 /// Returns a reference to the underlying `native_handle_t`. as_ref(&self) -> &ffi::native_handle_t116 fn as_ref(&self) -> &ffi::native_handle_t { 117 // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is 118 // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's 119 // aliasing rules by giving the reference a lifetime matching that of `&self`. 120 unsafe { self.0.as_ref() } 121 } 122 123 /// Returns the number of file descriptors included in the native handle. fd_count(&self) -> usize124 fn fd_count(&self) -> usize { 125 self.as_ref().numFds.try_into().unwrap() 126 } 127 128 /// Returns the number of integer values included in the native handle. int_count(&self) -> usize129 fn int_count(&self) -> usize { 130 self.as_ref().numInts.try_into().unwrap() 131 } 132 133 /// Returns a slice reference for all the used `data` field of the native handle, including both 134 /// file descriptors and integers. data(&self) -> &[c_int]135 fn data(&self) -> &[c_int] { 136 let total_count = self.fd_count() + self.int_count(); 137 // SAFETY: The data must have been initialised with this number of elements when the 138 // `NativeHandle` was created. 139 unsafe { self.as_ref().data.as_slice(total_count) } 140 } 141 142 /// Wraps a raw `native_handle_t` pointer, taking ownership of it. 143 /// 144 /// # Safety 145 /// 146 /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used 147 /// anywhere else after calling this method. from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self148 pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self { 149 Self(native_handle) 150 } 151 152 /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer. 153 /// 154 /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so 155 /// the caller remains responsible for closing and freeing it. 156 /// 157 /// # Safety 158 /// 159 /// `native_handle` must be a valid pointer to a `native_handle_t`. clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self>160 pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> { 161 // SAFETY: The caller promised that `native_handle` was valid. 162 let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) }; 163 NonNull::new(cloned).map(Self) 164 } 165 166 /// Returns a raw pointer to the wrapped `native_handle_t`. 167 /// 168 /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't 169 /// be closed or deleted. as_raw(&self) -> NonNull<ffi::native_handle_t>170 pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> { 171 self.0 172 } 173 174 /// Turns the `NativeHandle` into a raw `native_handle_t`. 175 /// 176 /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is 177 /// responsible for closing and freeing it. into_raw(self) -> NonNull<ffi::native_handle_t>178 pub fn into_raw(self) -> NonNull<ffi::native_handle_t> { 179 let raw = self.0; 180 forget(self); 181 raw 182 } 183 } 184 185 impl Clone for NativeHandle { clone(&self) -> Self186 fn clone(&self) -> Self { 187 // SAFETY: Our wrapped `native_handle_t` pointer is always valid. 188 unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null") 189 } 190 } 191 192 impl Drop for NativeHandle { drop(&mut self)193 fn drop(&mut self) { 194 // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed 195 // after this because we own it and are being dropped. 196 unsafe { 197 assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0); 198 assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0); 199 } 200 } 201 } 202 203 impl From<AidlNativeHandle> for NativeHandle { from(aidl_native_handle: AidlNativeHandle) -> Self204 fn from(aidl_native_handle: AidlNativeHandle) -> Self { 205 let fds = aidl_native_handle.fds.into_iter().map(OwnedFd::from).collect(); 206 Self::new(fds, &aidl_native_handle.ints).unwrap() 207 } 208 } 209 210 impl From<NativeHandle> for AidlNativeHandle { from(native_handle: NativeHandle) -> Self211 fn from(native_handle: NativeHandle) -> Self { 212 let ints = native_handle.ints().to_owned(); 213 let fds = native_handle.into_fds().into_iter().map(ParcelFileDescriptor::new).collect(); 214 Self { ints, fds } 215 } 216 } 217 218 // SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file 219 // descriptors, which aren't tied to any particular thread. 220 unsafe impl Send for NativeHandle {} 221 222 // SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just 223 // integers and file descriptors. 224 unsafe impl Sync for NativeHandle {} 225 226 #[cfg(test)] 227 mod test { 228 use super::*; 229 use std::fs::File; 230 231 #[test] create_empty()232 fn create_empty() { 233 let handle = NativeHandle::new(vec![], &[]).unwrap(); 234 assert_eq!(handle.fds().len(), 0); 235 assert_eq!(handle.ints(), &[]); 236 } 237 238 #[test] create_with_ints()239 fn create_with_ints() { 240 let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap(); 241 assert_eq!(handle.fds().len(), 0); 242 assert_eq!(handle.ints(), &[1, 2, 42]); 243 } 244 245 #[test] create_with_fd()246 fn create_with_fd() { 247 let file = File::open("/dev/null").unwrap(); 248 let handle = NativeHandle::new(vec![file.into()], &[]).unwrap(); 249 assert_eq!(handle.fds().len(), 1); 250 assert_eq!(handle.ints(), &[]); 251 } 252 253 #[test] clone()254 fn clone() { 255 let file = File::open("/dev/null").unwrap(); 256 let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); 257 assert_eq!(original.ints(), &[42]); 258 assert_eq!(original.fds().len(), 1); 259 260 let cloned = original.clone(); 261 drop(original); 262 263 assert_eq!(cloned.ints(), &[42]); 264 assert_eq!(cloned.fds().len(), 1); 265 266 drop(cloned); 267 } 268 269 #[test] to_fds()270 fn to_fds() { 271 let file = File::open("/dev/null").unwrap(); 272 let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); 273 assert_eq!(original.ints(), &[42]); 274 assert_eq!(original.fds().len(), 1); 275 276 let fds = original.into_fds(); 277 assert_eq!(fds.len(), 1); 278 } 279 280 #[test] to_aidl()281 fn to_aidl() { 282 let file = File::open("/dev/null").unwrap(); 283 let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); 284 assert_eq!(original.ints(), &[42]); 285 assert_eq!(original.fds().len(), 1); 286 287 let aidl = AidlNativeHandle::from(original); 288 assert_eq!(&aidl.ints, &[42]); 289 assert_eq!(aidl.fds.len(), 1); 290 } 291 292 #[test] to_from_aidl()293 fn to_from_aidl() { 294 let file = File::open("/dev/null").unwrap(); 295 let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); 296 assert_eq!(original.ints(), &[42]); 297 assert_eq!(original.fds().len(), 1); 298 299 let aidl = AidlNativeHandle::from(original); 300 assert_eq!(&aidl.ints, &[42]); 301 assert_eq!(aidl.fds.len(), 1); 302 303 let converted_back = NativeHandle::from(aidl); 304 assert_eq!(converted_back.ints(), &[42]); 305 assert_eq!(converted_back.fds().len(), 1); 306 } 307 } 308