]>
Commit | Line | Data |
---|---|---|
1 | use std::ffi::CString; | |
2 | use std::os::unix::io::AsRawFd; | |
3 | ||
4 | use anyhow::Error; | |
5 | use nix::errno::Errno; | |
6 | use nix::sys::stat; | |
7 | ||
8 | use crate::fork::forking_syscall; | |
9 | use crate::lxcseccomp::ProxyMessageBuffer; | |
10 | use crate::process::PidFd; | |
11 | use crate::sc_libc_try; | |
12 | use crate::syscall::SyscallStatus; | |
13 | use crate::tools::Fd; | |
14 | ||
15 | pub async fn mknod(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> { | |
16 | let mode = msg.arg_mode_t(1)?; | |
17 | let dev = msg.arg_dev_t(2)?; | |
18 | if !check_mknod_dev(mode, dev) { | |
19 | return Ok(Errno::EPERM.into()); | |
20 | } | |
21 | ||
22 | let pathname = msg.arg_c_string(0)?; | |
23 | let cwd = msg.pid_fd().fd_cwd()?; | |
24 | ||
25 | do_mknodat(msg.pid_fd(), cwd, pathname, mode, dev).await | |
26 | } | |
27 | ||
28 | pub async fn mknodat(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> { | |
29 | let mode = msg.arg_mode_t(2)?; | |
30 | let dev = msg.arg_dev_t(3)?; | |
31 | if !check_mknod_dev(mode, dev) { | |
32 | return Ok(Errno::EPERM.into()); | |
33 | } | |
34 | ||
35 | let dirfd = msg.arg_fd(0, libc::O_DIRECTORY)?; | |
36 | let pathname = msg.arg_c_string(1)?; | |
37 | ||
38 | do_mknodat(msg.pid_fd(), dirfd, pathname, mode, dev).await | |
39 | } | |
40 | ||
41 | fn check_mknod_dev(mode: stat::mode_t, dev: stat::dev_t) -> bool { | |
42 | let sflag = mode & libc::S_IFMT; | |
43 | let major = stat::major(dev); | |
44 | let minor = stat::minor(dev); | |
45 | ||
46 | match (sflag, major, minor) { | |
47 | (libc::S_IFREG, 0, 0) => true, // touch | |
48 | (libc::S_IFCHR, 0, 0) => true, // whiteout | |
49 | (libc::S_IFCHR, 5, 0) => true, // /dev/tty | |
50 | (libc::S_IFCHR, 5, 1) => true, // /dev/console | |
51 | (libc::S_IFCHR, 5, 2) => true, // /dev/ptmx | |
52 | (libc::S_IFCHR, 1, 3) => true, // /dev/null | |
53 | (libc::S_IFCHR, 1, 5) => true, // /dev/zero | |
54 | (libc::S_IFCHR, 1, 7) => true, // /dev/full | |
55 | (libc::S_IFCHR, 1, 8) => true, // /dev/random | |
56 | (libc::S_IFCHR, 1, 9) => true, // /dev/urandom | |
57 | _ => false, | |
58 | } | |
59 | } | |
60 | ||
61 | async fn do_mknodat( | |
62 | pidfd: &PidFd, | |
63 | dirfd: Fd, | |
64 | pathname: CString, | |
65 | mode: stat::mode_t, | |
66 | dev: stat::dev_t, | |
67 | ) -> Result<SyscallStatus, Error> { | |
68 | let caps = pidfd.user_caps()?; | |
69 | ||
70 | Ok(forking_syscall(move || { | |
71 | caps.apply(&PidFd::current()?)?; | |
72 | let out = | |
73 | sc_libc_try!(unsafe { libc::mknodat(dirfd.as_raw_fd(), pathname.as_ptr(), mode, dev) }); | |
74 | Ok(SyscallStatus::Ok(out.into())) | |
75 | }) | |
76 | .await?) | |
77 | } |