diff options
| author | 2017-02-03 13:40:04 -0800 | |
|---|---|---|
| committer | 2017-02-10 17:19:52 -0800 | |
| commit | b24760fd49d6475885eb4edae7b2f42888d5e30f (patch) | |
| tree | 8699084af503bcc10c903f9eb6b693dfed086669 | |
| parent | 270fff6a7c6c80ad24c20be9fbf152fcfdf61758 (diff) | |
Fix permissions for lshal
Instead of IServiceManager::debugDump, lshal now relies
on list and get. lshal itself will call getDebugInfo
on each interface, so that each interface can check if
the call is from a root user, then decide to leak
addresses or not.
Bug: 34899586
Test: lshal
Change-Id: I8eb9168c3b071b8b1f27dbeaa0ac27d2067200d7
| -rw-r--r-- | cmds/lshal/lshal.cpp | 156 |
1 files changed, 104 insertions, 52 deletions
diff --git a/cmds/lshal/lshal.cpp b/cmds/lshal/lshal.cpp index bc5eaf24c5..07cd9f44a6 100644 --- a/cmds/lshal/lshal.cpp +++ b/cmds/lshal/lshal.cpp @@ -28,16 +28,20 @@ #include <android/hidl/manager/1.0/IServiceManager.h> #include <hidl/ServiceManagement.h> -template <typename A, typename B, typename C, typename D, typename E> +using ::android::hardware::hidl_string; + +template <typename A, typename B, typename C, typename D, typename E, typename F> void printColumn(std::stringstream &stream, - const A &a, const B &b, const C &c, const D &d, const E &e) { + const A &a, const B &b, const C &c, const D &d, const E &, const F &f) { using namespace ::std; stream << left << setw(70) << a << "\t" << setw(20) << b << "\t" << setw(10) << c << "\t" << setw(5) << d << "\t" - << setw(0) << e + // TODO(b/34984175): enable selecting columns + // << setw(16) << e << "\t" + << setw(0) << f << endl; } @@ -47,12 +51,20 @@ std::string toHexString(uint64_t t) { return os.str(); } -::android::status_t getReferencedPids( +std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) { + const char *pos = strchr(s.c_str(), c); + if (pos == nullptr) { + return {s, {}}; + } + return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)}; +} + +bool getReferencedPids( pid_t serverPid, std::map<uint64_t, std::string> *objects) { std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid)); if (!ifs.is_open()) { - return ::android::PERMISSION_DENIED; + return false; } static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+"); @@ -77,66 +89,106 @@ std::string toHexString(uint64_t t) { (*objects)[ptr] += line.substr(pos + proc.size()); } } - return ::android::OK; + return true; } - -int dump() { +void dumpBinderized(std::stringstream &stream, const std::string &mode, + const sp<IServiceManager> &manager) { using namespace ::std; using namespace ::android::hardware; using namespace ::android::hidl::manager::V1_0; - - std::map<std::string, ::android::sp<IServiceManager>> mapping = { - {"hwbinder", defaultServiceManager()}, - {"passthrough", getPassthroughServiceManager()} - }; - - std::stringstream stream; - - stream << "All services:" << endl; - stream << left; - printColumn(stream, "Interface", "Instance", "Transport", "Server", "Clients"); - - for (const auto &pair : mapping) { - const std::string &mode = pair.first; - const ::android::sp<IServiceManager> &manager = pair.second; - - if (manager == nullptr) { - cerr << "Failed to get IServiceManager for " << mode << "!" << endl; - continue; - } - - auto ret = manager->debugDump([&](const auto ®istered) { - // server pid, .ptr value of binder object, child pids - std::map<pid_t, std::map<uint64_t, std::string>> allPids; - for (const auto &info : registered) { - if (info.pid < 0) { - continue; - } - pid_t serverPid = info.pid; - allPids[serverPid].clear(); + using namespace ::android::hidl::base::V1_0; + auto listRet = manager->list([&] (const auto &fqInstanceNames) { + // server pid, .ptr value of binder object, child pids + std::map<std::string, DebugInfo> allDebugInfos; + std::map<pid_t, std::map<uint64_t, std::string>> allPids; + for (const auto &fqInstanceName : fqInstanceNames) { + const auto pair = split(fqInstanceName, '/'); + const auto &serviceName = pair.first; + const auto &instanceName = pair.second; + auto getRet = manager->get(serviceName, instanceName); + if (!getRet.isOk()) { + cerr << "Warning: Skipping \"" << fqInstanceName << "\": " + << "cannot be fetched from service manager:" + << getRet.description() << endl; + continue; } - for (auto &pair : allPids) { - pid_t serverPid = pair.first; - if (getReferencedPids(serverPid, &allPids[serverPid]) != ::android::OK) { - std::cerr << "Warning: no information for PID " << serverPid - << ", are you root?" << std::endl; + sp<IBase> service = getRet; + if (service == nullptr) { + cerr << "Warning: Skipping \"" << fqInstanceName << "\": " + << "cannot be fetched from service manager (null)"; + continue; + } + auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) { + allDebugInfos[fqInstanceName] = debugInfo; + if (debugInfo.pid >= 0) { + allPids[static_cast<pid_t>(debugInfo.pid)].clear(); } + }); + if (!debugRet.isOk()) { + cerr << "Warning: Skipping \"" << fqInstanceName << "\": " + << "debugging information cannot be retrieved:" + << debugRet.description() << endl; + } + } + for (auto &pair : allPids) { + pid_t serverPid = pair.first; + if (!getReferencedPids(serverPid, &allPids[serverPid])) { + std::cerr << "Warning: no information for PID " << serverPid + << ", are you root?" << std::endl; } - for (const auto &info : registered) { + } + for (const auto &fqInstanceName : fqInstanceNames) { + const auto pair = split(fqInstanceName, '/'); + const auto &serviceName = pair.first; + const auto &instanceName = pair.second; + auto it = allDebugInfos.find(fqInstanceName); + if (it == allDebugInfos.end()) { printColumn(stream, - info.interfaceName, - info.instanceName.empty() ? "N/A" : info.instanceName, + serviceName, + instanceName, mode, - info.pid < 0 ? "N/A" : std::to_string(info.pid), - info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]); + "N/A", + "N/A", + "" + ); + continue; } - }); - if (!ret.isOk()) { - cerr << "Failed to list services for " << mode << ": " - << ret.description() << endl; + const DebugInfo &info = it->second; + printColumn(stream, + serviceName, + instanceName, + mode, + info.pid < 0 ? "N/A" : std::to_string(info.pid), + info.ptr == 0 ? "N/A" : toHexString(info.ptr), + info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr] + ); } + + }); + if (!listRet.isOk()) { + cerr << "Error: Failed to list services for " << mode << ": " + << listRet.description() << endl; + } +} + +int dump() { + using namespace ::std; + using namespace ::android::hardware; + + std::stringstream stream; + + stream << "All services:" << endl; + stream << left; + printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients"); + + auto bManager = defaultServiceManager(); + if (bManager == nullptr) { + cerr << "Failed to get defaultServiceManager()!" << endl; + } else { + dumpBinderized(stream, "hwbinder", bManager); } + cout << stream.rdbuf(); return 0; } |