aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-04-17 03:04:48 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-04-17 03:04:48 +0000
commit9a623f74f4d0dde267732c4c81a4baf9499f741e (patch)
tree2599f8acad9ba3c1dab43a2352313c1126f714cf
parent9d33f57037c43bb4e0508a0d09fd38151ad226a1 (diff)
parent43046804aad712ad752641ec4c756f9c418e1fad (diff)
downloadminijail-9a623f74f4d0dde267732c4c81a4baf9499f741e.tar.gz
Snap for 7290612 from 43046804aad712ad752641ec4c756f9c418e1fad to sc-v2-release
Change-Id: I9e65656f3ed77496f4a1323f4ed8061b4764ff24
-rw-r--r--rust/minijail/Cargo.toml5
-rw-r--r--rust/minijail/src/lib.rs67
-rw-r--r--rust/minijail/tests/fork_remap.rs81
3 files changed, 133 insertions, 20 deletions
diff --git a/rust/minijail/Cargo.toml b/rust/minijail/Cargo.toml
index 6cf9837..db0652f 100644
--- a/rust/minijail/Cargo.toml
+++ b/rust/minijail/Cargo.toml
@@ -8,3 +8,8 @@ edition = "2018"
[dependencies]
libc = "0.2.44"
minijail-sys = { path = "../minijail-sys" } # provided by ebuild
+
+[[test]]
+name = "fork_remap"
+path = "tests/fork_remap.rs"
+harness = false
diff --git a/rust/minijail/src/lib.rs b/rust/minijail/src/lib.rs
index 7805721..b052dc6 100644
--- a/rust/minijail/src/lib.rs
+++ b/rust/minijail/src/lib.rs
@@ -230,6 +230,29 @@ extern "C" {
fn __libc_current_sigrtmax() -> libc::c_int;
}
+fn translate_wait_error(ret: libc::c_int) -> Result<()> {
+ if ret == 0 {
+ return Ok(());
+ }
+ if ret == MINIJAIL_ERR_NO_COMMAND as libc::c_int {
+ return Err(Error::NoCommand);
+ }
+ if ret == MINIJAIL_ERR_NO_ACCESS as libc::c_int {
+ return Err(Error::NoAccess);
+ }
+ let sig_base: libc::c_int = MINIJAIL_ERR_SIG_BASE as libc::c_int;
+ let sig_max_code: libc::c_int = unsafe { __libc_current_sigrtmax() } + sig_base;
+ if ret > sig_base && ret <= sig_max_code {
+ return Err(Error::Killed(
+ (ret - MINIJAIL_ERR_SIG_BASE as libc::c_int) as u8,
+ ));
+ }
+ if ret > 0 && ret <= 0xff {
+ return Err(Error::ReturnCode(ret as u8));
+ }
+ unreachable!();
+}
+
impl Minijail {
/// Creates a new jail configuration.
pub fn new() -> Result<Minijail> {
@@ -745,26 +768,17 @@ impl Minijail {
unsafe {
ret = minijail_wait(self.jail);
}
- if ret == 0 {
- return Ok(());
- }
- if ret == MINIJAIL_ERR_NO_COMMAND as libc::c_int {
- return Err(Error::NoCommand);
- }
- if ret == MINIJAIL_ERR_NO_ACCESS as libc::c_int {
- return Err(Error::NoAccess);
- }
- let sig_base: libc::c_int = MINIJAIL_ERR_SIG_BASE as libc::c_int;
- let sig_max_code: libc::c_int = unsafe { __libc_current_sigrtmax() } + sig_base;
- if ret > sig_base && ret <= sig_max_code {
- return Err(Error::Killed(
- (ret - MINIJAIL_ERR_SIG_BASE as libc::c_int) as u8,
- ));
- }
- if ret > 0 && ret <= 0xff {
- return Err(Error::ReturnCode(ret as u8));
- }
- unreachable!();
+ translate_wait_error(ret)
+ }
+
+ /// Send a SIGTERM to the child process and wait for its return code.
+ pub fn kill(&self) -> Result<()> {
+ let ret = unsafe {
+ // The kill does not change any internal state.
+ minijail_kill(self.jail)
+ };
+ // minijail_kill waits for the process, so also translate the returned wait error.
+ translate_wait_error(ret)
}
}
@@ -901,6 +915,19 @@ mod tests {
}
#[test]
+ fn kill_success() {
+ let j = Minijail::new().unwrap();
+ j.run(
+ Path::new("usr/bin/sleep"),
+ &[1, 2],
+ &["/usr/bin/sleep", "5"],
+ )
+ .unwrap();
+ const EXPECTED_SIGNAL: u8 = libc::SIGTERM as u8;
+ expect_result!(j.kill(), Err(Error::Killed(EXPECTED_SIGNAL)));
+ }
+
+ #[test]
#[ignore] // privileged operation.
fn chroot() {
let mut j = Minijail::new().unwrap();
diff --git a/rust/minijail/tests/fork_remap.rs b/rust/minijail/tests/fork_remap.rs
new file mode 100644
index 0000000..8ace83b
--- /dev/null
+++ b/rust/minijail/tests/fork_remap.rs
@@ -0,0 +1,81 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! A test of Minijail::fork_remap.
+//!
+//! It needs to be run on its own because it forks the process and by default cargo test is
+//! multi-threaded, and we do not want copies of the other worker threads leaking into the child
+//! process.
+
+use std::fs::{read_link, File, OpenOptions};
+use std::io::{self, Read};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::path::Path;
+
+use minijail::Minijail;
+
+const DEV_NULL: &str = "/dev/null";
+const DEV_ZERO: &str = "/dev/zero";
+
+const DEST_FD1: RawFd = 7;
+const DEST_FD2: RawFd = 8;
+
+fn open_dev_zero() -> Result<File, io::Error> {
+ OpenOptions::new()
+ .read(true)
+ .write(true)
+ .open(Path::new(DEV_ZERO))
+}
+
+fn main() {
+ let mut check_file1 = open_dev_zero().unwrap();
+ let mut check_file2 = open_dev_zero().unwrap();
+ let j = Minijail::new().unwrap();
+
+ for p in &[0, 1, check_file1.as_raw_fd(), check_file2.as_raw_fd()] {
+ let path = format!("/proc/self/fd/{}", p);
+ let target = read_link(Path::new(&path));
+ eprintln!("P: {} -> {:?}", p, &target);
+ }
+
+ if unsafe {
+ j.fork_remap(&[
+ (2, 2),
+ (check_file1.as_raw_fd(), DEST_FD1),
+ (check_file2.as_raw_fd(), DEST_FD2),
+ ])
+ }
+ .unwrap()
+ != 0
+ {
+ j.wait().unwrap();
+ eprintln!("Parent done.");
+ return;
+ }
+
+ // Safe because we are re-taking ownership of a remapped fd after forking.
+ check_file1 = unsafe { File::from_raw_fd(DEST_FD1) };
+ check_file2 = unsafe { File::from_raw_fd(DEST_FD2) };
+
+ for (p, expected) in &[
+ (0, DEV_NULL),
+ (1, DEV_NULL),
+ (DEST_FD1, DEV_ZERO),
+ (DEST_FD2, DEV_ZERO),
+ ] {
+ let path = format!("/proc/self/fd/{}", p);
+ let target = read_link(Path::new(&path));
+ eprintln!("C: {} -> {:?}", p, &target);
+ if !matches!(&target, Ok(p) if p == Path::new(expected)) {
+ panic!("C: got {:?}; expected Ok({:?})", target, expected);
+ }
+ }
+
+ const BUFFER_LEN: usize = 16;
+ let mut buffer = [0xffu8; BUFFER_LEN];
+ check_file1.read_exact(&mut buffer).unwrap();
+ assert_eq!(&buffer, &[0u8; BUFFER_LEN]);
+
+ eprintln!("Child done.");
+}