Commit 79d229fc authored by Tom Sepez's avatar Tom Sepez Committed by Commit Bot

[linux] O_EXCL requirement in brokered open call too restrictive.

The restriction is only required when "temporary file" permissions
have been granted, since that is what implies no access to
pre-existing files.

Fixes the issue hit by
  https://chromium-review.googlesource.com/c/chromium/src/+/818486

in that the network service may try to ensure a file is present via
a single call with O_CREAT without knowing if it pre-exists.

Change-Id: I3cf3f2389a78a5a46f43505a64d106614e4dcf90
Reviewed-on: https://chromium-review.googlesource.com/820611
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarJorge Lucangeli Obes <jorgelo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523527}
parent ca442712
...@@ -148,13 +148,9 @@ bool BrokerFilePermission::CheckOpen(const char* requested_filename, ...@@ -148,13 +148,9 @@ bool BrokerFilePermission::CheckOpen(const char* requested_filename,
return false; return false;
} }
// If O_CREAT is present, ensure O_EXCL // If this file is to be temporary, ensure it is created, not pre-existing.
if ((flags & O_CREAT) && !(flags & O_EXCL)) { // See https://crbug.com/415681#c17
return false; if (temporary_only_ && (!(flags & O_CREAT) || !(flags & O_EXCL))) {
}
// If this file is to be temporary, ensure it's created.
if (temporary_only_ && !(flags & O_CREAT)) {
return false; return false;
} }
......
...@@ -49,6 +49,13 @@ class SANDBOX_EXPORT BrokerFilePermission { ...@@ -49,6 +49,13 @@ class SANDBOX_EXPORT BrokerFilePermission {
return BrokerFilePermission(path, true, false, true, true, true); return BrokerFilePermission(path, true, false, true, true, true);
} }
// Temporary files must always be newly created and do not confer rights to
// use pre-existing files of the same name.
static BrokerFilePermission ReadWriteCreateTemporary(
const std::string& path) {
return BrokerFilePermission(path, false, true, true, true, true);
}
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);
......
...@@ -161,8 +161,9 @@ void CheckPerm(const BrokerFilePermission& perm, ...@@ -161,8 +161,9 @@ void CheckPerm(const BrokerFilePermission& perm,
ASSERT_TRUE( ASSERT_TRUE(
perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL)); perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
break; break;
case O_CLOEXEC:
case O_CREAT: case O_CREAT:
continue; // Handled below.
case O_CLOEXEC:
default: default:
ASSERT_FALSE( ASSERT_FALSE(
perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL)); perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
...@@ -225,7 +226,6 @@ void CheckUnlink(BrokerFilePermission& perm, ...@@ -225,7 +226,6 @@ void CheckUnlink(BrokerFilePermission& perm,
int access_flags) { int access_flags) {
bool unlink; bool unlink;
ASSERT_FALSE(perm.CheckOpen(path, access_flags, NULL, &unlink)); ASSERT_FALSE(perm.CheckOpen(path, access_flags, NULL, &unlink));
ASSERT_FALSE(perm.CheckOpen(path, access_flags | O_CREAT, NULL, &unlink));
ASSERT_TRUE( ASSERT_TRUE(
perm.CheckOpen(path, access_flags | O_CREAT | O_EXCL, NULL, &unlink)); perm.CheckOpen(path, access_flags | O_CREAT | O_EXCL, NULL, &unlink));
ASSERT_TRUE(unlink); ASSERT_TRUE(unlink);
......
...@@ -641,53 +641,93 @@ TEST(BrokerProcess, BrokerDiesOnClosedChannel) { ...@@ -641,53 +641,93 @@ TEST(BrokerProcess, BrokerDiesOnClosedChannel) {
TEST(BrokerProcess, CreateFile) { TEST(BrokerProcess, CreateFile) {
std::string temp_str; std::string temp_str;
std::string perm_str;
{ {
ScopedTemporaryFile tmp_file; ScopedTemporaryFile temp_file;
temp_str = tmp_file.full_file_name(); ScopedTemporaryFile perm_file;
temp_str = temp_file.full_file_name();
perm_str = perm_file.full_file_name();
} }
const char* tempfile_name = temp_str.c_str(); const char* tempfile_name = temp_str.c_str();
const char* permfile_name = perm_str.c_str();
BrokerCommandSet command_set = BrokerCommandSet command_set =
MakeBrokerCommandSet({COMMAND_ACCESS, COMMAND_OPEN}); MakeBrokerCommandSet({COMMAND_ACCESS, COMMAND_OPEN});
std::vector<BrokerFilePermission> permissions = { std::vector<BrokerFilePermission> permissions = {
BrokerFilePermission::ReadWriteCreate(tempfile_name)}; BrokerFilePermission::ReadWriteCreateTemporary(tempfile_name),
BrokerFilePermission::ReadWriteCreate(permfile_name),
};
BrokerProcess open_broker(kFakeErrnoSentinel, command_set, permissions); BrokerProcess open_broker(kFakeErrnoSentinel, command_set, permissions);
ASSERT_TRUE(open_broker.Init(base::BindRepeating(&NoOpCallback))); ASSERT_TRUE(open_broker.Init(base::BindRepeating(&NoOpCallback)));
int fd = -1; int fd = -1;
// Try without O_EXCL // Opening a temp file using O_CREAT but not O_EXCL must not be allowed
// by the broker so as to prevent spying on any pre-existing files.
fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT); fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT);
ASSERT_EQ(fd, -kFakeErrnoSentinel); ASSERT_EQ(fd, -kFakeErrnoSentinel);
const char kTestText[] = "TESTTESTTEST"; // Opening a temp file in a normal way must not be allowed by the broker,
// Create a file // either.
fd = open_broker.Open(tempfile_name, O_RDWR);
ASSERT_EQ(fd, -kFakeErrnoSentinel);
// Opening a temp file with both O_CREAT and O_EXCL is allowed since the
// file is known not to exist outside the scope of ScopedTemporaryFile.
fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL);
ASSERT_GE(fd, 0); ASSERT_GE(fd, 0);
{ close(fd);
base::ScopedFD scoped_fd(fd);
// Confirm fail if file exists // Manually create a conflict for the temp filename.
int bad_fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); fd = open(tempfile_name, O_RDWR | O_CREAT, 0600);
ASSERT_EQ(bad_fd, -EEXIST); ASSERT_GE(fd, 0);
close(fd);
// Opening a temp file with both O_CREAT and O_EXCL is allowed but fails
// per the OS when there is a conflict with a pre-existing file.
fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL);
ASSERT_EQ(fd, -EEXIST);
// Write to the descriptor opened by the broker. // Opening a new permanent file without specifying O_EXCL is allowed.
fd = open_broker.Open(permfile_name, O_RDWR | O_CREAT);
ASSERT_GE(fd, 0);
close(fd);
// Opening an existing permanent file without specifying O_EXCL is allowed.
fd = open_broker.Open(permfile_name, O_RDWR | O_CREAT);
ASSERT_GE(fd, 0);
close(fd);
// Opening an existing file with O_EXCL is allowed but fails per the OS.
fd = open_broker.Open(permfile_name, O_RDWR | O_CREAT | O_EXCL);
ASSERT_EQ(fd, -EEXIST);
const char kTestText[] = "TESTTESTTEST";
fd = open_broker.Open(permfile_name, O_RDWR);
ASSERT_GE(fd, 0);
{
// Write to the descriptor opened by the broker and close.
base::ScopedFD scoped_fd(fd);
ssize_t len = HANDLE_EINTR(write(fd, kTestText, sizeof(kTestText))); ssize_t len = HANDLE_EINTR(write(fd, kTestText, sizeof(kTestText)));
ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText))); ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText)));
} }
int fd_check = open(tempfile_name, O_RDONLY); int fd_check = open(permfile_name, O_RDONLY);
ASSERT_GE(fd_check, 0); ASSERT_GE(fd_check, 0);
{ {
base::ScopedFD scoped_fd(fd_check); base::ScopedFD scoped_fd(fd_check);
char buf[1024]; char buf[1024];
ssize_t len = HANDLE_EINTR(read(fd_check, buf, sizeof(buf))); ssize_t len = HANDLE_EINTR(read(fd_check, buf, sizeof(buf)));
ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText))); ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText)));
ASSERT_EQ(memcmp(kTestText, buf, sizeof(kTestText)), 0); ASSERT_EQ(memcmp(kTestText, buf, sizeof(kTestText)), 0);
} }
// Cleanup.
unlink(tempfile_name);
unlink(permfile_name);
} }
void TestStatHelper(bool fast_check_in_client) { void TestStatHelper(bool fast_check_in_client) {
......
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