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

Commit ab0a32e6 authored by Alex Buynytskyy's avatar Alex Buynytskyy Committed by Android (Google) Code Review
Browse files

Merge "Disallow read logs collection if user changes their mind." into rvc-dev

parents 7bfa49bf 96e350b3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ cc_defaults {
        "libbinder",
        "libcrypto",
        "libcutils",
        "libdataloader",
        "libincfs",
        "liblog",
        "libz",
+98 −47
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#define LOG_TAG "IncrementalService"

#include "IncrementalService.h"
#include "IncrementalServiceValidation.h"

#include <android-base/file.h>
#include <android-base/logging.h>
@@ -50,6 +51,9 @@ using namespace std::literals;
using namespace android::content::pm;
namespace fs = std::filesystem;

constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS";
constexpr const char* kOpUsage = "android:get_usage_stats";

namespace android::incremental {

namespace {
@@ -232,6 +236,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
      : mVold(sm.getVoldService()),
        mDataLoaderManager(sm.getDataLoaderManager()),
        mIncFs(sm.getIncFs()),
        mAppOpsManager(sm.getAppOpsManager()),
        mIncrementalDir(rootDir) {
    if (!mVold) {
        LOG(FATAL) << "Vold service is unavailable";
@@ -239,6 +244,9 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
    if (!mDataLoaderManager) {
        LOG(FATAL) << "DataLoaderManagerService is unavailable";
    }
    if (!mAppOpsManager) {
        LOG(FATAL) << "AppOpsManager is unavailable";
    }
    mountExistingImages();
}

@@ -279,12 +287,9 @@ void IncrementalService::onDump(int fd) {
        dprintf(fd, "\t\troot: %s\n", mnt.root.c_str());
        dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load());
        dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load());
        dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime));
        dprintf(fd, "\t\tsavedDataLoaderParams:\n");
        if (!mnt.savedDataLoaderParams) {
            dprintf(fd, "\t\t\tnone\n");
        } else {
            const auto& params = mnt.savedDataLoaderParams.value();
        {
            const auto& params = mnt.dataLoaderParams;
            dprintf(fd, "\t\tdataLoaderParams:\n");
            dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str());
            dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str());
            dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str());
@@ -332,6 +337,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() {
    }

    std::thread([this, mounts = std::move(mounts)]() {
        /* TODO(b/151241369): restore data loaders on reboot.
        for (auto&& ifs : mounts) {
            if (prepareDataLoader(*ifs)) {
                LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId;
@@ -340,6 +346,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() {
                LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId;
            }
        }
        */
        mPrepareDataLoaders.set_value_at_thread_exit();
    }).detach();
    return mPrepareDataLoaders.get_future();
