sandbox_ipc/windows/
channel.rs

1use super::{Channel, SendableWinHandle};
2
3use std::{io, mem, ptr, process};
4use std::time::Duration;
5use std::os::windows::prelude::*;
6use std::ffi::{OsString, OsStr};
7
8use uuid::Uuid;
9use serde::{Serializer, Deserializer};
10use tokio::io::{AsyncRead, AsyncWrite};
11use tokio::reactor::{PollEvented, Handle as TokioHandle};
12use futures::{Poll};
13use platform::mio_named_pipes::NamedPipe as MioNamedPipe;
14use winapi::shared::minwindef::{DWORD, ULONG, BOOL, TRUE, FALSE};
15use winapi::shared::ntdef::{HANDLE};
16use winapi::shared::winerror::{ERROR_IO_PENDING};
17use winapi::um::minwinbase::{OVERLAPPED, SECURITY_ATTRIBUTES};
18use winapi::um::winbase::{PIPE_TYPE_MESSAGE, PIPE_READMODE_MESSAGE, PIPE_REJECT_REMOTE_CLIENTS, PIPE_ACCESS_DUPLEX, FILE_FLAG_OVERLAPPED, INFINITE};
19use winapi::um::winbase::{GetNamedPipeClientProcessId, GetNamedPipeServerProcessId};
20use winapi::um::winnt::{PROCESS_DUP_HANDLE, GENERIC_READ, GENERIC_WRITE, PSECURITY_DESCRIPTOR, PACL};
21use winapi::um::errhandlingapi::{GetLastError};
22use winapi::um::processthreadsapi::{GetCurrentProcess, GetCurrentProcessId, GetProcessId, OpenProcess};
23use winapi::um::namedpipeapi::{ConnectNamedPipe, WaitNamedPipeW, CreateNamedPipeW};
24use winapi::um::fileapi::{OPEN_EXISTING, CreateFileW};
25use winapi::um::ioapiset::{GetOverlappedResultEx};
26use winhandle::*;
27use widestring::WideCString;
28
29#[derive(Debug)]
30pub(crate) struct MessageChannel {
31    pipe: PollEvented<MioNamedPipe>,
32    server: bool,
33    target: HandleTarget,
34}
35
36#[derive(Debug)]
37pub(crate) enum HandleTarget<H = ProcessHandle> {
38    #[allow(dead_code)]
39    None,
40    CurrentProcess,
41    RemoteProcess(H),
42}
43
44impl MessageChannel {
45    pub fn pair(tokio_loop: &TokioHandle) -> io::Result<(MessageChannel, MessageChannel)> {
46        let (server_pipe, client_pipe) = raw_pipe_pair(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS)?;
47
48        Ok((
49            MessageChannel {
50                pipe: PollEvented::new_with_handle(unsafe { MioNamedPipe::from_raw_handle(server_pipe.into_raw()) }, tokio_loop)?,
51                server: true,
52                target: HandleTarget::CurrentProcess,
53            },
54            MessageChannel {
55                pipe: PollEvented::new_with_handle(unsafe { MioNamedPipe::from_raw_handle(client_pipe.into_raw()) }, tokio_loop)?,
56                server: false,
57                target: HandleTarget::CurrentProcess,
58            },
59        ))
60    }
61
62    pub fn establish_with_child<F>(command: &mut process::Command, tokio_loop: &TokioHandle, transmit_and_launch: F) -> io::Result<(Self, process::Child)> where
63        F: FnOnce(&mut process::Command, ChildMessageChannel) -> io::Result<process::Child>
64    {
65        Self::establish_with_child_custom(tokio_loop, |to_be_sent| {
66            let child = transmit_and_launch(command, to_be_sent)?;
67            Ok((::ProcessHandle::from_windows_handle(&child)?.0, child))
68        })
69    }
70
71    pub fn establish_with_child_custom<F, T>(tokio_loop: &TokioHandle, transmit_and_launch: F) -> io::Result<(Self, T)> where
72        F: FnOnce(ChildMessageChannel) -> io::Result<(ProcessHandle, T)>,
73    {
74        let (server_pipe, client_pipe) = raw_pipe_pair(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS)?;
75        let inheritable_process_handle = WinHandle::from_raw(unsafe { GetCurrentProcess() }).unwrap().clone_ex(true, ClonedHandleAccess::Explicit(PROCESS_DUP_HANDLE))?;
76        let to_be_sent = ChildMessageChannel {
77            channel_handle: client_pipe.modify(true, ClonedHandleAccess::Same)?,
78            remote_process_handle: Some(inheritable_process_handle),
79            remote_process_id: unsafe { GetCurrentProcessId() },
80        };
81
82        let (child_handle, t) = transmit_and_launch(to_be_sent)?;
83        let channel = MessageChannel {
84            pipe: PollEvented::new_with_handle(unsafe { MioNamedPipe::from_raw_handle(server_pipe.into_raw()) }, tokio_loop)?,
85            server: true,
86            target: HandleTarget::RemoteProcess(child_handle),
87        };
88
89        Ok((channel, t))
90    }
91}
92
93impl Channel for MessageChannel {
94    fn handle_target(&self) -> HandleTarget<&ProcessHandle> {
95        match self.target {
96            HandleTarget::None => HandleTarget::None,
97            HandleTarget::CurrentProcess => HandleTarget::CurrentProcess,
98            HandleTarget::RemoteProcess(ref p) => HandleTarget::RemoteProcess(p),
99        }
100    }
101}
102
103#[derive(Debug, Serialize, Deserialize)]
104pub(crate) struct ChildMessageChannel {
105    #[serde(with = "inheritable_channel_serialize")]
106    channel_handle: WinHandle,
107    #[serde(with = "inheritable_channel_serialize_opt")]
108    remote_process_handle: Option<WinHandle>,
109    remote_process_id: DWORD,
110}
111
112mod inheritable_channel_serialize {
113    use super::*;
114
115    use serde::{Serialize, Deserialize};
116
117    pub fn serialize<S>(handle: &WinHandle, serializer: S) -> Result<S::Ok, S::Error> where
118        S: Serializer,
119    {
120        usize::serialize(&(handle.get() as usize), serializer)
121    }
122
123    pub fn deserialize<'de, D>(deserializer: D) -> Result<WinHandle, D::Error> where
124        D: Deserializer<'de>,
125    {
126        use serde::de::Error;
127
128        let handle = usize::deserialize(deserializer)?;
129        WinHandle::from_raw(handle as HANDLE)
130            .ok_or_else(|| D::Error::custom(io::Error::new(io::ErrorKind::InvalidData, "received invalid inherited handle")))
131    }
132}
133
134mod inheritable_channel_serialize_opt {
135    use super::*;
136
137    use serde::{Serialize, Deserialize};
138
139    pub fn serialize<S>(handle: &Option<WinHandle>, serializer: S) -> Result<S::Ok, S::Error> where
140        S: Serializer,
141    {
142        Option::<usize>::serialize(&handle.as_ref().map(|handle|(handle.get() as usize)), serializer)
143    }
144
145    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<WinHandle>, D::Error> where
146        D: Deserializer<'de>,
147    {
148        use serde::de::Error;
149
150        if let Some(handle) = Option::<usize>::deserialize(deserializer)? {
151            Ok(Some(WinHandle::from_raw(handle as HANDLE)
152                .ok_or_else(|| D::Error::custom(io::Error::new(io::ErrorKind::InvalidData, "received invalid inherited handle")))?
153            ))
154        } else {
155            Ok(None)
156        }
157    }
158}
159
160impl ChildMessageChannel {
161    pub fn into_channel(self, tokio: &TokioHandle) -> io::Result<MessageChannel> {
162        Ok(
163            MessageChannel {
164                pipe: PollEvented::new_with_handle(unsafe { MioNamedPipe::from_raw_handle(self.channel_handle.into_raw()) }, tokio)?,
165                server: false,
166                target: if let Some(handle) = self.remote_process_handle {
167                    HandleTarget::RemoteProcess(ProcessHandle {
168                        handle: SendableWinHandle(handle),
169                        id: self.remote_process_id,
170                    })
171                } else {
172                    HandleTarget::None
173                },
174            }
175        )
176    }
177}
178
179pub trait ChildRawMessageChannelExt {
180    fn handles(&self) -> ChildMessageChannelHandles;
181}
182
183impl ChildRawMessageChannelExt for ::ChildRawMessageChannel {
184    fn handles(&self) -> ChildMessageChannelHandles {
185        ChildMessageChannelHandles { channel_handle: &self.0, index: 0 }
186    }
187}
188
189pub trait ChildMessageChannelExt {
190    fn handles(&self) -> ChildMessageChannelHandles;
191}
192
193impl ChildMessageChannelExt for ::ChildMessageChannel {
194    fn handles(&self) -> ChildMessageChannelHandles {
195        ChildMessageChannelHandles { channel_handle: &self.inner, index: 0 }
196    }
197}
198
199pub struct ChildMessageChannelHandles<'a> {
200    channel_handle: &'a ChildMessageChannel,
201    index: usize,
202}
203
204impl<'a> Iterator for ChildMessageChannelHandles<'a> {
205    type Item = HANDLE;
206
207    fn next(&mut self) -> Option<HANDLE> {
208        let handle = match self.index {
209            0 => Some(self.channel_handle.channel_handle.get()),
210            1 => self.channel_handle.remote_process_handle.as_ref().map(|x| x.get()),
211            _ => return None,
212        };
213        self.index += 1;
214        handle
215    }
216}
217
218#[derive(Serialize, Deserialize, Debug)]
219pub(crate) struct PreMessageChannel {
220    pipe: SendableWinHandle,
221    server: bool,
222}
223
224impl PreMessageChannel {
225    pub fn pair() -> io::Result<(Self, Self)> {
226        let (server_pipe, client_pipe) = raw_pipe_pair(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS)?;
227
228        Ok((
229            PreMessageChannel { pipe: SendableWinHandle(server_pipe), server: true },
230            PreMessageChannel { pipe: SendableWinHandle(client_pipe), server: false },
231        ))
232    }
233
234    pub fn into_channel(self, process_handle: ProcessHandle, tokio_loop: &TokioHandle) -> io::Result<MessageChannel> {
235        Ok(MessageChannel {
236            pipe: PollEvented::new_with_handle(unsafe { MioNamedPipe::from_raw_handle(self.pipe.0.into_raw()) }, tokio_loop)?,
237            server: self.server,
238            target: HandleTarget::RemoteProcess(process_handle),
239        })
240    }
241
242    pub fn into_sealed_channel(self, tokio_loop: &TokioHandle) -> io::Result<MessageChannel> {
243        Ok(MessageChannel {
244            pipe: PollEvented::new_with_handle(unsafe { MioNamedPipe::from_raw_handle(self.pipe.0.into_raw()) }, tokio_loop)?,
245            server: self.server,
246            target: HandleTarget::None,
247        })
248    }
249}
250
251#[derive(Serialize, Deserialize, Debug)]
252pub(crate) struct ProcessHandle {
253    pub(crate) handle: SendableWinHandle,
254    pub(crate) id: DWORD,
255}
256
257impl ProcessHandle {
258    pub fn current() -> io::Result<Self> {
259        let handle = WinHandle::from_raw(unsafe { GetCurrentProcess() }).unwrap()
260            .clone_ex(false, ClonedHandleAccess::Explicit(PROCESS_DUP_HANDLE))?;
261        let id = unsafe { GetCurrentProcessId() };
262        Ok(ProcessHandle {
263            handle: SendableWinHandle(handle),
264            id,
265        })
266    }
267
268    pub fn clone(&self) -> io::Result<Self> {
269        Ok(ProcessHandle {
270            handle: SendableWinHandle(self.handle.0.clone()?),
271            id: self.id,
272        })
273    }
274
275    pub fn from_child(child: &process::Child) -> io::Result<Self> {
276        Ok(ProcessHandle {
277            handle: SendableWinHandle(WinHandle::clone_from_ex(child, false, ClonedHandleAccess::Explicit(PROCESS_DUP_HANDLE))?),
278            id: child.id(),
279        })
280    }
281}
282
283pub trait ProcessHandleExt: Sized {
284    fn from_windows_handle<H>(handle: &H) -> io::Result<Self> where H: AsRawHandle;
285    unsafe fn from_windows_handle_raw(handle: HANDLE) -> io::Result<Self>;
286}
287
288impl ProcessHandleExt for ::ProcessHandle {
289    /// Creates a `ProcessHandle` from a raw Windows process handle.
290    /// 
291    /// The handle must have the PROCESS_DUP_HANDLE and PROCESS_QUERY_INFORMATION access rights. The handle
292    /// need not stay open.
293    fn from_windows_handle<H>(handle: &H) -> io::Result<Self> where H: AsRawHandle {
294        unsafe { Self::from_windows_handle_raw(handle.as_raw_handle()) }
295    }
296
297    /// Creates a `ProcessHandle` from a raw Windows process handle.
298    /// 
299    /// The handle must have the PROCESS_DUP_HANDLE and PROCESS_QUERY_INFORMATION access rights. The handle
300    /// need not stay open.
301    unsafe fn from_windows_handle_raw(handle: HANDLE) -> io::Result<Self> {
302        let id = GetProcessId(handle);
303        if id == 0 {
304            return Err(io::Error::last_os_error());
305        }
306        Ok(::ProcessHandle(ProcessHandle {
307            handle: SendableWinHandle(WinHandle::clone_from_raw_ex(handle, false, ClonedHandleAccess::Explicit(PROCESS_DUP_HANDLE))?),
308            id,
309        }))
310    }
311}
312
313pub(crate) struct NamedMessageChannel {
314    name: OsString,
315    server_pipe: WinHandle,
316    overlapped: Box<OVERLAPPED>,
317    tokio_loop: TokioHandle,
318}
319
320impl NamedMessageChannel {
321    pub fn new(tokio: &TokioHandle) -> io::Result<Self> {
322        let pipe_name = format!(r#"\\.\pipe\{}"#, Uuid::new_v4());
323
324        unsafe {
325            let server_pipe = winapi_handle_call! { CreateNamedPipeW(
326                WideCString::from_str(&pipe_name).unwrap().as_ptr(),
327                PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
328                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
329                1,
330                0, 0,
331                0,
332                ptr::null_mut()
333            )}?;
334
335            // Begin connection operation on server half
336            let mut overlapped: Box<OVERLAPPED> = Box::new(mem::zeroed());
337
338            if ConnectNamedPipe(
339                server_pipe.get(),
340                &mut *overlapped
341            ) != 0 {
342                return Err(io::Error::last_os_error());
343            }
344
345            if GetLastError() != ERROR_IO_PENDING {
346                return Err(io::Error::last_os_error());
347            }
348
349            Ok(NamedMessageChannel {
350                name: OsString::from(pipe_name),
351                server_pipe,
352                overlapped,
353                tokio_loop: tokio.clone(),
354            })
355        }
356    }
357
358    pub fn name(&self) -> &OsStr {
359        &self.name
360    }
361
362    pub fn accept(mut self, timeout: Option<Duration>) -> io::Result<MessageChannel> {
363        unsafe {
364            let timeout = if let Some(duration) = timeout {
365                (duration.as_secs() * 1000 + (duration.subsec_nanos() as u64 / (1000 * 1000))) as ULONG
366            } else {
367                INFINITE
368            };
369            let mut bytes: DWORD = 0;
370            winapi_bool_call!(GetOverlappedResultEx(
371                self.server_pipe.get(),
372                &mut *self.overlapped,
373                &mut bytes,
374                timeout,
375                TRUE
376            ))?;
377
378            let mut process_id: ULONG = 0;
379            winapi_bool_call!(GetNamedPipeClientProcessId(
380                self.server_pipe.get(),
381                &mut process_id,
382            ))?;
383
384            let remote_process_handle = winapi_handle_call!(OpenProcess(
385                PROCESS_DUP_HANDLE,
386                FALSE,
387                process_id,
388            ))?;
389
390            let remote_process_handle = ProcessHandle {
391                handle: SendableWinHandle(remote_process_handle),
392                id: process_id as DWORD, 
393            };
394
395            Ok(MessageChannel {
396                pipe: PollEvented::new_with_handle(MioNamedPipe::from_raw_handle(self.server_pipe.into_raw()), &self.tokio_loop)?,
397                server: true,
398                target: HandleTarget::RemoteProcess(remote_process_handle),
399            })
400        }
401    }
402
403    pub fn connect<N>(name: N, timeout: Option<Duration>, tokio_loop: &TokioHandle) -> io::Result<MessageChannel> where
404        N: AsRef<OsStr>,
405    {
406        unsafe {
407            let name = WideCString::from_str(name.as_ref())
408                .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid name for named pipe"))?;
409
410            let timeout = if let Some(duration) = timeout {
411                (duration.as_secs() * 1000 + (duration.subsec_nanos() as u64 / (1000 * 1000))) as DWORD
412            } else {
413                NMPWAIT_WAIT_FOREVER
414            };
415
416            winapi_bool_call!(WaitNamedPipeW(
417                name.as_ptr(),
418                timeout,
419            ))?;
420
421            let client_pipe = winapi_handle_call! { CreateFileW(
422                name.as_ptr(),
423                GENERIC_READ | GENERIC_WRITE,
424                0,
425                ptr::null_mut(),
426                OPEN_EXISTING,
427                SECURITY_IDENTIFICATION | FILE_FLAG_OVERLAPPED,
428                ptr::null_mut()
429            )}?;
430
431            let mut process_id: ULONG = 0;
432            winapi_bool_call!(GetNamedPipeServerProcessId(
433                client_pipe.get(),
434                &mut process_id,
435            ))?;
436
437            let remote_process_handle = winapi_handle_call!(OpenProcess(
438                PROCESS_DUP_HANDLE,
439                FALSE,
440                process_id,
441            ))?;
442
443            let remote_process_handle = ProcessHandle {
444                handle: SendableWinHandle(remote_process_handle),
445                id: process_id,
446            };
447
448            Ok(MessageChannel {
449                pipe: PollEvented::new_with_handle(MioNamedPipe::from_raw_handle(client_pipe.into_raw()), tokio_loop)?,
450                server: false,
451                target: HandleTarget::RemoteProcess(remote_process_handle),
452            })
453        }
454    }
455}
456
457impl io::Write for MessageChannel {
458    fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
459        self.pipe.write(buffer)
460    }
461
462    fn flush(&mut self) -> io::Result<()> {
463        self.pipe.flush()
464    }
465}
466
467impl AsyncWrite for MessageChannel {
468    fn shutdown(&mut self) -> Poll<(), io::Error> {
469        self.pipe.shutdown()
470    }
471}
472
473impl io::Read for MessageChannel {
474    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
475        self.pipe.read(buffer)
476    }
477}
478
479impl AsyncRead for MessageChannel {
480
481}
482
483fn raw_pipe_pair(pipe_type: DWORD) -> io::Result<(WinHandle, WinHandle)> {
484    unsafe {
485        let pipe_name = OsString::from(format!(r#"\\.\pipe\{}"#, Uuid::new_v4()));
486
487        // Give pipe a null security descriptor
488        let mut security_descriptor: [u8; 256] = mem::zeroed(); // TODO: don't fudge this structure
489        winapi_bool_call!(log: InitializeSecurityDescriptor(security_descriptor.as_mut_ptr() as _, 1))?;
490        winapi_bool_call!(log: SetSecurityDescriptorDacl(security_descriptor.as_mut_ptr() as _, TRUE, ptr::null_mut(), FALSE))?;
491
492        let mut security_attributes = SECURITY_ATTRIBUTES {
493            nLength: mem::size_of::<SECURITY_ATTRIBUTES>() as DWORD,
494            lpSecurityDescriptor: security_descriptor.as_mut_ptr() as _,
495            bInheritHandle: FALSE,
496        };
497
498        debug!("creating named pipe pair {:?}", pipe_name);
499        let server_pipe = winapi_handle_call! { CreateNamedPipeW(
500            WideCString::from_str(&pipe_name).unwrap().as_ptr(),
501            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
502            pipe_type,
503            1,
504            0, 0,
505            0,
506            &mut security_attributes,
507        )}?;
508
509        // Begin connection operation on server half
510        let mut overlapped: OVERLAPPED = mem::zeroed();
511
512        // This should not succeed (we are doing overlapped IO)
513        if ConnectNamedPipe(
514            server_pipe.get(),
515            &mut overlapped
516        ) != 0 {
517            return Err(io::Error::last_os_error());
518        }
519
520        if GetLastError() != ERROR_IO_PENDING {
521            return Err(io::Error::last_os_error());
522        }
523
524
525        let client_pipe = winapi_handle_call!(log: CreateFileW(
526            WideCString::from_str(&pipe_name).unwrap().as_ptr(),
527            GENERIC_READ | GENERIC_WRITE,
528            0,
529            &mut security_attributes,
530            OPEN_EXISTING,
531            SECURITY_IDENTIFICATION | FILE_FLAG_OVERLAPPED,
532            ptr::null_mut()
533        ))?;
534
535        let mut bytes: DWORD = 0;
536        winapi_bool_call!(log: GetOverlappedResultEx(
537            server_pipe.get(),
538            &mut overlapped,
539            &mut bytes,
540            1000,
541            TRUE
542        ))?;
543    
544        Ok((server_pipe, client_pipe))
545    }
546}
547
548const SECURITY_IDENTIFICATION: DWORD = 65536;
549const NMPWAIT_WAIT_FOREVER: DWORD = 0xFFFFFFFF;
550
551extern "system" {
552    fn InitializeSecurityDescriptor(desc: PSECURITY_DESCRIPTOR, revision: DWORD) -> BOOL;
553    fn SetSecurityDescriptorDacl(desc: PSECURITY_DESCRIPTOR, bDaclPresent: BOOL, pDacl: PACL, bDaclDefaulted: BOOL) -> BOOL;
554}