more quota code

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-07-15 16:19:39 +02:00
parent 6651043d52
commit 7470f14b85
5 changed files with 135 additions and 22 deletions

View File

@ -2,7 +2,7 @@
use std::convert::TryFrom;
use std::ffi::CString;
use std::os::raw::c_int;
use std::os::raw::{c_int, c_uint};
use std::os::unix::fs::FileExt;
use std::os::unix::io::RawFd;
use std::{io, mem};
@ -317,6 +317,36 @@ impl ProxyMessageBuffer {
.ok_or_else(|| Errno::EINVAL.into())
}
/// Read a user space pointer parameter.
#[inline]
pub fn arg_struct<T>(&self, arg: u32) -> Result<T, Error> {
let offset = self.arg(arg)?;
let mut data: T = unsafe { mem::zeroed() };
let slice = unsafe {
std::slice::from_raw_parts_mut(&mut data as *mut _ as *mut u8, mem::size_of::<T>())
};
let got = self.mem_fd().read_at(slice, offset)?;
if got != mem::size_of::<T>() {
Err(Errno::EINVAL.into())
} else {
Ok(data)
}
}
/// Read a user space pointer parameter.
#[inline]
pub fn mem_write_struct<T>(&self, offset: u64, data: &T) -> io::Result<()> {
let slice = unsafe {
std::slice::from_raw_parts(data as *const T as *const u8, mem::size_of::<T>())
};
let got = self.mem_fd().write_at(slice, offset)?;
if got != mem::size_of::<T>() {
Err(Errno::EINVAL.into())
} else {
Ok(())
}
}
/// Checked way to get a `mode_t` argument.
#[inline]
pub fn arg_mode_t(&self, arg: u32) -> Result<nix::sys::stat::mode_t, Error> {
@ -340,10 +370,16 @@ impl ProxyMessageBuffer {
}
}
/// Checked way to get a c_uint argument.
#[inline]
pub fn arg_uint(&self, arg: u32) -> Result<c_uint, Error> {
c_uint::try_from(self.arg(arg)?).map_err(|_| Errno::EINVAL.into())
}
/// Checked way to get a c_int argument.
#[inline]
pub fn arg_int(&self, arg: u32) -> Result<c_int, Error> {
c_int::try_from(self.arg(arg)?).map_err(|_| Errno::EINVAL.into())
self.arg_uint(arg).map(|u| u as c_int)
}
/// Checked way to get a `caddr_t` argument.

View File

