• 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 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