@@ -459,13 +466,15 @@ StorageId IncrementalService::createStorage(
        return kInvalidStorageId;
    }

    ifs->dataLoaderParams = std::move(dataLoaderParams);

    {
        metadata::Mount m;
        m.mutable_storage()->set_id(ifs->mountId);
        m.mutable_loader()->set_type((int)dataLoaderParams.type);
        m.mutable_loader()->set_package_name(dataLoaderParams.packageName);
        m.mutable_loader()->set_class_name(dataLoaderParams.className);
        m.mutable_loader()->set_arguments(dataLoaderParams.arguments);
        m.mutable_loader()->set_type((int)ifs->dataLoaderParams.type);
        m.mutable_loader()->set_package_name(ifs->dataLoaderParams.packageName);
        m.mutable_loader()->set_class_name(ifs->dataLoaderParams.className);
        m.mutable_loader()->set_arguments(ifs->dataLoaderParams.arguments);
        const auto metadata = m.SerializeAsString();
        m.mutable_loader()->release_arguments();
        m.mutable_loader()->release_class_name();
@@ -493,7 +502,7 @@ StorageId IncrementalService::createStorage(
    // Done here as well, all data structures are in good state.
    secondCleanupOnFailure.release();

    if (!prepareDataLoader(*ifs, &dataLoaderParams, &dataLoaderStatusListener)) {
    if (!prepareDataLoader(*ifs, &dataLoaderStatusListener)) {
        LOG(ERROR) << "prepareDataLoader() failed";
        deleteStorageLocked(*ifs, std::move(l));
        return kInvalidStorageId;
@@ -573,11 +582,30 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog
        return -EINVAL;
    }

    ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs;
    if (enableReadLogs) {
        // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok.
        registerAppOpsCallback(ifs->dataLoaderParams.packageName);
    }

    return applyStorageParams(*ifs);
}

int IncrementalService::applyStorageParams(IncFsMount& ifs) {
    const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled;
    if (enableReadLogs) {
        if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage);
            !status.isOk()) {
            LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8();
            return fromBinderStatus(status);
        }
    }

    using unique_fd = ::android::base::unique_fd;
    ::android::os::incremental::IncrementalFileSystemControlParcel control;
    control.cmd.reset(unique_fd(dup(ifs->control.cmd())));
    control.pendingReads.reset(unique_fd(dup(ifs->control.pendingReads())));
    auto logsFd = ifs->control.logs();
    control.cmd.reset(unique_fd(dup(ifs.control.cmd())));
    control.pendingReads.reset(unique_fd(dup(ifs.control.pendingReads())));
    auto logsFd = ifs.control.logs();
    if (logsFd >= 0) {
        control.log.reset(unique_fd(dup(logsFd)));
    }
@@ -586,12 +614,7 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog
    const auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
    if (!status.isOk()) {
        LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8();
        return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
                ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
                                                        : status.serviceSpecificErrorCode() == 0
                                ? -EFAULT
                                : status.serviceSpecificErrorCode()
                : -EIO;
        return fromBinderStatus(status);
    }

    return 0;
@@ -1015,16 +1038,26 @@ bool IncrementalService::mountExistingImage(std::string_view root) {

    auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this);

    auto m = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control,
    auto mount = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control,
                                                 path::join(mountTarget, constants().infoMdName));
    if (!m.has_loader() || !m.has_storage()) {
    if (!mount.has_loader() || !mount.has_storage()) {
        LOG(ERROR) << "Bad mount metadata in mount at " << root;
        return false;
    }

    ifs->mountId = m.storage().id();
    ifs->mountId = mount.storage().id();
    mNextId = std::max(mNextId, ifs->mountId + 1);

    // DataLoader params
    {
        auto& dlp = ifs->dataLoaderParams;
        const auto& loader = mount.loader();
        dlp.type = (android::content::pm::DataLoaderType)loader.type();
        dlp.packageName = loader.package_name();
        dlp.className = loader.class_name();
        dlp.arguments = loader.arguments();
    }

    std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
    auto d = openDir(path::c_str(mountTarget));
    while (auto e = ::readdir(d.get())) {
@@ -1095,23 +1128,9 @@ bool IncrementalService::mountExistingImage(std::string_view root) {
}

bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
                                           DataLoaderParamsParcel* params,
                                           const DataLoaderStatusListener* externalListener) {
    if (!mSystemReady.load(std::memory_order_relaxed)) {
        std::unique_lock l(ifs.lock);
        if (params) {
            if (ifs.savedDataLoaderParams) {
                LOG(WARNING) << "Trying to pass second set of data loader parameters, ignored it";
            } else {
                ifs.savedDataLoaderParams = std::move(*params);
            }
        } else {
            if (!ifs.savedDataLoaderParams) {
                LOG(ERROR) << "Mount " << ifs.mountId
                           << " is broken: no data loader params (system is not ready yet)";
                return false;
            }
        }
        return true; // eventually...
    }

@@ -1121,12 +1140,6 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
        return true;
    }

    auto* dlp = params ? params
                       : ifs.savedDataLoaderParams ? &ifs.savedDataLoaderParams.value() : nullptr;
    if (!dlp) {
        LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params";
        return false;
    }
    FileSystemControlParcel fsControlParcel;
    fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>();
    fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd())));
@@ -1138,13 +1151,11 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
                                              externalListener ? *externalListener
                                                               : DataLoaderStatusListener());
    bool created = false;
    auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, *dlp, fsControlParcel,
                                                           listener, &created);
    auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, ifs.dataLoaderParams, fsControlParcel, listener, &created);
    if (!status.isOk() || !created) {
        LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId;
        return false;
    }
    ifs.savedDataLoaderParams.reset();
    return true;
}

@@ -1268,6 +1279,42 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
    return success;
}

void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
    if (packageName.empty()) {
        return;
    }

    {
        std::unique_lock lock{mCallbacksLock};
        if (!mCallbackRegistered.insert(packageName).second) {
            return;
        }
    }

    /* TODO(b/152633648): restore callback after it's not crashing Binder anymore.
    sp<AppOpsListener> listener = new AppOpsListener(*this, packageName);
    mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener);
    */
}

void IncrementalService::onAppOppChanged(const std::string& packageName) {
    std::vector<IfsMountPtr> affected;
    {
        std::lock_guard l(mLock);
        affected.reserve(mMounts.size());
        for (auto&& [id, ifs] : mMounts) {
            if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) {
                affected.push_back(ifs);
            }
        }
    }
    /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore.
    for (auto&& ifs : affected) {
        applyStorageParams(*ifs);
    }
    */
}

binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
                                                                                  int newStatus) {
    if (externalListener) {
@@ -1331,4 +1378,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange
    return binder::Status::ok();
}

void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) {
    incrementalService.onAppOppChanged(packageName);
}

} // namespace android::incremental
+30 −8
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#include "ServiceWrappers.h"
#include "android/content/pm/BnDataLoaderStatusListener.h"
#include "incfs.h"
#include "dataloader_ndk.h"
#include "path.h"

