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