1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-09-19 23:03:53 -04:00

isAllowedURI: Extract function and test

(cherry picked from commit 91ba7b2307)
This commit is contained in:
Robert Hensing 2023-12-06 12:41:47 +01:00
parent 2b0ce229aa
commit 90c7904abf
3 changed files with 125 additions and 5 deletions

View file

@ -602,6 +602,7 @@ void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value &
mkStorePathString(storePath, v); mkStorePathString(storePath, v);
} }
SourcePath EvalState::checkSourcePath(const SourcePath & path_) SourcePath EvalState::checkSourcePath(const SourcePath & path_)
{ {
// Don't check non-rootFS accessors, they're in a different namespace. // Don't check non-rootFS accessors, they're in a different namespace.
@ -650,21 +651,29 @@ SourcePath EvalState::checkSourcePath(const SourcePath & path_)
} }
void EvalState::checkURI(const std::string & uri) bool isAllowedURI(std::string_view uri, const Strings & allowedUris)
{ {
if (!evalSettings.restrictEval) return;
/* 'uri' should be equal to a prefix, or in a subdirectory of a /* 'uri' should be equal to a prefix, or in a subdirectory of a
prefix. Thus, the prefix https://github.co does not permit prefix. Thus, the prefix https://github.co does not permit
access to https://github.com. Note: this allows 'http://' and access to https://github.com. Note: this allows 'http://' and
'https://' as prefixes for any http/https URI. */ 'https://' as prefixes for any http/https URI. */
for (auto & prefix : evalSettings.allowedUris.get()) for (auto & prefix : allowedUris) {
if (uri == prefix || if (uri == prefix ||
(uri.size() > prefix.size() (uri.size() > prefix.size()
&& prefix.size() > 0 && prefix.size() > 0
&& hasPrefix(uri, prefix) && hasPrefix(uri, prefix)
&& (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/'))) && (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/')))
return; return true;
}
return false;
}
void EvalState::checkURI(const std::string & uri)
{
if (!evalSettings.restrictEval) return;
if (isAllowedURI(uri, evalSettings.allowedUris.get())) return;
/* If the URI is a path, then check it against allowedPaths as /* If the URI is a path, then check it against allowedPaths as
well. */ well. */

View file

@ -841,6 +841,11 @@ std::string showType(const Value & v);
*/ */
SourcePath resolveExprPath(SourcePath path); SourcePath resolveExprPath(SourcePath path);
/**
* Whether a URI is allowed, assuming restrictEval is enabled
*/
bool isAllowedURI(std::string_view uri, const Strings & allowedPaths);
struct InvalidPathError : EvalError struct InvalidPathError : EvalError
{ {
Path path; Path path;

106
tests/unit/libexpr/eval.cc Normal file
View file

@ -0,0 +1,106 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "eval.hh"
#include "tests/libexpr.hh"
namespace nix {
TEST(nix_isAllowedURI, http_example_com) {
Strings allowed;
allowed.push_back("http://example.com");
ASSERT_TRUE(isAllowedURI("http://example.com", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com/foo", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com/foo/", allowed));
ASSERT_FALSE(isAllowedURI("/", allowed));
ASSERT_FALSE(isAllowedURI("http://example.co", allowed));
ASSERT_FALSE(isAllowedURI("http://example.como", allowed));
ASSERT_FALSE(isAllowedURI("http://example.org", allowed));
ASSERT_FALSE(isAllowedURI("http://example.org/foo", allowed));
}
TEST(nix_isAllowedURI, http_example_com_foo) {
Strings allowed;
allowed.push_back("http://example.com/foo");
ASSERT_TRUE(isAllowedURI("http://example.com/foo", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com/foo/", allowed));
ASSERT_FALSE(isAllowedURI("/foo", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com", allowed));
ASSERT_FALSE(isAllowedURI("http://example.como", allowed));
ASSERT_FALSE(isAllowedURI("http://example.org/foo", allowed));
// Broken?
// ASSERT_TRUE(isAllowedURI("http://example.com/foo?ok=1", allowed));
}
TEST(nix_isAllowedURI, http) {
Strings allowed;
allowed.push_back("http://");
ASSERT_TRUE(isAllowedURI("http://", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com/foo", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com/foo/", allowed));
ASSERT_TRUE(isAllowedURI("http://example.com", allowed));
ASSERT_FALSE(isAllowedURI("/", allowed));
ASSERT_FALSE(isAllowedURI("https://", allowed));
ASSERT_FALSE(isAllowedURI("http:foo", allowed));
}
TEST(nix_isAllowedURI, https) {
Strings allowed;
allowed.push_back("https://");
ASSERT_TRUE(isAllowedURI("https://example.com", allowed));
ASSERT_TRUE(isAllowedURI("https://example.com/foo", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com/https:", allowed));
}
TEST(nix_isAllowedURI, absolute_path) {
Strings allowed;
allowed.push_back("/var/evil"); // bad idea
ASSERT_TRUE(isAllowedURI("/var/evil", allowed));
ASSERT_TRUE(isAllowedURI("/var/evil/", allowed));
ASSERT_TRUE(isAllowedURI("/var/evil/foo", allowed));
ASSERT_TRUE(isAllowedURI("/var/evil/foo/", allowed));
ASSERT_FALSE(isAllowedURI("/", allowed));
ASSERT_FALSE(isAllowedURI("/var/evi", allowed));
ASSERT_FALSE(isAllowedURI("/var/evilo", allowed));
ASSERT_FALSE(isAllowedURI("/var/evilo/", allowed));
ASSERT_FALSE(isAllowedURI("/var/evilo/foo", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com/var/evil", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com//var/evil", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com//var/evil/foo", allowed));
}
TEST(nix_isAllowedURI, file_url) {
Strings allowed;
allowed.push_back("file:///var/evil"); // bad idea
ASSERT_TRUE(isAllowedURI("file:///var/evil", allowed));
ASSERT_TRUE(isAllowedURI("file:///var/evil/", allowed));
ASSERT_TRUE(isAllowedURI("file:///var/evil/foo", allowed));
ASSERT_TRUE(isAllowedURI("file:///var/evil/foo/", allowed));
ASSERT_FALSE(isAllowedURI("/", allowed));
ASSERT_FALSE(isAllowedURI("/var/evi", allowed));
ASSERT_FALSE(isAllowedURI("/var/evilo", allowed));
ASSERT_FALSE(isAllowedURI("/var/evilo/", allowed));
ASSERT_FALSE(isAllowedURI("/var/evilo/foo", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com/var/evil", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com//var/evil", allowed));
ASSERT_FALSE(isAllowedURI("http://example.com//var/evil/foo", allowed));
ASSERT_FALSE(isAllowedURI("http://var/evil", allowed));
ASSERT_FALSE(isAllowedURI("http:///var/evil", allowed));
ASSERT_FALSE(isAllowedURI("http://var/evil/", allowed));
ASSERT_FALSE(isAllowedURI("file:///var/evi", allowed));
ASSERT_FALSE(isAllowedURI("file:///var/evilo", allowed));
ASSERT_FALSE(isAllowedURI("file:///var/evilo/", allowed));
ASSERT_FALSE(isAllowedURI("file:///var/evilo/foo", allowed));
ASSERT_FALSE(isAllowedURI("file:///", allowed));
ASSERT_FALSE(isAllowedURI("file://", allowed));
}
} // namespace nix