1 // Copyright 2022 The Chromium OS Authors. All rights reserved.
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 use libc::c_ulong;
20 use std::ffi::{CString, OsStr};
21 use std::iter::once;
22 use std::mem::MaybeUninit;
23 use std::os::windows::ffi::OsStrExt;
24 use std::os::windows::io::RawHandle;
25 use std::slice;
26 use std::sync::Once;
27 use std::{io, ptr};
28 use winapi::shared::minwindef::{DWORD, FALSE, TRUE};
29 use winapi::um::handleapi::{
30 CloseHandle, DuplicateHandle, SetHandleInformation, INVALID_HANDLE_VALUE,
31 };
32 use winapi::um::minwinbase::STILL_ACTIVE;
33 use winapi::um::processthreadsapi::{
34 GetCurrentProcess, GetExitCodeProcess, OpenProcess, ResumeThread,
35 };
36 use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO};
37 use winapi::um::winbase::{CreateFileMappingA, HANDLE_FLAG_INHERIT};
38 use winapi::um::winnt::{DUPLICATE_SAME_ACCESS, HRESULT, PROCESS_DUP_HANDLE};
39
40 #[macro_export]
41 macro_rules! syscall_bail {
42 ($details:expr) => {
43 ::anyhow::bail!(
44 "{} (Error code {})",
45 $details,
46 ::winapi::um::errhandlingapi::GetLastError()
47 )
48 };
49 }
50
51 /// Returns the lower 32 bits of a u64 as a u32 (c_ulong/DWORD)
get_low_order(number: u64) -> c_ulong52 pub fn get_low_order(number: u64) -> c_ulong {
53 (number & (u32::max_value() as u64)) as c_ulong
54 }
55
56 /// Returns the upper 32 bits of a u64 as a u32 (c_ulong/DWORD)
get_high_order(number: u64) -> c_ulong57 pub fn get_high_order(number: u64) -> c_ulong {
58 (number >> 32) as c_ulong
59 }
60
61 static INIT_NATIVE_SYSTEM_INFO: Once = Once::new();
62 static mut NATIVE_SYSTEM_INFO: MaybeUninit<SYSTEM_INFO> = MaybeUninit::uninit();
63
pagesize() -> usize64 pub fn pagesize() -> usize {
65 get_native_system_info().dwPageSize as usize
66 }
67
allocation_granularity() -> u6468 pub fn allocation_granularity() -> u64 {
69 get_native_system_info().dwAllocationGranularity as u64
70 }
71
number_of_processors() -> usize72 pub fn number_of_processors() -> usize {
73 get_native_system_info().dwNumberOfProcessors as usize
74 }
75
get_native_system_info() -> SYSTEM_INFO76 fn get_native_system_info() -> SYSTEM_INFO {
77 INIT_NATIVE_SYSTEM_INFO.call_once(|| unsafe {
78 // Safe because this is a universally available call on modern Windows systems.
79 GetNativeSystemInfo(NATIVE_SYSTEM_INFO.as_mut_ptr());
80 });
81 // Safe because it is guaranteed to be initialized by GetNativeSystemInfo above.
82 unsafe { NATIVE_SYSTEM_INFO.assume_init() }
83 }
84
win32_string(value: &str) -> CString85 pub fn win32_string(value: &str) -> CString {
86 CString::new(value).unwrap()
87 }
88
win32_wide_string(value: &str) -> Vec<u16>89 pub fn win32_wide_string(value: &str) -> Vec<u16> {
90 OsStr::new(value).encode_wide().chain(once(0)).collect()
91 }
92
93 /// Returns the length, in u16 words (*not* UTF-16 chars), of a null-terminated u16 string.
94 /// Safe when `wide` is non-null and points to a u16 string terminated by a null character.
strlen_ptr_u16(wide: *const u16) -> usize95 unsafe fn strlen_ptr_u16(wide: *const u16) -> usize {
96 assert!(!wide.is_null());
97 for i in 0.. {
98 if *wide.offset(i) == 0 {
99 return i as usize;
100 }
101 }
102 unreachable!()
103 }
104
105 /// Converts a UTF-16 null-terminated string to an owned `String`. Any invalid code points are
106 /// converted to `std::char::REPLACEMENT_CHARACTER`.
107 /// 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) -> String108 pub unsafe fn from_ptr_win32_wide_string(wide: *const u16) -> String {
109 assert!(!wide.is_null());
110 let len = strlen_ptr_u16(wide);
111 let slice = slice::from_raw_parts(wide, len);
112 String::from_utf16_lossy(slice)
113 }
114
duplicate_handle_with_target_pid(hndl: RawHandle, target_pid: u32) -> io::Result<RawHandle>115 pub fn duplicate_handle_with_target_pid(hndl: RawHandle, target_pid: u32) -> io::Result<RawHandle> {
116 // Safe because caller will guarentee `hndl` and `target_pid` are valid and won't be dropped.
117 unsafe {
118 let target_process_handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, target_pid);
119 if target_process_handle.is_null() {
120 return Err(io::Error::last_os_error());
121 }
122 let result = duplicate_handle_with_target_handle(hndl, target_process_handle);
123 CloseHandle(target_process_handle);
124 result
125 }
126 }
127
duplicate_handle_from_source_process( source_process_handle: RawHandle, hndl: RawHandle, target_process_handle: RawHandle, ) -> io::Result<RawHandle>128 pub fn duplicate_handle_from_source_process(
129 source_process_handle: RawHandle,
130 hndl: RawHandle,
131 target_process_handle: RawHandle,
132 ) -> io::Result<RawHandle> {
133 // Safe because:
134 // 1. We are checking the return code
135 // 2. new_handle_ptr points to a valid location on the stack
136 // 3. Caller guarantees hndl is a real valid handle.
137 unsafe {
138 let mut new_handle: RawHandle = ptr::null_mut();
139 let success_flag = DuplicateHandle(
140 /* hSourceProcessHandle= */ source_process_handle,
141 /* hSourceHandle= */ hndl,
142 /* hTargetProcessHandle= */ target_process_handle,
143 /* lpTargetHandle= */ &mut new_handle,
144 /* dwDesiredAccess= */ 0,
145 /* bInheritHandle= */ TRUE,
146 /* dwOptions= */ DUPLICATE_SAME_ACCESS,
147 );
148
149 if success_flag == FALSE {
150 Err(io::Error::last_os_error())
151 } else {
152 Ok(new_handle)
153 }
154 }
155 }
156
duplicate_handle_with_target_handle( hndl: RawHandle, target_process_handle: RawHandle, ) -> io::Result<RawHandle>157 fn duplicate_handle_with_target_handle(
158 hndl: RawHandle,
159 target_process_handle: RawHandle,
160 ) -> io::Result<RawHandle> {
161 // Safe because `GetCurrentProcess` just gets the current process handle.
162 duplicate_handle_from_source_process(
163 unsafe { GetCurrentProcess() },
164 hndl,
165 target_process_handle,
166 )
167 }
168
duplicate_handle(hndl: RawHandle) -> io::Result<RawHandle>169 pub fn duplicate_handle(hndl: RawHandle) -> io::Result<RawHandle> {
170 // Safe because `GetCurrentProcess` just gets the current process handle.
171 duplicate_handle_with_target_handle(hndl, unsafe { GetCurrentProcess() })
172 }
173
174 /// Sets whether a handle is inheritable. Note that this only works on some types of handles,
175 /// such as files, pipes, etc. See
176 /// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-sethandleinformation#parameters
177 /// for further details.
set_handle_inheritance(hndl: RawHandle, inheritable: bool) -> io::Result<()>178 pub fn set_handle_inheritance(hndl: RawHandle, inheritable: bool) -> io::Result<()> {
179 // Safe because even if hndl is invalid, no unsafe memory access will result.
180 let res = unsafe {
181 SetHandleInformation(
182 hndl,
183 HANDLE_FLAG_INHERIT,
184 if inheritable { HANDLE_FLAG_INHERIT } else { 0 },
185 )
186 };
187 if res == 0 {
188 Err(io::Error::last_os_error())
189 } else {
190 Ok(())
191 }
192 }
193
194 /// Rusty version of CreateFileMappingA.
195 ///
196 /// # Safety
197 /// 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>198 pub unsafe fn create_file_mapping(
199 handle: Option<RawHandle>,
200 size: u64,
201 protection: DWORD,
202 name: Option<&str>,
203 ) -> io::Result<RawHandle> {
204 let name_cstr = name.map(|s| CString::new(s).unwrap());
205 let name = name_cstr.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut());
206
207 // Safe because:
208 // 1. The caller guarantees handle is valid (if provided).
209 // 2. The C string is guaranteed valid.
210 // 3. We check the results of the call.
211 let mapping_handle = CreateFileMappingA(
212 match handle {
213 Some(h) => h,
214 None => INVALID_HANDLE_VALUE,
215 },
216 SecurityAttributes::new_with_security_descriptor(
217 SelfRelativeSecurityDescriptor::get_singleton(),
218 /* inherit= */ true,
219 )
220 .as_mut(),
221 protection,
222 get_high_order(size),
223 get_low_order(size),
224 name,
225 );
226
227 if mapping_handle.is_null() {
228 Err(io::Error::last_os_error())
229 } else {
230 Ok(mapping_handle)
231 }
232 }
233
234 #[derive(PartialEq)]
235 pub enum ThreadState {
236 // The specified thread was not suspended.
237 NotSuspended,
238 // The specified thread was suspended, but was restarted.
239 Restarted,
240 // The specified thread is still suspended.
241 StillSuspended,
242 }
243
244 /// Decrements a thread's suspend count. When the suspend count reaches 0, the
245 /// thread is resumed. Returned `ThreadState` indicates whether the thread was
246 /// resumed.
resume_thread(handle: RawHandle) -> io::Result<ThreadState>247 pub fn resume_thread(handle: RawHandle) -> io::Result<ThreadState> {
248 // Safe as even an invalid handle should cause no adverse effects.
249 match unsafe { ResumeThread(handle) } {
250 u32::MAX => Err(io::Error::last_os_error()),
251 0 => Ok(ThreadState::NotSuspended),
252 1 => Ok(ThreadState::Restarted),
253 _ => Ok(ThreadState::StillSuspended),
254 }
255 }
256
257 /// Retrieves the termination status of the specified process.
get_exit_code_process(handle: RawHandle) -> io::Result<Option<DWORD>>258 pub fn get_exit_code_process(handle: RawHandle) -> io::Result<Option<DWORD>> {
259 let mut exit_code: DWORD = 0;
260 // Safe as even an invalid handle should cause no adverse effects.
261 match unsafe { GetExitCodeProcess(handle, &mut exit_code) } {
262 0 => Err(io::Error::last_os_error()),
263 _ => {
264 if exit_code == STILL_ACTIVE {
265 Ok(None)
266 } else {
267 Ok(Some(exit_code))
268 }
269 }
270 }
271 }
272
273 pub type HResult<T> = Result<T, HRESULT>;
274
275 // windows-rs bindings
276 #[cfg(target_env = "msvc")]
277 mod bindings {
278 ::windows::include_bindings!();
279 }
280 #[cfg(target_env = "msvc")]
281 pub use bindings::Windows::Win32::Globalization::ImmDisableIME;
282
283 #[cfg(test)]
284 mod tests {
285 use super::*;
286
287 #[test]
high_low_order_utilities()288 fn high_low_order_utilities() {
289 let some_number: u64 = 0xA3200500FFB40123;
290 let high_order: u64 = get_high_order(some_number).into();
291 let low_order: u64 = get_low_order(some_number).into();
292 assert_eq!(some_number, (high_order << 32) + low_order);
293 }
294
295 #[test]
strlen()296 fn strlen() {
297 let u16s = [0];
298 assert_eq!(unsafe { strlen_ptr_u16((&u16s).as_ptr()) }, 0);
299 let u16s = [
300 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, 0,
301 ];
302 assert_eq!(unsafe { strlen_ptr_u16((&u16s).as_ptr()) }, 9);
303 }
304
305 #[test]
from_win32_wide_string()306 fn from_win32_wide_string() {
307 let u16s = [0];
308 assert_eq!(unsafe { from_ptr_win32_wide_string((&u16s).as_ptr()) }, "");
309 let u16s = [
310 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, 0,
311 ];
312 assert_eq!(
313 unsafe { from_ptr_win32_wide_string((&u16s).as_ptr()) },
314 "mus�ic�"
315 );
316 }
317 }
318