apparmor support

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-07-11 11:09:27 +02:00
parent f6a483ad15
commit 42f2575678
4 changed files with 69 additions and 2 deletions

42
src/apparmor.rs Normal file
View File

@ -0,0 +1,42 @@
//! AppArmor utility functions.
use std::ffi::{CStr, OsStr, OsString};
use std::io::{self, Write};
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use crate::pidfd::PidFd;
pub fn get_label(pidfd: &PidFd) -> io::Result<Option<OsString>> {
let mut out = match pidfd.read_file(unsafe {
CStr::from_bytes_with_nul_unchecked(b"attr/current\0")
}) {
Ok(out) => out,
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => return Ok(None),
Err(other) => return Err(other.into()),
};
if out.len() == 0 {
return Err(io::ErrorKind::UnexpectedEof.into());
}
if let Some(pos) = out.iter().position(|c| *c == b' ' || *c == b'\n') {
out.truncate(pos);
}
Ok(Some(OsString::from_vec(out)))
}
pub fn set_label(pidfd: &PidFd, label: &OsStr) -> io::Result<()> {
let mut file = pidfd.open_file(
unsafe { CStr::from_bytes_with_nul_unchecked(b"attr/current\0") },
libc::O_RDWR | libc::O_CLOEXEC,
0
)?;
let mut bytes = Vec::with_capacity(14 + label.len());
bytes.extend_from_slice(b"changeprofile ");
bytes.extend_from_slice(label.as_bytes());
file.write_all(&bytes)?;
Ok(())
}

View File

@ -6,6 +6,7 @@ use std::io;
use failure::{bail, format_err, Error};
use nix::sys::socket::SockAddr;
pub mod apparmor;
pub mod client;
pub mod fork;
pub mod lxcseccomp;

View File

@ -45,6 +45,14 @@ pub struct ProcStatus {
}
impl PidFd {
pub fn current() -> io::Result<Self> {
let fd = libc_try!(unsafe {
libc::open(b"/proc/self\0".as_ptr() as _, libc::O_DIRECTORY | libc::O_CLOEXEC)
});
Ok(Self(fd, unsafe { libc::getpid() }))
}
pub fn open(pid: pid_t) -> io::Result<Self> {
let path = CString::new(format!("/proc/{}", pid)).unwrap();
@ -260,6 +268,15 @@ impl PidFd {
Ok(cgroups)
}
pub fn read_file(&self, file: &CStr) -> io::Result<Vec<u8>> {
use io::Read;
let mut reader = self.open_file(file, libc::O_RDONLY | libc::O_CLOEXEC, 0)?;
let mut out = Vec::new();
reader.read_to_end(&mut out)?;
Ok(out)
}
pub fn user_caps(&self) -> Result<UserCaps, Error> {
UserCaps::new(self)
}
@ -380,12 +397,14 @@ pub struct UserCaps<'a> {
umask: libc::mode_t,
cgroup_v1_devices: Option<OsString>,
cgroup_v2: Option<OsString>,
apparmor_profile: Option<OsString>,
}
impl UserCaps<'_> {
pub fn new(pidfd: &PidFd) -> Result<UserCaps, Error> {
let status = pidfd.get_status()?;
let cgroups = pidfd.get_cgroups()?;
let apparmor_profile = crate::apparmor::get_label(pidfd)?;
Ok(UserCaps {
pidfd,
@ -397,6 +416,7 @@ impl UserCaps<'_> {
umask: status.umask,
cgroup_v1_devices: cgroups.get("devices").map(|s| s.to_owned()),
cgroup_v2: cgroups.v2().map(|s| s.to_owned()),
apparmor_profile,
})
}
@ -434,11 +454,14 @@ impl UserCaps<'_> {
Ok(())
}
pub fn apply(self) -> io::Result<()> {
pub fn apply(self, own_pidfd: &PidFd) -> io::Result<()> {
self.apply_cgroups()?;
self.pidfd.mount_namespace()?.setns()?;
self.pidfd.enter_chroot()?;
self.pidfd.enter_cwd()?;
if let Some(ref label) = self.apparmor_profile {
crate::apparmor::set_label(own_pidfd, label)?;
}
self.apply_user_caps()?;
Ok(())
}

View File

@ -67,7 +67,8 @@ async fn do_mknodat(
let caps = pidfd.user_caps()?;
Ok(forking_syscall(move || {
caps.apply()?;
let this = PidFd::current()?;
caps.apply(&this)?;
let out =
sc_libc_try!(unsafe { libc::mknodat(dirfd.as_raw_fd(), pathname.as_ptr(), mode, dev) });
Ok(SyscallStatus::Ok(out.into()))