Skip to content

Commit

Permalink
entry: convert hard link absolute paths to relative ones
Browse files Browse the repository at this point in the history
When unpacking a docker image, some hard links may be pointing to, say,
/bin/gunzip. Those were failing the validate_inside_dst() check,
preventing to unpack the image.

Fix this by re-using the same logic as we are already using for actual
files, removing the leading '/' from the link target path.

We do this only if the absolute link is not an ancestor of the target
dir as we want to support this use case according to the existing
absolute_hardlink() test.
  • Loading branch information
Guillaume Desmottes committed May 18, 2021
1 parent 326e990 commit 238fa14
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/entry.rs
Expand Up @@ -475,6 +475,23 @@ impl<'a> EntryFields<'a> {
// links though they're canonicalized to their existing path
// so we need to validate at this time.
Some(ref p) => {
let src = if src.is_absolute() {
// link points to an absolute path, assume it's relative to the target dir
// by removing the leading '/' as we already do for files, see unpack_in() comments.
let dest_canon = p.canonicalize()?;
if !src.starts_with(&dest_canon) {
// Skip root component, making the target relative to the target dir
let components = src.components().skip(1);
components.collect()
} else {
// the paths pointed by the link is an ancestor of the target dir so
// we can keep it as it.
src.to_path_buf()
}
} else {
src.to_path_buf()
};

let link_src = p.join(src);
self.validate_inside_dst(p, &link_src)?;
link_src
Expand Down
10 changes: 10 additions & 0 deletions tests/entry.rs
Expand Up @@ -62,12 +62,22 @@ fn absolute_hardlink() {
header.set_cksum();
t!(ar.append(&header, &[][..]));

let mut header = tar::Header::new_gnu();
header.set_size(0);
header.set_entry_type(tar::EntryType::Link);
t!(header.set_path("baz"));
// This absolute path on root will be converted when unpacking
t!(header.set_link_name("/foo"));
header.set_cksum();
t!(ar.append(&header, &[][..]));

let bytes = t!(ar.into_inner());
let mut ar = tar::Archive::new(&bytes[..]);

t!(ar.unpack(td.path()));
t!(td.path().join("foo").metadata());
t!(td.path().join("bar").metadata());
t!(td.path().join("baz").metadata());
}

#[test]
Expand Down

0 comments on commit 238fa14

Please sign in to comment.