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 use std::convert::TryFrom;
6 use std::fs::File;
7 use std::io;
8 use std::marker::Send;
9 use std::marker::Sync;
10 use std::ops::Drop;
11 use std::os::windows::io::AsRawHandle;
12 use std::os::windows::io::FromRawHandle;
13 use std::os::windows::io::IntoRawHandle;
14 use std::os::windows::io::RawHandle;
15
16 use winapi::shared::minwindef::FALSE;
17 use winapi::shared::minwindef::TRUE;
18 use winapi::um::handleapi::CloseHandle;
19 use winapi::um::handleapi::DuplicateHandle;
20 use winapi::um::processthreadsapi::GetCurrentProcess;
21 use winapi::um::winnt::DUPLICATE_SAME_ACCESS;
22
23 use crate::rutabaga_os::descriptor::AsRawDescriptor;
24 use crate::rutabaga_os::descriptor::Descriptor;
25 use crate::rutabaga_os::descriptor::FromRawDescriptor;
26 use crate::rutabaga_os::descriptor::IntoRawDescriptor;
27 use crate::rutabaga_os::descriptor::SafeDescriptor;
28
29 type Error = std::io::Error;
30 type Result<T> = std::result::Result<T, Error>;
31
32 pub type RawDescriptor = RawHandle;
33
34 impl Drop for SafeDescriptor {
drop(&mut self)35 fn drop(&mut self) {
36 // SAFETY: Safe because we own the descriptor.
37 unsafe { CloseHandle(self.descriptor as _) };
38 }
39 }
40
41 impl AsRawHandle for SafeDescriptor {
as_raw_handle(&self) -> RawHandle42 fn as_raw_handle(&self) -> RawHandle {
43 self.as_raw_descriptor()
44 }
45 }
46
duplicate_handle_from_source_process( source_process_handle: RawHandle, hndl: RawHandle, target_process_handle: RawHandle, ) -> io::Result<RawHandle>47 pub fn duplicate_handle_from_source_process(
48 source_process_handle: RawHandle,
49 hndl: RawHandle,
50 target_process_handle: RawHandle,
51 ) -> io::Result<RawHandle> {
52 // SAFETY: Safe because:
53 // 1. We are checking the return code
54 // 2. new_handle_ptr points to a valid location on the stack
55 // 3. Caller guarantees hndl is a real valid handle.
56 unsafe {
57 let new_handle: RawHandle = std::ptr::null_mut();
58 let success_flag = DuplicateHandle(
59 /* hSourceProcessHandle= */ source_process_handle as _,
60 /* hSourceHandle= */ hndl as _,
61 /* hTargetProcessHandle= */ target_process_handle as _,
62 /* lpTargetHandle= */ new_handle as _,
63 /* dwDesiredAccess= */ 0,
64 /* bInheritHandle= */ TRUE,
65 /* dwOptions= */ DUPLICATE_SAME_ACCESS,
66 );
67
68 if success_flag == FALSE {
69 Err(io::Error::last_os_error())
70 } else {
71 Ok(new_handle)
72 }
73 }
74 }
75
duplicate_handle_with_target_handle( hndl: RawHandle, target_process_handle: RawHandle, ) -> io::Result<RawHandle>76 fn duplicate_handle_with_target_handle(
77 hndl: RawHandle,
78 target_process_handle: RawHandle,
79 ) -> io::Result<RawHandle> {
80 duplicate_handle_from_source_process(
81 // SAFETY:
82 // Safe because `GetCurrentProcess` just gets the current process handle.
83 unsafe { GetCurrentProcess() as _ },
84 hndl,
85 target_process_handle,
86 )
87 }
88
duplicate_handle(hndl: RawHandle) -> io::Result<RawHandle>89 pub fn duplicate_handle(hndl: RawHandle) -> io::Result<RawHandle> {
90 // SAFETY:
91 // Safe because `GetCurrentProcess` just gets the current process handle.
92 duplicate_handle_with_target_handle(hndl, unsafe { GetCurrentProcess() as _ })
93 }
94
95 impl TryFrom<&dyn AsRawHandle> for SafeDescriptor {
96 type Error = std::io::Error;
97
try_from(handle: &dyn AsRawHandle) -> std::result::Result<Self, Self::Error>98 fn try_from(handle: &dyn AsRawHandle) -> std::result::Result<Self, Self::Error> {
99 Ok(SafeDescriptor {
100 descriptor: duplicate_handle(handle.as_raw_handle())?,
101 })
102 }
103 }
104
105 impl SafeDescriptor {
106 /// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
107 /// share the same underlying count within the kernel.
try_clone(&self) -> Result<SafeDescriptor>108 pub fn try_clone(&self) -> Result<SafeDescriptor> {
109 // SAFETY:
110 // Safe because `duplicate_handle` will return a valid handle, or at the very least error
111 // out.
112 Ok(unsafe { SafeDescriptor::from_raw_descriptor(duplicate_handle(self.descriptor)?) })
113 }
114 }
115
116 // SAFETY:
117 // On Windows, RawHandles are represented by raw pointers but are not used as such in
118 // rust code, and are therefore safe to send between threads.
119 unsafe impl Send for SafeDescriptor {}
120 // SAFETY: See safety comments for impl Send
121 unsafe impl Sync for SafeDescriptor {}
122
123 // SAFETY:
124 // On Windows, RawHandles are represented by raw pointers but are opaque to the
125 // userspace and cannot be derefenced by rust code, and are therefore safe to
126 // send between threads.
127 unsafe impl Send for Descriptor {}
128 // SAFETY: See safety comments for impl Send
129 unsafe impl Sync for Descriptor {}
130
131 macro_rules! AsRawDescriptor {
132 ($name:ident) => {
133 impl AsRawDescriptor for $name {
134 fn as_raw_descriptor(&self) -> RawDescriptor {
135 return self.as_raw_handle();
136 }
137 }
138 };
139 }
140
141 macro_rules! FromRawDescriptor {
142 ($name:ident) => {
143 impl FromRawDescriptor for $name {
144 // SAFETY: It is caller's responsibility to ensure that the descriptor is valid.
145 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
146 return $name::from_raw_handle(descriptor);
147 }
148 }
149 };
150 }
151
152 macro_rules! IntoRawDescriptor {
153 ($name:ident) => {
154 impl IntoRawDescriptor for $name {
155 fn into_raw_descriptor(self) -> RawDescriptor {
156 return self.into_raw_handle();
157 }
158 }
159 };
160 }
161
162 // Implementations for File. This enables the File-type to use the cross-platform
163 // RawDescriptor, but does not mean File should be used as a generic
164 // descriptor container. That should go to either SafeDescriptor or another more
165 // relevant container type.
166 // TODO(b/148971445): Ensure there are no usages of File that aren't actually files.
167 AsRawDescriptor!(File);
168 FromRawDescriptor!(File);
169 IntoRawDescriptor!(File);
170