sandbox_ipc/unix/
mod.rs

1use ::io::{SendableFile, SendableSocket};
2use ser::{SerializeWrapper, SerializeWrapperGuard};
3
4extern crate libc;
5extern crate mio;
6
7mod channel;
8mod sharedmem;
9mod sync;
10mod fd;
11
12pub use self::channel::*;
13pub(crate) use self::sharedmem::*;
14pub(crate) use self::sync::*;
15use self::fd::*;
16
17use std::{io, fs, mem, ptr, slice};
18use std::cell::RefCell;
19use std::borrow::Borrow;
20use std::ffi::OsStr;
21use std::os::unix::prelude::*;
22
23use serde::{Serialize, Deserialize, Serializer, Deserializer};
24
25thread_local! {
26    static CURRENT_SERIALIZE_CHANNEL_REMOTE_PROCESS: RefCell<Option<HandleSender>> = RefCell::new(None);
27    static CURRENT_DESERIALIZE_CHANNEL_REMOTE_PROCESS: RefCell<Option<HandleReceiver>> = RefCell::new(None);
28}
29
30#[derive(Debug)]
31pub struct SendableFd<B = libc::c_int>(pub B);
32
33impl Serialize for SendableFd {
34    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
35        where S: Serializer
36    {
37        use serde::ser::Error;
38
39        CURRENT_SERIALIZE_CHANNEL_REMOTE_PROCESS.with(|sender_guard| {
40            let mut sender_guard = sender_guard.borrow_mut();
41            let sender = sender_guard.as_mut()
42                .ok_or_else(|| S::Error::custom("attempted to serialize file descriptor outside of IPC channel"))?;
43            let index = sender.send(self.0)
44                .map_err(|err| S::Error::custom(err))?;
45            usize::serialize(&index, serializer)
46        })
47    }
48}
49
50impl<'a, B> Serialize for SendableFd<&'a B> where
51    B: AsRawFd,
52{
53    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
54        where S: Serializer
55    {
56        SendableFd(self.0.as_raw_fd()).serialize(serializer)
57    }
58}
59
60impl<'de> Deserialize<'de> for SendableFd {
61    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
62        where D: Deserializer<'de>
63    {
64        use serde::de::Error;
65
66        CURRENT_DESERIALIZE_CHANNEL_REMOTE_PROCESS.with(|receiver_guard| {
67            let mut receiver_guard = receiver_guard.borrow_mut();
68            let receiver = receiver_guard.as_mut()
69                .ok_or_else(|| D::Error::custom("attempted to deserialize file descriptor outside of IPC channel"))?;
70            let index = usize::deserialize(deserializer)?;
71            let fd = receiver.recv(index)
72                .map_err(|err| D::Error::custom(err))?;
73            Ok(SendableFd(fd))
74        })
75    }
76}
77
78
79impl<B> Serialize for SendableFile<B> where
80    B: Borrow<fs::File>,
81{
82    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83        where S: Serializer
84    {
85        SendableFd(self.0.borrow().as_raw_fd()).serialize(serializer)
86    }
87}
88
89impl<'de> Deserialize<'de> for SendableFile {
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91        where D: Deserializer<'de>
92    {
93        let handle = SendableFd::deserialize(deserializer)?;
94        Ok(SendableFile(unsafe { fs::File::from_raw_fd(handle.0) }))
95    }
96}
97
98impl<B> Serialize for SendableSocket<B> where
99    B: AsRawFd,
100{
101    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
102        where S: Serializer
103    {
104        SendableFd(self.0.as_raw_fd()).serialize(serializer)
105    }
106}
107
108impl<'de, B> Deserialize<'de> for SendableSocket<B> where
109    B: FromRawFd,
110{
111    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
112        where D: Deserializer<'de>
113    {
114        let handle = SendableFd::deserialize(deserializer)?;
115        Ok(SendableSocket(unsafe { B::from_raw_fd(handle.0) }))
116    }
117}
118
119pub(crate) struct ChannelSerializeWrapper;
120
121impl<'a, C> SerializeWrapper<'a, C> for ChannelSerializeWrapper where
122    C: Channel,
123{
124    type SerializeGuard = ChannelSerializeGuard<'a>;
125    type DeserializeGuard = ChannelDeserializeGuard;
126
127    fn before_serialize(channel: &'a mut C) -> ChannelSerializeGuard {
128        let sender = HandleSender {
129            fds: [0; MAX_MSG_FDS],
130            index: 0,
131        };
132        let mut sender = Some(sender);
133
134        CURRENT_SERIALIZE_CHANNEL_REMOTE_PROCESS.with(|x| 
135            mem::swap(
136                &mut *x.borrow_mut(),
137                &mut sender,
138            )
139        );
140        ChannelSerializeGuard(sender, channel.cmsg())
141    }
142
143    fn before_deserialize(channel: &'a mut C) -> ChannelDeserializeGuard {
144        let mut receiver = HandleReceiver {
145            fds: [0; MAX_MSG_FDS],
146            fds_count: channel.cmsg().current_fd_count(),
147        };
148        receiver.fds[..receiver.fds_count].copy_from_slice(channel.cmsg().fds());
149        let mut receiver = Some(receiver);
150
151        CURRENT_DESERIALIZE_CHANNEL_REMOTE_PROCESS.with(|x|
152            mem::swap(
153                &mut *x.borrow_mut(),
154                &mut receiver,
155            )
156        );
157        ChannelDeserializeGuard(receiver)
158    }
159}
160
161pub(crate) struct ChannelSerializeGuard<'a>(Option<HandleSender>, &'a mut Cmsg);
162
163impl<'a> Drop for ChannelSerializeGuard<'a> {
164    fn drop(&mut self) {
165        CURRENT_SERIALIZE_CHANNEL_REMOTE_PROCESS.with(|sender_guard| {
166            let mut sender_guard = sender_guard.borrow_mut();
167            *sender_guard = self.0.take();
168        });
169    }
170}
171
172impl<'a> SerializeWrapperGuard<'a> for ChannelSerializeGuard<'a> {
173    fn commit(self) {
174        CURRENT_SERIALIZE_CHANNEL_REMOTE_PROCESS.with(|sender_guard| {
175            let mut sender_guard = sender_guard.borrow_mut();
176            let sender = sender_guard.as_mut().unwrap();
177            self.1.set_fds(&sender.fds[..sender.index]);
178        });
179    }
180}
181
182pub(crate) struct ChannelDeserializeGuard(Option<HandleReceiver>);
183
184impl Drop for ChannelDeserializeGuard {
185    fn drop(&mut self) {
186        CURRENT_DESERIALIZE_CHANNEL_REMOTE_PROCESS.with(|x| *x.borrow_mut() = self.0.take());
187    }
188}
189
190impl<'a> SerializeWrapperGuard<'a> for ChannelDeserializeGuard {
191    fn commit(self) {
192    }
193}
194
195pub(crate) trait Channel {
196    fn cmsg(&mut self) -> &mut Cmsg;
197}
198
199struct HandleSender {
200    fds: [libc::c_int; MAX_MSG_FDS],
201    index: usize,
202}
203
204struct HandleReceiver {
205    fds: [libc::c_int; MAX_MSG_FDS],
206    fds_count: usize,
207}
208
209impl HandleSender {
210    fn send(&mut self, fd: libc::c_int) -> io::Result<usize> {
211        let index = self.index;
212
213        if index >= self.fds.len() {
214            return Err(io::Error::new(io::ErrorKind::InvalidInput, "too many file descriptors in message destined for channel"));
215        }
216
217        // We need to clone fds in case they are dropped before the message is sent
218        let new_fd = unsafe { libc::dup(fd) };
219        if new_fd < 0 {
220            return Err(io::Error::last_os_error());
221        }
222        set_cloexec(new_fd)?;
223        // FIXME: close dup fds
224
225        self.fds[index] = new_fd;
226        self.index += 1;
227        Ok(index)
228    }
229}
230
231impl HandleReceiver {
232    fn recv(&self, index: usize) -> io::Result<libc::c_int> {
233        if index >= self.fds_count {
234            return Err(io::Error::new(io::ErrorKind::InvalidData, "out of range file descriptor index"));
235        }
236        let fd = self.fds[index];
237
238        if unsafe { libc::fcntl(fd, libc::F_GETFD, 0) } < 0 {
239            return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid file descriptor received"));
240        }
241
242        set_cloexec(fd)?;
243
244        Ok(fd)
245    }
246}
247
248fn set_cloexec(fd: libc::c_int) -> io::Result<()> {
249    unsafe {
250        let old_flags = libc::fcntl(fd, libc::F_GETFD, 0);
251        if libc::fcntl(fd, libc::F_SETFD, old_flags | libc::FD_CLOEXEC) == -1 {
252            return Err(io::Error::last_os_error());
253        }
254        Ok(())
255    }
256}
257
258fn clear_cloexec(fd: libc::c_int) -> io::Result<()> {
259    unsafe {
260        let old_flags = libc::fcntl(fd, libc::F_GETFD, 0);
261        if libc::fcntl(fd, libc::F_SETFD, old_flags & !libc::FD_CLOEXEC) == -1 {
262            return Err(io::Error::last_os_error());
263        }
264        Ok(())
265    }
266}
267
268fn sockaddr_un(path: &OsStr) -> libc::sockaddr_un {
269    unsafe {
270        let mut addr: libc::sockaddr_un = mem::zeroed();
271        addr.sun_family = libc::AF_UNIX as _;
272        assert!(path.len() < addr.sun_path.len(), "path too long for sockaddr_un");
273        addr.sun_path[..path.len()].copy_from_slice(mem::transmute(path.as_bytes()));
274
275        addr
276    }
277}
278
279#[allow(non_snake_case)]
280fn CMSG_LEN(length: libc::size_t) -> libc::size_t {
281    CMSG_ALIGN(mem::size_of::<libc::cmsghdr>()) + length
282}
283
284#[allow(non_snake_case)]
285unsafe fn CMSG_DATA(cmsg: *mut libc::cmsghdr) -> *mut libc::c_void {
286    (cmsg as *mut libc::c_uchar).offset(CMSG_ALIGN(
287            mem::size_of::<libc::cmsghdr>()) as isize) as *mut libc::c_void
288}
289
290#[allow(non_snake_case)]
291fn CMSG_ALIGN(length: libc::size_t) -> libc::size_t {
292    (length + mem::size_of::<libc::size_t>() - 1) & !(mem::size_of::<libc::size_t>() - 1)
293}
294
295#[allow(non_snake_case)]
296fn CMSG_SPACE(length: libc::size_t) -> libc::size_t {
297    CMSG_ALIGN(length) + CMSG_ALIGN(mem::size_of::<libc::cmsghdr>())
298}
299
300pub(crate) struct Cmsg {
301    msg_hdr: libc::msghdr,
302    buffer: Vec<u8>,
303    iovec: Box<libc::iovec>,
304    fd_count: usize,
305}
306
307unsafe impl Send for Cmsg {}
308unsafe impl Sync for Cmsg {}
309
310impl Cmsg {
311    fn new(fd_count: usize) -> Self {
312        unsafe {
313            let fd_payload_size = mem::size_of::<libc::c_int>() * fd_count;
314            let mut buffer = vec![0u8; CMSG_SPACE(fd_payload_size)];
315            let mut iovec: Box<libc::iovec> = Box::new(mem::zeroed());
316
317            iovec.iov_base = ptr::null_mut();
318            iovec.iov_len = 0;
319
320            let cmsg_hdr = &mut *(buffer.as_mut_ptr() as *mut libc::cmsghdr);
321            cmsg_hdr.cmsg_len = CMSG_LEN(fd_payload_size as _) as _;
322            cmsg_hdr.cmsg_level = libc::SOL_SOCKET;
323            cmsg_hdr.cmsg_type = libc::SCM_RIGHTS;
324
325            let mut msg_hdr: libc::msghdr = mem::zeroed();
326            msg_hdr.msg_name = ptr::null_mut();
327            msg_hdr.msg_namelen = 0;
328            msg_hdr.msg_iov = &mut *iovec;
329            msg_hdr.msg_iovlen = 1;
330            msg_hdr.msg_control = cmsg_hdr as *mut _ as *mut libc::c_void;
331            msg_hdr.msg_controllen = cmsg_hdr.cmsg_len;
332            msg_hdr.msg_flags = 0;
333
334            Cmsg { msg_hdr, buffer, iovec, fd_count }
335        }
336    }
337
338    unsafe fn set_data(&mut self, bytes: &[u8]) {
339        self.iovec.iov_base = bytes.as_ptr() as *mut _;
340        self.iovec.iov_len = bytes.len() as _;
341    }
342
343    fn set_fds(&mut self, fds: &[libc::c_int]) {
344        assert!(fds.len() <= self.fd_count, "insufficient space for file descriptors in cmsg");
345
346        let cmsg_hdr = unsafe { &mut *(self.buffer.as_mut_ptr() as *mut libc::cmsghdr) };
347        let fd_payload_size = mem::size_of::<libc::c_int>() * fds.len();
348        cmsg_hdr.cmsg_len = CMSG_LEN(fd_payload_size as _) as _;
349        self.msg_hdr.msg_controllen = cmsg_hdr.cmsg_len;
350
351        let fds_dest = unsafe { slice::from_raw_parts_mut(CMSG_DATA(self.buffer.as_ptr() as _) as *mut libc::c_int, fds.len()) };
352        fds_dest.copy_from_slice(fds);
353    }
354
355    fn reset_fd_count(&mut self) {
356        let cmsg_hdr = unsafe { &mut *(self.buffer.as_mut_ptr() as *mut libc::cmsghdr) };
357        let fd_payload_size = mem::size_of::<libc::c_int>() * self.fd_count;
358        cmsg_hdr.cmsg_len = CMSG_LEN(fd_payload_size as _) as _;
359        self.msg_hdr.msg_controllen = cmsg_hdr.cmsg_len;
360    }
361
362    fn current_fd_count(&self) -> usize {
363        let cmsg_hdr = unsafe { &*(self.buffer.as_ptr() as *const libc::cmsghdr) };
364        (cmsg_hdr.cmsg_len as usize - CMSG_ALIGN(mem::size_of::<libc::cmsghdr>())) / mem::size_of::<libc::c_int>()
365    }
366
367    unsafe fn ptr(&mut self) -> *mut libc::msghdr {
368        &mut self.msg_hdr
369    }
370
371    fn fds(&self) -> &[libc::c_int] {
372        unsafe { slice::from_raw_parts(CMSG_DATA(self.buffer.as_ptr() as _) as *mut libc::c_int, self.current_fd_count()) }
373    }
374}