using namespace android::os::incremental;
@@ -132,6 +133,7 @@ public:
    bool startLoading(StorageId storage) const;
    bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
                                 std::string_view libDirRelativePath, std::string_view abi);

    class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener {
    public:
        IncrementalDataLoaderListener(IncrementalService& incrementalService,
@@ -145,6 +147,16 @@ public:
        DataLoaderStatusListener externalListener;
    };

    class AppOpsListener : public android::BnAppOpsCallback {
    public:
        AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {}
        void opChanged(int32_t op, const String16& packageName) override;

    private:
        IncrementalService& incrementalService;
        const std::string packageName;
    };

private:
    struct IncFsMount {
        struct Bind {
@@ -169,11 +181,11 @@ private:
        /*const*/ MountId mountId;
        StorageMap storages;
        BindMap bindPoints;
        std::optional<DataLoaderParamsParcel> savedDataLoaderParams;
        DataLoaderParamsParcel dataLoaderParams;
        DataLoaderFilesystemParams dataLoaderFilesystemParams;
        std::atomic<int> nextStorageDirNo{0};
        std::atomic<int> dataLoaderStatus = -1;
        bool dataLoaderStartRequested = false;
        TimePoint connectionLostTime = TimePoint();
        const IncrementalService& incrementalService;

        IncFsMount(std::string root, MountId mountId, Control control,
@@ -181,7 +193,9 @@ private:
              : root(std::move(root)),
                control(std::move(control)),
                mountId(mountId),
                incrementalService(incrementalService) {}
                incrementalService(incrementalService) {
            dataLoaderFilesystemParams.readLogsEnabled = false;
        }
        IncFsMount(IncFsMount&&) = delete;
        IncFsMount& operator=(IncFsMount&&) = delete;
        ~IncFsMount();
@@ -208,8 +222,7 @@ private:
                           std::string&& source, std::string&& target, BindKind kind,
                           std::unique_lock<std::mutex>& mainLock);

    bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr,
                           const DataLoaderStatusListener* externalListener = nullptr);
    bool prepareDataLoader(IncFsMount& ifs, const DataLoaderStatusListener* externalListener = nullptr);
    bool startDataLoader(MountId mountId) const;

    BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
@@ -221,10 +234,16 @@ private:
    std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage,
                                       std::string_view path);

    int applyStorageParams(IncFsMount& ifs);

    void registerAppOpsCallback(const std::string& packageName);
    void onAppOppChanged(const std::string& packageName);

    // Member variables
    std::unique_ptr<VoldServiceWrapper> mVold;
    std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
    std::unique_ptr<IncFsWrapper> mIncFs;
    std::unique_ptr<VoldServiceWrapper> const mVold;
    std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager;
    std::unique_ptr<IncFsWrapper> const mIncFs;
    std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager;
    const std::string mIncrementalDir;

    mutable std::mutex mLock;
@@ -232,6 +251,9 @@ private:
    MountMap mMounts;
    BindPathMap mBindsByPath;

    std::mutex mCallbacksLock;
    std::set<std::string> mCallbackRegistered;

    std::atomic_bool mSystemReady = false;
    StorageId mNextId = 0;
    std::promise<void> mPrepareDataLoaders;
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <android-base/stringprintf.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
#include <binder/PermissionController.h>
#include <binder/Status.h>

namespace android::incremental {

inline binder::Status Ok() {
    return binder::Status::ok();
}

inline binder::Status Exception(uint32_t code, const std::string& msg) {
    return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
}

inline int fromBinderStatus(const binder::Status& status) {
    return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
            ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
                                                    : status.serviceSpecificErrorCode() == 0
                            ? -EFAULT
                            : status.serviceSpecificErrorCode()
            : -EIO;
}

inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation) {
    using android::base::StringPrintf;

    int32_t pid;
    int32_t uid;

    if (!PermissionCache::checkCallingPermission(String16(permission), &pid, &uid)) {
        return Exception(binder::Status::EX_SECURITY,
                         StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
    }

    // Caller must also have op granted.
    PermissionController pc;
    // Package is a required parameter. Need to obtain one.
    Vector<String16> packages;
    pc.getPackagesForUid(uid, packages);
    if (packages.empty()) {
        return Exception(binder::Status::EX_SECURITY,
                         StringPrintf("UID %d / PID %d has no packages", uid, pid));
    }
    switch (auto result = pc.noteOp(String16(operation), uid, packages[0]); result) {
        case PermissionController::MODE_ALLOWED:
        case PermissionController::MODE_DEFAULT:
            return binder::Status::ok();
        default:
            return Exception(binder::Status::EX_SECURITY,
                             StringPrintf("UID %d / PID %d lacks app-op %s, error %d", uid, pid,
                                          operation, result));
    }
}

} // namespace android::incremental
+4 −0
Original line number Diff line number Diff line
@@ -59,4 +59,8 @@ std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() {
    return std::make_unique<RealIncFs>();
}

std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() {
    return std::make_unique<RealAppOpsManager>();
}

} // namespace android::os::incremental
Loading