xref: /aosp_15_r20/external/crosvm/win_util/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Library for common Windows-specfic utilities
6 //!
7 //! TODO(b/223723424) win_util should be merged into win_sys_util or part of the
8 //! base.
9 
10 // Do nothing on unix as win_util is windows only.
11 #![cfg(windows)]
12 // TODO: Many pub functions take `RawHandle` (which is a pointer on Windows) but are not marked
13 // `unsafe`.
14 #![allow(clippy::not_unsafe_ptr_arg_deref)]
15 
16 mod large_integer;
17 pub use crate::large_integer::*;
18 
19 mod security_attributes;
20 pub use crate::security_attributes::*;
21 
22 mod dll_notification;
23 use std::ffi::CString;
24 use std::ffi::OsStr;
25 use std::ffi::OsString;
26 use std::io;
27 use std::iter::once;
28 use std::os::windows::ffi::OsStrExt;
29 use std::os::windows::ffi::OsStringExt;
30 use std::os::windows::io::RawHandle;
31 use std::ptr;
32 use std::slice;
33 
34 mod keyboard;
35 pub use keyboard::*;
36 use libc::c_ulong;
37 use serde::Deserialize;
38 use serde::Serialize;
39 use winapi::shared::minwindef::DWORD;
40 use winapi::shared::minwindef::FALSE;
41 use winapi::shared::minwindef::TRUE;
42 use winapi::shared::ntdef::UNICODE_STRING;
43 use winapi::um::handleapi::CloseHandle;
44 use winapi::um::handleapi::DuplicateHandle;
45 use winapi::um::handleapi::SetHandleInformation;
46 use winapi::um::handleapi::INVALID_HANDLE_VALUE;
47 use winapi::um::minwinbase::STILL_ACTIVE;
48 use winapi::um::processthreadsapi::GetCurrentProcess;
49 use winapi::um::processthreadsapi::GetExitCodeProcess;
50 use winapi::um::processthreadsapi::OpenProcess;
51 use winapi::um::processthreadsapi::ResumeThread;
52 use winapi::um::winbase::CreateFileMappingA;
53 use winapi::um::winbase::HANDLE_FLAG_INHERIT;
54 use winapi::um::winnt::DUPLICATE_SAME_ACCESS;
55 use winapi::um::winnt::HRESULT;
56 use winapi::um::winnt::PROCESS_DUP_HANDLE;
57 use winapi::um::winnt::WCHAR;
58 
59 pub use crate::dll_notification::*;
60 
61 pub mod dpapi;
62 
63 #[macro_export]
64 macro_rules! syscall_bail {
65     ($details:expr) => {
66         // SAFETY: Safe because GetLastError is thread safe and won't access the memory.
67         ::anyhow::bail!("{} (Error code {})", $details, unsafe {
68             ::winapi::um::errhandlingapi::GetLastError()
69         })
70     };
71 }
72 
73 #[macro_export]
74 macro_rules! fail_if_zero {
75     ($syscall:expr) => {
76         if $syscall == 0 {
77             return Err(io::Error::last_os_error());
78         }
79     };
80 }
81 
82 /// Returns the lower 32 bits of a u64 as a u32 (c_ulong/DWORD)
get_low_order(number: u64) -> c_ulong83 pub fn get_low_order(number: u64) -> c_ulong {
84     (number & (u32::MAX as u64)) as c_ulong
85 }
86 
87 /// Returns the upper 32 bits of a u64 as a u32 (c_ulong/DWORD)
get_high_order(number: u64) -> c_ulong88 pub fn get_high_order(number: u64) -> c_ulong {
89     (number >> 32) as c_ulong
90 }
91 
win32_string(value: &str) -> CString92 pub fn win32_string(value: &str) -> CString {
93     CString::new(value).unwrap()
94 }
95 
win32_wide_string(value: &str) -> Vec<u16>96 pub fn win32_wide_string(value: &str) -> Vec<u16> {
97     OsStr::new(value).encode_wide().chain(once(0)).collect()
98 }
99 
100 /// Returns the length, in u16 words (*not* UTF-16 chars), of a null-terminated u16 string.
101 /// Safe when `wide` is non-null and points to a u16 string terminated by a null character.
strlen_ptr_u16(wide: *const u16) -> usize102 unsafe fn strlen_ptr_u16(wide: *const u16) -> usize {
103     assert!(!wide.is_null());
104     for i in 0.. {
105         if *wide.offset(i) == 0 {
106             return i as usize;
107         }
108     }
109     unreachable!()
110 }
111 
112 /// Converts a UTF-16 null-terminated string to an owned `String`.  Any invalid code points are
113 /// converted to `std::char::REPLACEMENT_CHARACTER`.
114 ///
115 /// # Safety
116 ///
117 /// Safe when `wide` is non-null and points to a u16 string terminated by a null character.
from_ptr_win32_wide_string(wide: *const u16) -> String118 pub unsafe fn from_ptr_win32_wide_string(wide: *const u16) -> String {
119     assert!(!wide.is_null());
120     let len = strlen_ptr_u16(wide);
121     let slice = slice::from_raw_parts(wide, len);
122     String::from_utf16_lossy(slice)
123 }
124 
125 /// Converts a `UNICODE_STRING` into an `OsString`.
126 /// ## Safety
127 /// Safe when `unicode_string` is non-null and points to a valid
128 /// `UNICODE_STRING` struct.
unicode_string_to_os_string(unicode_string: &UNICODE_STRING) -> OsString129 pub fn unicode_string_to_os_string(unicode_string: &UNICODE_STRING) -> OsString {
130     // SAFETY:
131     // * Buffer is guaranteed to be properly aligned and valid for the entire length of the string.
132     // * The slice is only temporary, until we perform the `from_wide` conversion with `OsString`,
133     //   so the memory referenced by the slice is not modified during that duration.
134     OsString::from_wide(unsafe {
135         slice::from_raw_parts(
136             unicode_string.Buffer,
137             unicode_string.Length as usize / std::mem::size_of::<WCHAR>(),
138         )
139     })
140 }
141 
duplicate_handle_with_target_pid(hndl: RawHandle, target_pid: u32) -> io::Result<RawHandle>142 pub fn duplicate_handle_with_target_pid(hndl: RawHandle, target_pid: u32) -> io::Result<RawHandle> {
143     // SAFETY: Caller will guarantee `hndl` and `target_pid` are valid and won't be dropped.
144     unsafe {
145         let target_process_handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, target_pid);
146         if target_process_handle.is_null() {
147             return Err(io::Error::last_os_error());
148         }
149         let result = duplicate_handle_with_target_handle(hndl, target_process_handle);
150         CloseHandle(target_process_handle);
151         result
152     }
153 }
154 
duplicate_handle_from_source_process( source_process_handle: RawHandle, hndl: RawHandle, target_process_handle: RawHandle, ) -> io::Result<RawHandle>155 pub fn duplicate_handle_from_source_process(
156     source_process_handle: RawHandle,
157     hndl: RawHandle,
158     target_process_handle: RawHandle,
159 ) -> io::Result<RawHandle> {
160     // SAFETY:
161     // 1. We are checking the return code
162     // 2. new_handle_ptr points to a valid location on the stack
163     // 3. Caller guarantees hndl is a real valid handle.
164     unsafe {
165         let mut new_handle: RawHandle = ptr::null_mut();
166         let success_flag = DuplicateHandle(
167             /* hSourceProcessHandle= */ source_process_handle,
168             /* hSourceHandle= */ hndl,
169             /* hTargetProcessHandle= */ target_process_handle,
170             /* lpTargetHandle= */ &mut new_handle,
171             /* dwDesiredAccess= */ 0,
172             /* bInheritHandle= */ TRUE,
173             /* dwOptions= */ DUPLICATE_SAME_ACCESS,
174         );
175 
176         if success_flag == FALSE {
177             Err(io::Error::last_os_error())
178         } else {
179             Ok(new_handle)
180         }
181     }
182 }
183 
duplicate_handle_with_target_handle( hndl: RawHandle, target_process_handle: RawHandle, ) -> io::Result<RawHandle>184 fn duplicate_handle_with_target_handle(
185     hndl: RawHandle,
186     target_process_handle: RawHandle,
187 ) -> io::Result<RawHandle> {
188     duplicate_handle_from_source_process(
189         // SAFETY: `GetCurrentProcess` just gets the current process handle.
190         unsafe { GetCurrentProcess() },
191         hndl,
192         target_process_handle,
193     )
194 }
195 
duplicate_handle(hndl: RawHandle) -> io::Result<RawHandle>196 pub fn duplicate_handle(hndl: RawHandle) -> io::Result<RawHandle> {
197     // SAFETY: `GetCurrentProcess` just gets the current process handle.
198     duplicate_handle_with_target_handle(hndl, unsafe { GetCurrentProcess() })
199 }
200 
201 /// Sets whether a handle is inheritable. Note that this only works on some types of handles,
202 /// such as files, pipes, etc. See
203 /// <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-sethandleinformation#parameters>
204 /// for further details.
set_handle_inheritance(hndl: RawHandle, inheritable: bool) -> io::Result<()>205 pub fn set_handle_inheritance(hndl: RawHandle, inheritable: bool) -> io::Result<()> {
206     // SAFETY: Even if hndl is invalid, no unsafe memory access will result.
207     let res = unsafe {
208         SetHandleInformation(
209             hndl,
210             HANDLE_FLAG_INHERIT,
211             if inheritable { HANDLE_FLAG_INHERIT } else { 0 },
212         )
213     };
214     if res == 0 {
215         Err(io::Error::last_os_error())
216     } else {
217         Ok(())
218     }
219 }
220 
221 /// Rusty version of CreateFileMappingA.
222 ///
223 /// # Safety
224 /// If provided, the caller must ensure hndl is valid.
create_file_mapping( handle: Option<RawHandle>, size: u64, protection: DWORD, name: Option<&str>, ) -> io::Result<RawHandle>225 pub unsafe fn create_file_mapping(
226     handle: Option<RawHandle>,
227     size: u64,
228     protection: DWORD,
229     name: Option<&str>,
230 ) -> io::Result<RawHandle> {
231     let name_cstr = name.map(|s| CString::new(s).unwrap());
232     let name = name_cstr.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut());
233 
234     // Safe because:
235     // 1. The caller guarantees handle is valid (if provided).
236     // 2. The C string is guaranteed valid.
237     // 3. We check the results of the call.
238     let mapping_handle = CreateFileMappingA(
239         match handle {
240             Some(h) => h,
241             None => INVALID_HANDLE_VALUE,
242         },
243         SecurityAttributes::new_with_security_descriptor(
244             SelfRelativeSecurityDescriptor::get_singleton(),
245             /* inherit= */ true,
246         )
247         .as_mut(),
248         protection,
249         get_high_order(size),
250         get_low_order(size),
251         name,
252     );
253 
254     if mapping_handle.is_null() {
255         Err(io::Error::last_os_error())
256     } else {
257         Ok(mapping_handle)
258     }
259 }
260 
261 #[derive(PartialEq, Eq)]
262 pub enum ThreadState {
263     // The specified thread was not suspended.
264     NotSuspended,
265     // The specified thread was suspended, but was restarted.
266     Restarted,
267     // The specified thread is still suspended.
268     StillSuspended,
269 }
270 
271 /// Decrements a thread's suspend count. When the suspend count reaches 0, the
272 /// thread is resumed. Returned `ThreadState` indicates whether the thread was
273 /// resumed.
resume_thread(handle: RawHandle) -> io::Result<ThreadState>274 pub fn resume_thread(handle: RawHandle) -> io::Result<ThreadState> {
275     // SAFETY: Even an invalid handle should cause no adverse effects.
276     match unsafe { ResumeThread(handle) } {
277         u32::MAX => Err(io::Error::last_os_error()),
278         0 => Ok(ThreadState::NotSuspended),
279         1 => Ok(ThreadState::Restarted),
280         _ => Ok(ThreadState::StillSuspended),
281     }
282 }
283 
284 /// Retrieves the termination status of the specified process.
get_exit_code_process(handle: RawHandle) -> io::Result<Option<DWORD>>285 pub fn get_exit_code_process(handle: RawHandle) -> io::Result<Option<DWORD>> {
286     let mut exit_code: DWORD = 0;
287     // SAFETY: Even an invalid handle should cause no adverse effects.
288     match unsafe { GetExitCodeProcess(handle, &mut exit_code) } {
289         0 => Err(io::Error::last_os_error()),
290         _ => {
291             if exit_code == STILL_ACTIVE {
292                 Ok(None)
293             } else {
294                 Ok(Some(exit_code))
295             }
296         }
297     }
298 }
299 
300 pub type HResult<T> = Result<T, HRESULT>;
301 
302 /// Each type of process should have its own type here. This affects both exit
303 /// handling and sandboxing policy.
304 ///
305 /// WARNING: do NOT change the values items in this enum. The enum value is used in our exit codes,
306 /// and relied upon by metrics analysis. The max value for this enum is 0x1F = 31 as it is
307 /// restricted to five bits per `crate::crosvm::sys::windows::exit::to_process_type_error`.
308 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize, enumn::N)]
309 #[repr(u8)]
310 pub enum ProcessType {
311     UnknownType = 0,
312     Block = 1,
313     Main = 2,
314     Metrics = 3,
315     Net = 4,
316     Slirp = 5,
317     Gpu = 6,
318     Snd = 7,
319     Broker = 8,
320     Spu = 9,
321 }
322 
323 /// State of a crosvm child process.
324 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
325 pub enum ProcessState {
326     UnknownState,
327     /// Process is running normally.
328     Healthy,
329     /// Process died unexpectedly - it is either killed, crashed or something else.
330     Died,
331     /// Process exited on request or gracefully.
332     Exited,
333 }
334 
335 /// Priority of a crosvm child process.
336 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
337 pub enum ProcessPriority {
338     UnknwonPriority,
339     /// Crosvm critical process. In absence of this process crosvm cannot function normally.
340     Critical,
341     /// Non-critical process - the process is safe to restart. Crosvm/guest may continue to
342     /// function normally when such process dies.
343     NonCritical,
344 }
345 
346 /// Information about crosvm child process.
347 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
348 pub struct ProcessInfo {
349     pub id: u64,
350     pub ptype: ProcessType,
351     pub priority: ProcessPriority,
352     pub state: ProcessState,
353 }
354 #[cfg(test)]
355 mod tests {
356     use super::*;
357 
358     #[test]
high_low_order_utilities()359     fn high_low_order_utilities() {
360         let some_number: u64 = 0xA3200500FFB40123;
361         let high_order: u64 = get_high_order(some_number).into();
362         let low_order: u64 = get_low_order(some_number).into();
363         assert_eq!(some_number, (high_order << 32) + low_order);
364     }
365 
366     #[test]
strlen()367     fn strlen() {
368         let u16s = [0];
369         // SAFETY: u16s is a valid wide string
370         assert_eq!(unsafe { strlen_ptr_u16(u16s.as_ptr()) }, 0);
371         let u16s = [
372             0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, 0,
373         ];
374         // SAFETY: u16s is a valid wide string
375         assert_eq!(unsafe { strlen_ptr_u16(u16s.as_ptr()) }, 9);
376     }
377 
378     #[test]
from_win32_wide_string()379     fn from_win32_wide_string() {
380         let u16s = [0];
381         // SAFETY: u16s is a valid wide string
382         assert_eq!(unsafe { from_ptr_win32_wide_string(u16s.as_ptr()) }, "");
383         let u16s = [
384             0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, 0,
385         ];
386         assert_eq!(
387             // SAFETY: u16s is a valid wide string
388             unsafe { from_ptr_win32_wide_string(u16s.as_ptr()) },
389             "��mus�ic�"
390         );
391     }
392 }
393