Commit d2787ed6 authored by Drew Davenport's avatar Drew Davenport Committed by Commit Bot

sandbox: Add StatOnlyWithIntermediateDirs()

Some use cases, such as some implementations of realpath(), require
calling stat() on all intermediate dirs of a path, but otherwise
do not need to open or read those directories.

Bug=b:112486795
Test=sandbox_linux_unittests passed

Change-Id: Iea0bad8be9e238a854de383ac6dc5124f462ead3
Reviewed-on: https://chromium-review.googlesource.com/1185376Reviewed-by: default avatarJorge Lucangeli Obes <jorgelo@chromium.org>
Commit-Queue: Drew Davenport <ddavenport@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585586}
parent fbfc48c1
...@@ -204,8 +204,8 @@ bool BrokerFilePermission::CheckStat(const char* requested_filename, ...@@ -204,8 +204,8 @@ bool BrokerFilePermission::CheckStat(const char* requested_filename,
if (CheckAccessInternal(requested_filename, F_OK, file_to_access)) if (CheckAccessInternal(requested_filename, F_OK, file_to_access))
return true; return true;
// Allow stat() on leading directories if have create permission. // Allow stat() on leading directories if have create or stat() permission.
if (!allow_create_) if (!(allow_create_ || allow_stat_with_intermediates_))
return false; return false;
// NOTE: ValidatePath proved requested_length != 0; // NOTE: ValidatePath proved requested_length != 0;
...@@ -214,7 +214,10 @@ bool BrokerFilePermission::CheckStat(const char* requested_filename, ...@@ -214,7 +214,10 @@ bool BrokerFilePermission::CheckStat(const char* requested_filename,
// Special case for root: only one slash, otherwise must have a second // Special case for root: only one slash, otherwise must have a second
// slash in the right spot to avoid substring matches. // slash in the right spot to avoid substring matches.
// |allow_stat_with_intermediates_| can match on the full path, and
// |allow_create_| only matches a leading directory.
if ((requested_length == 1 && requested_filename[0] == '/') || if ((requested_length == 1 && requested_filename[0] == '/') ||
(allow_stat_with_intermediates_ && path_ == requested_filename) ||
(requested_length < path_.length() && (requested_length < path_.length() &&
memcmp(path_.c_str(), requested_filename, requested_length) == 0 && memcmp(path_.c_str(), requested_filename, requested_length) == 0 &&
path_.c_str()[requested_length] == '/')) { path_.c_str()[requested_length] == '/')) {
...@@ -236,13 +239,15 @@ BrokerFilePermission::BrokerFilePermission(const std::string& path, ...@@ -236,13 +239,15 @@ BrokerFilePermission::BrokerFilePermission(const std::string& path,
bool temporary_only, bool temporary_only,
bool allow_read, bool allow_read,
bool allow_write, bool allow_write,
bool allow_create) bool allow_create,
bool allow_stat_with_intermediates)
: path_(path), : path_(path),
recursive_(recursive), recursive_(recursive),
temporary_only_(temporary_only), temporary_only_(temporary_only),
allow_read_(allow_read), allow_read_(allow_read),
allow_write_(allow_write), allow_write_(allow_write),
allow_create_(allow_create) { allow_create_(allow_create),
allow_stat_with_intermediates_(allow_stat_with_intermediates) {
// Must have enough length for a '/' // Must have enough length for a '/'
CHECK(path_.length() > 0) << GetErrorMessageForTests(); CHECK(path_.length() > 0) << GetErrorMessageForTests();
......
...@@ -25,40 +25,45 @@ class SANDBOX_EXPORT BrokerFilePermission { ...@@ -25,40 +25,45 @@ class SANDBOX_EXPORT BrokerFilePermission {
BrokerFilePermission& operator=(const BrokerFilePermission&) = default; BrokerFilePermission& operator=(const BrokerFilePermission&) = default;
static BrokerFilePermission ReadOnly(const std::string& path) { static BrokerFilePermission ReadOnly(const std::string& path) {
return BrokerFilePermission(path, false, false, true, false, false); return BrokerFilePermission(path, false, false, true, false, false, false);
} }
static BrokerFilePermission ReadOnlyRecursive(const std::string& path) { static BrokerFilePermission ReadOnlyRecursive(const std::string& path) {
return BrokerFilePermission(path, true, false, true, false, false); return BrokerFilePermission(path, true, false, true, false, false, false);
} }
static BrokerFilePermission WriteOnly(const std::string& path) { static BrokerFilePermission WriteOnly(const std::string& path) {
return BrokerFilePermission(path, false, false, false, true, false); return BrokerFilePermission(path, false, false, false, true, false, false);
} }
static BrokerFilePermission ReadWrite(const std::string& path) { static BrokerFilePermission ReadWrite(const std::string& path) {
return BrokerFilePermission(path, false, false, true, true, false); return BrokerFilePermission(path, false, false, true, true, false, false);
} }
static BrokerFilePermission ReadWriteCreate(const std::string& path) { static BrokerFilePermission ReadWriteCreate(const std::string& path) {
return BrokerFilePermission(path, false, false, true, true, true); return BrokerFilePermission(path, false, false, true, true, true, false);
} }
static BrokerFilePermission ReadWriteCreateRecursive( static BrokerFilePermission ReadWriteCreateRecursive(
const std::string& path) { const std::string& path) {
return BrokerFilePermission(path, true, false, true, true, true); return BrokerFilePermission(path, true, false, true, true, true, false);
} }
// Temporary files must always be newly created and do not confer rights to // Temporary files must always be newly created and do not confer rights to
// use pre-existing files of the same name. // use pre-existing files of the same name.
static BrokerFilePermission ReadWriteCreateTemporary( static BrokerFilePermission ReadWriteCreateTemporary(
const std::string& path) { const std::string& path) {
return BrokerFilePermission(path, false, true, true, true, true); return BrokerFilePermission(path, false, true, true, true, true, false);
} }
static BrokerFilePermission ReadWriteCreateTemporaryRecursive( static BrokerFilePermission ReadWriteCreateTemporaryRecursive(
const std::string& path) { const std::string& path) {
return BrokerFilePermission(path, true, true, true, true, true); return BrokerFilePermission(path, true, true, true, true, true, false);
}
static BrokerFilePermission StatOnlyWithIntermediateDirs(
const std::string& path) {
return BrokerFilePermission(path, false, false, false, false, false, true);
} }
// Returns true if |requested_filename| is allowed to be accessed // Returns true if |requested_filename| is allowed to be accessed
...@@ -108,7 +113,8 @@ class SANDBOX_EXPORT BrokerFilePermission { ...@@ -108,7 +113,8 @@ class SANDBOX_EXPORT BrokerFilePermission {
bool temporary_only, bool temporary_only,
bool allow_read, bool allow_read,
bool allow_write, bool allow_write,
bool allow_create); bool allow_create,
bool allow_stat_with_intermediates);
// ValidatePath checks |path| and returns true if these conditions are met // ValidatePath checks |path| and returns true if these conditions are met
// * Greater than 0 length // * Greater than 0 length
...@@ -138,6 +144,8 @@ class SANDBOX_EXPORT BrokerFilePermission { ...@@ -138,6 +144,8 @@ class SANDBOX_EXPORT BrokerFilePermission {
bool allow_read_; bool allow_read_;
bool allow_write_; bool allow_write_;
bool allow_create_; bool allow_create_;
// Allow stat() for |path| and all intermediate dirs.
bool allow_stat_with_intermediates_;
}; };
} // namespace syscall_broker } // namespace syscall_broker
......
...@@ -260,6 +260,30 @@ TEST(BrokerFilePermission, ReadWriteCreateTemporaryRecursive) { ...@@ -260,6 +260,30 @@ TEST(BrokerFilePermission, ReadWriteCreateTemporaryRecursive) {
// expected. // expected.
} }
TEST(BrokerFilePermission, StatOnlyWithIntermediateDirs) {
const char kPath[] = "/tmp/good/path";
const char kLeading1[] = "/";
const char kLeading2[] = "/tmp";
const char kLeading3[] = "/tmp/good/path";
const char kTrailing[] = "/tmp/good/path/bad";
BrokerFilePermission perm =
BrokerFilePermission::StatOnlyWithIntermediateDirs(kPath);
// No open or access permission.
ASSERT_FALSE(perm.CheckOpen(kPath, O_RDONLY, NULL, NULL));
ASSERT_FALSE(perm.CheckOpen(kPath, O_WRONLY, NULL, NULL));
ASSERT_FALSE(perm.CheckOpen(kPath, O_RDWR, NULL, NULL));
ASSERT_FALSE(perm.CheckAccess(kPath, R_OK, NULL));
ASSERT_FALSE(perm.CheckAccess(kPath, W_OK, NULL));
// Stat for all leading paths, but not trailing paths.
ASSERT_TRUE(perm.CheckStat(kPath, NULL));
ASSERT_TRUE(perm.CheckStat(kLeading1, NULL));
ASSERT_TRUE(perm.CheckStat(kLeading2, NULL));
ASSERT_TRUE(perm.CheckStat(kLeading3, NULL));
ASSERT_FALSE(perm.CheckStat(kTrailing, NULL));
}
TEST(BrokerFilePermission, ValidatePath) { TEST(BrokerFilePermission, ValidatePath) {
EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/path")); EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/path"));
EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/")); EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/"));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment