Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bdeb9b12 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11426397 from e9998d1c to 24Q2-release

Change-Id: Ie80c756190c5d61dd64d13b03e742f23369160b4
parents 393e9462 e9998d1c
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -4017,24 +4017,37 @@ binder::Status InstalldNativeService::enableFsverity(const sp<IFsveritySetupAuth
        return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Received a null auth token");
    }

    // Authenticate to check the targeting file is the same inode as the authFd.
    // Authenticate to check the targeting file is the same inode as the authFd. With O_PATH, we
    // prevent a malicious client from blocking installd by providing a path to FIFO. After the
    // authentication, the actual open is safe.
    sp<IBinder> authTokenBinder = IInterface::asBinder(authToken)->localBinder();
    if (authTokenBinder == nullptr) {
        return exception(binder::Status::EX_SECURITY, "Received a non-local auth token");
    }
    auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder);
    unique_fd rfd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
    unique_fd pathFd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_PATH));
    // Returns a constant errno to avoid one app probing file existence of the others, before the
    // authentication is done.
    const int kFixedErrno = EPERM;
    if (pathFd.get() < 0) {
        PLOG(DEBUG) << "Failed to open the path";
        *_aidl_return = kFixedErrno;
        return ok();
    }
    std::string procFdPath(StringPrintf("/proc/self/fd/%d", pathFd.get()));
    struct stat stFromPath;
    if (fstat(rfd.get(), &stFromPath) < 0) {
        *_aidl_return = errno;
    if (stat(procFdPath.c_str(), &stFromPath) < 0) {
        PLOG(DEBUG) << "Failed to stat proc fd " << pathFd.get() << " -> " << filePath;
        *_aidl_return = kFixedErrno;
        return ok();
    }
    auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder);
    if (!authTokenInstance->isSameStat(stFromPath)) {
        LOG(DEBUG) << "FD authentication failed";
        *_aidl_return = EPERM;
        *_aidl_return = kFixedErrno;
        return ok();
    }

    unique_fd rfd(open(procFdPath.c_str(), O_RDONLY | O_CLOEXEC));
    fsverity_enable_arg arg = {};
    arg.version = 1;
    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+31 −6
Original line number Diff line number Diff line
@@ -194,6 +194,12 @@ static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
    });
}

static void unlink_path(const std::string& path) {
    if (unlink(path.c_str()) < 0) {
        PLOG(DEBUG) << "Failed to unlink " + path;
    }
}

class ServiceTest : public testing::Test {
protected:
    InstalldNativeService* service;
@@ -555,7 +561,7 @@ protected:
TEST_F(FsverityTest, enableFsverity) {
    const std::string path = kTestPath + "/foo";
    create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
    UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
    UniqueFile raii(/*fd=*/-1, path, &unlink_path);

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

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

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

TEST_F(FsverityTest, enableFsverity_errnoBeforeAuthenticated) {
    const std::string path = kTestPath + "/foo";
    create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
    UniqueFile raii(/*fd=*/-1, path, &unlink_path);

    // Expect to fs-verity setup to succeed
    sp<IFsveritySetupAuthToken> authToken;
    binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken);
    EXPECT_TRUE(status.isOk());
    EXPECT_TRUE(authToken != nullptr);

    // Verity errno before the fd authentication is constant (EPERM)
    int32_t errno_local;
    status = service->enableFsverity(authToken, path + "-non-exist", "fake.package.name",
                                     &errno_local);
    EXPECT_TRUE(status.isOk());
    EXPECT_EQ(errno_local, EPERM);
}

TEST_F(FsverityTest, createFsveritySetupAuthToken_ReadonlyFdDoesNotAuthenticate) {
    const std::string path = kTestPath + "/foo";
    create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
    UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
    UniqueFile raii(/*fd=*/-1, path, &unlink_path);

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

    // Expect the fs-verity setup to fail
    sp<IFsveritySetupAuthToken> authToken;
+1 −0
Original line number Diff line number Diff line
@@ -492,6 +492,7 @@ bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
    if (read(fd, &on, sizeof(on)) == -1) {
        ALOGE("%s: error reading to %s: %s", __func__,
                 names[static_cast<int>(feature)], strerror(errno));
        close(fd);
        return false;
    }
    close(fd);
+47 −12
Original line number Diff line number Diff line
@@ -114,8 +114,8 @@ static_assert(PADDING8(8) == 0);

RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept {
    mData = t.mData;
    mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize());
    mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize());
    mSentDataOnly.setData(t.getDataParcel().data(), t.getDataParcel().dataSize());
    mReplyDataOnly.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize());
}

