From 08b0d02944eb94359726ac61af3c3ab84b53ee7d Mon Sep 17 00:00:00 2001 From: Sarah Brofeldt Date: Mon, 4 Jan 2021 19:39:21 +0100 Subject: [PATCH 1/2] dockerTools: Fix streamLayeredImage for symlinks When archiving `/nix/store/foo` and `foo` is itself a symlink, we must not traverse the symlink target, but archive the `foo` symlink itself --- pkgs/build-support/docker/stream_layered_image.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkgs/build-support/docker/stream_layered_image.py b/pkgs/build-support/docker/stream_layered_image.py index cbae0f723f92..e35bd0b0e8c0 100644 --- a/pkgs/build-support/docker/stream_layered_image.py +++ b/pkgs/build-support/docker/stream_layered_image.py @@ -83,7 +83,11 @@ def archive_paths_to(obj, paths, mtime): for path in paths: path = pathlib.Path(path) - files = itertools.chain([path], path.rglob("*")) + if path.is_symlink(): + files = [path] + else: + files = itertools.chain([path], path.rglob("*")) + for filename in sorted(files): ti = append_root(tar.gettarinfo(filename)) From ffe5ff6009017ebbc384e38b5a26e37556d60ecc Mon Sep 17 00:00:00 2001 From: Sarah Brofeldt Date: Mon, 4 Jan 2021 21:33:32 +0100 Subject: [PATCH 2/2] dockerTools: Test buildLayeredImage with symlinks This exercises layer creation in face of store path symlinks, ensuring they are not dereferenced, which can lead to broken layer tarballs --- nixos/tests/docker-tools.nix | 7 +++++++ pkgs/build-support/docker/examples.nix | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index 8402ba68b720..369ef94f9fad 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -247,5 +247,12 @@ import ./make-test-python.nix ({ pkgs, ... }: { ).strip() == "${if pkgs.system == "aarch64-linux" then "amd64" else "arm64"}" ) + + with subtest("buildLayeredImage doesn't dereference /nix/store symlink layers"): + docker.succeed( + "docker load --input='${examples.layeredStoreSymlink}'", + "docker run --rm ${examples.layeredStoreSymlink.imageName} bash -c 'test -L ${examples.layeredStoreSymlink.passthru.symlink}'", + "docker rmi ${examples.layeredStoreSymlink.imageName}", + ) ''; }) diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix index 85ddeb257405..86375a40baa0 100644 --- a/pkgs/build-support/docker/examples.nix +++ b/pkgs/build-support/docker/examples.nix @@ -416,4 +416,15 @@ rec { contents = crossPkgs.hello; }; + # layered image where a store path is itself a symlink + layeredStoreSymlink = + let + target = pkgs.writeTextDir "dir/target" "Content doesn't matter."; + symlink = pkgs.runCommandNoCC "symlink" {} "ln -s ${target} $out"; + in + pkgs.dockerTools.buildLayeredImage { + name = "layeredstoresymlink"; + tag = "latest"; + contents = [ pkgs.bash symlink ]; + } // { passthru = { inherit symlink; }; }; }