pxar: handle missing GROUP_OBJ ACL entries

Previously we did not store GROUP_OBJ ACL entries for
directories, this means that these were lost which may
potentially elevate group permissions if they were masked
before via ACLs, so we also show a warning.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2021-04-02 10:45:07 +02:00
parent 9f40e09d0a
commit 79e58a903e
3 changed files with 36 additions and 19 deletions

View File

@ -1,6 +1,6 @@
use std::ffi::{OsStr, OsString}; use std::ffi::OsString;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use nix::dir::Dir; use nix::dir::Dir;
@ -78,10 +78,6 @@ impl PxarDir {
pub fn metadata(&self) -> &Metadata { pub fn metadata(&self) -> &Metadata {
&self.metadata &self.metadata
} }
pub fn file_name(&self) -> &OsStr {
&self.file_name
}
} }
pub struct PxarDirStack { pub struct PxarDirStack {
@ -159,4 +155,8 @@ impl PxarDirStack {
.try_as_borrowed_fd() .try_as_borrowed_fd()
.ok_or_else(|| format_err!("lost track of directory file descriptors")) .ok_or_else(|| format_err!("lost track of directory file descriptors"))
} }
pub fn path(&self) -> &Path {
&self.path
}
} }

View File

@ -285,6 +285,8 @@ impl Extractor {
/// When done with a directory we can apply its metadata if it has been created. /// When done with a directory we can apply its metadata if it has been created.
pub fn leave_directory(&mut self) -> Result<(), Error> { pub fn leave_directory(&mut self) -> Result<(), Error> {
let path_info = self.dir_stack.path().to_owned();
let dir = self let dir = self
.dir_stack .dir_stack
.pop() .pop()
@ -296,7 +298,7 @@ impl Extractor {
self.feature_flags, self.feature_flags,
dir.metadata(), dir.metadata(),
fd.as_raw_fd(), fd.as_raw_fd(),
&CString::new(dir.file_name().as_bytes())?, &path_info,
&mut self.on_error, &mut self.on_error,
) )
.map_err(|err| format_err!("failed to apply directory metadata: {}", err))?; .map_err(|err| format_err!("failed to apply directory metadata: {}", err))?;
@ -329,6 +331,7 @@ impl Extractor {
metadata, metadata,
parent, parent,
file_name, file_name,
self.dir_stack.path(),
&mut self.on_error, &mut self.on_error,
) )
} }
@ -382,6 +385,7 @@ impl Extractor {
metadata, metadata,
parent, parent,
file_name, file_name,
self.dir_stack.path(),
&mut self.on_error, &mut self.on_error,
) )
} }
@ -437,7 +441,7 @@ impl Extractor {
self.feature_flags, self.feature_flags,
metadata, metadata,
file.as_raw_fd(), file.as_raw_fd(),
file_name, self.dir_stack.path(),
&mut self.on_error, &mut self.on_error,
) )
} }
@ -494,7 +498,7 @@ impl Extractor {
self.feature_flags, self.feature_flags,
metadata, metadata,
file.as_raw_fd(), file.as_raw_fd(),
file_name, self.dir_stack.path(),
&mut self.on_error, &mut self.on_error,
) )
} }

View File

@ -1,5 +1,6 @@
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::Path;
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use nix::errno::Errno; use nix::errno::Errno;
@ -62,6 +63,7 @@ pub fn apply_at(
metadata: &Metadata, metadata: &Metadata,
parent: RawFd, parent: RawFd,
file_name: &CStr, file_name: &CStr,
path_info: &Path,
on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send), on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
) -> Result<(), Error> { ) -> Result<(), Error> {
let fd = proxmox::tools::fd::Fd::openat( let fd = proxmox::tools::fd::Fd::openat(
@ -71,7 +73,7 @@ pub fn apply_at(
Mode::empty(), Mode::empty(),
)?; )?;
apply(flags, metadata, fd.as_raw_fd(), file_name, on_error) apply(flags, metadata, fd.as_raw_fd(), path_info, on_error)
} }
pub fn apply_initial_flags( pub fn apply_initial_flags(
@ -94,7 +96,7 @@ pub fn apply(
flags: Flags, flags: Flags,
metadata: &Metadata, metadata: &Metadata,
fd: RawFd, fd: RawFd,
file_name: &CStr, path_info: &Path,
on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send), on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
) -> Result<(), Error> { ) -> Result<(), Error> {
let c_proc_path = CString::new(format!("/proc/self/fd/{}", fd)).unwrap(); let c_proc_path = CString::new(format!("/proc/self/fd/{}", fd)).unwrap();
@ -116,7 +118,7 @@ pub fn apply(
apply_xattrs(flags, c_proc_path.as_ptr(), metadata, &mut skip_xattrs) apply_xattrs(flags, c_proc_path.as_ptr(), metadata, &mut skip_xattrs)
.or_else(&mut *on_error)?; .or_else(&mut *on_error)?;
add_fcaps(flags, c_proc_path.as_ptr(), metadata, &mut skip_xattrs).or_else(&mut *on_error)?; add_fcaps(flags, c_proc_path.as_ptr(), metadata, &mut skip_xattrs).or_else(&mut *on_error)?;
apply_acls(flags, &c_proc_path, metadata) apply_acls(flags, &c_proc_path, metadata, path_info)
.map_err(|err| format_err!("failed to apply acls: {}", err)) .map_err(|err| format_err!("failed to apply acls: {}", err))
.or_else(&mut *on_error)?; .or_else(&mut *on_error)?;
apply_quota_project_id(flags, fd, metadata).or_else(&mut *on_error)?; apply_quota_project_id(flags, fd, metadata).or_else(&mut *on_error)?;
@ -147,7 +149,7 @@ pub fn apply(
Err(err) => { Err(err) => {
on_error(format_err!( on_error(format_err!(
"failed to restore mtime attribute on {:?}: {}", "failed to restore mtime attribute on {:?}: {}",
file_name, path_info,
err err
))?; ))?;
} }
@ -227,7 +229,12 @@ fn apply_xattrs(
Ok(()) Ok(())
} }
fn apply_acls(flags: Flags, c_proc_path: &CStr, metadata: &Metadata) -> Result<(), Error> { fn apply_acls(
flags: Flags,
c_proc_path: &CStr,
metadata: &Metadata,
path_info: &Path,
) -> Result<(), Error> {
if !flags.contains(Flags::WITH_ACL) || metadata.acl.is_empty() { if !flags.contains(Flags::WITH_ACL) || metadata.acl.is_empty() {
return Ok(()); return Ok(());
} }
@ -257,11 +264,17 @@ fn apply_acls(flags: Flags, c_proc_path: &CStr, metadata: &Metadata) -> Result<(
acl.add_entry_full(acl::ACL_GROUP_OBJ, None, group_obj.permissions.0)?; acl.add_entry_full(acl::ACL_GROUP_OBJ, None, group_obj.permissions.0)?;
} }
None => { None => {
acl.add_entry_full( let mode = acl::mode_group_to_acl_permissions(metadata.stat.mode);
acl::ACL_GROUP_OBJ,
None, acl.add_entry_full(acl::ACL_GROUP_OBJ, None, mode)?;
acl::mode_group_to_acl_permissions(metadata.stat.mode),
)?; if !metadata.acl.users.is_empty() || !metadata.acl.groups.is_empty() {
eprintln!(
"Warning: {:?}: Missing GROUP_OBJ entry in ACL, resetting to value of MASK",
path_info,
);
acl.add_entry_full(acl::ACL_MASK, None, mode)?;
}
} }
} }