std::optional<RecordedTransaction> RecordedTransaction::fromDetails(
@@ -136,12 +136,21 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(
        return std::nullopt;
    }

    if (t.mSent.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) {
    if (const auto* kernelFields = dataParcel.maybeKernelFields()) {
        for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
            uint64_t offset = kernelFields->mObjects[i];
            t.mData.mSentObjectData.push_back(offset);
        }
    }

    if (t.mSentDataOnly.setData(dataParcel.data(), dataParcel.dataBufferSize()) !=
        android::NO_ERROR) {
        ALOGE("Failed to set sent parcel data.");
        return std::nullopt;
    }

    if (t.mReply.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) {
    if (t.mReplyDataOnly.setData(replyParcel.data(), replyParcel.dataBufferSize()) !=
        android::NO_ERROR) {
        ALOGE("Failed to set reply parcel data.");
        return std::nullopt;
    }
@@ -154,6 +163,7 @@ enum {
    DATA_PARCEL_CHUNK = 2,
    REPLY_PARCEL_CHUNK = 3,
    INTERFACE_NAME_CHUNK = 4,
    DATA_PARCEL_OBJECT_CHUNK = 5,
    END_CHUNK = 0x00ffffff,
};

@@ -265,7 +275,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
                break;
            }
            case DATA_PARCEL_CHUNK: {
                if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                if (t.mSentDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                                            chunk.dataSize) != android::NO_ERROR) {
                    ALOGE("Failed to set sent parcel data.");
                    return std::nullopt;
@@ -273,13 +283,22 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
                break;
            }
            case REPLY_PARCEL_CHUNK: {
                if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                if (t.mReplyDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                                             chunk.dataSize) != android::NO_ERROR) {
                    ALOGE("Failed to set reply parcel data.");
                    return std::nullopt;
                }
                break;
            }
            case DATA_PARCEL_OBJECT_CHUNK: {
                const uint64_t* objects = reinterpret_cast<const uint64_t*>(payloadMap);
                size_t metaDataSize = (chunk.dataSize / sizeof(uint64_t));
                ALOGI("Total objects found in saved parcel %zu", metaDataSize);
                for (size_t index = 0; index < metaDataSize; ++index) {
                    t.mData.mSentObjectData.push_back(objects[index]);
                }
                break;
            }
            case END_CHUNK:
                break;
            default:
@@ -343,14 +362,26 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const {
        return UNKNOWN_ERROR;
    }

    if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataBufferSize(), mSent.data())) {
    if (NO_ERROR !=
        writeChunk(fd, DATA_PARCEL_CHUNK, mSentDataOnly.dataBufferSize(), mSentDataOnly.data())) {
        ALOGE("Failed to write sent Parcel to fd %d", fd.get());
        return UNKNOWN_ERROR;
    }
    if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataBufferSize(), mReply.data())) {

    if (NO_ERROR !=
        writeChunk(fd, REPLY_PARCEL_CHUNK, mReplyDataOnly.dataBufferSize(),
                   mReplyDataOnly.data())) {
        ALOGE("Failed to write reply Parcel to fd %d", fd.get());
        return UNKNOWN_ERROR;
    }

    if (NO_ERROR !=
        writeChunk(fd, DATA_PARCEL_OBJECT_CHUNK, mData.mSentObjectData.size() * sizeof(uint64_t),
                   reinterpret_cast<const uint8_t*>(mData.mSentObjectData.data()))) {
        ALOGE("Failed to write sent parcel object metadata to fd %d", fd.get());
        return UNKNOWN_ERROR;
    }

    if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) {
        ALOGE("Failed to write end chunk to fd %d", fd.get());
        return UNKNOWN_ERROR;
@@ -384,10 +415,14 @@ uint32_t RecordedTransaction::getVersion() const {
    return mData.mHeader.version;
}

const std::vector<uint64_t>& RecordedTransaction::getObjectOffsets() const {
    return mData.mSentObjectData;
}

const Parcel& RecordedTransaction::getDataParcel() const {
    return mSent;
    return mSentDataOnly;
}

const Parcel& RecordedTransaction::getReplyParcel() const {
    return mReply;
    return mReplyDataOnly;
}
+6 −0
Original line number Diff line number Diff line
@@ -55,6 +55,9 @@ class String8;
class TextOutput;
namespace binder {
class Status;
namespace debug {
class RecordedTransaction;
}
}

class Parcel {
@@ -1443,6 +1446,9 @@ private:
    // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference
    // this
    size_t getBlobAshmemSize() const;

    // Needed so that we can save object metadata to the disk
    friend class android::binder::debug::RecordedTransaction;
};

// ---------------------------------------------------------------------------
Loading