use std::os::unix::io::RawFd;
use std::path::{Path, PathBuf};
use crate::seccomp::notif::NotifAction;
use crate::sys::structs::SeccompNotif;
pub(crate) fn combine_bundle(original: &[u8], ca_pem: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(original.len() + ca_pem.len() + 1);
out.extend_from_slice(original);
if !original.is_empty() && !original.ends_with(b"\n") {
out.push(b'\n');
}
out.extend_from_slice(ca_pem);
out
}
pub(crate) fn path_matches(resolved: &Path, inject_paths: &[PathBuf]) -> bool {
inject_paths.iter().any(|p| p == resolved)
}
pub(crate) fn handle_ca_inject_open(
notif: &SeccompNotif,
inject_paths: &[PathBuf],
ca_pem: &[u8],
notif_fd: RawFd,
) -> Option<NotifAction> {
let resolved = crate::procfs::resolve_open_target(notif, notif_fd)?;
if !path_matches(&resolved, inject_paths) {
return None;
}
let child_view = format!("/proc/{}/root{}", notif.pid, resolved.to_str()?);
let original = std::fs::read(&child_view).ok()?;
let combined = combine_bundle(&original, ca_pem);
Some(NotifAction::inject_bytes(&combined))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn combine_inserts_newline_when_missing() {
let out = combine_bundle(b"AAA", b"BBB\n");
assert_eq!(out, b"AAA\nBBB\n");
}
#[test]
fn combine_no_extra_newline_when_present() {
let out = combine_bundle(b"AAA\n", b"BBB\n");
assert_eq!(out, b"AAA\nBBB\n");
}
#[test]
fn combine_empty_original() {
let out = combine_bundle(b"", b"BBB\n");
assert_eq!(out, b"BBB\n");
}
#[test]
fn path_matches_exact_only() {
let paths = vec![PathBuf::from("/etc/ssl/certs/ca-certificates.crt")];
assert!(path_matches(Path::new("/etc/ssl/certs/ca-certificates.crt"), &paths));
assert!(!path_matches(Path::new("/etc/ssl/certs/other.crt"), &paths));
}
}