diff --git a/src/libstore/include/nix/store/posix-fs-canonicalise.hh b/src/libstore/include/nix/store/posix-fs-canonicalise.hh index 629759cfec3..7767f05d869 100644 --- a/src/libstore/include/nix/store/posix-fs-canonicalise.hh +++ b/src/libstore/include/nix/store/posix-fs-canonicalise.hh @@ -6,12 +6,47 @@ #include "nix/util/types.hh" #include "nix/util/error.hh" +#include "nix/store/config.hh" namespace nix { typedef std::pair Inode; typedef std::set InodesSeen; +struct CanonicalizePathMetadataOptions +{ +#ifndef _WIN32 + /** + * If uidRange is not empty, this function will throw an error if it + * encounters files owned by a user outside of the closed interval + * [uidRange->first, uidRange->second]. + */ + std::optional> uidRange; +#endif + +#if NIX_SUPPORT_ACL + /** + * A list of ACLs that should be ignored when canonicalising. + * Normally Nix attempts to remove all ACLs from files and directories + * in the Nix store, but some ACLs like `security.selinux` or + * `system.nfs4_acl` can't be removed even by root. + */ + const StringSet & ignoredAcls; +#endif +}; + +/** + * Makes it easier to cope with conditionally-available fields. + * + * @todo Switch to a better way, as having a macro is not the nicest. + * This will be easier to do after further settings refactors. + */ +#if NIX_SUPPORT_ACL +# define NIX_WHEN_SUPPORT_ACLS(ARG) .ignoredAcls = ARG, +#else +# define NIX_WHEN_SUPPORT_ACLS(ARG) +#endif + /** * "Fix", or canonicalise, the meta-data of the files in a store path * after it has been built. In particular: @@ -24,25 +59,10 @@ typedef std::set InodesSeen; * * - the owner and group are set to the Nix user and group, if we're * running as root. (Unix only.) - * - * If uidRange is not empty, this function will throw an error if it - * encounters files owned by a user outside of the closed interval - * [uidRange->first, uidRange->second]. */ -void canonicalisePathMetaData( - const Path & path, -#ifndef _WIN32 - std::optional> uidRange, -#endif - InodesSeen & inodesSeen); +void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen); -void canonicalisePathMetaData( - const Path & path -#ifndef _WIN32 - , - std::optional> uidRange = std::nullopt -#endif -); +void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options); void canonicaliseTimestampAndPermissions(const Path & path); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 451cdfc683d..91c3867e5b5 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1083,7 +1083,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source, RepairF autoGC(); - canonicalisePathMetaData(realPath); + canonicalisePathMetaData(realPath, {NIX_WHEN_SUPPORT_ACLS(settings.ignoredAcls)}); optimisePath(realPath, repair); // FIXME: combine with hashPath() @@ -1243,7 +1243,8 @@ StorePath LocalStore::addToStoreFromDump( narHash = narSink.finish(); } - canonicalisePathMetaData(realPath); // FIXME: merge into restorePath + canonicalisePathMetaData( + realPath, {NIX_WHEN_SUPPORT_ACLS(settings.ignoredAcls)}); // FIXME: merge into restorePath optimisePath(realPath, repair); diff --git a/src/libstore/posix-fs-canonicalise.cc b/src/libstore/posix-fs-canonicalise.cc index 9c726671a22..fe1d0031622 100644 --- a/src/libstore/posix-fs-canonicalise.cc +++ b/src/libstore/posix-fs-canonicalise.cc @@ -1,10 +1,10 @@ #include "nix/store/posix-fs-canonicalise.hh" +#include "nix/store/build-result.hh" #include "nix/util/file-system.hh" #include "nix/util/signals.hh" #include "nix/util/util.hh" -#include "nix/store/globals.hh" #include "nix/store/store-api.hh" - +#include "nix/store/globals.hh" #include "store-config-private.hh" #if NIX_SUPPORT_ACL @@ -41,12 +41,8 @@ void canonicaliseTimestampAndPermissions(const Path & path) canonicaliseTimestampAndPermissions(path, lstat(path)); } -static void canonicalisePathMetaData_( - const Path & path, -#ifndef _WIN32 - std::optional> uidRange, -#endif - InodesSeen & inodesSeen) +static void +canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen) { checkInterrupt(); @@ -80,7 +76,7 @@ static void canonicalisePathMetaData_( throw SysError("querying extended attributes of '%s'", path); for (auto & eaName : tokenizeString(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) { - if (settings.ignoredAcls.get().count(eaName)) + if (options.ignoredAcls.count(eaName)) continue; if (lremovexattr(path.c_str(), eaName.c_str()) == -1) throw SysError("removing extended attribute '%s' from '%s'", eaName, path); @@ -95,7 +91,7 @@ static void canonicalisePathMetaData_( However, ignore files that we chown'ed ourselves previously to ensure that we don't fail on hard links within the same build (i.e. "touch $out/foo; ln $out/foo $out/bar"). */ - if (uidRange && (st.st_uid < uidRange->first || st.st_uid > uidRange->second)) { + if (options.uidRange && (st.st_uid < options.uidRange->first || st.st_uid > options.uidRange->second)) { if (S_ISDIR(st.st_mode) || !inodesSeen.count(Inode(st.st_dev, st.st_ino))) throw BuildError(BuildResult::Failure::OutputRejected, "invalid ownership on file '%1%'", path); mode_t mode = st.st_mode & ~S_IFMT; @@ -131,29 +127,14 @@ static void canonicalisePathMetaData_( if (S_ISDIR(st.st_mode)) { for (auto & i : DirectoryIterator{path}) { checkInterrupt(); - canonicalisePathMetaData_( - i.path().string(), -#ifndef _WIN32 - uidRange, -#endif - inodesSeen); + canonicalisePathMetaData_(i.path().string(), options, inodesSeen); } } } -void canonicalisePathMetaData( - const Path & path, -#ifndef _WIN32 - std::optional> uidRange, -#endif - InodesSeen & inodesSeen) +void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen) { - canonicalisePathMetaData_( - path, -#ifndef _WIN32 - uidRange, -#endif - inodesSeen); + canonicalisePathMetaData_(path, options, inodesSeen); #ifndef _WIN32 /* On platforms that don't have lchown(), the top-level path can't @@ -167,21 +148,10 @@ void canonicalisePathMetaData( #endif } -void canonicalisePathMetaData( - const Path & path -#ifndef _WIN32 - , - std::optional> uidRange -#endif -) +void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options) { InodesSeen inodesSeen; - canonicalisePathMetaData_( - path, -#ifndef _WIN32 - uidRange, -#endif - inodesSeen); + canonicalisePathMetaData_(path, options, inodesSeen); } } // namespace nix diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index ed8b41ca454..eeba6a8834f 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -1459,7 +1459,13 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() rewriting doesn't contain a hard link to /etc/shadow or something like that. */ canonicalisePathMetaData( - actualPath, buildUser ? std::optional(buildUser->getUIDRange()) : std::nullopt, inodesSeen); + actualPath, + { +#ifndef _WIN32 + .uidRange = buildUser ? std::optional(buildUser->getUIDRange()) : std::nullopt, +#endif + NIX_WHEN_SUPPORT_ACLS(settings.ignoredAcls)}, + inodesSeen); bool discardReferences = false; if (auto udr = get(drvOptions.unsafeDiscardReferences, outputName)) { @@ -1581,7 +1587,15 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() /* FIXME: set proper permissions in restorePath() so we don't have to do another traversal. */ - canonicalisePathMetaData(actualPath, {}, inodesSeen); + canonicalisePathMetaData( + actualPath, + { +#ifndef _WIN32 + // builder UIDs are already dealt with + .uidRange = std::nullopt, +#endif + NIX_WHEN_SUPPORT_ACLS(settings.ignoredAcls)}, + inodesSeen); } }; @@ -1738,7 +1752,15 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() /* FIXME: set proper permissions in restorePath() so we don't have to do another traversal. */ - canonicalisePathMetaData(actualPath, {}, inodesSeen); + canonicalisePathMetaData( + actualPath, + { +#ifndef _WIN32 + // builder UIDs are already dealt with + .uidRange = std::nullopt, +#endif + NIX_WHEN_SUPPORT_ACLS(settings.ignoredAcls)}, + inodesSeen); /* Calculate where we'll move the output files. In the checking case we will leave leave them where they are, for now, rather than move to diff --git a/src/nix/nix-store/nix-store.cc b/src/nix/nix-store/nix-store.cc index 96584bd1d5e..04979ceb62b 100644 --- a/src/nix/nix-store/nix-store.cc +++ b/src/nix/nix-store/nix-store.cc @@ -6,6 +6,7 @@ #include "nix/store/store-cast.hh" #include "nix/store/local-fs-store.hh" #include "nix/store/log-store.hh" +#include "nix/store/local-store.hh" #include "nix/store/serve-protocol.hh" #include "nix/store/serve-protocol-connection.hh" #include "nix/main/shared.hh" @@ -16,13 +17,12 @@ #include "nix/store/path-with-outputs.hh" #include "nix/store/export-import.hh" #include "nix/util/strings.hh" +#include "nix/store/posix-fs-canonicalise.hh" #include "man-pages.hh" #ifndef _WIN32 // TODO implement on Windows or provide allowed-to-noop interface -# include "nix/store/local-store.hh" # include "nix/util/monitor-fd.hh" -# include "nix/store/posix-fs-canonicalise.hh" #endif #include @@ -49,7 +49,6 @@ static int rootNr = 0; static bool noOutput = false; static std::shared_ptr store; -#ifndef _WIN32 // TODO reenable on Windows once we have `LocalStore` there ref ensureLocalStore() { auto store2 = std::dynamic_pointer_cast(store); @@ -57,7 +56,6 @@ ref ensureLocalStore() throw Error("you don't have sufficient rights to use this command"); return ref(store2); } -#endif static StorePath useDeriver(const StorePath & path) { @@ -590,11 +588,8 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) if (!store->isValidPath(info->path) || reregister) { /* !!! races */ if (canonicalise) -#ifdef _WIN32 // TODO implement on Windows - throw UnimplementedError("file attribute canonicalisation Is not implemented on Windows"); -#else - canonicalisePathMetaData(store->printStorePath(info->path), {}); -#endif + canonicalisePathMetaData( + store->printStorePath(info->path), {NIX_WHEN_SUPPORT_ACLS(settings.ignoredAcls)}); if (!hashGiven) { HashResult hash = hashPath( {store->requireStoreObjectAccessor(info->path, /*requireValidPath=*/false)}, @@ -607,9 +602,7 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) } } -#ifndef _WIN32 // TODO reenable on Windows once we have `LocalStore` there ensureLocalStore()->registerValidPaths(infos); -#endif } static void opLoadDB(Strings opFlags, Strings opArgs)