Directory permissions not always canonicalized
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
Does this have any implications for backwards compatibility (that we care about...)?
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.
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!
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
I opened #13526 to implement the proposed (and I think correct) fix.
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