src/pxar/sequential_decoder.rs: impl functionality to restore xattrs/fcaps from pxar achives
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
parent
b303057a19
commit
596182056b
@ -20,6 +20,7 @@ use nix::fcntl::OFlag;
|
||||
use nix::sys::stat::Mode;
|
||||
use nix::errno::Errno;
|
||||
use nix::NixPath;
|
||||
use crate::tools::xattr;
|
||||
|
||||
// This one need Read, but works without Seek
|
||||
pub struct SequentialDecoder<'a, R: Read> {
|
||||
@ -128,15 +129,71 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
fn restore_attributes(&mut self, _entry: &CaFormatEntry) -> Result<CaFormatHeader, Error> {
|
||||
fn read_xattr(&mut self, size: usize) -> Result<CaFormatXAttr, Error> {
|
||||
let mut buffer = vec![0u8; size];
|
||||
self.reader.read_exact(&mut buffer)?;
|
||||
|
||||
match buffer.iter().position(|c| *c == '\0' as u8) {
|
||||
Some(pos) => {
|
||||
// pos needs to be within the first 256 bytes in order to
|
||||
// terminate a valid xattr name
|
||||
if pos > 255 {
|
||||
bail!("Invalid zero termination for xattr name.");
|
||||
}
|
||||
if !xattr::name_store(&buffer[0..pos]) || xattr::security_capability(&buffer[0..pos]) {
|
||||
bail!("Invalid name for xattr - {}.", String::from_utf8_lossy(&buffer[0..pos]));
|
||||
}
|
||||
let name = buffer[0..pos].to_vec();
|
||||
let value = buffer[pos + 1..size].to_vec();
|
||||
return Ok(CaFormatXAttr {
|
||||
name: name,
|
||||
value: value,
|
||||
});
|
||||
},
|
||||
_ => bail!("Incorrect zero termination in xattr."),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_fcaps(&mut self, size: usize) -> Result<CaFormatFCaps, Error> {
|
||||
let mut buffer = vec![0u8; size];
|
||||
self.reader.read_exact(&mut buffer)?;
|
||||
|
||||
Ok(CaFormatFCaps { data: buffer })
|
||||
}
|
||||
|
||||
fn restore_attributes(&mut self, entry: &CaFormatEntry, fd: RawFd) -> Result<CaFormatHeader, Error> {
|
||||
let mut xattrs: Vec<CaFormatXAttr> = Vec::new();
|
||||
let mut fcaps: Option<CaFormatFCaps> = None;
|
||||
|
||||
let mut head: CaFormatHeader = self.read_item()?;
|
||||
let mut size = (head.size - HEADER_SIZE) as usize;
|
||||
loop {
|
||||
let head: CaFormatHeader = self.read_item()?;
|
||||
match head.htype {
|
||||
// fimxe: impl ...
|
||||
_ => return Ok(head),
|
||||
CA_FORMAT_XATTR => xattrs.push(self.read_xattr(size)?),
|
||||
CA_FORMAT_FCAPS => fcaps = Some(self.read_fcaps(size)?),
|
||||
_ => break,
|
||||
}
|
||||
head = self.read_item()?;
|
||||
size = (head.size - HEADER_SIZE) as usize;
|
||||
}
|
||||
self.restore_xattrs_fcaps_fd(fd, xattrs, fcaps)?;
|
||||
|
||||
Ok(head)
|
||||
}
|
||||
|
||||
fn restore_xattrs_fcaps_fd(&mut self, fd: RawFd, xattrs: Vec<CaFormatXAttr>, fcaps: Option<CaFormatFCaps>) -> Result<(), Error> {
|
||||
for xattr in xattrs {
|
||||
if let Err(err) = xattr::fsetxattr(fd, xattr) {
|
||||
bail!("fsetxattr failed with error: {}", err);
|
||||
}
|
||||
}
|
||||
if let Some(fcaps) = fcaps {
|
||||
if let Err(err) = xattr::fsetxattr_fcaps(fd, fcaps) {
|
||||
bail!("fsetxattr_fcaps failed with error: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn restore_mode(&mut self, entry: &CaFormatEntry, fd: RawFd) -> Result<(), Error> {
|
||||
@ -319,7 +376,12 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
};
|
||||
}
|
||||
|
||||
let mut head = self.restore_attributes(&entry)?;
|
||||
self.restore_ugid(&entry, dir.as_raw_fd())?;
|
||||
// fcaps have to be restored after restore_ugid as chown clears security.capability xattr, see CVE-2015-1350
|
||||
let mut head = match self.restore_attributes(&entry, dir.as_raw_fd()) {
|
||||
Ok(head) => head,
|
||||
Err(err) => bail!("Restoring of directory attributes failed - {}", err),
|
||||
};
|
||||
|
||||
while head.htype == CA_FORMAT_FILENAME {
|
||||
let name = self.read_filename(head.size)?;
|
||||
@ -341,7 +403,6 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
|
||||
self.restore_mode(&entry, dir.as_raw_fd())?;
|
||||
self.restore_mtime(&entry, dir.as_raw_fd())?;
|
||||
self.restore_ugid(&entry, dir.as_raw_fd())?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@ -429,7 +490,12 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
Err(err) => bail!("open file {:?} failed - {}", full_path, err),
|
||||
};
|
||||
|
||||
let head = self.restore_attributes(&entry)?;
|
||||
self.restore_ugid(&entry, file.as_raw_fd())?;
|
||||
// fcaps have to be restored after restore_ugid as chown clears security.capability xattr, see CVE-2015-1350
|
||||
let head = match self.restore_attributes(&entry, file.as_raw_fd()) {
|
||||
Ok(head) => head,
|
||||
Err(err) => bail!("Restoring of file attributes failed - {}", err),
|
||||
};
|
||||
|
||||
if head.htype != CA_FORMAT_PAYLOAD {
|
||||
bail!("got unknown header type for file entry {:016x}", head.htype);
|
||||
@ -453,7 +519,6 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
|
||||
self.restore_mode(&entry, file.as_raw_fd())?;
|
||||
self.restore_mtime(&entry, file.as_raw_fd())?;
|
||||
self.restore_ugid(&entry, file.as_raw_fd())?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@ -513,7 +578,21 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
print_head(&head);
|
||||
}
|
||||
match head.htype {
|
||||
|
||||
//TODO verify the correct order of occurrence
|
||||
CA_FORMAT_XATTR => {
|
||||
let size = (head.size - HEADER_SIZE) as usize;
|
||||
let xattr: CaFormatXAttr = self.read_xattr(size)?;
|
||||
if verbose {
|
||||
println!("XAttr: {:?}: {:?}", String::from_utf8_lossy(&xattr.name), String::from_utf8_lossy(&xattr.value));
|
||||
}
|
||||
}
|
||||
CA_FORMAT_FCAPS => {
|
||||
let size = (head.size - HEADER_SIZE) as usize;
|
||||
let fcaps: CaFormatFCaps = self.read_fcaps(size)?;
|
||||
if verbose {
|
||||
println!("FCaps: {:?}", fcaps);
|
||||
}
|
||||
}
|
||||
CA_FORMAT_FILENAME => {
|
||||
let name = self.read_filename(head.size)?;
|
||||
if verbose { println!("Name: {:?}", name); }
|
||||
@ -540,34 +619,53 @@ impl <'a, R: Read> SequentialDecoder<'a, R> {
|
||||
} else if (ifmt == libc::S_IFBLK) || (ifmt == libc::S_IFCHR) ||
|
||||
(ifmt == libc::S_IFLNK) || (ifmt == libc::S_IFREG)
|
||||
{
|
||||
let head: CaFormatHeader = self.read_item()?;
|
||||
if verbose {
|
||||
print_head(&head);
|
||||
}
|
||||
loop {
|
||||
let head: CaFormatHeader = self.read_item()?;
|
||||
if verbose {
|
||||
print_head(&head);
|
||||
}
|
||||
|
||||
match head.htype {
|
||||
match head.htype {
|
||||
|
||||
CA_FORMAT_SYMLINK => {
|
||||
let target = self.read_link(head.size)?;
|
||||
if verbose {
|
||||
println!("Symlink: {:?}", target);
|
||||
CA_FORMAT_SYMLINK => {
|
||||
let target = self.read_link(head.size)?;
|
||||
if verbose {
|
||||
println!("Symlink: {:?}", target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CA_FORMAT_DEVICE => {
|
||||
let device: CaFormatDevice = self.read_item()?;
|
||||
if verbose {
|
||||
println!("Device: {}, {}", device.major, device.minor);
|
||||
CA_FORMAT_DEVICE => {
|
||||
let device: CaFormatDevice = self.read_item()?;
|
||||
if verbose {
|
||||
println!("Device: {}, {}", device.major, device.minor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CA_FORMAT_PAYLOAD => {
|
||||
let payload_size = (head.size - HEADER_SIZE) as usize;
|
||||
if verbose {
|
||||
println!("Payload: {}", payload_size);
|
||||
CA_FORMAT_XATTR => {
|
||||
let size = (head.size - HEADER_SIZE) as usize;
|
||||
let xattr: CaFormatXAttr = self.read_xattr(size)?;
|
||||
if verbose {
|
||||
println!("XAttr: {:?}: {:?}", String::from_utf8_lossy(&xattr.name), String::from_utf8_lossy(&xattr.value));
|
||||
}
|
||||
}
|
||||
CA_FORMAT_FCAPS => {
|
||||
let size = (head.size - HEADER_SIZE) as usize;
|
||||
let fcaps: CaFormatFCaps = self.read_fcaps(size)?;
|
||||
if verbose {
|
||||
println!("FCaps: {:?}", fcaps);
|
||||
}
|
||||
}
|
||||
CA_FORMAT_PAYLOAD => {
|
||||
let payload_size = (head.size - HEADER_SIZE) as usize;
|
||||
if verbose {
|
||||
println!("Payload: {}", payload_size);
|
||||
}
|
||||
self.skip_bytes(payload_size)?;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
panic!("got unexpected header type inside non-directory");
|
||||
}
|
||||
self.skip_bytes(payload_size)?;
|
||||
}
|
||||
_ => {
|
||||
panic!("got unexpected header type inside non-directory");
|
||||
}
|
||||
}
|
||||
} else if ifmt == libc::S_IFIFO {
|
||||
|
Loading…
Reference in New Issue
Block a user