xattr: cleanup: don't use pxar types in the API

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-04-24 11:14:43 +02:00
parent 27a3decbfe
commit 9094186a57
2 changed files with 30 additions and 58 deletions

View File

@ -341,12 +341,14 @@ impl<R: Read> SequentialDecoder<R> {
fcaps: &Option<PxarFCaps>, fcaps: &Option<PxarFCaps>,
) -> Result<(), Error> { ) -> Result<(), Error> {
for xattr in xattrs { for xattr in xattrs {
if let Err(err) = xattr::fsetxattr(fd, &xattr) { let name = CString::new(&xattr.name[..])
.map_err(|_| format_err!("invalid xattr name with zeroes"))?;
if let Err(err) = xattr::fsetxattr(fd, &name, &xattr.value) {
bail!("fsetxattr failed with error: {}", err); bail!("fsetxattr failed with error: {}", err);
} }
} }
if let Some(fcaps) = fcaps { if let Some(fcaps) = fcaps {
if let Err(err) = xattr::fsetxattr_fcaps(fd, &fcaps) { if let Err(err) = xattr::fsetxattr_fcaps(fd, &fcaps.data) {
bail!("fsetxattr_fcaps failed with error: {}", err); bail!("fsetxattr_fcaps failed with error: {}", err);
} }
} }

View File

@ -5,9 +5,16 @@ use std::os::unix::io::RawFd;
use nix::errno::Errno; use nix::errno::Errno;
use proxmox::c_str;
use proxmox::tools::vec; use proxmox::tools::vec;
use crate::pxar::{PxarXAttr, PxarFCaps}; /// `"security.capability"` as a CStr to typos.
///
/// This cannot be `const` until `const_cstr_unchecked` is stable.
#[inline]
fn xattr_name_fcaps() -> &'static CStr {
c_str!("security.capability")
}
/// Result of `flistxattr`, allows iterating over the attributes as a list of `&CStr`s. /// Result of `flistxattr`, allows iterating over the attributes as a list of `&CStr`s.
/// ///
@ -110,38 +117,26 @@ pub fn fgetxattr(fd: RawFd, name: &CStr) -> Result<Vec<u8>, nix::errno::Errno> {
Ok(buffer) Ok(buffer)
} }
pub fn fsetxattr(fd: RawFd, xattr: &PxarXAttr) -> Result<(), nix::errno::Errno> { /// Set an extended attribute on a file descriptor.
let mut name = xattr.name.clone(); pub fn fsetxattr(fd: RawFd, name: &CStr, data: &[u8]) -> Result<(), nix::errno::Errno> {
name.push(b'\0');
let flags = 0 as libc::c_int; let flags = 0 as libc::c_int;
let result = unsafe { let result = unsafe {
libc::fsetxattr(fd, name.as_ptr() as *const libc::c_char, xattr.value.as_ptr() as *const libc::c_void, xattr.value.len(), flags) libc::fsetxattr(fd, name.as_ptr(), data.as_ptr() as *const libc::c_void, data.len(), flags)
}; };
if result < 0 { if result < 0 {
let err = Errno::last(); return Err(Errno::last());
return Err(err);
} }
Ok(()) Ok(())
} }
pub fn fsetxattr_fcaps(fd: RawFd, fcaps: &PxarFCaps) -> Result<(), nix::errno::Errno> { pub fn fsetxattr_fcaps(fd: RawFd, fcaps: &[u8]) -> Result<(), nix::errno::Errno> {
// TODO casync checks and removes capabilities if they are set // TODO casync checks and removes capabilities if they are set
let name = b"security.capability\0"; fsetxattr(fd, xattr_name_fcaps(), fcaps)
let flags = 0 as libc::c_int;
let result = unsafe {
libc::fsetxattr(fd, name.as_ptr() as *const libc::c_char, fcaps.data.as_ptr() as *const libc::c_void, fcaps.data.len(), flags)
};
if result < 0 {
let err = Errno::last();
return Err(err);
}
Ok(())
} }
pub fn is_security_capability(name: &CStr) -> bool { pub fn is_security_capability(name: &CStr) -> bool {
name.to_bytes() == b"security.capability" name.to_bytes() == xattr_name_fcaps().to_bytes()
} }
/// Check if the passed name buffer starts with a valid xattr namespace prefix /// Check if the passed name buffer starts with a valid xattr namespace prefix
@ -161,14 +156,16 @@ pub fn is_valid_xattr_name(c_name: &CStr) -> bool {
mod tests { mod tests {
use super::*; use super::*;
use std::ffi::CString;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use nix::errno::Errno; use nix::errno::Errno;
use proxmox::c_str;
#[test] #[test]
fn test_fsetxattr_fgetxattr() { fn test_fsetxattr_fgetxattr() {
use proxmox::c_str;
let path = "./tests/xattrs.txt"; let path = "./tests/xattrs.txt";
let file = OpenOptions::new() let file = OpenOptions::new()
.write(true) .write(true)
@ -178,45 +175,22 @@ mod tests {
let fd = file.as_raw_fd(); let fd = file.as_raw_fd();
let valid_user = PxarXAttr {
name: b"user.attribute0".to_vec(),
value: b"value0".to_vec(),
};
let valid_empty_value = PxarXAttr {
name: b"user.empty".to_vec(),
value: Vec::new(),
};
let invalid_trusted = PxarXAttr {
name: b"trusted.attribute0".to_vec(),
value: b"value0".to_vec(),
};
let invalid_name_prefix = PxarXAttr {
name: b"users.attribte0".to_vec(),
value: b"value".to_vec(),
};
let mut name = b"user.".to_vec(); let mut name = b"user.".to_vec();
for _ in 0..260 { for _ in 0..260 {
name.push(b'a'); name.push(b'a');
} }
let invalid_name_length = PxarXAttr { let invalid_name = CString::new(name).unwrap();
name,
value: b"err".to_vec(),
};
assert!(fsetxattr(fd, &valid_user).is_ok()); assert!(fsetxattr(fd, c_str!("user.attribute0"), b"value0").is_ok());
assert!(fsetxattr(fd, &valid_empty_value).is_ok()); assert!(fsetxattr(fd, c_str!("user.empty"), b"").is_ok());
if nix::unistd::Uid::current() != nix::unistd::ROOT { if nix::unistd::Uid::current() != nix::unistd::ROOT {
assert_eq!(fsetxattr(fd, &invalid_trusted), Err(Errno::EPERM)); assert_eq!(fsetxattr(fd, c_str!("trusted.attribute0"), b"value0"), Err(Errno::EPERM));
} }
assert_eq!(fsetxattr(fd, &invalid_name_prefix), Err(Errno::EOPNOTSUPP)); assert_eq!(fsetxattr(fd, c_str!("garbage.attribute0"), b"value"), Err(Errno::EOPNOTSUPP));
assert_eq!(fsetxattr(fd, &invalid_name_length), Err(Errno::ERANGE)); assert_eq!(fsetxattr(fd, &invalid_name, b"err"), Err(Errno::ERANGE));
let v0 = fgetxattr(fd, c_str!("user.attribute0")).unwrap(); let v0 = fgetxattr(fd, c_str!("user.attribute0")).unwrap();
let v1 = fgetxattr(fd, c_str!("user.empty")).unwrap(); let v1 = fgetxattr(fd, c_str!("user.empty")).unwrap();
@ -230,16 +204,12 @@ mod tests {
#[test] #[test]
fn test_is_valid_xattr_name() { fn test_is_valid_xattr_name() {
use std::ffi::CString;
use proxmox::c_str;
let too_long = CString::new(vec![b'a'; 265]).unwrap(); let too_long = CString::new(vec![b'a'; 265]).unwrap();
assert!(!is_valid_xattr_name(&too_long)); assert!(!is_valid_xattr_name(&too_long));
assert!(!is_valid_xattr_name(c_str!("system.attr"))); assert!(!is_valid_xattr_name(c_str!("system.attr")));
assert!(is_valid_xattr_name(c_str!("user.attr"))); assert!(is_valid_xattr_name(c_str!("user.attr")));
assert!(is_valid_xattr_name(c_str!("trusted.attr"))); assert!(is_valid_xattr_name(c_str!("trusted.attr")));
assert!(is_valid_xattr_name(c_str!("security.capability"))); assert!(is_valid_xattr_name(super::xattr_name_fcaps()));
} }
} }