Skip to content

Fix permission denied when building symlink derivation which points t…#9723

Closed
Artturin wants to merge 1 commit intoNixOS:masterfrom
Artturin:fixpermdeniedbind
Closed

Fix permission denied when building symlink derivation which points t…#9723
Artturin wants to merge 1 commit intoNixOS:masterfrom
Artturin:fixpermdeniedbind

Conversation

@Artturin
Copy link
Copy Markdown
Member

@Artturin Artturin commented Jan 8, 2024

…o a symlink out of the store

Fix issue #9579

error: getting attributes of path '/nix/store/ws9yl6ph10v79gx4p9ilhyxg214xf7i7-direct-symlink': Permission denied

let
  pkgs = import /home/artturin/nixgits/my-nixpkgs { };
  local = "/home/artturin/nixgits/my-nixpkgs";
in
rec {
  direct-symlink = pkgs.runCommand "direct-symlink" { } ''
    ln -vs ${local}/.version $out
  '';
  indirect-symlink = pkgs.runCommand "indirect-symlink" { } ''
    # Doesn't fail
    # ln -vs ${direct-symlink} $out/not-top
    # Fails
    ln -vs ${direct-symlink} $out
  '';
}

Motivation

Context

Priorities and Process

Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

copyPath(source, target);
return;
// either link or copy
// link doesn't work at all
Copy link
Copy Markdown
Member Author

@Artturin Artturin Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't work in the case of the example in the commit message
---------------------

Hmm

  indirect-symlink = pkgs.runCommand "indirect-symlink" { } ''
    cat ${direct-symlink}
    ln -vs ${direct-symlink} $out
  '';

> cat: /nix/store/k3isri0ks6l63rk54z4714dc67sd1cp3-direct-symlink: No such file or directory

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented out the auto deletion of the chroot dir

$ sudo ls -l /nix/store/q5glq907j6jn39aw99ncmcv5ijvnh5cs-indirect-symlink.drv.chroot/nix/store/55lg749likjz3ivq2varjcbj17xjam40-direct-symlink
lrwxrwxrwx root root 37 B Sat Jan 20 18:13:44 2024  /nix/store/q5glq907j6jn39aw99ncmcv5ijvnh5cs-indirect-symlink.drv.chroot/nix/store/55lg749likjz3ivq2varjcbj17xjam40-direct-symlink@ ⇒ /home/artturin/nixgits/my-nixpkgs/.version

I think what is happening is that the symlink to /home/... is being mounted/linked/copied to the chroot but the chroot doesn't have access to the result of the symlink

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked on 2.18.1 and there was still cat: /nix/store/55lg749likjz3ivq2varjcbj17xjam40-direct-symlink: No such file or directory, therefore it's not a regression caused by #8965

…o a symlink out of the store

Fix issue 9579 caused by PR 8965

`error: getting attributes of path '/nix/store/ws9yl6ph10v79gx4p9ilhyxg214xf7i7-direct-symlink': Permission denied`

```nix
let
  pkgs = import /home/artturin/nixgits/my-nixpkgs { };
  local = "/home/artturin/nixgits/my-nixpkgs";
in
rec {
  direct-symlink = pkgs.runCommand "direct-symlink" { } ''
    ln -vs ${local}/.version $out
  '';
  indirect-symlink = pkgs.runCommand "indirect-symlink" { } ''
    # Doesn't fail
    # ln -vs ${direct-symlink} $out/not-top
    # Fails
    ln -vs ${direct-symlink} $out
  '';
}
```

`cat ${direct-symlink}` still fails with `cat: /nix/store/55lg749likjz3ivq2varjcbj17xjam40-direct-symlink: No such file or directory` but that was happening with 2.18.1 before the PR 8965
@Artturin Artturin requested a review from Ericson2314 January 20, 2024 19:31
@Artturin Artturin marked this pull request as ready for review January 20, 2024 19:31
@Artturin Artturin requested a review from thufschmitt as a code owner January 20, 2024 19:31
@Ericson2314 Ericson2314 self-assigned this Jan 22, 2024
@Artturin
Copy link
Copy Markdown
Member Author

Artturin commented Jan 22, 2024

Tried to make a test but it works in nix build and nix develop both on master and with this PR (the test is being run)

commit 31554217b0bbf3392125f3c6d24d340d092deec3
Author: Artturin <Artturin@artturin.com>
Date:   2024-01-22 17:57:50 +0200

    Add test for out of store symlink
    
    Issue 9579
    
    "error: getting attributes of path '/nix/store/ws9yl6ph10v79gx4p9ilhyxg214xf7i7-direct-symlink': Permission denied"

diff --git a/tests/functional/local.mk b/tests/functional/local.mk
index 192e275e3..05bebae5d 100644
--- a/tests/functional/local.mk
+++ b/tests/functional/local.mk
@@ -110,6 +110,7 @@ nix_tests = \
   build.sh \
   build-delete.sh \
   output-normalization.sh \
+  out-of-store-symlink.sh \
   selfref-gc.sh \
   db-migration.sh \
   bash-profile.sh \
