Skip to content

Commit eee1cf5

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge "Only open a path that is a regular file" into main
2 parents 2aac811 + c4cff3d commit eee1cf5

2 files changed

Lines changed: 50 additions & 12 deletions

File tree

cmds/installd/InstalldNativeService.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4029,24 +4029,37 @@ binder::Status InstalldNativeService::enableFsverity(const sp<IFsveritySetupAuth
40294029
return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Received a null auth token");
40304030
}
40314031

4032-
// Authenticate to check the targeting file is the same inode as the authFd.
4032+
// Authenticate to check the targeting file is the same inode as the authFd. With O_PATH, we
4033+
// prevent a malicious client from blocking installd by providing a path to FIFO. After the
4034+
// authentication, the actual open is safe.
40334035
sp<IBinder> authTokenBinder = IInterface::asBinder(authToken)->localBinder();
40344036
if (authTokenBinder == nullptr) {
40354037
return exception(binder::Status::EX_SECURITY, "Received a non-local auth token");
40364038
}
4037-
auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder);
4038-
unique_fd rfd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
4039+
unique_fd pathFd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_PATH));
4040+
// Returns a constant errno to avoid one app probing file existence of the others, before the
4041+
// authentication is done.
4042+
const int kFixedErrno = EPERM;
4043+
if (pathFd.get() < 0) {
4044+
PLOG(DEBUG) << "Failed to open the path";
4045+
*_aidl_return = kFixedErrno;
4046+
return ok();
4047+
}
4048+
std::string procFdPath(StringPrintf("/proc/self/fd/%d", pathFd.get()));
40394049
struct stat stFromPath;
4040-
if (fstat(rfd.get(), &stFromPath) < 0) {
4041-
*_aidl_return = errno;
4050+
if (stat(procFdPath.c_str(), &stFromPath) < 0) {
4051+
PLOG(DEBUG) << "Failed to stat proc fd " << pathFd.get() << " -> " << filePath;
4052+
*_aidl_return = kFixedErrno;
40424053
return ok();
40434054
}
4055+
auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder);
40444056
if (!authTokenInstance->isSameStat(stFromPath)) {
40454057
LOG(DEBUG) << "FD authentication failed";
4046-
*_aidl_return = EPERM;
4058+
*_aidl_return = kFixedErrno;
40474059
return ok();
40484060
}
40494061

4062+
unique_fd rfd(open(procFdPath.c_str(), O_RDONLY | O_CLOEXEC));
40504063
fsverity_enable_arg arg = {};
40514064
arg.version = 1;
40524065
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

cmds/installd/tests/installd_service_test.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
194194
});
195195
}
196196

197+
static void unlink_path(const std::string& path) {
198+
if (unlink(path.c_str()) < 0) {
199+
PLOG(DEBUG) << "Failed to unlink " + path;
200+
}
201+
}
202+
197203
class ServiceTest : public testing::Test {
198204
protected:
199205
InstalldNativeService* service;
@@ -555,7 +561,7 @@ class FsverityTest : public ServiceTest {
555561
TEST_F(FsverityTest, enableFsverity) {
556562
const std::string path = kTestPath + "/foo";
557563
create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
558-
UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
564+
UniqueFile raii(/*fd=*/-1, path, &unlink_path);
559565

560566
// Expect to fs-verity setup to succeed
561567
sp<IFsveritySetupAuthToken> authToken;
@@ -573,7 +579,7 @@ TEST_F(FsverityTest, enableFsverity) {
573579
TEST_F(FsverityTest, enableFsverity_nullAuthToken) {
574580
const std::string path = kTestPath + "/foo";
575581
create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
576-
UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
582+
UniqueFile raii(/*fd=*/-1, path, &unlink_path);
577583

578584
// Verity null auth token fails
579585
sp<IFsveritySetupAuthToken> authToken;
@@ -586,7 +592,7 @@ TEST_F(FsverityTest, enableFsverity_nullAuthToken) {
586592
TEST_F(FsverityTest, enableFsverity_differentFile) {
587593
const std::string path = kTestPath + "/foo";
588594
create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
589-
UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
595+
UniqueFile raii(/*fd=*/-1, path, &unlink_path);
590596

591597
// Expect to fs-verity setup to succeed
592598
sp<IFsveritySetupAuthToken> authToken;
@@ -597,17 +603,36 @@ TEST_F(FsverityTest, enableFsverity_differentFile) {
597603
// Verity auth token does not work for a different file
598604
const std::string anotherPath = kTestPath + "/bar";
599605
ASSERT_TRUE(android::base::WriteStringToFile("content", anotherPath));
600-
UniqueFile raii2(/*fd=*/-1, anotherPath, [](const std::string& path) { unlink(path.c_str()); });
606+
UniqueFile raii2(/*fd=*/-1, anotherPath, &unlink_path);
601607
int32_t errno_local;
602608
status = service->enableFsverity(authToken, anotherPath, "fake.package.name", &errno_local);
603609
EXPECT_TRUE(status.isOk());
604610
EXPECT_NE(errno_local, 0);
605611
}
606612

613+
TEST_F(FsverityTest, enableFsverity_errnoBeforeAuthenticated) {
614+
const std::string path = kTestPath + "/foo";
615+
create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
616+
UniqueFile raii(/*fd=*/-1, path, &unlink_path);
617+
618+
// Expect to fs-verity setup to succeed
619+
sp<IFsveritySetupAuthToken> authToken;
620+
binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken);
621+
EXPECT_TRUE(status.isOk());
622+
EXPECT_TRUE(authToken != nullptr);
623+
624+
// Verity errno before the fd authentication is constant (EPERM)
625+
int32_t errno_local;
626+
status = service->enableFsverity(authToken, path + "-non-exist", "fake.package.name",
627+
&errno_local);
628+
EXPECT_TRUE(status.isOk());
629+
EXPECT_EQ(errno_local, EPERM);
630+
}
631+
607632
TEST_F(FsverityTest, createFsveritySetupAuthToken_ReadonlyFdDoesNotAuthenticate) {
608633
const std::string path = kTestPath + "/foo";
609634
create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
610-
UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
635+
UniqueFile raii(/*fd=*/-1, path, &unlink_path);
611636

612637
// Expect the fs-verity setup to fail
613638
sp<IFsveritySetupAuthToken> authToken;
@@ -619,7 +644,7 @@ TEST_F(FsverityTest, createFsveritySetupAuthToken_UnownedFile) {
619644
const std::string path = kTestPath + "/foo";
620645
// Simulate world-writable file owned by another app
621646
create_with_content(path, kTestAppUid + 1, kTestAppUid + 1, 0666, "content");
622-
UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
647+
UniqueFile raii(/*fd=*/-1, path, &unlink_path);
623648

624649
// Expect the fs-verity setup to fail
625650
sp<IFsveritySetupAuthToken> authToken;

0 commit comments

Comments
 (0)