1 //! Types and routines used to manipulate arguments from the wire format
2 
3 use std::ffi::CStr;
4 use std::io::Result as IoResult;
5 use std::os::unix::io::RawFd;
6 use std::ptr;
7 
8 use nix::Error as NixError;
9 
10 use crate::protocol::{Argument, ArgumentType, Message};
11 
12 use smallvec::SmallVec;
13 
14 /// Error generated when trying to serialize a message into buffers
15 #[derive(Debug)]
16 pub enum MessageWriteError {
17     /// The buffer is too small to hold the message contents
18     BufferTooSmall,
19     /// The message contains a FD that could not be dup-ed
20     DupFdFailed(std::io::Error),
21 }
22 
23 impl std::error::Error for MessageWriteError {}
24 
25 #[cfg(not(tarpaulin_include))]
26 impl std::fmt::Display for MessageWriteError {
fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>27     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
28         match self {
29             MessageWriteError::BufferTooSmall => {
30                 f.write_str("The provided buffer is too small to hold message content.")
31             }
32             MessageWriteError::DupFdFailed(e) => {
33                 write!(
34                     f,
35                     "The message contains a file descriptor that could not be dup()-ed ({}).",
36                     e
37                 )
38             }
39         }
40     }
41 }
42 
43 /// Error generated when trying to deserialize a message from buffers
44 #[derive(Debug, Clone)]
45 pub enum MessageParseError {
46     /// The message references a FD but the buffer FD is empty
47     MissingFD,
48     /// More data is needed to deserialize the message
49     MissingData,
50     /// The message is malformed and cannot be parsed
51     Malformed,
52 }
53 
54 impl std::error::Error for MessageParseError {}
55 
56 #[cfg(not(tarpaulin_include))]
57 impl std::fmt::Display for MessageParseError {
fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>58     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
59         match *self {
60             MessageParseError::MissingFD => {
61                 f.write_str("The message references a FD but the buffer FD is empty.")
62             }
63             MessageParseError::MissingData => {
64                 f.write_str("More data is needed to deserialize the message")
65             }
66             MessageParseError::Malformed => {
67                 f.write_str("The message is malformed and cannot be parsed")
68             }
69         }
70     }
71 }
72 
73 /// Serialize the contents of this message into provided buffers
74 ///
75 /// Returns the number of elements written in each buffer
76 ///
77 /// Any serialized Fd will be `dup()`-ed in the process
write_to_buffers( msg: &Message<u32>, payload: &mut [u32], mut fds: &mut [RawFd], ) -> Result<(usize, usize), MessageWriteError>78 pub fn write_to_buffers(
79     msg: &Message<u32>,
80     payload: &mut [u32],
81     mut fds: &mut [RawFd],
82 ) -> Result<(usize, usize), MessageWriteError> {
83     let orig_payload_len = payload.len();
84     let orig_fds_len = fds.len();
85     // Helper function to write a u32 or a RawFd to its buffer
86     fn write_buf<T>(u: T, payload: &mut [T]) -> Result<&mut [T], MessageWriteError> {
87         if let Some((head, tail)) = payload.split_first_mut() {
88             *head = u;
89             Ok(tail)
90         } else {
91             Err(MessageWriteError::BufferTooSmall)
92         }
93     }
94 
95     // Helper function to write byte arrays in payload
96     fn write_array_to_payload<'a>(
97         array: &[u8],
98         payload: &'a mut [u32],
99     ) -> Result<&'a mut [u32], MessageWriteError> {
100         let array_len = array.len();
101         let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 };
102         // need enough space to store the whole array with padding and a size header
103         if payload.len() < 1 + word_len {
104             return Err(MessageWriteError::BufferTooSmall);
105         }
106         // size header
107         payload[0] = array_len as u32;
108         let (buffer_slice, rest) = payload[1..].split_at_mut(word_len);
109         unsafe {
110             ptr::copy(array.as_ptr(), buffer_slice.as_mut_ptr() as *mut u8, array_len);
111         }
112         Ok(rest)
113     }
114 
115     let free_size = payload.len();
116     if free_size < 2 {
117         return Err(MessageWriteError::BufferTooSmall);
118     }
119 
120     let (header, mut payload) = payload.split_at_mut(2);
121 
122     // we store all fds we dup-ed in this, which will auto-close
123     // them on drop, if any of the `?` early-returns
124     let mut pending_fds = FdStore::new();
125 
126     // write the contents in the buffer
127     for arg in &msg.args {
128         // Just to make the borrow checker happy
129         let old_payload = payload;
130         match *arg {
131             Argument::Int(i) => payload = write_buf(i as u32, old_payload)?,
132             Argument::Uint(u) => payload = write_buf(u, old_payload)?,
133             Argument::Fixed(f) => payload = write_buf(f as u32, old_payload)?,
134             Argument::Str(ref s) => {
135                 payload = write_array_to_payload(s.as_bytes_with_nul(), old_payload)?;
136             }
137             Argument::Object(o) => payload = write_buf(o, old_payload)?,
138             Argument::NewId(n) => payload = write_buf(n, old_payload)?,
139             Argument::Array(ref a) => {
140                 payload = write_array_to_payload(a, old_payload)?;
141             }
142             Argument::Fd(fd) => {
143                 let old_fds = fds;
144                 let dup_fd = dup_fd_cloexec(fd).map_err(MessageWriteError::DupFdFailed)?;
145                 pending_fds.push(dup_fd);
146                 fds = write_buf(dup_fd, old_fds)?;
147                 payload = old_payload;
148             }
149         }
150     }
151 
152     // we reached here, all writing was successful
153     // no FD needs to be closed
154     pending_fds.clear();
155 
156     let wrote_size = (free_size - payload.len()) * 4;
157     header[0] = msg.sender_id;
158     header[1] = ((wrote_size as u32) << 16) | u32::from(msg.opcode);
159     Ok((orig_payload_len - payload.len(), orig_fds_len - fds.len()))
160 }
161 
162 /// Attempts to parse a single wayland message with the given signature.
163 ///
164 /// If the buffers contains several messages, only the first one will be parsed,
165 /// and the unused tail of the buffers is returned. If a single message was present,
166 /// the returned slices should thus be empty.
167 ///
168 /// Errors if the message is malformed.
169 #[allow(clippy::type_complexity)]
parse_message<'a, 'b>( raw: &'a [u32], signature: &[ArgumentType], fds: &'b [RawFd], ) -> Result<(Message<u32>, &'a [u32], &'b [RawFd]), MessageParseError>170 pub fn parse_message<'a, 'b>(
171     raw: &'a [u32],
172     signature: &[ArgumentType],
173     fds: &'b [RawFd],
174 ) -> Result<(Message<u32>, &'a [u32], &'b [RawFd]), MessageParseError> {
175     // helper function to read arrays
176     fn read_array_from_payload(
177         array_len: usize,
178         payload: &[u32],
179     ) -> Result<(&[u8], &[u32]), MessageParseError> {
180         let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 };
181         if word_len > payload.len() {
182             return Err(MessageParseError::MissingData);
183         }
184         let (array_contents, rest) = payload.split_at(word_len);
185         let array = unsafe {
186             ::std::slice::from_raw_parts(array_contents.as_ptr() as *const u8, array_len)
187         };
188         Ok((array, rest))
189     }
190 
191     if raw.len() < 2 {
192         return Err(MessageParseError::MissingData);
193     }
194 
195     let sender_id = raw[0];
196     let word_2 = raw[1];
197     let opcode = (word_2 & 0x0000_FFFF) as u16;
198     let len = (word_2 >> 16) as usize / 4;
199 
200     if len < 2 || len > raw.len() {
201         return Err(MessageParseError::Malformed);
202     }
203 
204     let (mut payload, rest) = raw.split_at(len);
205     payload = &payload[2..];
206     let mut fds = fds;
207 
208     let arguments = signature
209         .iter()
210         .map(|argtype| {
211             if let ArgumentType::Fd = *argtype {
212                 // don't consume input but fd
213                 if let Some((&front, tail)) = fds.split_first() {
214                     fds = tail;
215                     Ok(Argument::Fd(front))
216                 } else {
217                     Err(MessageParseError::MissingFD)
218                 }
219             } else if let Some((&front, mut tail)) = payload.split_first() {
220                 let arg =
221                     match *argtype {
222                         ArgumentType::Int => Ok(Argument::Int(front as i32)),
223                         ArgumentType::Uint => Ok(Argument::Uint(front)),
224                         ArgumentType::Fixed => Ok(Argument::Fixed(front as i32)),
225                         ArgumentType::Str(_) => read_array_from_payload(front as usize, tail)
226                             .and_then(|(v, rest)| {
227                                 tail = rest;
228                                 match CStr::from_bytes_with_nul(v) {
229                                     Ok(s) => Ok(Argument::Str(Box::new(s.into()))),
230                                     Err(_) => Err(MessageParseError::Malformed),
231                                 }
232                             }),
233                         ArgumentType::Object(_) => Ok(Argument::Object(front)),
234                         ArgumentType::NewId(_) => Ok(Argument::NewId(front)),
235                         ArgumentType::Array(_) => read_array_from_payload(front as usize, tail)
236                             .map(|(v, rest)| {
237                                 tail = rest;
238                                 Argument::Array(Box::new(v.into()))
239                             }),
240                         ArgumentType::Fd => unreachable!(),
241                     };
242                 payload = tail;
243                 arg
244             } else {
245                 Err(MessageParseError::MissingData)
246             }
247         })
248         .collect::<Result<SmallVec<_>, MessageParseError>>()?;
249 
250     let msg = Message { sender_id, opcode, args: arguments };
251     Ok((msg, rest, fds))
252 }
253 
254 /// Duplicate a `RawFd` and set the CLOEXEC flag on the copy
dup_fd_cloexec(fd: RawFd) -> IoResult<RawFd>255 pub fn dup_fd_cloexec(fd: RawFd) -> IoResult<RawFd> {
256     use nix::fcntl;
257     match fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD_CLOEXEC(0)) {
258         Ok(newfd) => Ok(newfd),
259         Err(NixError::EINVAL) => {
260             // F_DUPFD_CLOEXEC is not recognized, kernel too old, fallback
261             // to setting CLOEXEC manually
262             let newfd = fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD(0))?;
263 
264             let flags = fcntl::fcntl(newfd, fcntl::FcntlArg::F_GETFD);
265             let result = flags
266                 .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
267                 .and_then(|f| fcntl::fcntl(newfd, fcntl::FcntlArg::F_SETFD(f)));
268             match result {
269                 Ok(_) => {
270                     // setting the O_CLOEXEC worked
271                     Ok(newfd)
272                 }
273                 Err(e) => {
274                     // something went wrong in F_GETFD or F_SETFD
275                     let _ = ::nix::unistd::close(newfd);
276                     Err(e.into())
277                 }
278             }
279         }
280         Err(e) => Err(e.into()),
281     }
282 }
283 
284 /*
285  * utility struct that closes every FD it contains on drop
286  */
287 
288 struct FdStore {
289     fds: Vec<RawFd>,
290 }
291 
292 impl FdStore {
new() -> FdStore293     fn new() -> FdStore {
294         FdStore { fds: Vec::new() }
295     }
push(&mut self, fd: RawFd)296     fn push(&mut self, fd: RawFd) {
297         self.fds.push(fd);
298     }
clear(&mut self)299     fn clear(&mut self) {
300         self.fds.clear();
301     }
302 }
303 
304 impl Drop for FdStore {
drop(&mut self)305     fn drop(&mut self) {
306         use nix::unistd::close;
307         for fd in self.fds.drain(..) {
308             // not much can be done if we can't close that anyway...
309             let _ = close(fd);
310         }
311     }
312 }
313 
314 #[cfg(test)]
315 mod tests {
316     use super::*;
317     use crate::protocol::AllowNull;
318     use smallvec::smallvec;
319     use std::ffi::CString;
320 
321     #[test]
into_from_raw_cycle()322     fn into_from_raw_cycle() {
323         let mut bytes_buffer = vec![0; 1024];
324         let mut fd_buffer = vec![0; 10];
325 
326         let msg = Message {
327             sender_id: 42,
328             opcode: 7,
329             args: smallvec![
330                 Argument::Uint(3),
331                 Argument::Fixed(-89),
332                 Argument::Str(Box::new(CString::new(&b"I like trains!"[..]).unwrap())),
333                 Argument::Array(vec![1, 2, 3, 4, 5, 6, 7, 8, 9].into()),
334                 Argument::Object(88),
335                 Argument::NewId(56),
336                 Argument::Int(-25),
337             ],
338         };
339         // write the message to the buffers
340         write_to_buffers(&msg, &mut bytes_buffer[..], &mut fd_buffer[..]).unwrap();
341         // read them back
342         let (rebuilt, _, _) = parse_message(
343             &bytes_buffer[..],
344             &[
345                 ArgumentType::Uint,
346                 ArgumentType::Fixed,
347                 ArgumentType::Str(AllowNull::No),
348                 ArgumentType::Array(AllowNull::No),
349                 ArgumentType::Object(AllowNull::No),
350                 ArgumentType::NewId(AllowNull::No),
351                 ArgumentType::Int,
352             ],
353             &fd_buffer[..],
354         )
355         .unwrap();
356         assert_eq!(rebuilt, msg);
357     }
358 }
359