mumble-voip_mumble/plugins/HostLinux.cpp

162 lines
3.4 KiB
C++

// Copyright 2020-2023 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "HostLinux.h"
#include "mumble_positional_audio_utils.h"
#include <cstring>
#include <libgen.h>
#include <sstream>
#include <sys/uio.h>
HostLinux::HostLinux(const procid_t pid) : m_pid(pid) {
}
HostLinux::~HostLinux() {
}
bool HostLinux::peek(const procptr_t address, void *dst, const size_t size) const {
iovec in;
in.iov_base = reinterpret_cast< void * >(address);
in.iov_len = size;
iovec out;
out.iov_base = dst;
out.iov_len = size;
const auto ret = process_vm_readv(m_pid, &out, 1, &in, 1, 0);
return (ret != -1 && static_cast< size_t >(ret) == in.iov_len);
}
Modules HostLinux::modules() const {
std::ostringstream path;
path << "/proc/";
path << m_pid;
path << "/maps";
const auto maps = readFile(path.str());
if (maps.size() == 0) {
return {};
}
Modules modules;
std::string name;
std::stringstream stream(maps);
while (stream) {
auto ret = readUntil(stream, '-');
if (!ret.second) {
return modules;
}
MemoryRegion region;
region.address = std::stoull(ret.first, nullptr, 16);
ret = readUntil(stream, ' ');
if (!ret.second) {
return modules;
}
region.size = std::stoull(ret.first, nullptr, 16) - region.address;
ret = readUntil(stream, ' ');
if (!ret.second) {
return modules;
}
for (const auto character : ret.first) {
switch (character) {
case 'r':
region.readable = true;
break;
case 'w':
region.writable = true;
break;
case 'x':
region.executable = true;
break;
}
}
// Skip offset, dev and inode
for (uint8_t i = 0; i < 3; ++i) {
if (!skipUntil(stream, ' ', false)) {
return modules;
}
}
// Eat spaces until we're at the beginning of the path
if (!skipUntil(stream, ' ', true)) {
return modules;
}
// Throw up last eaten character
stream.unget();
ret = readUntil(stream, '\n');
if (!ret.second) {
return modules;
}
if (ret.first.size() == 0) {
// Anonymous region, let's add it to the module that owns the previous one
if (!name.empty()) {
auto iter = modules.find(name);
iter->second.addRegion(region);
}
continue;
}
// Only treat path as a real path if it starts with "/"
if (ret.first[0] != '/') {
continue;
}
const auto lastSlashPos = ret.first.find_last_of('/');
if (ret.first.size() > lastSlashPos + 1) {
name = ret.first.substr(lastSlashPos + 1);
const auto iter = modules.find(name);
if (iter != modules.cend()) {
iter->second.addRegion(region);
} else {
Module module(name);
module.addRegion(region);
modules.insert(std::make_pair(name, module));
}
}
}
return modules;
}
bool HostLinux::isWine(const procid_t id) {
std::ostringstream ss;
ss << "/proc/";
ss << id;
ss << "/exe";
char *path = realpath(ss.str().c_str(), nullptr);
if (!path) {
return false;
}
const char *filename = basename(path);
if (!filename) {
return false;
}
const auto ret = strcmp(filename, "wine-preloader") == 0 || strcmp(filename, "wine64-preloader") == 0;
// basename() returns a pointer to the basename's position in the string passed as argument.
// For that reason we cannot free 'path' before performing the check.
free(path);
return ret;
}