1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Small system utility modules for usage by other modules.
6
7 pub mod affinity;
8 mod alloc;
9 #[macro_use]
10 pub mod handle_eintr;
11 #[macro_use]
12 pub mod ioctl;
13 #[macro_use]
14 pub mod syslog;
15 mod capabilities;
16 mod clock;
17 mod errno;
18 mod eventfd;
19 mod file_flags;
20 mod file_traits;
21 mod fork;
22 mod guest_address;
23 pub mod guest_memory;
24 mod mmap;
25 pub mod net;
26 mod passwd;
27 mod poll;
28 mod priority;
29 mod raw_fd;
30 mod seek_hole;
31 mod shm;
32 pub mod signal;
33 mod signalfd;
34 mod sock_ctrl_msg;
35 mod struct_util;
36 mod tempdir;
37 mod terminal;
38 mod timerfd;
39 mod write_zeroes;
40
41 pub use crate::affinity::*;
42 pub use crate::alloc::LayoutAllocation;
43 pub use crate::capabilities::drop_capabilities;
44 pub use crate::clock::{Clock, FakeClock};
45 use crate::errno::errno_result;
46 pub use crate::errno::{Error, Result};
47 pub use crate::eventfd::*;
48 pub use crate::file_flags::*;
49 pub use crate::fork::*;
50 pub use crate::guest_address::*;
51 pub use crate::guest_memory::*;
52 pub use crate::ioctl::*;
53 pub use crate::mmap::*;
54 pub use crate::passwd::*;
55 pub use crate::poll::*;
56 pub use crate::priority::*;
57 pub use crate::raw_fd::*;
58 pub use crate::shm::*;
59 pub use crate::signal::*;
60 pub use crate::signalfd::*;
61 pub use crate::sock_ctrl_msg::*;
62 pub use crate::struct_util::*;
63 pub use crate::tempdir::*;
64 pub use crate::terminal::*;
65 pub use crate::timerfd::*;
66 pub use poll_token_derive::*;
67
68 pub use crate::file_traits::{FileReadWriteVolatile, FileSetLen, FileSync};
69 pub use crate::guest_memory::Error as GuestMemoryError;
70 pub use crate::mmap::Error as MmapError;
71 pub use crate::seek_hole::SeekHole;
72 pub use crate::signalfd::Error as SignalFdError;
73 pub use crate::write_zeroes::{PunchHole, WriteZeroes};
74
75 use std::ffi::CStr;
76 use std::fs::{remove_file, File};
77 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
78 use std::os::unix::net::UnixDatagram;
79 use std::ptr;
80
81 use libc::{
82 c_long, gid_t, kill, pid_t, pipe2, syscall, sysconf, uid_t, waitpid, O_CLOEXEC, SIGKILL,
83 WNOHANG, _SC_PAGESIZE,
84 };
85
86 use syscall_defines::linux::LinuxSyscall::SYS_getpid;
87
88 /// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
89 #[inline(always)]
pagesize() -> usize90 pub fn pagesize() -> usize {
91 // Trivially safe
92 unsafe { sysconf(_SC_PAGESIZE) as usize }
93 }
94
95 /// Uses the system's page size in bytes to round the given value up to the nearest page boundary.
96 #[inline(always)]
round_up_to_page_size(v: usize) -> usize97 pub fn round_up_to_page_size(v: usize) -> usize {
98 let page_mask = pagesize() - 1;
99 (v + page_mask) & !page_mask
100 }
101
102 /// This bypasses `libc`'s caching `getpid(2)` wrapper which can be invalid if a raw clone was used
103 /// elsewhere.
104 #[inline(always)]
getpid() -> pid_t105 pub fn getpid() -> pid_t {
106 // Safe because this syscall can never fail and we give it a valid syscall number.
107 unsafe { syscall(SYS_getpid as c_long) as pid_t }
108 }
109
110 /// Safe wrapper for `geteuid(2)`.
111 #[inline(always)]
geteuid() -> uid_t112 pub fn geteuid() -> uid_t {
113 // trivially safe
114 unsafe { libc::geteuid() }
115 }
116
117 /// Safe wrapper for `getegid(2)`.
118 #[inline(always)]
getegid() -> gid_t119 pub fn getegid() -> gid_t {
120 // trivially safe
121 unsafe { libc::getegid() }
122 }
123
124 /// Safe wrapper for chown(2).
125 #[inline(always)]
chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()>126 pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
127 // Safe since we pass in a valid string pointer and check the return value.
128 let ret = unsafe { libc::chown(path.as_ptr(), uid, gid) };
129
130 if ret < 0 {
131 errno_result()
132 } else {
133 Ok(())
134 }
135 }
136
137 /// The operation to perform with `flock`.
138 pub enum FlockOperation {
139 LockShared,
140 LockExclusive,
141 Unlock,
142 }
143
144 /// Safe wrapper for flock(2) with the operation `op` and optionally `nonblocking`. The lock will be
145 /// dropped automatically when `file` is dropped.
146 #[inline(always)]
flock(file: &dyn AsRawFd, op: FlockOperation, nonblocking: bool) -> Result<()>147 pub fn flock(file: &dyn AsRawFd, op: FlockOperation, nonblocking: bool) -> Result<()> {
148 let mut operation = match op {
149 FlockOperation::LockShared => libc::LOCK_SH,
150 FlockOperation::LockExclusive => libc::LOCK_EX,
151 FlockOperation::Unlock => libc::LOCK_UN,
152 };
153
154 if nonblocking {
155 operation |= libc::LOCK_NB;
156 }
157
158 // Safe since we pass in a valid fd and flock operation, and check the return value.
159 let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
160
161 if ret < 0 {
162 errno_result()
163 } else {
164 Ok(())
165 }
166 }
167
168 /// The operation to perform with `fallocate`.
169 pub enum FallocateMode {
170 PunchHole,
171 ZeroRange,
172 }
173
174 /// Safe wrapper for `fallocate()`.
fallocate( file: &dyn AsRawFd, mode: FallocateMode, keep_size: bool, offset: u64, len: u64, ) -> Result<()>175 pub fn fallocate(
176 file: &dyn AsRawFd,
177 mode: FallocateMode,
178 keep_size: bool,
179 offset: u64,
180 len: u64,
181 ) -> Result<()> {
182 let offset = if offset > libc::off64_t::max_value() as u64 {
183 return Err(Error::new(libc::EINVAL));
184 } else {
185 offset as libc::off64_t
186 };
187
188 let len = if len > libc::off64_t::max_value() as u64 {
189 return Err(Error::new(libc::EINVAL));
190 } else {
191 len as libc::off64_t
192 };
193
194 let mut mode = match mode {
195 FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE,
196 FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE,
197 };
198
199 if keep_size {
200 mode |= libc::FALLOC_FL_KEEP_SIZE;
201 }
202
203 // Safe since we pass in a valid fd and fallocate mode, validate offset and len,
204 // and check the return value.
205 let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) };
206 if ret < 0 {
207 errno_result()
208 } else {
209 Ok(())
210 }
211 }
212
213 /// Reaps a child process that has terminated.
214 ///
215 /// Returns `Ok(pid)` where `pid` is the process that was reaped or `Ok(0)` if none of the children
216 /// have terminated. An `Error` is with `errno == ECHILD` if there are no children left to reap.
217 ///
218 /// # Examples
219 ///
220 /// Reaps all child processes until there are no terminated children to reap.
221 ///
222 /// ```
223 /// fn reap_children() {
224 /// loop {
225 /// match sys_util::reap_child() {
226 /// Ok(0) => println!("no children ready to reap"),
227 /// Ok(pid) => {
228 /// println!("reaped {}", pid);
229 /// continue
230 /// },
231 /// Err(e) if e.errno() == libc::ECHILD => println!("no children left"),
232 /// Err(e) => println!("error reaping children: {}", e),
233 /// }
234 /// break
235 /// }
236 /// }
237 /// ```
reap_child() -> Result<pid_t>238 pub fn reap_child() -> Result<pid_t> {
239 // Safe because we pass in no memory, prevent blocking with WNOHANG, and check for error.
240 let ret = unsafe { waitpid(-1, ptr::null_mut(), WNOHANG) };
241 if ret == -1 {
242 errno_result()
243 } else {
244 Ok(ret)
245 }
246 }
247
248 /// Kill all processes in the current process group.
249 ///
250 /// On success, this kills all processes in the current process group, including the current
251 /// process, meaning this will not return. This is equivalent to a call to `kill(0, SIGKILL)`.
kill_process_group() -> Result<()>252 pub fn kill_process_group() -> Result<()> {
253 let ret = unsafe { kill(0, SIGKILL) };
254 if ret == -1 {
255 errno_result()
256 } else {
257 // Kill succeeded, so this process never reaches here.
258 unreachable!();
259 }
260 }
261
262 /// Spawns a pipe pair where the first pipe is the read end and the second pipe is the write end.
263 ///
264 /// If `close_on_exec` is true, the `O_CLOEXEC` flag will be set during pipe creation.
pipe(close_on_exec: bool) -> Result<(File, File)>265 pub fn pipe(close_on_exec: bool) -> Result<(File, File)> {
266 let flags = if close_on_exec { O_CLOEXEC } else { 0 };
267 let mut pipe_fds = [-1; 2];
268 // Safe because pipe2 will only write 2 element array of i32 to the given pointer, and we check
269 // for error.
270 let ret = unsafe { pipe2(&mut pipe_fds[0], flags) };
271 if ret == -1 {
272 errno_result()
273 } else {
274 // Safe because both fds must be valid for pipe2 to have returned sucessfully and we have
275 // exclusive ownership of them.
276 Ok(unsafe {
277 (
278 File::from_raw_fd(pipe_fds[0]),
279 File::from_raw_fd(pipe_fds[1]),
280 )
281 })
282 }
283 }
284
285 /// Used to attempt to clean up a named pipe after it is no longer used.
286 pub struct UnlinkUnixDatagram(pub UnixDatagram);
287 impl AsRef<UnixDatagram> for UnlinkUnixDatagram {
as_ref(&self) -> &UnixDatagram288 fn as_ref(&self) -> &UnixDatagram {
289 &self.0
290 }
291 }
292 impl Drop for UnlinkUnixDatagram {
drop(&mut self)293 fn drop(&mut self) {
294 if let Ok(addr) = self.0.local_addr() {
295 if let Some(path) = addr.as_pathname() {
296 if let Err(e) = remove_file(path) {
297 warn!("failed to remove control socket file: {}", e);
298 }
299 }
300 }
301 }
302 }
303
304 /// Verifies that |raw_fd| is actually owned by this process and duplicates it to ensure that
305 /// we have a unique handle to it.
validate_raw_fd(raw_fd: RawFd) -> Result<RawFd>306 pub fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> {
307 // Checking that close-on-exec isn't set helps filter out FDs that were opened by
308 // crosvm as all crosvm FDs are close on exec.
309 // Safe because this doesn't modify any memory and we check the return value.
310 let flags = unsafe { libc::fcntl(raw_fd, libc::F_GETFD) };
311 if flags < 0 || (flags & libc::FD_CLOEXEC) != 0 {
312 return Err(Error::new(libc::EBADF));
313 }
314
315 // Duplicate the fd to ensure that we don't accidentally close an fd previously
316 // opened by another subsystem. Safe because this doesn't modify any memory and
317 // we check the return value.
318 let dup_fd = unsafe { libc::fcntl(raw_fd, libc::F_DUPFD_CLOEXEC, 0) };
319 if dup_fd < 0 {
320 return Err(Error::last());
321 }
322 Ok(dup_fd as RawFd)
323 }
324