/* * Copyright (C) 2026 oxmc / PawletOS * SPDX-License-Identifier: Apache-2.0 */ #include "handlers.h" #include #include #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(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