@ -386,6 +386,7 @@ impl Capabilities {
#[must_use = "not using UserCaps may be a security issue"]
pub struct UserCaps<'a> {
pidfd: &'a PidFd,
apply_uids: bool,
euid: libc::uid_t,
egid: libc::gid_t,
fsuid: libc::uid_t,
@ -405,6 +406,7 @@ impl UserCaps<'_> {
Ok(UserCaps {
pidfd,
apply_uids: true,
euid: status.uids.euid,
egid: status.uids.egid,
fsuid: status.uids.fsuid,
@ -440,20 +442,31 @@ impl UserCaps<'_> {
fn apply_user_caps(&self) -> io::Result<()> {
use crate::capability::SecureBits;
unsafe {
libc::umask(self.umask);
if self.apply_uids {
unsafe {
libc::umask(self.umask);
}
let mut secbits = SecureBits::get_current()?;
secbits |= SecureBits::KEEP_CAPS | SecureBits::NO_SETUID_FIXUP;
secbits.apply()?;
c_try!(unsafe { libc::setegid(self.egid) });
c_try!(unsafe { libc::setfsgid(self.fsgid) });
c_try!(unsafe { libc::seteuid(self.euid) });
c_try!(unsafe { libc::setfsuid(self.fsuid) });
}
let mut secbits = SecureBits::get_current()?;
secbits |= SecureBits::KEEP_CAPS | SecureBits::NO_SETUID_FIXUP;
secbits.apply()?;
c_try!(unsafe { libc::setegid(self.egid) });
c_try!(unsafe { libc::setfsgid(self.fsgid) });
c_try!(unsafe { libc::seteuid(self.euid) });
c_try!(unsafe { libc::setfsuid(self.fsuid) });
self.capabilities.capset()?;
Ok(())
}
pub fn disable_uid_change(&mut self) {
self.apply_uids = false;
}
pub fn disable_cgroup_change(&mut self) {
self.cgroup_v1_devices = None;
self.cgroup_v2 = None;
}
pub fn apply(self, own_pidfd: &PidFd) -> io::Result<()> {
self.apply_cgroups()?;
self.pidfd.mount_namespace()?.setns()?;

View File

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

View File

@ -1,6 +1,6 @@
use std::ffi::CString;
use std::ptr;
use std::os::raw::c_int;
use std::{mem, ptr};
use std::os::raw::{c_int, c_uint};
use failure::Error;
use nix::errno::Errno;
@ -54,12 +54,75 @@ pub async fn quotactl(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error>
// let _id = msg.arg_int(2)?;
// let _addr = msg.arg_caddr_t(3)?;
match cmd >> SUBCMDSHIFT {
let subcmd = ((cmd as c_uint) >> SUBCMDSHIFT) as c_int;
match subcmd {
libc::Q_GETINFO => q_getinfo(msg, cmd, special).await,
libc::Q_GETFMT => q_getfmt(msg, cmd, special).await,
libc::Q_QUOTAON => q_quotaon(msg, cmd, special).await,
_ => Ok(Errno::ENOSYS.into()),
_ => {
eprintln!("Unhandled quota subcommand: {}", subcmd);
Ok(Errno::ENOSYS.into())
}
}
}
//#[allow(non_camel_case_names)]
#[repr(C)]
struct dqinfo {
dqi_bgrace: u64,
dqi_igrace: u64,
dqi_flags: u32,
dqi_valid: u32,
}
pub async fn q_getinfo(
msg: &ProxyMessageBuffer,
cmd: c_int,
special: Option<CString>,
) -> Result<SyscallStatus, Error> {
let id = msg.arg_int(2)?;
let addr = msg.arg_caddr_t(3)? as u64;
let mut caps = msg.pid_fd().user_caps()?;
Ok(forking_syscall(move || {
caps.apply(&PidFd::current()?)?;
let mut data: dqinfo = unsafe { mem::zeroed() };
let special = special.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null());
sc_libc_try!(unsafe {
libc::quotactl(cmd, special, id, &mut data as *mut dqinfo as *mut i8)
});
msg.mem_write_struct(addr, &data)?;
Ok(SyscallStatus::Ok(0))
})
.await?)
}
pub async fn q_getfmt(
msg: &ProxyMessageBuffer,
cmd: c_int,
special: Option<CString>,
) -> Result<SyscallStatus, Error> {
let id = msg.arg_int(2)?;
let addr = msg.arg_caddr_t(3)? as u64;
let mut caps = msg.pid_fd().user_caps()?;
Ok(forking_syscall(move || {
caps.apply(&PidFd::current()?)?;
let mut data: u32 = 0;
let special = special.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null());
sc_libc_try!(unsafe {
libc::quotactl(cmd, special, id, &mut data as *mut u32 as *mut i8)
});
msg.mem_write_struct(addr, &data)?;
Ok(SyscallStatus::Ok(0))
})
.await?)
}
pub async fn q_quotaon(
msg: &ProxyMessageBuffer,
cmd: c_int,
@ -67,13 +130,14 @@ pub async fn q_quotaon(
) -> Result<SyscallStatus, Error> {
let id = msg.arg_int(2)?;
let addr = msg.arg_caddr_t(3)? as usize;
let special = special.map(|c| c.as_ptr()).unwrap_or(ptr::null()) as usize;
let caps = msg.pid_fd().user_caps()?;
let mut caps = msg.pid_fd().user_caps()?;
Ok(forking_syscall(move || {
let this = PidFd::current()?;
caps.apply(&this)?;
let out = sc_libc_try!(unsafe { libc::quotactl(cmd, special as _, id, addr as _) });
caps.apply(&PidFd::current()?)?;
let special = special.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null());
let out = sc_libc_try!(unsafe { libc::quotactl(cmd, special, id, addr as _) });
Ok(SyscallStatus::Ok(out.into()))
})
.await?)

View File

@ -21,6 +21,7 @@ impl From<Errno> for SyscallStatus {
}
}
#[derive(Debug)]
pub enum Syscall {
Mknod,
MknodAt,