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