]> git.proxmox.com Git - pve-lxc-syscalld.git/blame - src/process/pid_fd.rs
don't create tokio-reactor-associated pipes before fork
[pve-lxc-syscalld.git] / src / process / pid_fd.rs
CommitLineData
e420f6f9
WB
1//! pidfd helper functionality
2
401ab6a2 3use std::ffi::{CStr, OsString};
512f780a 4use std::io::{self, BufRead, BufReader};
937921aa 5use std::os::raw::c_int;
3bbd1db0 6use std::os::unix::ffi::OsStringExt;
e420f6f9
WB
7use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
8
512f780a
WB
9use failure::{bail, Error};
10use libc::pid_t;
11
3bbd1db0 12use crate::capability::Capabilities;
e420f6f9
WB
13use crate::nsfd::{ns_type, NsFd};
14use crate::tools::Fd;
e420f6f9 15
3bbd1db0
WB
16use super::{CGroups, IdMap, IdMapEntry, ProcStatus, Uids, UserCaps};
17
512f780a 18pub struct PidFd(RawFd, pid_t);
9aa2a15a 19file_descriptor_impl!(PidFd);
512f780a 20
401ab6a2 21pub const SYS_PIDFD_OPEN: libc::c_long = 434; // asm-generic
9ab7f72f 22
e420f6f9 23impl PidFd {
42f25756 24 pub fn current() -> io::Result<Self> {
401ab6a2 25 Self::open(unsafe { libc::getpid() })
42f25756
WB
26 }
27
512f780a 28 pub fn open(pid: pid_t) -> io::Result<Self> {
d6ba646c 29 let fd = c_try!(unsafe { libc::syscall(SYS_PIDFD_OPEN, pid, 0) });
401ab6a2 30 Ok(Self(fd as RawFd, pid))
512f780a
WB
31 }
32
92eface0
WB
33 /// Turn a valid pid file descriptor into a PidFd.
34 ///
35 /// # Safety
36 ///
37 /// The file descriptor must already be a valid pidfd, this is not checked. This function only
38 /// fails if reading the pid from the pidfd's proc entry fails.
512f780a
WB
39 pub unsafe fn try_from_fd(fd: Fd) -> io::Result<Self> {
40 let mut this = Self(fd.into_raw_fd(), -1 as pid_t);
41 let pid = this.read_pid()?;
42 this.1 = pid;
43 Ok(this)
e420f6f9
WB
44 }
45
46 pub fn mount_namespace(&self) -> io::Result<NsFd<ns_type::Mount>> {
1e80bab0 47 NsFd::openat(self.0, c_str!("ns/mnt"))
e420f6f9
WB
48 }
49
50 pub fn cgroup_namespace(&self) -> io::Result<NsFd<ns_type::Cgroup>> {
1e80bab0 51 NsFd::openat(self.0, c_str!("ns/cgroup"))
e420f6f9
WB
52 }
53
54 pub fn user_namespace(&self) -> io::Result<NsFd<ns_type::User>> {
1e80bab0 55 NsFd::openat(self.0, c_str!("ns/user"))
e420f6f9
WB
56 }
57
3bb4df0b 58 fn fd(&self, path: &CStr, flags: c_int, mode: c_int) -> io::Result<Fd> {
7ca1a14c 59 Ok(Fd(c_try!(unsafe {
e420f6f9
WB
60 libc::openat(
61 self.as_raw_fd(),
937921aa
WB
62 path.as_ptr() as *const _,
63 flags | libc::O_CLOEXEC,
3bb4df0b 64 mode,
e420f6f9
WB
65 )
66 })))
67 }
937921aa
WB
68
69 pub fn fd_cwd(&self) -> io::Result<Fd> {
1e80bab0 70 self.fd(c_str!("cwd"), libc::O_DIRECTORY, 0)
937921aa
WB
71 }
72
73 pub fn fd_num(&self, num: RawFd, flags: c_int) -> io::Result<Fd> {
3bb4df0b 74 let path = format!("fd/{}\0", num);
512f780a
WB
75 self.fd(
76 unsafe { CStr::from_bytes_with_nul_unchecked(path.as_bytes()) },
77 flags,
78 0,
79 )
937921aa 80 }
275009ec 81
bff40ab9 82 pub fn enter_cwd(&self) -> io::Result<()> {
7ca1a14c 83 c_try!(unsafe { libc::fchdir(self.fd_cwd()?.as_raw_fd()) });
bff40ab9
WB
84 Ok(())
85 }
86
87 pub fn enter_chroot(&self) -> io::Result<()> {
7ca1a14c
WB
88 c_try!(unsafe { libc::fchdir(self.as_raw_fd()) });
89 c_try!(unsafe { libc::chroot(b"root\0".as_ptr() as *const _) });
90 c_try!(unsafe { libc::chdir(b"/\0".as_ptr() as *const _) });
512f780a
WB
91 Ok(())
92 }
3bb4df0b
WB
93
94 // procfs files cannot be async, we cannot add them to epoll...
95 pub fn open_file(&self, path: &CStr, flags: c_int, mode: c_int) -> io::Result<std::fs::File> {
96 Ok(unsafe { std::fs::File::from_raw_fd(self.fd(path, flags, mode)?.into_raw_fd()) })
97 }
98
512f780a
WB
99 #[inline]
100 fn open_buffered(&self, path: &CStr) -> io::Result<impl BufRead> {
101 Ok(BufReader::new(self.open_file(
102 path,
3bb4df0b
WB
103 libc::O_RDONLY | libc::O_CLOEXEC,
104 0,
512f780a
WB
105 )?))
106 }
107
108 #[inline]
109 pub fn get_pid(&self) -> pid_t {
110 self.1
111 }
112
113 fn read_pid(&self) -> io::Result<pid_t> {
1e80bab0 114 let reader = self.open_buffered(c_str!("status"))?;
512f780a
WB
115
116 for line in reader.lines() {
117 let line = line?;
118 let mut parts = line.split_ascii_whitespace();
119 if parts.next() == Some("Pid:") {
120 let pid = parts
121 .next()
122 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "bad 'Pid:' line in proc"))?
123 .parse::<pid_t>()
124 .map_err(|_| {
125 io::Error::new(io::ErrorKind::Other, "failed to parse pid from proc")
126 })?;
127 return Ok(pid);
128 }
129 }
130
131 Err(io::ErrorKind::NotFound.into())
132 }
133
1349eed4
WB
134 #[inline]
135 fn __check_uid_gid(value: Option<&str>) -> io::Result<libc::uid_t> {
136 value
137 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "bad 'Uid/Gid:' line in proc"))?
138 .parse::<libc::uid_t>()
139 .map_err(|_| io::Error::new(io::ErrorKind::Other, "failed to parse uid from proc"))
140 }
141
512f780a 142 pub fn get_status(&self) -> io::Result<ProcStatus> {
1e80bab0 143 let reader = self.open_buffered(c_str!("status"))?;
512f780a 144
512f780a
WB
145 #[inline]
146 fn check_u64_hex(value: Option<&str>) -> io::Result<u64> {
147 Ok(u64::from_str_radix(
148 value.ok_or_else(|| {
149 io::Error::new(io::ErrorKind::Other, "bad numeric property line in proc")
150 })?,
151 16,
152 )
153 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?)
154 }
155
156 #[inline]
157 fn check_u32_oct(value: Option<&str>) -> io::Result<u32> {
158 Ok(u32::from_str_radix(
159 value.ok_or_else(|| {
160 io::Error::new(io::ErrorKind::Other, "bad numeric property line in proc")
161 })?,
162 8,
163 )
164 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?)
165 }
3bb4df0b 166
512f780a
WB
167 let mut ids = Uids::default();
168 let mut caps = Capabilities::default();
169 let mut umask = 0o022;
3bb4df0b
WB
170 for line in reader.lines() {
171 let line = line?;
172 let mut parts = line.split_ascii_whitespace();
173 match parts.next() {
174 Some("Uid:") => {
1349eed4
WB
175 ids.ruid = Self::__check_uid_gid(parts.next())?;
176 ids.euid = Self::__check_uid_gid(parts.next())?;
177 ids.suid = Self::__check_uid_gid(parts.next())?;
178 ids.fsuid = Self::__check_uid_gid(parts.next())?;
3bb4df0b
WB
179 }
180 Some("Gid:") => {
1349eed4
WB
181 ids.rgid = Self::__check_uid_gid(parts.next())?;
182 ids.egid = Self::__check_uid_gid(parts.next())?;
183 ids.sgid = Self::__check_uid_gid(parts.next())?;
184 ids.fsgid = Self::__check_uid_gid(parts.next())?;
3bb4df0b 185 }
512f780a
WB
186 Some("CapInh:") => caps.inheritable = check_u64_hex(parts.next())?,
187 Some("CapPrm:") => caps.permitted = check_u64_hex(parts.next())?,
188 Some("CapEff:") => caps.effective = check_u64_hex(parts.next())?,
189 //Some("CapBnd:") => caps.bounding = check_u64_hex(parts.next())?,
190 Some("Umask:") => umask = check_u32_oct(parts.next())?,
3bb4df0b
WB
191 _ => continue,
192 }
512f780a
WB
193 }
194
195 Ok(ProcStatus {
196 uids: ids,
197 capabilities: caps,
198 umask,
199 })
200 }
201
202 pub fn get_cgroups(&self) -> Result<CGroups, Error> {
1e80bab0 203 let reader = self.open_buffered(c_str!("cgroup"))?;
512f780a
WB
204
205 let mut cgroups = CGroups::new();
206
207 for line in reader.split(b'\n') {
208 let line = line?;
209 let mut parts = line.splitn(3, |b| *b == b':');
210 let num = parts.next();
211 let name = parts.next();
212 let path = parts.next();
f3cae2a7 213 if num.is_none() || name.is_none() || path.is_none() || parts.next().is_some() {
512f780a 214 bail!("failed to parse cgroup line: {:?}", line);
3bb4df0b 215 }
512f780a
WB
216
217 let name = String::from_utf8(name.unwrap().to_vec())?;
218 let path = OsString::from_vec(path.unwrap().to_vec());
219
9486338a 220 if name.is_empty() {
512f780a
WB
221 cgroups.v2 = Some(path);
222 } else {
223 for entry in name.split(',') {
224 cgroups.v1.insert(entry.to_string(), path.clone());
225 }
226 }
227 }
228
229 Ok(cgroups)
230 }
231
1349eed4
WB
232 pub fn get_uid_gid_map(&self, file: &CStr) -> Result<IdMap, Error> {
233 let reader = self.open_buffered(file)?;
234
235 let mut entries = Vec::new();
236 for line in reader.lines() {
237 let line = line?;
238 let mut parts = line.split_ascii_whitespace();
9486338a
WB
239 let ns = u64::from(Self::__check_uid_gid(parts.next())?);
240 let host = u64::from(Self::__check_uid_gid(parts.next())?);
241 let range = u64::from(Self::__check_uid_gid(parts.next())?);
1349eed4
WB
242 entries.push(IdMapEntry { ns, host, range });
243 }
244
3bbd1db0 245 Ok(IdMap::new(entries))
1349eed4
WB
246 }
247
248 pub fn get_uid_map(&self) -> Result<IdMap, Error> {
1e80bab0 249 self.get_uid_gid_map(c_str!("uid_map"))
1349eed4
WB
250 }
251
252 pub fn get_gid_map(&self) -> Result<IdMap, Error> {
1e80bab0 253 self.get_uid_gid_map(c_str!("gid_map"))
1349eed4
WB
254 }
255
42f25756
WB
256 pub fn read_file(&self, file: &CStr) -> io::Result<Vec<u8>> {
257 use io::Read;
258
259 let mut reader = self.open_file(file, libc::O_RDONLY | libc::O_CLOEXEC, 0)?;
260 let mut out = Vec::new();
261 reader.read_to_end(&mut out)?;
262 Ok(out)
263 }
264
512f780a
WB
265 pub fn user_caps(&self) -> Result<UserCaps, Error> {
266 UserCaps::new(self)
267 }
268}