nix icon indicating copy to clipboard operation
nix copied to clipboard

Directory permissions not always canonicalized

Open roberth opened this issue 8 months ago • 4 comments

Looks like permissions are set in canonicaliseTimestampAndPermissions and 0444 is not updated to 0555 for directories.

E.g. 0554 is canonicalized, but not 0444.

$ nix build -L --impure --expr 'with import ./. { };
let
  script = "mkdir -p $out/foo && touch $out/foo/bar && chmod o-x $out/foo";
  badDir = runCommand "bad-directory-permissions" { } script;
in runCommand "cat-file" { inherit badDir; } "stat $badDir/foo && cat $badDir/foo/bar && touch $out"'
cat-file>   File: /nix/store/42fsalzfn075vhhxbmrvbma37v3wf5wz-bad-directory-permissions/foo
cat-file>   Size: 6             Blocks: 0          IO Block: 4096   directory
cat-file> Device: 0,33  Inode: 242782051   Links: 1
cat-file> Access: (0555/dr-xr-xr-x)  Uid: (65534/  nobody)   Gid: (65534/ nogroup)
cat-file> Access: 2025-03-27 17:18:14.000000000 +0000
cat-file> Modify: 1970-01-01 00:00:01.000000000 +0000
cat-file> Change: 2025-03-27 17:18:14.682332844 +0000
cat-file>  Birth: 2025-03-27 17:18:14.682332844 +0000

Perhaps

-if (mode != 0444 && mode != 0555) {
+bool is_dir = S_ISDIR(st.st_mode);
+if ((mode != 0444 || is_dir) && mode != 0555) {
     mode = (st.st_mode & S_IFMT)
          | 0444
-         | (st.st_mode & S_IXUSR ? 0111 : 0);
+         | (st.st_mode & S_IXUSR || is_dir ? 0111 : 0);
     if (chmod(path.c_str(), mode) == -1)
         throw SysError("changing mode of '%1%' to %2$o", path, mode);
     }

Originally posted by @tie in https://github.com/NixOS/nixpkgs/pull/393381#discussion_r2017216579

roberth avatar Mar 28 '25 17:03 roberth

Does this have any implications for backwards compatibility (that we care about...)?

cole-h avatar Mar 31 '25 15:03 cole-h

I don’t think so, directories do not have permissions in NAR format (so are always 0555 after deserialization), and store paths with wrong permissions can’t be copied to another host.

$ nix build --print-out-paths --impure --expr 'with import ./. { }; runCommand "bad-directory-permissions" { } "mkdir -p $out/foo && touch $out/foo/bar && chmod -x $out/foo"' 
/nix/store/99swczlgqpmkqvsd8vzzlqygxw56giqz-bad-directory-permissions
$ nix copy --to ssh-ng://saitama /nix/store/99swczlgqpmkqvsd8vzzlqygxw56giqz-bad-directory-permissions
error: getting status of '/nix/store/99swczlgqpmkqvsd8vzzlqygxw56giqz-bad-directory-permissions/foo/bar': Permission denied

That is, this should only be a “breaking” change if someone was deliberately relying on a bug in permission canonicalization on a local machine.

tie avatar Mar 31 '25 15:03 tie

Valid issue. The proposed fix seems to be on the right track. Would be great if someone can PR and check things like back-compat or other interactions. Thanks!

tomberek avatar Jun 04 '25 19:06 tomberek

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

https://discourse.nixos.org/t/2025-05-04-nix-team-meeting-minutes-230/65206/1

nixos-discourse avatar Jun 04 '25 22:06 nixos-discourse

I opened #13526 to implement the proposed (and I think correct) fix.

philiptaron avatar Jul 23 '25 20:07 philiptaron

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

https://discourse.nixos.org/t/2025-08-06-nix-team-meeting-minutes-239-240/67694/1

nixos-discourse avatar Aug 06 '25 20:08 nixos-discourse