summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/test/test_mount.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /third_party/rust/nix/test/test_mount.rs
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nix/test/test_mount.rs')
-rw-r--r--third_party/rust/nix/test/test_mount.rs390
1 files changed, 153 insertions, 237 deletions
diff --git a/third_party/rust/nix/test/test_mount.rs b/third_party/rust/nix/test/test_mount.rs
index 5cf00408e8..a4f0903dba 100644
--- a/third_party/rust/nix/test/test_mount.rs
+++ b/third_party/rust/nix/test/test_mount.rs
@@ -1,267 +1,183 @@
-mod common;
-
-// Implementation note: to allow unprivileged users to run it, this test makes
-// use of user and mount namespaces. On systems that allow unprivileged user
-// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
-// without root.
-
-#[cfg(target_os = "linux")]
-mod test_mount {
- use std::fs::{self, File};
- use std::io::{self, Read, Write};
- use std::os::unix::fs::OpenOptionsExt;
- use std::os::unix::fs::PermissionsExt;
- use std::process::{self, Command};
-
- use libc::{EACCES, EROFS};
-
- use nix::errno::Errno;
- use nix::mount::{mount, umount, MsFlags};
- use nix::sched::{unshare, CloneFlags};
- use nix::sys::stat::{self, Mode};
- use nix::unistd::getuid;
-
- static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
+use std::fs::{self, File};
+use std::io::{Read, Write};
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::fs::PermissionsExt;
+use std::process::Command;
+
+use libc::{EACCES, EROFS};
+
+use nix::mount::{mount, umount, MsFlags};
+use nix::sys::stat::{self, Mode};
+
+use crate::*;
+
+static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
exit 23";
- const EXPECTED_STATUS: i32 = 23;
+const EXPECTED_STATUS: i32 = 23;
- const NONE: Option<&'static [u8]> = None;
- #[allow(clippy::bind_instead_of_map)] // False positive
- pub fn test_mount_tmpfs_without_flags_allows_rwx() {
- let tempdir = tempfile::tempdir().unwrap();
+const NONE: Option<&'static [u8]> = None;
- mount(
- NONE,
- tempdir.path(),
- Some(b"tmpfs".as_ref()),
- MsFlags::empty(),
- NONE,
- )
- .unwrap_or_else(|e| panic!("mount failed: {e}"));
+#[test]
+fn test_mount_tmpfs_without_flags_allows_rwx() {
+ require_capability!(
+ "test_mount_tmpfs_without_flags_allows_rwx",
+ CAP_SYS_ADMIN
+ );
+ let tempdir = tempfile::tempdir().unwrap();
+
+ mount(
+ NONE,
+ tempdir.path(),
+ Some(b"tmpfs".as_ref()),
+ MsFlags::empty(),
+ NONE,
+ )
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+ let test_path = tempdir.path().join("test");
+
+ // Verify write.
+ fs::OpenOptions::new()
+ .create(true)
+ .write(true)
+ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
+ .open(&test_path)
+ .and_then(|mut f| f.write(SCRIPT_CONTENTS))
+ .unwrap_or_else(|e| panic!("write failed: {e}"));
+
+ // Verify read.
+ let mut buf = Vec::new();
+ File::open(&test_path)
+ .and_then(|mut f| f.read_to_end(&mut buf))
+ .unwrap_or_else(|e| panic!("read failed: {e}"));
+ assert_eq!(buf, SCRIPT_CONTENTS);
+
+ // Verify execute.
+ assert_eq!(
+ EXPECTED_STATUS,
+ Command::new(&test_path)
+ .status()
+ .unwrap_or_else(|e| panic!("exec failed: {e}"))
+ .code()
+ .unwrap_or_else(|| panic!("child killed by signal"))
+ );
- let test_path = tempdir.path().join("test");
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
- // Verify write.
- fs::OpenOptions::new()
- .create(true)
- .write(true)
- .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
- .open(&test_path)
- .or_else(|e| {
- if Errno::from_i32(e.raw_os_error().unwrap())
- == Errno::EOVERFLOW
- {
- // Skip tests on certain Linux kernels which have a bug
- // regarding tmpfs in namespaces.
- // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is
- // not. There is no legitimate reason for open(2) to return
- // EOVERFLOW here.
- // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087
- let stderr = io::stderr();
- let mut handle = stderr.lock();
- writeln!(
- handle,
- "Buggy Linux kernel detected. Skipping test."
- )
- .unwrap();
- process::exit(0);
- } else {
- panic!("open failed: {e}");
- }
- })
- .and_then(|mut f| f.write(SCRIPT_CONTENTS))
- .unwrap_or_else(|e| panic!("write failed: {e}"));
+#[test]
+fn test_mount_rdonly_disallows_write() {
+ require_capability!("test_mount_rdonly_disallows_write", CAP_SYS_ADMIN);
+ let tempdir = tempfile::tempdir().unwrap();
+
+ mount(
+ NONE,
+ tempdir.path(),
+ Some(b"tmpfs".as_ref()),
+ MsFlags::MS_RDONLY,
+ NONE,
+ )
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+ // EROFS: Read-only file system
+ assert_eq!(
+ EROFS,
+ File::create(tempdir.path().join("test"))
+ .unwrap_err()
+ .raw_os_error()
+ .unwrap()
+ );
- // Verify read.
- let mut buf = Vec::new();
- File::open(&test_path)
- .and_then(|mut f| f.read_to_end(&mut buf))
- .unwrap_or_else(|e| panic!("read failed: {e}"));
- assert_eq!(buf, SCRIPT_CONTENTS);
-
- // Verify execute.
- assert_eq!(
- EXPECTED_STATUS,
- Command::new(&test_path)
- .status()
- .unwrap_or_else(|e| panic!("exec failed: {e}"))
- .code()
- .unwrap_or_else(|| panic!("child killed by signal"))
- );
-
- umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
- }
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
- pub fn test_mount_rdonly_disallows_write() {
- let tempdir = tempfile::tempdir().unwrap();
+#[test]
+fn test_mount_noexec_disallows_exec() {
+ require_capability!("test_mount_noexec_disallows_exec", CAP_SYS_ADMIN);
+ let tempdir = tempfile::tempdir().unwrap();
+
+ mount(
+ NONE,
+ tempdir.path(),
+ Some(b"tmpfs".as_ref()),
+ MsFlags::MS_NOEXEC,
+ NONE,
+ )
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+ let test_path = tempdir.path().join("test");
+
+ fs::OpenOptions::new()
+ .create(true)
+ .write(true)
+ .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
+ .open(&test_path)
+ .and_then(|mut f| f.write(SCRIPT_CONTENTS))
+ .unwrap_or_else(|e| panic!("write failed: {e}"));
+
+ // Verify that we cannot execute despite a+x permissions being set.
+ let mode = stat::Mode::from_bits_truncate(
+ fs::metadata(&test_path)
+ .map(|md| md.permissions().mode())
+ .unwrap_or_else(|e| panic!("metadata failed: {e}")),
+ );
- mount(
- NONE,
- tempdir.path(),
- Some(b"tmpfs".as_ref()),
- MsFlags::MS_RDONLY,
- NONE,
- )
- .unwrap_or_else(|e| panic!("mount failed: {e}"));
+ assert!(
+ mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
+ "{:?} did not have execute permissions",
+ &test_path
+ );
+
+ // EACCES: Permission denied
+ assert_eq!(
+ EACCES,
+ Command::new(&test_path)
+ .status()
+ .unwrap_err()
+ .raw_os_error()
+ .unwrap()
+ );
- // EROFS: Read-only file system
- assert_eq!(
- EROFS,
- File::create(tempdir.path().join("test"))
- .unwrap_err()
- .raw_os_error()
- .unwrap()
- );
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
- umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
- }
+#[test]
+fn test_mount_bind() {
+ require_capability!("test_mount_bind", CAP_SYS_ADMIN);
+ let tempdir = tempfile::tempdir().unwrap();
+ let file_name = "test";
- pub fn test_mount_noexec_disallows_exec() {
- let tempdir = tempfile::tempdir().unwrap();
+ {
+ let mount_point = tempfile::tempdir().unwrap();
mount(
+ Some(tempdir.path()),
+ mount_point.path(),
NONE,
- tempdir.path(),
- Some(b"tmpfs".as_ref()),
- MsFlags::MS_NOEXEC,
+ MsFlags::MS_BIND,
NONE,
)
.unwrap_or_else(|e| panic!("mount failed: {e}"));
- let test_path = tempdir.path().join("test");
-
fs::OpenOptions::new()
.create(true)
.write(true)
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
- .open(&test_path)
+ .open(mount_point.path().join(file_name))
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
.unwrap_or_else(|e| panic!("write failed: {e}"));
- // Verify that we cannot execute despite a+x permissions being set.
- let mode = stat::Mode::from_bits_truncate(
- fs::metadata(&test_path)
- .map(|md| md.permissions().mode())
- .unwrap_or_else(|e| panic!("metadata failed: {e}")),
- );
-
- assert!(
- mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
- "{:?} did not have execute permissions",
- &test_path
- );
-
- // EACCES: Permission denied
- assert_eq!(
- EACCES,
- Command::new(&test_path)
- .status()
- .unwrap_err()
- .raw_os_error()
- .unwrap()
- );
-
- umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+ umount(mount_point.path())
+ .unwrap_or_else(|e| panic!("umount failed: {e}"));
}
- pub fn test_mount_bind() {
- let tempdir = tempfile::tempdir().unwrap();
- let file_name = "test";
-
- {
- let mount_point = tempfile::tempdir().unwrap();
-
- mount(
- Some(tempdir.path()),
- mount_point.path(),
- NONE,
- MsFlags::MS_BIND,
- NONE,
- )
- .unwrap_or_else(|e| panic!("mount failed: {e}"));
-
- fs::OpenOptions::new()
- .create(true)
- .write(true)
- .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
- .open(mount_point.path().join(file_name))
- .and_then(|mut f| f.write(SCRIPT_CONTENTS))
- .unwrap_or_else(|e| panic!("write failed: {e}"));
-
- umount(mount_point.path())
- .unwrap_or_else(|e| panic!("umount failed: {e}"));
- }
-
- // Verify the file written in the mount shows up in source directory, even
- // after unmounting.
-
- let mut buf = Vec::new();
- File::open(tempdir.path().join(file_name))
- .and_then(|mut f| f.read_to_end(&mut buf))
- .unwrap_or_else(|e| panic!("read failed: {e}"));
- assert_eq!(buf, SCRIPT_CONTENTS);
- }
+ // Verify the file written in the mount shows up in source directory, even
+ // after unmounting.
- pub fn setup_namespaces() {
- // Hold on to the uid in the parent namespace.
- let uid = getuid();
-
- unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| {
- let stderr = io::stderr();
- let mut handle = stderr.lock();
- writeln!(handle,
- "unshare failed: {e}. Are unprivileged user namespaces available?").unwrap();
- writeln!(handle, "mount is not being tested").unwrap();
- // Exit with success because not all systems support unprivileged user namespaces, and
- // that's not what we're testing for.
- process::exit(0);
- });
-
- // Map user as uid 1000.
- fs::OpenOptions::new()
- .write(true)
- .open("/proc/self/uid_map")
- .and_then(|mut f| f.write(format!("1000 {uid} 1\n").as_bytes()))
- .unwrap_or_else(|e| panic!("could not write uid map: {e}"));
- }
+ let mut buf = Vec::new();
+ File::open(tempdir.path().join(file_name))
+ .and_then(|mut f| f.read_to_end(&mut buf))
+ .unwrap_or_else(|e| panic!("read failed: {e}"));
+ assert_eq!(buf, SCRIPT_CONTENTS);
}
-
-// Test runner
-
-/// Mimic normal test output (hackishly).
-#[cfg(target_os = "linux")]
-macro_rules! run_tests {
- ( $($test_fn:ident),* ) => {{
- println!();
-
- $(
- print!("test test_mount::{} ... ", stringify!($test_fn));
- $test_fn();
- println!("ok");
- )*
-
- println!();
- }}
-}
-
-#[cfg(target_os = "linux")]
-fn main() {
- use test_mount::{
- setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec,
- test_mount_rdonly_disallows_write,
- test_mount_tmpfs_without_flags_allows_rwx,
- };
- skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351");
- setup_namespaces();
-
- run_tests!(
- test_mount_tmpfs_without_flags_allows_rwx,
- test_mount_rdonly_disallows_write,
- test_mount_noexec_disallows_exec,
- test_mount_bind
- );
-}
-
-#[cfg(not(target_os = "linux"))]
-fn main() {}