1 //! Types and routines used to manipulate arguments from the wire format
2 
3 use std::ffi::{CStr, CString};
4 use std::os::unix::io::RawFd;
5 use std::ptr;
6 
7 use nix::errno::Errno;
8 use nix::{Error as NixError, Result as NixResult};
9 
10 use smallvec::SmallVec;
11 
12 // The value of 4 is chosen for the following reasons:
13 // - almost all messages have 4 arguments or less
14 // - there are some potentially spammy events that have 3/4 arguments (wl_touch.move has 4 for example)
15 //
16 // This brings the size of Message to 11*usize (instead of 4*usize with a regular vec), but eliminates
17 // almost all allocations that may occur during the processing of messages, both client-side and server-side.
18 const INLINE_ARGS: usize = 4;
19 
20 /// Wire metadata of a given message
21 #[derive(Copy, Clone, Debug)]
22 pub struct MessageDesc {
23     /// Name of this message
24     pub name: &'static str,
25     /// Signature of the message
26     pub signature: &'static [ArgumentType],
27     /// Minimum required version of the interface
28     pub since: u32,
29     /// Whether this message is a destructor
30     pub destructor: bool,
31 }
32 
33 /// Enum of possible argument types as recognized by the wire
34 #[derive(Copy, Clone, PartialEq, Debug)]
35 pub enum ArgumentType {
36     /// i32
37     Int,
38     /// u32
39     Uint,
40     /// fixed point, 1/256 precision
41     Fixed,
42     /// CString
43     Str,
44     /// id of a wayland object
45     Object,
46     /// id of a newly created wayland object
47     NewId,
48     /// Vec<u8>
49     Array,
50     /// RawFd
51     Fd,
52 }
53 
54 /// Enum of possible argument as recognized by the wire, including values
55 #[derive(Clone, PartialEq, Debug)]
56 #[allow(clippy::box_vec)]
57 pub enum Argument {
58     /// i32
59     Int(i32),
60     /// u32
61     Uint(u32),
62     /// fixed point, 1/256 precision
63     Fixed(i32),
64     /// CString
65     ///
66     /// The value is boxed to reduce the stack size of Argument. The performance
67     /// impact is negligible as `string` arguments are pretty rare in the protocol.
68     Str(Box<CString>),
69     /// id of a wayland object
70     Object(u32),
71     /// id of a newly created wayland object
72     NewId(u32),
73     /// Vec<u8>
74     ///
75     /// The value is boxed to reduce the stack size of Argument. The performance
76     /// impact is negligible as `array` arguments are pretty rare in the protocol.
77     Array(Box<Vec<u8>>),
78     /// RawFd
79     Fd(RawFd),
80 }
81 
82 impl Argument {
83     /// Retrieve the type of a given argument instance
get_type(&self) -> ArgumentType84     pub fn get_type(&self) -> ArgumentType {
85         match *self {
86             Argument::Int(_) => ArgumentType::Int,
87             Argument::Uint(_) => ArgumentType::Uint,
88             Argument::Fixed(_) => ArgumentType::Fixed,
89             Argument::Str(_) => ArgumentType::Str,
90             Argument::Object(_) => ArgumentType::Object,
91             Argument::NewId(_) => ArgumentType::NewId,
92             Argument::Array(_) => ArgumentType::Array,
93             Argument::Fd(_) => ArgumentType::Fd,
94         }
95     }
96 }
97 
98 impl std::fmt::Display for Argument {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result99     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100         match self {
101             Argument::Int(value) => write!(f, "{}", value),
102             Argument::Uint(value) => write!(f, "{}", value),
103             Argument::Fixed(value) => write!(f, "{}", value),
104             Argument::Str(value) => write!(f, "{:?}", value),
105             Argument::Object(value) => write!(f, "{}", value),
106             Argument::NewId(value) => write!(f, "{}", value),
107             Argument::Array(value) => write!(f, "{:?}", value),
108             Argument::Fd(value) => write!(f, "{}", value),
109         }
110     }
111 }
112 
113 /// A wire message
114 #[derive(Debug, Clone, PartialEq)]
115 pub struct Message {
116     /// ID of the object sending this message
117     pub sender_id: u32,
118     /// Opcode of the message
119     pub opcode: u16,
120     /// Arguments of the message
121     pub args: SmallVec<[Argument; INLINE_ARGS]>,
122 }
123 
124 /// Error generated when trying to serialize a message into buffers
125 #[derive(Debug, Clone)]
126 pub enum MessageWriteError {
127     /// The buffer is too small to hold the message contents
128     BufferTooSmall,
129     /// The message contains a FD that could not be dup-ed
130     DupFdFailed(::nix::Error),
131 }
132 
133 impl std::error::Error for MessageWriteError {}
134 
135 impl std::fmt::Display for MessageWriteError {
fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>136     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
137         match *self {
138             MessageWriteError::BufferTooSmall => {
139                 f.write_str("The provided buffer is too small to hold message content.")
140             }
141             MessageWriteError::DupFdFailed(_) => {
142                 f.write_str("The message contains a file descriptor that could not be dup()-ed.")
143             }
144         }
145     }
146 }
147 
148 /// Error generated when trying to deserialize a message from buffers
149 #[derive(Debug, Clone)]
150 pub enum MessageParseError {
151     /// The message references a FD but the buffer FD is empty
152     MissingFD,
153     /// More data is needed to deserialize the message
154     MissingData,
155     /// The message is malformed and cannot be parsed
156     Malformed,
157 }
158 
159 impl std::error::Error for MessageParseError {}
160 
161 impl std::fmt::Display for MessageParseError {
fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>162     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
163         match *self {
164             MessageParseError::MissingFD => {
165                 f.write_str("The message references a FD but the buffer FD is empty.")
166             }
167             MessageParseError::MissingData => {
168                 f.write_str("More data is needed to deserialize the message")
169             }
170             MessageParseError::Malformed => {
171                 f.write_str("The message is malformed and cannot be parsed")
172             }
173         }
174     }
175 }
176 
177 impl Message {
178     /// Serialize the contents of this message into provided buffers
179     ///
180     /// Returns the number of elements written in each buffer
181     ///
182     /// Any serialized Fd will be `dup()`-ed in the process
write_to_buffers( &self, payload: &mut [u32], mut fds: &mut [RawFd], ) -> Result<(usize, usize), MessageWriteError>183     pub fn write_to_buffers(
184         &self,
185         payload: &mut [u32],
186         mut fds: &mut [RawFd],
187     ) -> Result<(usize, usize), MessageWriteError> {
188         let orig_payload_len = payload.len();
189         let orig_fds_len = fds.len();
190         // Helper function to write a u32 or a RawFd to its buffer
191         fn write_buf<T>(u: T, payload: &mut [T]) -> Result<&mut [T], MessageWriteError> {
192             if let Some((head, tail)) = payload.split_first_mut() {
193                 *head = u;
194                 Ok(tail)
195             } else {
196                 Err(MessageWriteError::BufferTooSmall)
197             }
198         }
199 
200         // Helper function to write byte arrays in payload
201         fn write_array_to_payload<'a>(
202             array: &[u8],
203             payload: &'a mut [u32],
204         ) -> Result<&'a mut [u32], MessageWriteError> {
205             let array_len = array.len();
206             let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 };
207             // need enough space to store the whole array with padding and a size header
208             if payload.len() < 1 + word_len {
209                 return Err(MessageWriteError::BufferTooSmall);
210             }
211             // size header
212             payload[0] = array_len as u32;
213             let (buffer_slice, rest) = payload[1..].split_at_mut(word_len);
214             unsafe {
215                 ptr::copy(array.as_ptr(), buffer_slice.as_mut_ptr() as *mut u8, array_len);
216             }
217             Ok(rest)
218         }
219 
220         let free_size = payload.len();
221         if free_size < 2 {
222             return Err(MessageWriteError::BufferTooSmall);
223         }
224 
225         let (header, mut payload) = payload.split_at_mut(2);
226 
227         // we store all fds we dup-ed in this, which will auto-close
228         // them on drop, if any of the `?` early-returns
229         let mut pending_fds = FdStore::new();
230 
231         // write the contents in the buffer
232         for arg in &self.args {
233             // Just to make the borrow checker happy
234             let old_payload = payload;
235             match *arg {
236                 Argument::Int(i) => payload = write_buf(i as u32, old_payload)?,
237                 Argument::Uint(u) => payload = write_buf(u, old_payload)?,
238                 Argument::Fixed(f) => payload = write_buf(f as u32, old_payload)?,
239                 Argument::Str(ref s) => {
240                     payload = write_array_to_payload(s.as_bytes_with_nul(), old_payload)?;
241                 }
242                 Argument::Object(o) => payload = write_buf(o, old_payload)?,
243                 Argument::NewId(n) => payload = write_buf(n, old_payload)?,
244                 Argument::Array(ref a) => {
245                     payload = write_array_to_payload(&a, old_payload)?;
246                 }
247                 Argument::Fd(fd) => {
248                     let old_fds = fds;
249                     let dup_fd = dup_fd_cloexec(fd).map_err(MessageWriteError::DupFdFailed)?;
250                     pending_fds.push(dup_fd);
251                     fds = write_buf(dup_fd, old_fds)?;
252                     payload = old_payload;
253                 }
254             }
255         }
256 
257         // we reached here, all writing was successful
258         // no FD needs to be closed
259         pending_fds.clear();
260 
261         let wrote_size = (free_size - payload.len()) * 4;
262         header[0] = self.sender_id;
263         header[1] = ((wrote_size as u32) << 16) | u32::from(self.opcode);
264         Ok((orig_payload_len - payload.len(), orig_fds_len - fds.len()))
265     }
266 
267     /// Attempts to parse a single wayland message with the given signature.
268     ///
269     /// If the buffers contains several messages, only the first one will be parsed,
270     /// and the unused tail of the buffers is returned. If a single message was present,
271     /// the returned slices should thus be empty.
272     ///
273     /// Errors if the message is malformed.
from_raw<'a, 'b>( raw: &'a [u32], signature: &[ArgumentType], fds: &'b [RawFd], ) -> Result<(Message, &'a [u32], &'b [RawFd]), MessageParseError>274     pub fn from_raw<'a, 'b>(
275         raw: &'a [u32],
276         signature: &[ArgumentType],
277         fds: &'b [RawFd],
278     ) -> Result<(Message, &'a [u32], &'b [RawFd]), MessageParseError> {
279         // helper function to read arrays
280         fn read_array_from_payload(
281             array_len: usize,
282             payload: &[u32],
283         ) -> Result<(&[u8], &[u32]), MessageParseError> {
284             let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 };
285             if word_len > payload.len() {
286                 return Err(MessageParseError::MissingData);
287             }
288             let (array_contents, rest) = payload.split_at(word_len);
289             let array = unsafe {
290                 ::std::slice::from_raw_parts(array_contents.as_ptr() as *const u8, array_len)
291             };
292             Ok((array, rest))
293         }
294 
295         if raw.len() < 2 {
296             return Err(MessageParseError::MissingData);
297         }
298 
299         let sender_id = raw[0];
300         let word_2 = raw[1];
301         let opcode = (word_2 & 0x0000_FFFF) as u16;
302         let len = (word_2 >> 16) as usize / 4;
303 
304         if len < 2 || len > raw.len() {
305             return Err(MessageParseError::Malformed);
306         }
307 
308         let (mut payload, rest) = raw.split_at(len);
309         payload = &payload[2..];
310         let mut fds = fds;
311 
312         let arguments = signature
313             .iter()
314             .map(|argtype| {
315                 if let ArgumentType::Fd = *argtype {
316                     // don't consume input but fd
317                     if let Some((&front, tail)) = fds.split_first() {
318                         fds = tail;
319                         Ok(Argument::Fd(front))
320                     } else {
321                         Err(MessageParseError::MissingFD)
322                     }
323                 } else if let Some((&front, mut tail)) = payload.split_first() {
324                     let arg = match *argtype {
325                         ArgumentType::Int => Ok(Argument::Int(front as i32)),
326                         ArgumentType::Uint => Ok(Argument::Uint(front)),
327                         ArgumentType::Fixed => Ok(Argument::Fixed(front as i32)),
328                         ArgumentType::Str => read_array_from_payload(front as usize, tail)
329                             .and_then(|(v, rest)| {
330                                 tail = rest;
331                                 match CStr::from_bytes_with_nul(v) {
332                                     Ok(s) => Ok(Argument::Str(Box::new(s.into()))),
333                                     Err(_) => Err(MessageParseError::Malformed),
334                                 }
335                             }),
336                         ArgumentType::Object => Ok(Argument::Object(front)),
337                         ArgumentType::NewId => Ok(Argument::NewId(front)),
338                         ArgumentType::Array => {
339                             read_array_from_payload(front as usize, tail).map(|(v, rest)| {
340                                 tail = rest;
341                                 Argument::Array(Box::new(v.into()))
342                             })
343                         }
344                         ArgumentType::Fd => unreachable!(),
345                     };
346                     payload = tail;
347                     arg
348                 } else {
349                     Err(MessageParseError::MissingData)
350                 }
351             })
352             .collect::<Result<SmallVec<_>, MessageParseError>>()?;
353 
354         let msg = Message { sender_id, opcode, args: arguments };
355         Ok((msg, rest, fds))
356     }
357 }
358 
359 /// Duplicate a `RawFd` and set the CLOEXEC flag on the copy
dup_fd_cloexec(fd: RawFd) -> NixResult<RawFd>360 pub fn dup_fd_cloexec(fd: RawFd) -> NixResult<RawFd> {
361     use nix::fcntl;
362     match fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD_CLOEXEC(0)) {
363         Ok(newfd) => Ok(newfd),
364         Err(NixError::Sys(Errno::EINVAL)) => {
365             // F_DUPFD_CLOEXEC is not recognized, kernel too old, fallback
366             // to setting CLOEXEC manually
367             let newfd = fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD(0))?;
368 
369             let flags = fcntl::fcntl(newfd, fcntl::FcntlArg::F_GETFD);
370             let result = flags
371                 .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
372                 .and_then(|f| fcntl::fcntl(newfd, fcntl::FcntlArg::F_SETFD(f)));
373             match result {
374                 Ok(_) => {
375                     // setting the O_CLOEXEC worked
376                     Ok(newfd)
377                 }
378                 Err(e) => {
379                     // something went wrong in F_GETFD or F_SETFD
380                     let _ = ::nix::unistd::close(newfd);
381                     Err(e)
382                 }
383             }
384         }
385         Err(e) => Err(e),
386     }
387 }
388 
389 /*
390  * utility struct that closes every FD it contains on drop
391  */
392 
393 struct FdStore {
394     fds: Vec<RawFd>,
395 }
396 
397 impl FdStore {
new() -> FdStore398     fn new() -> FdStore {
399         FdStore { fds: Vec::new() }
400     }
push(&mut self, fd: RawFd)401     fn push(&mut self, fd: RawFd) {
402         self.fds.push(fd);
403     }
clear(&mut self)404     fn clear(&mut self) {
405         self.fds.clear();
406     }
407 }
408 
409 impl Drop for FdStore {
drop(&mut self)410     fn drop(&mut self) {
411         use nix::unistd::close;
412         for fd in self.fds.drain(..) {
413             // not much can be done if we can't close that anyway...
414             let _ = close(fd);
415         }
416     }
417 }
418 
419 #[cfg(test)]
420 mod tests {
421     use super::*;
422     use smallvec::smallvec;
423 
424     #[test]
into_from_raw_cycle()425     fn into_from_raw_cycle() {
426         let mut bytes_buffer = vec![0; 1024];
427         let mut fd_buffer = vec![0; 10];
428 
429         let msg = Message {
430             sender_id: 42,
431             opcode: 7,
432             args: smallvec![
433                 Argument::Uint(3),
434                 Argument::Fixed(-89),
435                 Argument::Str(Box::new(CString::new(&b"I like trains!"[..]).unwrap())),
436                 Argument::Array(vec![1, 2, 3, 4, 5, 6, 7, 8, 9].into()),
437                 Argument::Object(88),
438                 Argument::NewId(56),
439                 Argument::Int(-25),
440             ],
441         };
442         // write the message to the buffers
443         msg.write_to_buffers(&mut bytes_buffer[..], &mut fd_buffer[..]).unwrap();
444         // read them back
445         let (rebuilt, _, _) = Message::from_raw(
446             &bytes_buffer[..],
447             &[
448                 ArgumentType::Uint,
449                 ArgumentType::Fixed,
450                 ArgumentType::Str,
451                 ArgumentType::Array,
452                 ArgumentType::Object,
453                 ArgumentType::NewId,
454                 ArgumentType::Int,
455             ],
456             &fd_buffer[..],
457         )
458         .unwrap();
459         assert_eq!(rebuilt, msg);
460     }
461 }
462