diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 14837de92..ec3539327 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -8,6 +8,7 @@ #include "flake/flakeref.hh" #include "store-api.hh" #include "command.hh" +#include "fs-input-accessor.hh" namespace nix { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index a9c03b53c..40eb3eeab 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -9,6 +9,7 @@ #include "filetransfer.hh" #include "json.hh" #include "function-trace.hh" +#include "fs-input-accessor.hh" #include #include diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 9c809152e..4fee93b8a 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -22,6 +22,7 @@ class EvalState; class StorePath; struct SourcePath; enum RepairFlag : bool; +struct FSInputAccessor; typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 4d69a5d75..f098a4745 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -639,6 +639,7 @@ formal #include "eval.hh" #include "filetransfer.hh" #include "fetchers.hh" +#include "fs-input-accessor.hh" #include "store-api.hh" diff --git a/src/libexpr/paths.cc b/src/libexpr/paths.cc index f366722eb..9a5449695 100644 --- a/src/libexpr/paths.cc +++ b/src/libexpr/paths.cc @@ -1,5 +1,6 @@ #include "eval.hh" #include "util.hh" +#include "fs-input-accessor.hh" namespace nix { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 07afac1e9..15fb0f888 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -11,6 +11,7 @@ #include "value-to-json.hh" #include "value-to-xml.hh" #include "primops.hh" +#include "fs-input-accessor.hh" #include diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 5b3dde436..33e088f1a 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -1,5 +1,6 @@ #include "fetchers.hh" #include "store-api.hh" +#include "input-accessor.hh" #include diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index 2a03dcaad..ee8d89d74 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -3,13 +3,13 @@ #include "types.hh" #include "hash.hh" #include "path.hh" +#include "canon-path.hh" #include "attrs.hh" #include "url.hh" -#include "input-accessor.hh" #include -namespace nix { class Store; } +namespace nix { class Store; class InputAccessor; } namespace nix::fetchers { diff --git a/src/libfetchers/fs-input-accessor.cc b/src/libfetchers/fs-input-accessor.cc new file mode 100644 index 000000000..fa3224c90 --- /dev/null +++ b/src/libfetchers/fs-input-accessor.cc @@ -0,0 +1,140 @@ +#include "fs-input-accessor.hh" +#include "store-api.hh" + +namespace nix { + +struct FSInputAccessorImpl : FSInputAccessor +{ + CanonPath root; + std::optional> allowedPaths; + MakeNotAllowedError makeNotAllowedError; + + FSInputAccessorImpl( + const CanonPath & root, + std::optional> && allowedPaths, + MakeNotAllowedError && makeNotAllowedError) + : root(root) + , allowedPaths(std::move(allowedPaths)) + , makeNotAllowedError(std::move(makeNotAllowedError)) + { + displayPrefix = root.isRoot() ? "" : root.abs(); + } + + std::string readFile(const CanonPath & path) override + { + auto absPath = makeAbsPath(path); + checkAllowed(absPath); + return nix::readFile(absPath.abs()); + } + + bool pathExists(const CanonPath & path) override + { + auto absPath = makeAbsPath(path); + return isAllowed(absPath) && nix::pathExists(absPath.abs()); + } + + Stat lstat(const CanonPath & path) override + { + auto absPath = makeAbsPath(path); + checkAllowed(absPath); + auto st = nix::lstat(absPath.abs()); + return Stat { + .type = + S_ISREG(st.st_mode) ? tRegular : + S_ISDIR(st.st_mode) ? tDirectory : + S_ISLNK(st.st_mode) ? tSymlink : + tMisc, + .isExecutable = S_ISREG(st.st_mode) && st.st_mode & S_IXUSR + }; + } + + DirEntries readDirectory(const CanonPath & path) override + { + auto absPath = makeAbsPath(path); + checkAllowed(absPath); + DirEntries res; + for (auto & entry : nix::readDirectory(absPath.abs())) { + std::optional type; + switch (entry.type) { + case DT_REG: type = Type::tRegular; break; + case DT_LNK: type = Type::tSymlink; break; + case DT_DIR: type = Type::tDirectory; break; + } + if (isAllowed(absPath + entry.name)) + res.emplace(entry.name, type); + } + return res; + } + + std::string readLink(const CanonPath & path) override + { + auto absPath = makeAbsPath(path); + checkAllowed(absPath); + return nix::readLink(absPath.abs()); + } + + CanonPath makeAbsPath(const CanonPath & path) + { + return root + path; + } + + void checkAllowed(const CanonPath & absPath) override + { + if (!isAllowed(absPath)) + throw makeNotAllowedError + ? makeNotAllowedError(absPath) + : RestrictedPathError("access to path '%s' is forbidden", absPath); + } + + bool isAllowed(const CanonPath & absPath) + { + if (!absPath.isWithin(root)) + return false; + + if (allowedPaths) { + auto p = absPath.removePrefix(root); + if (!p.isAllowed(*allowedPaths)) + return false; + } + + return true; + } + + void allowPath(CanonPath path) override + { + if (allowedPaths) + allowedPaths->insert(std::move(path)); + } + + bool hasAccessControl() override + { + return (bool) allowedPaths; + } + + std::optional getPhysicalPath(const CanonPath & path) override + { + auto absPath = makeAbsPath(path); + if (isAllowed(absPath)) + return absPath; + else + return std::nullopt; + } +}; + +ref makeFSInputAccessor( + const CanonPath & root, + std::optional> && allowedPaths, + MakeNotAllowedError && makeNotAllowedError) +{ + return make_ref(root, std::move(allowedPaths), std::move(makeNotAllowedError)); +} + +ref makeStorePathAccessor( + ref store, + const StorePath & storePath, + MakeNotAllowedError && makeNotAllowedError) +{ + return makeFSInputAccessor(CanonPath(store->toRealPath(storePath)), {}, std::move(makeNotAllowedError)); +} + +} diff --git a/src/libfetchers/fs-input-accessor.hh b/src/libfetchers/fs-input-accessor.hh new file mode 100644 index 000000000..57b794553 --- /dev/null +++ b/src/libfetchers/fs-input-accessor.hh @@ -0,0 +1,29 @@ +#pragma once + +#include "input-accessor.hh" + +namespace nix { + +class StorePath; +class Store; + +struct FSInputAccessor : InputAccessor +{ + virtual void checkAllowed(const CanonPath & absPath) = 0; + + virtual void allowPath(CanonPath path) = 0; + + virtual bool hasAccessControl() = 0; +}; + +ref makeFSInputAccessor( + const CanonPath & root, + std::optional> && allowedPaths = {}, + MakeNotAllowedError && makeNotAllowedError = {}); + +ref makeStorePathAccessor( + ref store, + const StorePath & storePath, + MakeNotAllowedError && makeNotAllowedError = {}); + +} diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 2218f594b..a072a6cd0 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -7,6 +7,7 @@ #include "pathlocks.hh" #include "util.hh" #include "git.hh" +#include "fs-input-accessor.hh" #include "fetch-settings.hh" diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc index 4005a1f48..230e60217 100644 --- a/src/libfetchers/github.cc +++ b/src/libfetchers/github.cc @@ -7,6 +7,7 @@ #include "git.hh" #include "fetchers.hh" #include "fetch-settings.hh" +#include "input-accessor.hh" #include #include diff --git a/src/libfetchers/input-accessor.cc b/src/libfetchers/input-accessor.cc index 5df447f01..782213211 100644 --- a/src/libfetchers/input-accessor.cc +++ b/src/libfetchers/input-accessor.cc @@ -1,6 +1,5 @@ #include "input-accessor.hh" #include "util.hh" -#include "store-api.hh" #include @@ -110,140 +109,6 @@ SourcePath InputAccessor::root() return {ref(shared_from_this()), CanonPath::root}; } -struct FSInputAccessorImpl : FSInputAccessor -{ - CanonPath root; - std::optional> allowedPaths; - MakeNotAllowedError makeNotAllowedError; - - FSInputAccessorImpl( - const CanonPath & root, - std::optional> && allowedPaths, - MakeNotAllowedError && makeNotAllowedError) - : root(root) - , allowedPaths(std::move(allowedPaths)) - , makeNotAllowedError(std::move(makeNotAllowedError)) - { - displayPrefix = root.isRoot() ? "" : root.abs(); - } - - std::string readFile(const CanonPath & path) override - { - auto absPath = makeAbsPath(path); - checkAllowed(absPath); - return nix::readFile(absPath.abs()); - } - - bool pathExists(const CanonPath & path) override - { - auto absPath = makeAbsPath(path); - return isAllowed(absPath) && nix::pathExists(absPath.abs()); - } - - Stat lstat(const CanonPath & path) override - { - auto absPath = makeAbsPath(path); - checkAllowed(absPath); - auto st = nix::lstat(absPath.abs()); - return Stat { - .type = - S_ISREG(st.st_mode) ? tRegular : - S_ISDIR(st.st_mode) ? tDirectory : - S_ISLNK(st.st_mode) ? tSymlink : - tMisc, - .isExecutable = S_ISREG(st.st_mode) && st.st_mode & S_IXUSR - }; - } - - DirEntries readDirectory(const CanonPath & path) override - { - auto absPath = makeAbsPath(path); - checkAllowed(absPath); - DirEntries res; - for (auto & entry : nix::readDirectory(absPath.abs())) { - std::optional type; - switch (entry.type) { - case DT_REG: type = Type::tRegular; break; - case DT_LNK: type = Type::tSymlink; break; - case DT_DIR: type = Type::tDirectory; break; - } - if (isAllowed(absPath + entry.name)) - res.emplace(entry.name, type); - } - return res; - } - - std::string readLink(const CanonPath & path) override - { - auto absPath = makeAbsPath(path); - checkAllowed(absPath); - return nix::readLink(absPath.abs()); - } - - CanonPath makeAbsPath(const CanonPath & path) - { - return root + path; - } - - void checkAllowed(const CanonPath & absPath) override - { - if (!isAllowed(absPath)) - throw makeNotAllowedError - ? makeNotAllowedError(absPath) - : RestrictedPathError("access to path '%s' is forbidden", absPath); - } - - bool isAllowed(const CanonPath & absPath) - { - if (!absPath.isWithin(root)) - return false; - - if (allowedPaths) { - auto p = absPath.removePrefix(root); - if (!p.isAllowed(*allowedPaths)) - return false; - } - - return true; - } - - void allowPath(CanonPath path) override - { - if (allowedPaths) - allowedPaths->insert(std::move(path)); - } - - bool hasAccessControl() override - { - return (bool) allowedPaths; - } - - std::optional getPhysicalPath(const CanonPath & path) override - { - auto absPath = makeAbsPath(path); - if (isAllowed(absPath)) - return absPath; - else - return std::nullopt; - } -}; - -ref makeFSInputAccessor( - const CanonPath & root, - std::optional> && allowedPaths, - MakeNotAllowedError && makeNotAllowedError) -{ - return make_ref(root, std::move(allowedPaths), std::move(makeNotAllowedError)); -} - -ref makeStorePathAccessor( - ref store, - const StorePath & storePath, - MakeNotAllowedError && makeNotAllowedError) -{ - return makeFSInputAccessor(CanonPath(store->toRealPath(storePath)), {}, std::move(makeNotAllowedError)); -} - std::ostream & operator << (std::ostream & str, const SourcePath & path) { str << path.to_string(); diff --git a/src/libfetchers/input-accessor.hh b/src/libfetchers/input-accessor.hh index 2c0be75ff..1c6bd24cb 100644 --- a/src/libfetchers/input-accessor.hh +++ b/src/libfetchers/input-accessor.hh @@ -10,8 +10,6 @@ namespace nix { MakeError(RestrictedPathError, Error); struct SourcePath; -class StorePath; -class Store; struct InputAccessor : public std::enable_shared_from_this { @@ -77,27 +75,8 @@ struct InputAccessor : public std::enable_shared_from_this SourcePath root(); }; -struct FSInputAccessor : InputAccessor -{ - virtual void checkAllowed(const CanonPath & absPath) = 0; - - virtual void allowPath(CanonPath path) = 0; - - virtual bool hasAccessControl() = 0; -}; - typedef std::function MakeNotAllowedError; -ref makeFSInputAccessor( - const CanonPath & root, - std::optional> && allowedPaths = {}, - MakeNotAllowedError && makeNotAllowedError = {}); - -ref makeStorePathAccessor( - ref store, - const StorePath & storePath, - MakeNotAllowedError && makeNotAllowedError = {}); - struct SourcePath; struct MemoryInputAccessor : InputAccessor diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc index ccd504e15..416be7412 100644 --- a/src/libfetchers/mercurial.cc +++ b/src/libfetchers/mercurial.cc @@ -4,7 +4,7 @@ #include "tarfile.hh" #include "store-api.hh" #include "url-parts.hh" - +#include "fs-input-accessor.hh" #include "fetch-settings.hh" #include diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index 4d3dad679..1acac82a6 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -1,6 +1,7 @@ #include "fetchers.hh" #include "store-api.hh" #include "archive.hh" +#include "fs-input-accessor.hh" namespace nix::fetchers { diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc index 964a10124..45dab33ed 100644 --- a/src/libfetchers/tarball.cc +++ b/src/libfetchers/tarball.cc @@ -7,6 +7,7 @@ #include "tarfile.hh" #include "types.hh" #include "split.hh" +#include "fs-input-accessor.hh" namespace nix::fetchers {