From 882c2165486b11f7ed6e3c28d75f5b88d2234238 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 12 Jan 2016 23:29:50 +0000 Subject: Add missing check that path params don't attempt to navigate outside of the sandbox --- netfs/daemon/daemonVolume.cpp | 9 +++++++-- netfs/unittests/testCore.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/netfs/daemon/daemonVolume.cpp b/netfs/daemon/daemonVolume.cpp index 087eaf7..7ab8bd1 100644 --- a/netfs/daemon/daemonVolume.cpp +++ b/netfs/daemon/daemonVolume.cpp @@ -12,13 +12,14 @@ #include "lockHelpers.h" #include "modeCheck.h" #include +#include #include #include "daemon.h" extern std::map files; VolumeServer::VolumeServer(const boost::filesystem::path & r, const EntCache & u, const EntCache & g) : - root(r), + root(boost::filesystem::canonical(r)), userLookup(u), groupLookup(g) { @@ -326,6 +327,10 @@ boost::filesystem::path VolumeServer::resolvePath(const std::string & path) const { Lock(lock); - return root / path; + auto p((root / path).normalize()); + if (!boost::algorithm::starts_with(p.string(), root.string())) { + throw NetFS::SystemError(EPERM); + } + return p; } diff --git a/netfs/unittests/testCore.cpp b/netfs/unittests/testCore.cpp index 27a5cf4..7e5136e 100644 --- a/netfs/unittests/testCore.cpp +++ b/netfs/unittests/testCore.cpp @@ -48,6 +48,36 @@ BOOST_AUTO_TEST_CASE ( clientInitialised ) BOOST_REQUIRE_EQUAL(0, fuse->statfs("/", &s)); } +BOOST_AUTO_TEST_CASE( testSandboxing ) +{ + // A previous (bad) run might create one or more of these: + boost::filesystem::remove(rootDir / "outside"); + boost::filesystem::remove(rootDir / "sub" / "outside"); + boost::filesystem::remove(rootDir / "sub"); + struct fuse_file_info fi; + memset(&fi, 0, sizeof(fi)); + BOOST_REQUIRE_EQUAL(fuse->create("../outside", 0666, &fi), -EPERM); + BOOST_REQUIRE(!boost::filesystem::exists(rootDir / "outside")); + BOOST_REQUIRE_EQUAL(fuse->create("/../outside", 0666, &fi), -EPERM); + BOOST_REQUIRE(!boost::filesystem::exists(rootDir / "outside")); + BOOST_REQUIRE_EQUAL(fuse->create("../sub/outside", 0666, &fi), -EPERM); + BOOST_REQUIRE(!boost::filesystem::exists(rootDir / "sub" / "outside")); + BOOST_REQUIRE_EQUAL(fuse->create("/../sub/outside", 0666, &fi), -EPERM); + BOOST_REQUIRE(!boost::filesystem::exists(rootDir / "sub" / "outside")); + BOOST_REQUIRE_EQUAL(fuse->create("../sub/../outside", 0666, &fi), -EPERM); + BOOST_REQUIRE(!boost::filesystem::exists(rootDir / "outside")); + BOOST_REQUIRE_EQUAL(fuse->create("/../sub/../outside", 0666, &fi), -EPERM); + BOOST_REQUIRE(!boost::filesystem::exists(rootDir / "outside")); + int fd = fuse->create("/inside", 0666, &fi); + BOOST_REQUIRE(fd >= 0); + fuse->release("/inside", &fi); + BOOST_REQUIRE(boost::filesystem::exists(rootDir / "testExport" / "inside")); + int fd2 = fuse->create("inside", 0666, &fi); + BOOST_REQUIRE(fd2 >= 0); + fuse->release("inside", &fi); + BOOST_REQUIRE(boost::filesystem::exists(rootDir / "testExport" / "inside")); +} + BOOST_AUTO_TEST_SUITE_END(); BOOST_AUTO_TEST_CASE( testNoAuthNoPass ) -- cgit v1.2.3