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

Correctly mount file mount points in Overlay2Filesystem #858

Merged
merged 8 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions dissect/target/filesystems/overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,25 @@

# append and mount every layer
for dest, layer in layers:
if layer.is_file() and dest in ["/etc/hosts", "/etc/hostname", "/etc/resolv.conf"]:
# we could have collected a layer reference that actually does not exist on the host
if not layer.exists():
log.warning(

Check warning on line 94 in dissect/target/filesystems/overlay.py

View check run for this annotation

Codecov / codecov/patch

dissect/target/filesystems/overlay.py#L94

Added line #L94 was not covered by tests
"Can not mount layer %s for container %s as it does not exist on the host", layer, path.name
)
continue

Check warning on line 97 in dissect/target/filesystems/overlay.py

View check run for this annotation

Codecov / codecov/patch

dissect/target/filesystems/overlay.py#L97

Added line #L97 was not covered by tests

# mount points can be files
if layer.is_file():
layer_fs = VirtualFilesystem()
layer_fs.map_file_fh("/etc/" + layer.name, layer.open("rb"))
dest = dest.split("/")[0]
layer_fs.map_file_fh(dest, layer.open("rb"))

# regular overlay2 layers are directories
# mount points can be directories too
else:
layer_fs = DirectoryFilesystem(layer)

self.append_layer().mount(dest, layer_fs)
log.info("Adding layer %s to destination %s", layer, dest)
self.append_layer().mount("/" if layer.is_file() else dest, layer_fs)

def __repr__(self) -> str:
return f"<{self.__class__.__name__} {self.base_path}>"
4 changes: 2 additions & 2 deletions tests/_data/plugins/apps/container/docker/docker.tgz
Git LFS file not shown
29 changes: 24 additions & 5 deletions tests/filesystems/test_overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@


def test_overlay_filesystem_docker_container(target_linux_docker: Target) -> None:
mount_path = list(target_linux_docker.fs.path("/var/lib/docker/image/overlay2/layerdb/mounts/").iterdir())[0]
mount_path = target_linux_docker.fs.path(
"/var/lib/docker/image/overlay2/layerdb/mounts/f988f88e221d97930a665712cf16ab520f7e2c5af395660c145df93aebedf071" # noqa: E501
)
fs = Overlay2Filesystem(mount_path)

assert fs.__type__ == "overlay2"
assert len(fs.layers) == 4
assert len(fs.layers) == 9

assert sorted([str(p) for p in fs.path("/").iterdir()]) == sorted(
[
Expand All @@ -29,13 +31,14 @@ def test_overlay_filesystem_docker_container(target_linux_docker: Target) -> Non
"/usr",
"/srv",
"/.dockerenv",
"/container",
]
)

assert [str(p) for p in fs.path("/root").iterdir()] == [
"/root/secret.txt",
"/root/file.txt",
assert sorted([str(p) for p in fs.path("/root").iterdir()]) == [
"/root/.ash_history",
"/root/file.txt",
"/root/secret.txt",
]

assert fs.path("/root/secret.txt").open().read() == b"this is a secret!\n"
Expand All @@ -47,3 +50,19 @@ def test_overlay_filesystem_docker_container(target_linux_docker: Target) -> Non
assert fs.path("/bin/sh").readlink() == fs.path("/bin/busybox")
assert fs.path("/etc/ssl/cert.pem").resolve() == fs.path("/etc/ssl/certs/ca-certificates.crt")
assert fs.path("/usr/lib/libcrypto.so.3").resolve() == fs.path("/lib/libcrypto.so.3")

# test if standard mounts were correctly added
assert fs.path("/etc/hostname").exists()
assert fs.path("/etc/hostname").is_file()
assert fs.path("/etc/hostname").read_text() == "f988f88e221d\n"
assert fs.path("/etc/hosts").exists()
assert fs.path("/etc/resolv.conf").exists()

# test if custom mounts were correctly added
assert fs.path("/container/file.txt").exists()
assert fs.path("/container/file.txt").is_file()
assert fs.path("/container/file.txt").read_text() == "this is a mounted file!\n"
assert fs.path("/container/folder").exists()
assert fs.path("/container/folder").is_dir()
assert fs.path("/container/folder/some-file.txt").exists()
assert fs.path("/container/folder/some-file.txt").is_file()
12 changes: 7 additions & 5 deletions tests/plugins/child/test_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

def test_plugins_child_docker(target_linux_docker: Target) -> None:
target_linux_docker.add_plugin(DockerChildTargetPlugin)
children = list(target_linux_docker.list_children())
children = sorted(list(target_linux_docker.list_children()), key=lambda r: r.path)

assert len(children) == 3
assert children[0].type == "docker"
assert (
children[0].path
== "/var/lib/docker/image/overlay2/layerdb/mounts/f988f88e221d97930a665712cf16ab520f7e2c5af395660c145df93aebedf071" # noqa: E501
)

assert [c.path for c in children] == [
"/var/lib/docker/image/overlay2/layerdb/mounts/01b646bc043eb4ad72f3a64b4ffd9be2cbeb399e0a07497d749d724460ccad3a", # noqa: E501
"/var/lib/docker/image/overlay2/layerdb/mounts/589135d12011921ac6ce69753569da5f206f4bc792a9133727ddae860997ee66", # noqa: E501
"/var/lib/docker/image/overlay2/layerdb/mounts/f988f88e221d97930a665712cf16ab520f7e2c5af395660c145df93aebedf071", # noqa: E501
]