forked from nix-rust/nix
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the mount tests into the "test" program
Now that we aren't using namespaces, they don't need their own program.
- Loading branch information
Showing
3 changed files
with
158 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,187 +1,183 @@ | ||
#[macro_use] | ||
mod common; | ||
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; | ||
|
||
#[cfg(target_os = "linux")] | ||
mod test_mount { | ||
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 libc::{EACCES, EROFS}; | ||
use nix::mount::{mount, umount, MsFlags}; | ||
use nix::sys::stat::{self, Mode}; | ||
|
||
use nix::mount::{mount, umount, MsFlags}; | ||
use nix::sys::stat::{self, Mode}; | ||
use crate::*; | ||
|
||
static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh | ||
static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh | ||
exit 23"; | ||
|
||
const EXPECTED_STATUS: i32 = 23; | ||
|
||
const NONE: Option<&'static [u8]> = None; | ||
|
||
#[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")) | ||
); | ||
|
||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); | ||
} | ||
|
||
#[test] | ||
fn test_mount_rdonly_disallows_write() { | ||
require_capability!("test_mount_rdonly_disallows_write", CAP_SYS_ADMIN); | ||
let tempdir = tempfile::tempdir().unwrap(); | ||
const EXPECTED_STATUS: i32 = 23; | ||
|
||
const NONE: Option<&'static [u8]> = None; | ||
|
||
#[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")) | ||
); | ||
|
||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); | ||
} | ||
|
||
mount( | ||
NONE, | ||
tempdir.path(), | ||
Some(b"tmpfs".as_ref()), | ||
MsFlags::MS_RDONLY, | ||
NONE, | ||
) | ||
.unwrap_or_else(|e| panic!("mount 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() | ||
); | ||
|
||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); | ||
} | ||
|
||
// EROFS: Read-only file system | ||
assert_eq!( | ||
EROFS, | ||
File::create(tempdir.path().join("test")) | ||
.unwrap_err() | ||
.raw_os_error() | ||
.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}")), | ||
); | ||
|
||
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(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"; | ||
|
||
#[test] | ||
fn test_mount_noexec_disallows_exec() { | ||
require_capability!("test_mount_noexec_disallows_exec", CAP_SYS_ADMIN); | ||
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}")); | ||
} | ||
|
||
#[test] | ||
fn test_mount_bind() { | ||
require_capability!("test_mount_bind", CAP_SYS_ADMIN); | ||
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. | ||
|
||
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); | ||
} |