-
Notifications
You must be signed in to change notification settings - Fork 29
/
procfs.rs
76 lines (70 loc) · 2.62 KB
/
procfs.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! Utilities for working with `/proc`, where Linux's `procfs` is typically
//! mounted. `/proc` serves as an adjunct to Linux's main syscall surface area,
//! providing additional features with an awkward interface.
//!
//! This module does a considerable amount of work to determine whether `/proc`
//! is mounted, with actual `procfs`, and without any additional mount points
//! on top of the paths we open.
use crate::fs::{
errors, open, read_link_unchecked, set_times_follow_unchecked, OpenOptions, SystemTimeSpec,
};
use io_lifetimes::{AsFd, AsFilelike};
use rustix::fs::{chmodat, Mode, OFlags, RawMode};
use rustix::io::proc_self_fd;
use rustix::path::DecInt;
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::path::{Path, PathBuf};
use std::{fs, io};
pub(crate) fn get_path_from_proc_self_fd(file: &fs::File) -> io::Result<PathBuf> {
read_link_unchecked(
&proc_self_fd()?.as_filelike_view::<fs::File>(),
DecInt::from_fd(file).as_ref(),
PathBuf::new(),
)
}
/// Linux's `fchmodat` doesn't support `AT_NOFOLLOW_SYMLINK`, so we can't trust
/// that it won't follow a symlink outside the sandbox. As an alternative, the
/// symlinks in Linux's /proc/self/fd/* aren't ordinary symlinks, they're
/// "magic links", which are more transparent, to the point of allowing chmod
/// to work. So we open the file with `O_PATH` and then do `fchmodat` on the
/// corresponding /proc/self/fd/* link.
pub(crate) fn set_permissions_through_proc_self_fd(
start: &fs::File,
path: &Path,
perm: fs::Permissions,
) -> io::Result<()> {
let opath = open(
start,
path,
OpenOptions::new()
.read(true)
.custom_flags(OFlags::PATH.bits() as i32),
)?;
let dirfd = proc_self_fd()?;
let mode = Mode::from_bits(perm.mode() as RawMode).ok_or_else(errors::invalid_flags)?;
Ok(chmodat(&dirfd, DecInt::from_fd(&opath), mode)?)
}
pub(crate) fn set_times_through_proc_self_fd(
start: &fs::File,
path: &Path,
atime: Option<SystemTimeSpec>,
mtime: Option<SystemTimeSpec>,
) -> io::Result<()> {
let opath = open(
start,
path,
OpenOptions::new()
.read(true)
.custom_flags(OFlags::PATH.bits() as i32),
)?;
// Don't pass `AT_SYMLINK_NOFOLLOW`, because we do actually want to follow
// the first symlink. We don't want to follow any subsequent symlinks, but
// omitting `O_NOFOLLOW` above ensures that the destination of the link
// isn't a symlink.
set_times_follow_unchecked(
proc_self_fd()?.as_fd(),
DecInt::from_fd(&opath).as_ref(),
atime,
mtime,
)
}