Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Safe extraction of symlinks with absolut path (/<whatever>) as link target #77

Open
NodyHub opened this issue Aug 1, 2024 · 0 comments

Comments

@NodyHub
Copy link
Collaborator

NodyHub commented Aug 1, 2024

Assuming the situation where we want extract an docker image. This image contains all files, directories and symlinks that an operating system would contain.

Taking the ubuntu:latest as an example. The extraction will fail, bc/ the directory stucture contains symlinks that points to the root filesystem:

~/tmp/docker-image% docker image save ubuntu:latest -o ubuntu-latest.tar
~/tmp/docker-image% goextract -v -c ubuntu-latest.tar ubuntu/
time=2024-08-01T11:24:25.779+02:00 level=INFO msg="start extraction" type=tar
time=2024-08-01T11:24:25.779+02:00 level=DEBUG msg=extract name=blobs/
time=2024-08-01T11:24:25.779+02:00 level=INFO msg="created destination directory" path=ubuntu/
time=2024-08-01T11:24:25.780+02:00 level=DEBUG msg=extract name=blobs/sha256/
time=2024-08-01T11:24:25.780+02:00 level=DEBUG msg=extract name=blobs/sha256/592f8a5be2100a50cd5f2122303f8b3e99e295a4b2f1776c38e2b3d4eb95937b
time=2024-08-01T11:24:25.780+02:00 level=DEBUG msg=extract name=blobs/sha256/aac3af10edc6612ad169ab9f9267dbe90e421f650a089ddc3f63546d9aacb3ed
time=2024-08-01T11:24:25.835+02:00 level=DEBUG msg=extract name=blobs/sha256/e32790107538738f33227bc08ef818d0915d8eac8eb72ab89a5fb131efa7e51b
time=2024-08-01T11:24:25.836+02:00 level=DEBUG msg=extract name=blobs/sha256/ffb64c9b7e8b9f1891f7a72609d4e691c4671dc4aa83084fc7b5774958d827de
time=2024-08-01T11:24:25.836+02:00 level=DEBUG msg=extract name=index.json
time=2024-08-01T11:24:25.836+02:00 level=DEBUG msg=extract name=manifest.json
time=2024-08-01T11:24:25.836+02:00 level=DEBUG msg=extract name=oci-layout
time=2024-08-01T11:24:25.836+02:00 level=DEBUG msg=extract name=repositories
~/tmp/docker-image% cd ubuntu/blobs/sha256
~/.../blobs/sha256% goextract -v -c --max-files=-1 aac3af10edc6612ad169ab9f9267dbe90e421f650a089ddc3f63546d9aacb3ed os-layer
time=2024-08-01T11:25:01.069+02:00 level=INFO msg="start extraction" type=tar
time=2024-08-01T11:25:01.069+02:00 level=DEBUG msg=extract name=bin
time=2024-08-01T11:25:01.070+02:00 level=INFO msg="created destination directory" path=os-layer
time=2024-08-01T11:25:01.070+02:00 level=DEBUG msg=extract name=boot/
time=2024-08-01T11:25:01.070+02:00 level=DEBUG msg=extract name=dev/
time=2024-08-01T11:25:01.070+02:00 level=DEBUG msg=extract name=etc/
time=2024-08-01T11:25:01.070+02:00 level=DEBUG msg=extract name=etc/.pwd.lock
time=2024-08-01T11:25:01.070+02:00 level=DEBUG msg=extract name=etc/alternatives/
time=2024-08-01T11:25:01.070+02:00 level=DEBUG msg=extract name=etc/alternatives/README
time=2024-08-01T11:25:01.071+02:00 level=DEBUG msg=extract name=etc/alternatives/awk
2024/08/01 11:25:01 error during extraction: failed to create safe symlink: symlink with absolute path as target: /usr/bin/mawk

Offering extraction of symlinks with absolut paths does not poses go-extract to be vulnerable to arbitrary file writes in the filesystem.

Assuming the situation that an archive contains following files:

% tar -ztvf malformed.tar
lrw-------  0 0      0           0  1 Jan  1970 root -> /
-rw-------  0 0      0          13  1 Jan  1970 root/escaped_file

The symlink root -> / would be extracted, but go-extract prevents arbitrary writes by inventing the option config.FollowSymlinks().

// check for symlink
isSymlink, err := isSymlink(t, checkDir)
if err != nil {
return fmt.Errorf("failed to check symlink: %w", err)
}
if isSymlink {
if config.FollowSymlinks() {
config.Logger().Warn("following symlink", "sub-dir", subDirs)
} else {
return fmt.Errorf("symlink in path")
}
}

The extraction of root/escaped_file would be blocked.

To ensure that go-extract will not be vulnerable to a link-write attack, the sanity check for file overwrite need to be adjusted. Before the call to target.CreateFile is performed, we need to check if the target exist, is a symlink (with fi, err := target.Lstat; err == nil && fi.Mode & os.ModeSymlink != 0) and if following symlinks (config.FollowSymlinks() == true) is enabled.

By offering this feature, we can still extract archives, but puts the burden on the consumer to ensure that they are aware of the possible consumption of symlinks that point to arbitrary locations in the file system

@NodyHub NodyHub changed the title Feature: Extraction of symlinks with absolut path as link destination Feature: Safe extraction of symlinks with absolut path (/<whatever>) as link target Aug 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant