syd/unshare/
error.rs

1use std::{fmt, io};
2
3use nix::errno::Errno;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum ErrorCode {
7    Exec = 1,
8    CapSet = 2,
9    ParentDeathSignal = 3,
10    PreExec = 4,
11    ProcessStop = 5,
12    ResetSignal = 6,
13    Seccomp = 7,
14    SeccompFilterIoctl = 8,
15    SeccompFilterAppendOnly = 9,
16    SeccompSendFd = 10,
17    SeccompWaitFd = 11,
18    SetSid = 12,
19    SetPty = 13,
20    DupPty = 14,
21    SetPgrp = 15,
22    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
23    SetTSC = 16,
24}
25
26/// Error running process
27///
28/// This type has very large number of options and it's enum only to be
29/// compact. Probably you shouldn't match on the error cases but just format
30/// it for user into string.
31#[derive(Debug)]
32pub enum Error {
33    /// Unknown nix error
34    ///
35    /// Frankly, this error should not happen when running process. We just
36    /// keep it here in case `nix` returns this error, which should not happen.
37    NixError(i32), // Not sure it's possible, but it is here to convert from
38    // nix::Error safer
39    /// Some invalid error code received from child application
40    UnknownError,
41    /// Error when calling capset syscall
42    CapSet(i32),
43    /// Error when running execve() systemcall
44    Exec(i32),
45    /// Unable to set death signal (probably signal number invalid)
46    ParentDeathSignal(i32),
47    /// Before unfreeze callback error
48    BeforeUnfreeze(Box<dyn ::std::error::Error + Send + Sync + 'static>),
49    /// Before exec callback error
50    PreExec(i32),
51    /// Error stopping process
52    ProcessStop(i32),
53    /// Error resetting signals
54    ResetSignal(i32),
55    /// Seccomp error (loading filter, getting notify fd)
56    Seccomp(i32),
57    /// Error filtering ioctl(2) requests with seccomp
58    SeccompFilterIoctl(i32),
59    /// Error filtering pwritev2(2) requests with seccomp
60    SeccompFilterAppendOnly(i32),
61    /// Error sending notification fd through the seccomp sender channel
62    SeccompSendFd(i32),
63    /// Error waiting for parent to receive the seccomp fd
64    SeccompWaitFd(i32),
65    /// Error calling setsid(2)
66    SetSid(i32),
67    /// Error calling TIOCSCTTY ioctl(2)
68    SetPty(i32),
69    /// Error calling dup(2) on PTY fd
70    DupPty(i32),
71    /// Error calling tcsetpgrp(3)
72    SetPgrp(i32),
73    /// Error calling prctl PR_SET_TSC
74    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
75    SetTSC(i32),
76}
77
78impl std::error::Error for Error {}
79
80impl Error {
81    /// Similarly to `io::Error` returns bare error code
82    pub fn raw_os_error(&self) -> Option<i32> {
83        use self::Error::*;
84        match *self {
85            UnknownError => None,
86            NixError(x) => Some(x),
87            CapSet(x) => Some(x),
88            Exec(x) => Some(x),
89            ParentDeathSignal(x) => Some(x),
90            BeforeUnfreeze(..) => None,
91            PreExec(x) => Some(x),
92            ProcessStop(x) => Some(x),
93            ResetSignal(x) => Some(x),
94            Seccomp(x) => Some(x),
95            SeccompFilterIoctl(x) => Some(x),
96            SeccompFilterAppendOnly(x) => Some(x),
97            SeccompSendFd(x) => Some(x),
98            SeccompWaitFd(x) => Some(x),
99            SetSid(x) => Some(x),
100            SetPty(x) => Some(x),
101            DupPty(x) => Some(x),
102            SetPgrp(x) => Some(x),
103            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
104            SetTSC(x) => Some(x),
105        }
106    }
107}
108
109impl Error {
110    fn title(&self) -> &'static str {
111        use self::Error::*;
112        match *self {
113            UnknownError => "unexpected value received via signal pipe",
114            NixError(_) => "some unknown nix error",
115            CapSet(_) => "error when setting capabilities",
116            Exec(_) => "error when executing",
117            ParentDeathSignal(_) => "error when death signal",
118            BeforeUnfreeze(_) => "error in before_unfreeze callback",
119            PreExec(_) => "error in pre_exec callback",
120            ProcessStop(_) => "error stopping process",
121            ResetSignal(_) => "error resetting signals",
122            Seccomp(_) => "error in seccomp filter load",
123            SeccompFilterIoctl(_) => "error filtering ioctl requests with seccomp",
124            SeccompFilterAppendOnly(_) => "error filtering pwritev2 requests with seccomp",
125            SeccompSendFd(_) => "error sending seccomp file descriptor",
126            SeccompWaitFd(_) => "error waiting for parent to receive the seccomp file descriptor",
127            SetSid(_) => "error calling setsid",
128            SetPty(_) => "error setting pty as controlling terminal",
129            DupPty(_) => "error duplicating pty onto stdio fds",
130            SetPgrp(_) => "error setting foreground process group",
131            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
132            SetTSC(_) => "error setting timestamp counter prctl",
133        }
134    }
135}
136
137impl fmt::Display for Error {
138    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
139        use crate::unshare::Error::*;
140        if let Some(code) = self.raw_os_error() {
141            let errno = Errno::from_raw(code);
142            if let nix::errno::Errno::UnknownErrno = errno {
143                // May be OS knows error name better
144                write!(
145                    fmt,
146                    "{}: {}",
147                    self.title(),
148                    io::Error::from_raw_os_error(code)
149                )
150            } else {
151                // Format similar to that of std::io::Error
152                write!(
153                    fmt,
154                    "{}: {} (os error {})",
155                    self.title(),
156                    errno.desc(),
157                    code
158                )
159            }
160        } else {
161            match self {
162                BeforeUnfreeze(err) => {
163                    write!(fmt, "{}: {}", self.title(), err)
164                }
165                _ => write!(fmt, "{}", self.title()),
166            }
167        }
168    }
169}