diff --git a/tests/functional/out-of-store-symlink.nix b/tests/functional/out-of-store-symlink.nix
new file mode 100644
index 000000000..0271b0d9e
--- /dev/null
+++ b/tests/functional/out-of-store-symlink.nix
@@ -0,0 +1,22 @@
+with import ./config.nix;
+
+let
+  direct-symlink = mkDerivation rec {
+    name = "direct-symlink";
+    buildCommand = ''
+      ln -vs ${(builtins.unsafeGetAttrPos "name" direct-symlink).file} $out
+    '';
+    meta.description = "direct-symlink";
+  };
+in
+mkDerivation rec {
+  name = "indirect-symlink";
+  buildCommand = ''
+    # Fails with:
+    # `cat: /nix/store/f2l57qr1lapn3ksyqwivi9848q3g95y4-direct-symlink: No such file or directory`
+    # Probably because the sandbox does not have access to the target of the out of store symlink.
+    # cat ${direct-symlink}
+    ln -vs ${direct-symlink} $out
+  '';
+  meta.description = "direct-symlink";
+}
diff --git a/tests/functional/out-of-store-symlink.sh b/tests/functional/out-of-store-symlink.sh
new file mode 100644
index 000000000..9887966d6
--- /dev/null
+++ b/tests/functional/out-of-store-symlink.sh
@@ -0,0 +1,5 @@
+source common.sh
+
+clearStore
+
+nix build --no-link -f ./out-of-store-symlink.nix

@Ericson2314
Copy link
Copy Markdown
Member

@Artturin I lost a comment, but this should be using lstat not stat. The easiest way to do that is actually to use PosixSourceAccessor and the methods on it, which will return nicer types (and also be a platform abstraction helper later ("Posix" should be removed from its name)).

@thufschmitt
Copy link
Copy Markdown
Member

Discussed during the Nix maintainers meeting on 2024-01-22.
Assigned to @Ericson2314

Details - @Ericson2314: Oops, I thought I left a review here, but now I don't see anything.
  • Needs lstat

Assigned to @Ericson2314

@nixos-discourse
Copy link
Copy Markdown

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2024-01-22-nix-team-meeting-minutes-117/38838/1

@Artturin
Copy link
Copy Markdown
Member Author

Artturin commented Jan 27, 2024

@Artturin I lost a comment, but this should be using lstat not stat. The easiest way to do that is actually to use PosixSourceAccessor and the methods on it, which will return nicer types (and also be a platform abstraction helper later ("Posix" should be removed from its name)).

If I switch to lstat then error: bind mount from '/nix/store/f2l57qr1lapn3ksyqwivi9848q3g95y4-direct-symlink' to '/nix/store/s1k8hwbh09wnicl9yfpk108vzncjxhl2-indirect-symlink.drv.chroot/nix/store/f2l57qr1lapn3ksyqwivi9848q3g95y4-direct-symlink' failed: Permission denied

and if using the accessor
if (accessor.maybeLstat(CanonPath(source)) == -1) {

Diagnostics:
1. clang: Invalid operands to binary expression ('std::optional<Stat>' and 'int') [typecheck_invalid_operands]

@Ericson2314
Copy link
Copy Markdown
Member

@Artturin sorry for missing this. maybeLstat has a different return type, that is why the -1 comparison doesn't work! It returns a std::optional instead so you probably want to do

auto [accessor, canonPath] = PosixSourceAccessor::createAtRoot(tmpFile);
if (auto statOpt = accessor.maybeLstat(canonPath)) {

dyfrgi added a commit to dyfrgi/dotfiles that referenced this pull request Mar 8, 2024
This is very anti-Nix, but duplicates my old dotfile setup. From here it
will be possible to incrementally move configuration into Home Manager.

Note that as of today, this requires using nix version 2.18, which can
be installed with `sudo nix-env -i nix-2.18.1`. It may also be necessary
to explicitly restart the nix-daemon service with `sudo systemctl
daemon-reload` and `sudo systemctl restart nix-daemon.service`. This is
needed due to NixOS/nix#9579, which unfortunately is also not fixed in
nix 2.20.5, which is the new version in nixpkgs. It looks like
NixOS/nix#9723 will fix this and will hopefully land before nix 2.21.
@carschandler
Copy link
Copy Markdown

Any progress on this?

@alois31
Copy link
Copy Markdown
Contributor

alois31 commented Apr 6, 2024

If I switch to lstat then error: bind mount from '/nix/store/f2l57qr1lapn3ksyqwivi9848q3g95y4-direct-symlink' to '/nix/store/s1k8hwbh09wnicl9yfpk108vzncjxhl2-indirect-symlink.drv.chroot/nix/store/f2l57qr1lapn3ksyqwivi9848q3g95y4-direct-symlink' failed: Permission denied

It is not possible to bind-mount symlinks using mount. S_ISLNK should be checked explicitly and the source symlink be copied in this case.

@Ericson2314
Copy link
Copy Markdown
Member

Closed because #10456 is now merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants