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