Skip to content

Commit d582527

Browse files
author
Markus Bauer
committed
Add files/devices and subdirectories to fakeroot
1 parent 07b42cf commit d582527

File tree

4 files changed

+75
-6
lines changed

4 files changed

+75
-6
lines changed

examples/fakeroot.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ fn main() {
1010

1111
cmd.fakeroot_enable("/dev/shm/sandbox_root");
1212
cmd.fakeroot_mount("/bin", "/bin", true);
13+
cmd.fakeroot_mount_file("/dev/urandom", "/dev/urandom", false);
1314
cmd.fakeroot_mount("/etc", "/etc", true);
1415
cmd.fakeroot_mount("/lib", "/lib", true);
1516
cmd.fakeroot_mount("/lib64", "/lib64", true);

src/child.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,10 @@ pub unsafe fn child_after_clone(child: &ChildInfo) -> ! {
185185
});
186186

187187
child.cfg.fake_root_base.as_ref().map(|base| {
188-
if !build_fakeroot(base, child.cfg.fake_root_mounts.as_ref()) {
188+
if !build_fakeroot(base,
189+
child.cfg.fake_root_mkdirs.as_ref(),
190+
child.cfg.fake_root_touchs.as_ref(),
191+
child.cfg.fake_root_mounts.as_ref()) {
189192
fail(Err::ChangeRoot, epipe);
190193
}
191194
});

src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub struct Config {
2626
// TODO(tailhook) session leader
2727
pub fake_root_base: Option<CString>,
2828
pub fake_root_mounts: Vec<FakeRootMount>,
29+
pub fake_root_mkdirs: Vec<CString>,
30+
pub fake_root_touchs: Vec<CString>,
2931
}
3032

3133
impl Default for Config {
@@ -43,6 +45,8 @@ impl Default for Config {
4345
make_group_leader: false,
4446
fake_root_base: None,
4547
fake_root_mounts: Vec::new(),
48+
fake_root_mkdirs: Vec::new(),
49+
fake_root_touchs: Vec::new(),
4650
}
4751
}
4852
}

src/fakeroot.rs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::ffi_util::ToCString;
22
use crate::{Command, Namespace};
3-
use libc::{MNT_DETACH, MS_BIND, MS_PRIVATE, MS_RDONLY, MS_REC, MS_REMOUNT};
3+
use libc::{
4+
MNT_DETACH, MS_BIND, MS_PRIVATE, MS_RDONLY, MS_REC, MS_REMOUNT, O_CLOEXEC, O_CREAT, O_RDONLY,
5+
};
46
use std::ffi::{c_char, c_void, CString};
57
use std::path::Path;
68

@@ -29,6 +31,16 @@ impl Command {
2931
self.config.fake_root_base = Some(base.to_cstring());
3032
}
3133

34+
fn fakeroot_mkdir(&mut self, base: &str, dir: &Path) {
35+
dir.parent().map(|parent_dir| {
36+
if dir != parent_dir {
37+
self.fakeroot_mkdir(base, parent_dir);
38+
let outer_dir = format!("{}/{}", base, dir.to_str().unwrap());
39+
self.config.fake_root_mkdirs.push(outer_dir.to_cstring());
40+
}
41+
});
42+
}
43+
3244
/// Add an existing directory to the fakeroot.
3345
///
3446
/// fakeroot_enable() must be called first, otherwise this function will panic.
@@ -46,7 +58,39 @@ impl Command {
4658
.as_ref()
4759
.expect("call fakeroot_enable() first!")
4860
.to_str()
49-
.unwrap();
61+
.unwrap()
62+
.to_owned();
63+
self.fakeroot_mkdir(base.as_ref(), Path::new(dst));
64+
self.config.fake_root_mounts.push(FakeRootMount {
65+
mountpoint: dst.to_cstring(),
66+
mountpoint_outer: format!("{}/{}", base, dst).to_cstring(),
67+
src: src.as_ref().to_cstring(),
68+
readonly,
69+
is_special_fs: false,
70+
});
71+
}
72+
73+
/// Add an existing file or device to the fakeroot.
74+
///
75+
/// fakeroot_enable() must be called first, otherwise this function will panic.
76+
///
77+
/// Example usage:
78+
/// cmd.fakeroot_mount_file("/dev/urandom", "/dev/urandom", false);
79+
pub fn fakeroot_mount_file<P: AsRef<Path>>(&mut self, src: P, dst: &str, readonly: bool) {
80+
let base = self
81+
.config
82+
.fake_root_base
83+
.as_ref()
84+
.expect("call fakeroot_enable() first!")
85+
.to_str()
86+
.unwrap()
87+
.to_owned();
88+
Path::new(dst).parent().map(|parent_dir| {
89+
self.fakeroot_mkdir(base.as_ref(), parent_dir);
90+
});
91+
self.config
92+
.fake_root_touchs
93+
.push(format!("{}/{}", base, dst).to_cstring());
5094
self.config.fake_root_mounts.push(FakeRootMount {
5195
mountpoint: dst.to_cstring(),
5296
mountpoint_outer: format!("{}/{}", base, dst).to_cstring(),
@@ -69,7 +113,9 @@ impl Command {
69113
.as_ref()
70114
.expect("call fakeroot_enable() first!")
71115
.to_str()
72-
.unwrap();
116+
.unwrap()
117+
.to_owned();
118+
self.fakeroot_mkdir(base.as_ref(), Path::new(dst));
73119
self.config.fake_root_mounts.push(FakeRootMount {
74120
mountpoint: dst.to_cstring(),
75121
mountpoint_outer: format!("{}/{}", base, dst).to_cstring(),
@@ -81,7 +127,12 @@ impl Command {
81127
}
82128

83129
/// This syscall sequence is more or less taken from nsjail (https://github.com/google/nsjail).
84-
pub(crate) unsafe fn build_fakeroot(base: &CString, mountpoints: &[FakeRootMount]) -> bool {
130+
pub(crate) unsafe fn build_fakeroot(
131+
base: &CString,
132+
mkdirs: &[CString],
133+
touchs: &[CString],
134+
mountpoints: &[FakeRootMount],
135+
) -> bool {
85136
// define some libc constants
86137
let null_char = 0 as *const c_char;
87138
let null_void = 0 as *const c_void;
@@ -100,9 +151,19 @@ pub(crate) unsafe fn build_fakeroot(base: &CString, mountpoints: &[FakeRootMount
100151
return false;
101152
}
102153

154+
// create mount points
155+
for dir in mkdirs {
156+
libc::mkdir(dir.as_ptr(), 0o777);
157+
}
158+
for file in touchs {
159+
let fd = libc::open(file.as_ptr(), O_RDONLY | O_CREAT | O_CLOEXEC);
160+
if fd >= 0 {
161+
libc::close(fd);
162+
}
163+
}
164+
103165
// mount directories - still read-write (because MS_BIND + MS_RDONLY are not supported)
104166
for mount in mountpoints {
105-
libc::mkdir(mount.mountpoint_outer.as_ptr(), 0o777);
106167
let (src, fstype, flags) = if mount.is_special_fs {
107168
(null_char, mount.src.as_ptr(), 0)
108169
} else {

0 commit comments

Comments
 (0)