4e9f147e55
Adds pawlethwd, a native C++ system_ext daemon (coredomain) that detects peripherals, checks the hardware update catalog (ota.php?mode=hardware), verifies payloads, and flashes firmware via authorized handler plugins. - daemon/: manifest parse, libcurl HTTP + sha256, sysfs USB detection, catalog client, dlopen handler registry (fixed path + ABI + allowlist), state persistence, orchestration engine, AIDL service, main. - aidl/: IPawletHardwareUpdate (getComponents/getPendingUpdates/checkNow/...). - include/pawlet/hwh_abi.h: stable C plugin ABI. - handlers/usbdfu/: libpawlethwh_usbdfu.so, DFU 1.1 download over libusb. - sepolicy/: pawlethwd domain, pawlet_hw_data_file, service type. - schemas/, etc/supported_hardware.default.json, README design doc. - hwupdate.mk wires packages + ro.pawlet.hardware.manifest + sepolicy dir; inherited from config/common.mk. Trust: a server-named installer handler is honored only if allowlisted in the immutable supported_hardware.json, maps to a fixed dm-verity-protected .so path, is ABI/id-checked, and every payload is sha256-verified before a handler runs.
70 lines
2.1 KiB
C++
70 lines
2.1 KiB
C++
/*
|
|
* Copyright (C) 2026 oxmc / PawletOS
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include "handlers.h"
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include "util.h"
|
|
|
|
namespace pawlet::hwupdate {
|
|
namespace {
|
|
|
|
constexpr char kHandlerDir[] = "/system_ext/lib64/pawlet/hwh/";
|
|
|
|
// Handler ids come from the local allowlist; still, only accept a conservative
|
|
// character set so the id can never escape kHandlerDir.
|
|
bool ValidId(const std::string& id) {
|
|
if (id.empty() || id.size() > 64) return false;
|
|
for (char c : id) {
|
|
bool ok = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
(c >= '0' && c <= '9') || c == '_' || c == '-';
|
|
if (!ok) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
const pawlet_hwh_api* HandlerRegistry::Get(const std::string& id) {
|
|
if (auto it = cache_.find(id); it != cache_.end()) return it->second;
|
|
|
|
if (!ValidId(id)) {
|
|
LOG(ERROR) << "hwupdate: rejecting invalid handler id '" << id << "'";
|
|
return nullptr;
|
|
}
|
|
|
|
std::string path = std::string(kHandlerDir) + "libpawlethwh_" + id + ".so";
|
|
void* dl = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
|
|
if (!dl) {
|
|
LOG(ERROR) << "hwupdate: dlopen(" << path << ") failed: " << dlerror();
|
|
return nullptr;
|
|
}
|
|
|
|
auto entry = reinterpret_cast<const pawlet_hwh_api* (*)()>(dlsym(dl, "pawlet_hwh_entry"));
|
|
if (!entry) {
|
|
LOG(ERROR) << "hwupdate: " << path << " missing pawlet_hwh_entry";
|
|
dlclose(dl);
|
|
return nullptr;
|
|
}
|
|
|
|
const pawlet_hwh_api* api = entry();
|
|
if (!api || api->abi_version != PAWLET_HWH_ABI || !api->handler_id ||
|
|
!util::IEquals(api->handler_id, id) || !api->detect || !api->get_version ||
|
|
!api->flash) {
|
|
LOG(ERROR) << "hwupdate: " << path << " failed ABI/id validation";
|
|
dlclose(dl);
|
|
return nullptr;
|
|
}
|
|
|
|
LOG(INFO) << "hwupdate: loaded handler '" << id << "' (abi " << api->abi_version << ")";
|
|
// Intentionally keep dl open for the daemon's lifetime.
|
|
cache_[id] = api;
|
|
return api;
|
|
}
|
|
|
|
} // namespace pawlet::hwupdate
|