Skip to content

Commit e9d0ae5

Browse files
committed
refactor attr list handling
1 parent ad247b7 commit e9d0ae5

File tree

2 files changed

+135
-72
lines changed

2 files changed

+135
-72
lines changed

src/windows/spawn.rs

Lines changed: 23 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod attr_list;
2+
13
use crate::{
24
windows::{
35
pipe::{self, ReadPipe, WritePipe},
@@ -6,6 +8,7 @@ use crate::{
68
},
79
InputSpecificationData, OutputSpecificationData,
810
};
11+
use attr_list::AttrList;
912
use std::{
1013
ffi::{OsStr, OsString},
1114
mem::size_of,
@@ -22,7 +25,7 @@ use winapi::{
2225
minwinbase::SECURITY_ATTRIBUTES,
2326
processthreadsapi::{
2427
CreateProcessW, DeleteProcThreadAttributeList, InitializeProcThreadAttributeList,
25-
UpdateProcThreadAttribute, PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_LIST,
28+
PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_LIST,
2629
},
2730
winbase::{
2831
CreateFileMappingA, CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT,
@@ -147,76 +150,22 @@ pub(in crate::windows) struct ChildParams {
147150
// TODO: upstream to winapi: https://github.com/retep998/winapi-rs/pull/933/
148151
const MAGIC_PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES: usize = 131081;
149152

150-
struct AlignedMemBlock(*mut u8, usize);
151-
152-
impl AlignedMemBlock {
153-
fn layout(cnt: usize) -> std::alloc::Layout {
154-
assert!(cnt > 0);
155-
std::alloc::Layout::from_size_align(cnt, 8).unwrap()
156-
}
157-
158-
fn new(cnt: usize) -> AlignedMemBlock {
159-
let ptr = unsafe { std::alloc::alloc_zeroed(Self::layout(cnt)) };
160-
AlignedMemBlock(ptr, cnt)
161-
}
162-
163-
fn ptr(&self) -> *mut u8 {
164-
self.0
165-
}
166-
}
167-
168-
impl Drop for AlignedMemBlock {
169-
fn drop(&mut self) {
170-
unsafe {
171-
std::alloc::dealloc(self.0, Self::layout(self.1));
172-
}
173-
}
174-
}
175-
176153
pub(in crate::windows) fn spawn(
177154
sandbox: &WindowsSandbox,
178155
stdio: Stdio,
179156
params: ChildParams,
180157
) -> Result<PROCESS_INFORMATION, Error> {
181-
let proc_thread_attr_list_storage;
182158
let mut security_capabilities;
159+
let mut proc_thread_attr_list = AttrList::new(1)?;
183160
let mut startup_info = unsafe {
184161
let mut startup_info: STARTUPINFOEXW = std::mem::zeroed();
185-
let mut proc_thread_attr_list_len = 0;
186-
{
187-
InitializeProcThreadAttributeList(
188-
std::ptr::null_mut(),
189-
// we need only one attribute: security capabilities.
190-
1,
191-
0,
192-
&mut proc_thread_attr_list_len,
193-
);
194-
if GetLastError() != ERROR_INSUFFICIENT_BUFFER {
195-
return Err(Error::last());
196-
}
197-
}
198-
proc_thread_attr_list_storage = AlignedMemBlock::new(proc_thread_attr_list_len);
199-
let proc_thread_attr_list = proc_thread_attr_list_storage.ptr();
200-
startup_info.lpAttributeList = proc_thread_attr_list.cast();
201-
Cvt::nonzero(InitializeProcThreadAttributeList(
202-
startup_info.lpAttributeList,
203-
1,
204-
0,
205-
&mut proc_thread_attr_list_len,
206-
))?;
162+
207163
security_capabilities = sandbox.profile.get_security_capabilities();
208-
Cvt::nonzero(UpdateProcThreadAttribute(
209-
startup_info.lpAttributeList,
210-
// reserved
211-
0,
164+
165+
proc_thread_attr_list.add_attr(
212166
MAGIC_PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
213-
(&mut security_capabilities as *mut SECURITY_CAPABILITIES).cast(),
214-
std::mem::size_of::<SECURITY_ATTRIBUTES>(),
215-
// reserved
216-
std::ptr::null_mut(),
217-
// reserved
218-
std::ptr::null_mut(),
219-
))?;
167+
&mut security_capabilities,
168+
)?;
220169

221170
startup_info.StartupInfo.cb = size_of::<STARTUPINFOEXW>() as u32;
222171
startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
@@ -229,21 +178,24 @@ pub(in crate::windows) fn spawn(
229178
startup_info.StartupInfo.hStdInput = cvt_handle(stdio.stdin);
230179
startup_info.StartupInfo.hStdOutput = cvt_handle(stdio.stdout);
231180
startup_info.StartupInfo.hStdError = cvt_handle(stdio.stderr);
181+
182+
startup_info.lpAttributeList = proc_thread_attr_list.borrow_ptr();
232183
startup_info
233184
};
234185
let creation_flags = CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT;
235186
let mut info: PROCESS_INFORMATION = unsafe { std::mem::zeroed() };
187+
let application_name: Vec<u16> = params.exe.encode_wide().collect();
188+
let mut cmd_line = application_name.clone();
189+
for arg in params.argv {
190+
quote_arg(&mut cmd_line, &arg);
191+
}
192+
let (mut env, env_status) = encode_env(&params.env);
193+
if let EncodeEnvResult::Partial = env_status {
194+
tracing::warn!("skipped zero chars in provided environment");
195+
}
196+
let cwd: Vec<u16> = params.cwd.encode_wide().collect();
197+
236198
unsafe {
237-
let application_name: Vec<u16> = params.exe.encode_wide().collect();
238-
let mut cmd_line = application_name.clone();
239-
for arg in params.argv {
240-
quote_arg(&mut cmd_line, &arg);
241-
}
242-
let (mut env, env_status) = encode_env(&params.env);
243-
if let EncodeEnvResult::Partial = env_status {
244-
tracing::warn!("skipped zero chars in provided environment");
245-
}
246-
let cwd: Vec<u16> = params.cwd.encode_wide().collect();
247199
Cvt::nonzero(CreateProcessW(
248200
application_name.as_ptr(),
249201
cmd_line.as_mut_ptr(),
@@ -259,7 +211,6 @@ pub(in crate::windows) fn spawn(
259211
(&mut startup_info as *mut STARTUPINFOEXW).cast(),
260212
&mut info,
261213
))?;
262-
DeleteProcThreadAttributeList(startup_info.lpAttributeList);
263214
}
264215
Ok(info)
265216
}

src/windows/spawn/attr_list.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//! RAII wrapper for ProcThreadAttrList
2+
use std::marker::PhantomData;
3+
4+
use crate::windows::{Cvt, Error};
5+
use winapi::{
6+
shared::winerror::ERROR_INSUFFICIENT_BUFFER,
7+
um::{
8+
errhandlingapi::GetLastError,
9+
processthreadsapi::{
10+
DeleteProcThreadAttributeList, InitializeProcThreadAttributeList,
11+
UpdateProcThreadAttribute, PROC_THREAD_ATTRIBUTE_LIST,
12+
},
13+
},
14+
};
15+
16+
pub struct AttrList<'a> {
17+
storage: AlignedMemBlock,
18+
cap: usize,
19+
len: usize,
20+
phantom: PhantomData<&'a mut &'a mut ()>,
21+
}
22+
23+
impl<'a> AttrList<'a> {
24+
pub fn new(capacity: usize) -> Result<Self, Error> {
25+
let mut proc_thread_attr_list_len = 0;
26+
unsafe {
27+
InitializeProcThreadAttributeList(
28+
std::ptr::null_mut(),
29+
// we need only one attribute: security capabilities.
30+
1,
31+
0,
32+
&mut proc_thread_attr_list_len,
33+
);
34+
if GetLastError() != ERROR_INSUFFICIENT_BUFFER {
35+
return Err(Error::last());
36+
}
37+
}
38+
let storage = AlignedMemBlock::new(proc_thread_attr_list_len);
39+
unsafe {
40+
Cvt::nonzero(InitializeProcThreadAttributeList(
41+
storage.ptr().cast(),
42+
1,
43+
0,
44+
&mut proc_thread_attr_list_len,
45+
))?;
46+
}
47+
48+
Ok(AttrList {
49+
storage,
50+
cap: capacity,
51+
len: 0,
52+
phantom: PhantomData,
53+
})
54+
}
55+
56+
pub fn add_attr<T>(&mut self, attr_name: usize, attr_val: &'a mut T) -> Result<(), Error> {
57+
assert!(self.len < self.cap);
58+
unsafe {
59+
Cvt::nonzero(UpdateProcThreadAttribute(
60+
self.storage.ptr().cast(),
61+
// reserved
62+
0,
63+
attr_name,
64+
(attr_val as *mut T).cast(),
65+
std::mem::size_of::<T>(),
66+
// reserved
67+
std::ptr::null_mut(),
68+
// reserved
69+
std::ptr::null_mut(),
70+
))?;
71+
}
72+
self.len += 1;
73+
Ok(())
74+
}
75+
76+
pub fn borrow_ptr(&self) -> *mut PROC_THREAD_ATTRIBUTE_LIST {
77+
assert_eq!(self.len, self.cap);
78+
self.storage.ptr().cast()
79+
}
80+
}
81+
82+
impl<'a> Drop for AttrList<'a> {
83+
fn drop(&mut self) {
84+
unsafe { DeleteProcThreadAttributeList(self.storage.ptr().cast()) };
85+
}
86+
}
87+
88+
struct AlignedMemBlock(*mut u8, usize);
89+
90+
impl AlignedMemBlock {
91+
fn layout(cnt: usize) -> std::alloc::Layout {
92+
assert!(cnt > 0);
93+
std::alloc::Layout::from_size_align(cnt, 8).unwrap()
94+
}
95+
96+
fn new(cnt: usize) -> AlignedMemBlock {
97+
let ptr = unsafe { std::alloc::alloc_zeroed(Self::layout(cnt)) };
98+
AlignedMemBlock(ptr, cnt)
99+
}
100+
101+
fn ptr(&self) -> *mut u8 {
102+
self.0
103+
}
104+
}
105+
106+
impl Drop for AlignedMemBlock {
107+
fn drop(&mut self) {
108+
unsafe {
109+
std::alloc::dealloc(self.0, Self::layout(self.1));
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)