Merge pull request #2661 from cgwalters/port-cap-std

This commit is contained in:
Jonathan Lebon 2022-06-28 16:56:09 -04:00 committed by GitHub
commit e527cdc582
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 36 deletions

View File

@ -11,6 +11,7 @@ name = "ostree-test"
path = "src/insttestmain.rs" path = "src/insttestmain.rs"
[dependencies] [dependencies]
cap-std-ext = "0.25"
clap = "2.32.0" clap = "2.32.0"
structopt = "0.3" structopt = "0.3"
serde = "1.0.111" serde = "1.0.111"
@ -33,8 +34,6 @@ procspawn = "0.8"
rand = "0.8" rand = "0.8"
strum = "0.18.0" strum = "0.18.0"
strum_macros = "0.18.0" strum_macros = "0.18.0"
openat = "0.1.19"
openat-ext = "0.1.4"
nix = "0.23.0" nix = "0.23.0"
# See discussion in https://github.com/coreos/rpm-ostree/pull/2569#issuecomment-780569188 # See discussion in https://github.com/coreos/rpm-ostree/pull/2569#issuecomment-780569188
rpmostree-client = { git = "https://github.com/coreos/rpm-ostree", tag = "v2021.3" } rpmostree-client = { git = "https://github.com/coreos/rpm-ostree", tag = "v2021.3" }

View File

@ -1,5 +1,8 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use openat_ext::{FileExt, OpenatDirExt}; use cap_std::fs::Dir;
use cap_std_ext::cap_std;
use cap_std_ext::dirext::*;
use cap_std_ext::rustix::fs::MetadataExt;
use rand::Rng; use rand::Rng;
use sh_inline::bash; use sh_inline::bash;
use std::fs::File; use std::fs::File;
@ -52,40 +55,36 @@ pub(crate) fn is_elf(f: &mut File) -> Result<bool> {
pub(crate) fn mutate_one_executable_to( pub(crate) fn mutate_one_executable_to(
f: &mut File, f: &mut File,
name: &std::ffi::OsStr, name: &std::ffi::OsStr,
dest: &openat::Dir, dest: &Dir,
) -> Result<()> { ) -> Result<()> {
let mut destf = dest let perms = f.metadata()?.permissions();
.write_file(name, 0o755) dest.atomic_replace_with(name, |w| {
.context("Failed to open for write")?; std::io::copy(f, w)?;
f.copy_to(&destf).context("Failed to copy")?; // ELF is OK with us just appending some junk
// ELF is OK with us just appending some junk let extra = rand::thread_rng()
let extra = rand::thread_rng() .sample_iter(&rand::distributions::Alphanumeric)
.sample_iter(&rand::distributions::Alphanumeric) .take(10)
.take(10) .collect::<Vec<u8>>();
.collect::<Vec<u8>>(); w.write_all(&extra).context("Failed to append extra data")?;
destf w.get_mut()
.write_all(&extra) .as_file_mut()
.context("Failed to append extra data")?; .set_permissions(cap_std::fs::Permissions::from_std(perms))?;
Ok(()) Ok::<_, anyhow::Error>(())
})
} }
/// Find ELF files in the srcdir, write new copies to dest (only percentage) /// Find ELF files in the srcdir, write new copies to dest (only percentage)
pub(crate) fn mutate_executables_to( pub(crate) fn mutate_executables_to(src: &Dir, dest: &Dir, percentage: u32) -> Result<u32> {
src: &openat::Dir,
dest: &openat::Dir,
percentage: u32,
) -> Result<u32> {
use nix::sys::stat::Mode as NixMode; use nix::sys::stat::Mode as NixMode;
assert!(percentage > 0 && percentage <= 100); assert!(percentage > 0 && percentage <= 100);
let mut mutated = 0; let mut mutated = 0;
for entry in src.list_dir(".")? { for entry in src.entries()? {
let entry = entry?; let entry = entry?;
if src.get_file_type(&entry)? != openat::SimpleType::File { if entry.file_type()? != cap_std::fs::FileType::file() {
continue; continue;
} }
let meta = src.metadata(entry.file_name())?; let meta = entry.metadata()?;
let st = meta.stat(); let mode = NixMode::from_bits_truncate(meta.mode());
let mode = NixMode::from_bits_truncate(st.st_mode);
// Must be executable // Must be executable
if !mode.intersects(NixMode::S_IXUSR | NixMode::S_IXGRP | NixMode::S_IXOTH) { if !mode.intersects(NixMode::S_IXUSR | NixMode::S_IXGRP | NixMode::S_IXOTH) {
continue; continue;
@ -95,17 +94,17 @@ pub(crate) fn mutate_executables_to(
continue; continue;
} }
// Greater than 1k in size // Greater than 1k in size
if st.st_size < 1024 { if meta.size() < 1024 {
continue; continue;
} }
let mut f = src.open_file(entry.file_name())?; let mut f = entry.open()?.into_std();
if !is_elf(&mut f)? { if !is_elf(&mut f)? {
continue; continue;
} }
if !rand::thread_rng().gen_ratio(percentage, 100) { if !rand::thread_rng().gen_ratio(percentage, 100) {
continue; continue;
} }
mutate_one_executable_to(&mut f, entry.file_name(), dest) mutate_one_executable_to(&mut f, &entry.file_name(), dest)
.with_context(|| format!("Failed updating {:?}", entry.file_name()))?; .with_context(|| format!("Failed updating {:?}", entry.file_name()))?;
mutated += 1; mutated += 1;
} }
@ -124,15 +123,14 @@ pub(crate) fn update_os_tree<P: AsRef<Path>>(
let tempdir = tempfile::tempdir_in(repo_path.join("tmp"))?; let tempdir = tempfile::tempdir_in(repo_path.join("tmp"))?;
let mut mutated = 0; let mut mutated = 0;
{ {
let tempdir = openat::Dir::open(tempdir.path())?; let tempdir = Dir::open_ambient_dir(tempdir.path(), cap_std::ambient_authority())?;
let binary_dirs = &["usr/bin", "usr/sbin", "usr/lib", "usr/lib64"]; let binary_dirs = &["usr/bin", "usr/sbin", "usr/lib", "usr/lib64"];
let rootfs = openat::Dir::open("/")?; let rootfs = Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
for v in binary_dirs { for v in binary_dirs {
let v = *v; let v = *v;
if let Some(src) = rootfs.sub_dir_optional(v)? { if let Some(src) = rootfs.open_dir_optional(v)? {
tempdir.ensure_dir("usr", 0o755)?; tempdir.create_dir_all(v)?;
tempdir.ensure_dir(v, 0o755)?; let dest = tempdir.open_dir(v)?;
let dest = tempdir.sub_dir(v)?;
mutated += mutate_executables_to(&src, &dest, percentage) mutated += mutate_executables_to(&src, &dest, percentage)
.with_context(|| format!("Replacing binaries in {v}"))?; .with_context(|| format!("Replacing binaries in {v}"))?;
} }