mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Added more descriptive Syscall argument types, and an API for introspecting arguments.
PiperOrigin-RevId: 612904089 Change-Id: Ia0ef7b0559f7eed923981b13fa8224bc891e8c37
This commit is contained in:
parent
1f390c279e
commit
c6bab97690
|
@ -136,6 +136,7 @@ cc_library(
|
||||||
deps = [
|
deps = [
|
||||||
":util",
|
":util",
|
||||||
"//sandboxed_api:config",
|
"//sandboxed_api:config",
|
||||||
|
"//sandboxed_api/util:status",
|
||||||
"@com_google_absl//absl/algorithm:container",
|
"@com_google_absl//absl/algorithm:container",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/status:statusor",
|
"@com_google_absl//absl/status:statusor",
|
||||||
|
@ -799,6 +800,8 @@ cc_library(
|
||||||
"//sandboxed_api/util:file_helpers",
|
"//sandboxed_api/util:file_helpers",
|
||||||
"//sandboxed_api/util:fileops",
|
"//sandboxed_api/util:fileops",
|
||||||
"//sandboxed_api/util:raw_logging",
|
"//sandboxed_api/util:raw_logging",
|
||||||
|
"//sandboxed_api/util:status",
|
||||||
|
"@com_google_absl//absl/algorithm:container",
|
||||||
"@com_google_absl//absl/base:core_headers",
|
"@com_google_absl//absl/base:core_headers",
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
"@com_google_absl//absl/status:statusor",
|
"@com_google_absl//absl/status:statusor",
|
||||||
|
|
|
@ -90,6 +90,7 @@ target_link_libraries(sandbox2_syscall
|
||||||
absl::strings
|
absl::strings
|
||||||
sandbox2::util
|
sandbox2::util
|
||||||
sapi::base
|
sapi::base
|
||||||
|
sapi::status
|
||||||
PUBLIC absl::log
|
PUBLIC absl::log
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -687,7 +688,8 @@ add_library(sandbox2_util ${SAPI_LIB_TYPE}
|
||||||
)
|
)
|
||||||
add_library(sandbox2::util ALIAS sandbox2_util)
|
add_library(sandbox2::util ALIAS sandbox2_util)
|
||||||
target_link_libraries(sandbox2_util
|
target_link_libraries(sandbox2_util
|
||||||
PRIVATE absl::core_headers
|
PRIVATE absl::algorithm_container
|
||||||
|
absl::core_headers
|
||||||
absl::str_format
|
absl::str_format
|
||||||
absl::strings
|
absl::strings
|
||||||
sapi::config
|
sapi::config
|
||||||
|
@ -696,6 +698,7 @@ target_link_libraries(sandbox2_util
|
||||||
sapi::fileops
|
sapi::fileops
|
||||||
sapi::base
|
sapi::base
|
||||||
sapi::raw_logging
|
sapi::raw_logging
|
||||||
|
sapi::status
|
||||||
PUBLIC absl::status
|
PUBLIC absl::status
|
||||||
absl::statusor
|
absl::statusor
|
||||||
)
|
)
|
||||||
|
|
|
@ -74,6 +74,10 @@ std::string Syscall::GetName() const {
|
||||||
return absl::StrFormat("UNKNOWN[%d/0x%x]", nr_, nr_);
|
return absl::StrFormat("UNKNOWN[%d/0x%x]", nr_, nr_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<syscalls::ArgData> Syscall::GetArgumentsData() const {
|
||||||
|
return SyscallTable::get(arch_).GetArgumentsData(nr_, args_.data(), pid_);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> Syscall::GetArgumentsDescription() const {
|
std::vector<std::string> Syscall::GetArgumentsDescription() const {
|
||||||
return SyscallTable::get(arch_).GetArgumentsDescription(nr_, args_.data(),
|
return SyscallTable::get(arch_).GetArgumentsDescription(nr_, args_.data(),
|
||||||
pid_);
|
pid_);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "sandboxed_api/config.h" // IWYU pragma: export
|
#include "sandboxed_api/config.h" // IWYU pragma: export
|
||||||
|
#include "sandboxed_api/sandbox2/syscall_defs.h"
|
||||||
|
|
||||||
namespace sandbox2 {
|
namespace sandbox2 {
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ class Syscall {
|
||||||
uint64_t instruction_pointer() const { return ip_; }
|
uint64_t instruction_pointer() const { return ip_; }
|
||||||
|
|
||||||
std::string GetName() const;
|
std::string GetName() const;
|
||||||
|
std::vector<syscalls::ArgData> GetArgumentsData() const;
|
||||||
std::vector<std::string> GetArgumentsDescription() const;
|
std::vector<std::string> GetArgumentsDescription() const;
|
||||||
std::string GetDescription() const;
|
std::string GetDescription() const;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,36 +4,200 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/status/status.h"
|
||||||
#include "absl/status/statusor.h"
|
#include "absl/status/statusor.h"
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/types/span.h"
|
#include "absl/types/span.h"
|
||||||
#include "sandboxed_api/config.h"
|
#include "sandboxed_api/config.h"
|
||||||
#include "sandboxed_api/sandbox2/syscall.h"
|
#include "sandboxed_api/sandbox2/util.h"
|
||||||
|
#include "sandboxed_api/util/status_macros.h"
|
||||||
|
|
||||||
namespace sandbox2 {
|
namespace sandbox2 {
|
||||||
namespace syscalls {
|
namespace syscalls {
|
||||||
|
|
||||||
constexpr int kMaxArgs = 6;
|
constexpr int kMaxArgs = 6;
|
||||||
|
|
||||||
// Type of a given syscall argument. Used with argument conversion routines.
|
|
||||||
enum ArgType {
|
enum ArgType {
|
||||||
kGen = 1,
|
|
||||||
kInt,
|
|
||||||
kPath,
|
kPath,
|
||||||
kHex,
|
|
||||||
kOct,
|
|
||||||
kSocketCall,
|
|
||||||
kSocketCallPtr,
|
|
||||||
kSignal,
|
|
||||||
kString,
|
kString,
|
||||||
|
kGen,
|
||||||
|
kStruct,
|
||||||
|
kPtr,
|
||||||
|
kArray,
|
||||||
|
kInt,
|
||||||
|
kFlags,
|
||||||
|
kResource,
|
||||||
|
kPid,
|
||||||
|
kSignal,
|
||||||
|
kIpcResource,
|
||||||
|
kSharedAddress,
|
||||||
|
kGid,
|
||||||
|
kUid,
|
||||||
|
// These kLenN types indicate that the argument is a length, and which
|
||||||
|
// other argument it applies to. I.e., if parameter 3 is type kPollFdArray,
|
||||||
|
// and parameter 4 has the length, then parameter 4 is of type kLen3.
|
||||||
|
kLen0,
|
||||||
|
kLen1,
|
||||||
|
kLen2,
|
||||||
|
kLen3,
|
||||||
|
kLen4,
|
||||||
|
kLen5,
|
||||||
kAddressFamily,
|
kAddressFamily,
|
||||||
|
kGidArray,
|
||||||
|
kPollFdArray,
|
||||||
kSockaddr,
|
kSockaddr,
|
||||||
kSockmsghdr,
|
};
|
||||||
kCloneFlag,
|
|
||||||
|
constexpr absl::string_view ArgTypeToString(ArgType type) {
|
||||||
|
switch (type) {
|
||||||
|
case kPath:
|
||||||
|
return "path";
|
||||||
|
case kString:
|
||||||
|
return "string";
|
||||||
|
case kGen:
|
||||||
|
return "generic type";
|
||||||
|
case kStruct:
|
||||||
|
return "struct";
|
||||||
|
case kPtr:
|
||||||
|
return "pointer";
|
||||||
|
case kArray:
|
||||||
|
return "array";
|
||||||
|
case kInt:
|
||||||
|
return "int";
|
||||||
|
case kFlags:
|
||||||
|
return "flags";
|
||||||
|
case kResource:
|
||||||
|
return "resource";
|
||||||
|
case kPid:
|
||||||
|
return "pid";
|
||||||
|
case kSignal:
|
||||||
|
return "signal";
|
||||||
|
case kIpcResource:
|
||||||
|
return "ipc resource";
|
||||||
|
case kSharedAddress:
|
||||||
|
return "shared address";
|
||||||
|
case kGid:
|
||||||
|
return "gid";
|
||||||
|
case kUid:
|
||||||
|
return "uid";
|
||||||
|
case kLen0:
|
||||||
|
return "length of parameter 0";
|
||||||
|
case kLen1:
|
||||||
|
return "length of parameter 1";
|
||||||
|
case kLen2:
|
||||||
|
return "length of parameter 2";
|
||||||
|
case kLen3:
|
||||||
|
return "length of parameter 3";
|
||||||
|
case kLen4:
|
||||||
|
return "length of parameter 4";
|
||||||
|
case kLen5:
|
||||||
|
return "length of parameter 5";
|
||||||
|
case kAddressFamily:
|
||||||
|
return "address family";
|
||||||
|
case kGidArray:
|
||||||
|
return "gid array";
|
||||||
|
case kPollFdArray:
|
||||||
|
return "poll fd array";
|
||||||
|
case kSockaddr:
|
||||||
|
return "sockaddr struct";
|
||||||
|
default:
|
||||||
|
return "invalid type";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArgData {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
struct StructArray {
|
||||||
|
std::vector<T> array;
|
||||||
|
bool truncated;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArgData(syscalls::ArgType type, pid_t pid, uint64_t value,
|
||||||
|
std::optional<uint64_t> length = std::nullopt)
|
||||||
|
: type_(type), pid_(pid), value_(value), length_(length) {}
|
||||||
|
|
||||||
|
ArgType type() const { return type_; }
|
||||||
|
pid_t pid() const { return pid_; }
|
||||||
|
uint64_t value() const { return value_; }
|
||||||
|
std::optional<uint64_t> length() const { return length_; }
|
||||||
|
|
||||||
|
std::string GetDescription() const;
|
||||||
|
|
||||||
|
absl::StatusOr<std::string> ReadAsString() const {
|
||||||
|
return util::ReadCPathFromPid(pid_, value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
absl::StatusOr<T> ReadAsStruct() const {
|
||||||
|
if (length_.has_value() && *length_ < sizeof(T)) {
|
||||||
|
return absl::InternalError(absl::StrFormat(
|
||||||
|
"specified length [%llu] is not enough for to sizeof(%s) == %llu",
|
||||||
|
*length_, typeid(T).name(), sizeof(T)));
|
||||||
|
}
|
||||||
|
SAPI_ASSIGN_OR_RETURN(std::vector<uint8_t> b,
|
||||||
|
util::ReadBytesFromPid(pid_, value_, sizeof(T)));
|
||||||
|
return BytesToStruct<T>(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
absl::StatusOr<StructArray<T>> ReadAsStructArray() const {
|
||||||
|
static uint64_t kMaxAllowedBytes = 1 << 20; // 1MB
|
||||||
|
|
||||||
|
if (!length_.has_value()) {
|
||||||
|
return absl::InternalError("length is not set");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool truncated = false;
|
||||||
|
uint64_t length = *length_ * sizeof(T);
|
||||||
|
if (length > kMaxAllowedBytes) {
|
||||||
|
truncated = true;
|
||||||
|
length = (kMaxAllowedBytes / sizeof(T)) * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAPI_ASSIGN_OR_RETURN(std::vector<uint8_t> b,
|
||||||
|
util::ReadBytesFromPid(pid_, value_, length));
|
||||||
|
absl::Span<const uint8_t> bytes = absl::MakeSpan(b);
|
||||||
|
if (bytes.size() < length) {
|
||||||
|
return absl::InternalError("could not read full struct array");
|
||||||
|
}
|
||||||
|
std::vector<T> ret;
|
||||||
|
for (size_t i = 0; i < bytes.size(); i += sizeof(T)) {
|
||||||
|
SAPI_ASSIGN_OR_RETURN(T t, BytesToStruct<T>(bytes.subspan(i, sizeof(T))));
|
||||||
|
ret.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return StructArray<T>{std::move(ret), truncated};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
static absl::StatusOr<T> BytesToStruct(absl::Span<const uint8_t> bytes) {
|
||||||
|
static_assert(std::is_pod<T>(), "Can only cast bytes to POD structs");
|
||||||
|
if (bytes.size() < sizeof(T)) {
|
||||||
|
return absl::InternalError(absl::StrFormat(
|
||||||
|
"bytes size [%llu] is not equal to sizeof(%s) == %llu", bytes.size(),
|
||||||
|
typeid(T).name(), sizeof(T)));
|
||||||
|
}
|
||||||
|
T t;
|
||||||
|
memcpy(&t, bytes.data(), sizeof(T));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::StatusOr<std::string> GetDescriptionImpl() const;
|
||||||
|
|
||||||
|
syscalls::ArgType type_;
|
||||||
|
pid_t pid_;
|
||||||
|
uint64_t value_;
|
||||||
|
std::optional<uint64_t> length_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace syscalls
|
} // namespace syscalls
|
||||||
|
@ -50,10 +214,6 @@ class SyscallTable {
|
||||||
return num_args;
|
return num_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetArgumentDescription(uint64_t value,
|
|
||||||
syscalls::ArgType type,
|
|
||||||
pid_t pid);
|
|
||||||
|
|
||||||
static constexpr bool BySyscallNr(const SyscallTable::Entry& a,
|
static constexpr bool BySyscallNr(const SyscallTable::Entry& a,
|
||||||
const SyscallTable::Entry& b) {
|
const SyscallTable::Entry& b) {
|
||||||
return a.nr < b.nr;
|
return a.nr < b.nr;
|
||||||
|
@ -72,6 +232,10 @@ class SyscallTable {
|
||||||
|
|
||||||
absl::string_view GetName(int syscall) const;
|
absl::string_view GetName(int syscall) const;
|
||||||
|
|
||||||
|
std::vector<syscalls::ArgData> GetArgumentsData(int syscall,
|
||||||
|
const uint64_t values[],
|
||||||
|
pid_t pid) const;
|
||||||
|
|
||||||
std::vector<std::string> GetArgumentsDescription(int syscall,
|
std::vector<std::string> GetArgumentsDescription(int syscall,
|
||||||
const uint64_t values[],
|
const uint64_t values[],
|
||||||
pid_t pid) const;
|
pid_t pid) const;
|
||||||
|
|
|
@ -14,15 +14,18 @@
|
||||||
|
|
||||||
#include "sandboxed_api/sandbox2/util.h"
|
#include "sandboxed_api/sandbox2/util.h"
|
||||||
|
|
||||||
|
#include <linux/limits.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <csetjmp>
|
#include <csetjmp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -33,6 +36,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/algorithm/container.h"
|
||||||
#include "absl/base/attributes.h"
|
#include "absl/base/attributes.h"
|
||||||
#include "absl/base/macros.h"
|
#include "absl/base/macros.h"
|
||||||
#include "absl/base/optimization.h"
|
#include "absl/base/optimization.h"
|
||||||
|
@ -51,7 +55,7 @@
|
||||||
#include "sandboxed_api/util/fileops.h"
|
#include "sandboxed_api/util/fileops.h"
|
||||||
#include "sandboxed_api/util/path.h"
|
#include "sandboxed_api/util/path.h"
|
||||||
#include "sandboxed_api/util/raw_logging.h"
|
#include "sandboxed_api/util/raw_logging.h"
|
||||||
|
#include "sandboxed_api/util/status_macros.h"
|
||||||
namespace sandbox2::util {
|
namespace sandbox2::util {
|
||||||
|
|
||||||
namespace file = ::sapi::file;
|
namespace file = ::sapi::file;
|
||||||
|
@ -137,6 +141,19 @@ std::string GetProgName(pid_t pid) {
|
||||||
return file_util::fileops::Basename(file_util::fileops::ReadLink(fname));
|
return file_util::fileops::Basename(file_util::fileops::ReadLink(fname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::StatusOr<std::string> GetResolvedFdLink(pid_t pid, uint32_t fd) {
|
||||||
|
// The proc/PID/fd directory contains links for all of that process' file
|
||||||
|
// descriptors. They'll show up as more informative strings (paths, sockets).
|
||||||
|
std::string fd_path = absl::StrFormat("/proc/%u/fd/%u", pid, fd);
|
||||||
|
std::string result(PATH_MAX, '\0');
|
||||||
|
ssize_t size = readlink(fd_path.c_str(), &result[0], PATH_MAX);
|
||||||
|
if (size < 0) {
|
||||||
|
return absl::ErrnoToStatus(size, "failed to read link");
|
||||||
|
}
|
||||||
|
result.resize(size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetCmdLine(pid_t pid) {
|
std::string GetCmdLine(pid_t pid) {
|
||||||
std::string fname = file::JoinPath("/proc", absl::StrCat(pid), "cmdline");
|
std::string fname = file::JoinPath("/proc", absl::StrCat(pid), "cmdline");
|
||||||
std::string cmdline;
|
std::string cmdline;
|
||||||
|
@ -326,6 +343,29 @@ std::string GetSignalName(int signo) {
|
||||||
return absl::StrFormat("%s [%d]", kSignalNames[signo], signo);
|
return absl::StrFormat("%s [%d]", kSignalNames[signo], signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetAddressFamily(int addr_family) {
|
||||||
|
// Taken from definitions in `socket.h`. Each family's index in the array is
|
||||||
|
// also its integer value.
|
||||||
|
constexpr absl::string_view kAddressFamilies[] = {
|
||||||
|
"AF_UNSPEC", "AF_UNIX", "AF_INET", "AF_AX25",
|
||||||
|
"AF_IPX", "AF_APPLETALK", "AF_NETROM", "AF_BRIDGE",
|
||||||
|
"AF_ATMPVC", "AF_X25", "AF_INET6", "AF_ROSE",
|
||||||
|
"AF_DECnet", "AF_NETBEUI", "AF_SECURITY", "AF_KEY",
|
||||||
|
"AF_NETLINK", "AF_PACKET", "AF_ASH", "AF_ECONET",
|
||||||
|
"AF_ATMSVC", "AF_RDS", "AF_SNA", "AF_IRDA",
|
||||||
|
"AF_PPPOX", "AF_WANPIPE", "AF_LLC", "AF_IB",
|
||||||
|
"AF_MPLS", "AF_CAN", "AF_TIPC", "AF_BLUETOOTH",
|
||||||
|
"AF_IUCV", "AF_RXRPC", "AF_ISDN", "AF_PHONET",
|
||||||
|
"AF_IEEE802154", "AF_CAIF", "AF_ALG", "AF_NFC",
|
||||||
|
"AF_VSOCK", "AF_KCM", "AF_QIPCRTR", "AF_SMC",
|
||||||
|
"AF_XDP", "AF_MCTP"};
|
||||||
|
|
||||||
|
if (addr_family < 0 && addr_family >= ABSL_ARRAYSIZE(kAddressFamilies)) {
|
||||||
|
return absl::StrFormat("UNKNOWN_ADDRESS_FAMILY [%d]", addr_family);
|
||||||
|
}
|
||||||
|
return std::string(kAddressFamilies[addr_family]);
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetRlimitName(int resource) {
|
std::string GetRlimitName(int resource) {
|
||||||
switch (resource) {
|
switch (resource) {
|
||||||
case RLIMIT_AS:
|
case RLIMIT_AS:
|
||||||
|
@ -370,45 +410,53 @@ std::string GetPtraceEventName(int event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr) {
|
absl::StatusOr<std::vector<uint8_t>> ReadBytesFromPid(pid_t pid, uintptr_t ptr,
|
||||||
std::string path(PATH_MAX, '\0');
|
uint64_t size) {
|
||||||
iovec local_iov[] = {{&path[0], path.size()}};
|
|
||||||
|
|
||||||
static const uintptr_t page_size = getpagesize();
|
static const uintptr_t page_size = getpagesize();
|
||||||
static const uintptr_t page_mask = ~(page_size - 1);
|
static const uintptr_t page_mask = page_size - 1;
|
||||||
// See 'man process_vm_readv' for details on how to read NUL-terminated
|
|
||||||
// strings with this syscall.
|
// Input sanity checks.
|
||||||
size_t len1 = ((ptr + page_size) & page_mask) - ptr;
|
if (size == 0) {
|
||||||
len1 = (len1 > path.size()) ? path.size() : len1;
|
return std::vector<uint8_t>();
|
||||||
size_t len2 = (path.size() <= len1) ? 0UL : path.size() - len1;
|
|
||||||
// Second iov is wrapping around to NULL ptr.
|
|
||||||
if ((ptr + len1) < ptr) {
|
|
||||||
len2 = 0UL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec remote_iov[] = {
|
// Allocate enough bytes to hold the entire size.
|
||||||
{reinterpret_cast<void*>(ptr), len1},
|
std::vector<uint8_t> bytes(size, 0);
|
||||||
{reinterpret_cast<void*>(ptr + len1), len2},
|
iovec local_iov[] = {{bytes.data(), bytes.size()}};
|
||||||
};
|
// Stores all the necessary iovecs to move memory.
|
||||||
|
std::vector<iovec> remote_iov;
|
||||||
|
// Each iovec should be contained to a single page.
|
||||||
|
size_t consumed = 0;
|
||||||
|
while (consumed < size) {
|
||||||
|
// Read till the end of the page, at most the remaining number of bytes.
|
||||||
|
size_t chunk_size =
|
||||||
|
std::min(size - consumed, page_size - ((ptr + consumed) & page_mask));
|
||||||
|
remote_iov.push_back({reinterpret_cast<void*>(ptr + consumed), chunk_size});
|
||||||
|
consumed += chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
SAPI_RAW_VLOG(4, "ReadCPathFromPid (iovec): len1: %zu, len2: %zu", len1,
|
ssize_t result = process_vm_readv(pid, local_iov, ABSL_ARRAYSIZE(local_iov),
|
||||||
len2);
|
remote_iov.data(), remote_iov.size(), 0);
|
||||||
if (process_vm_readv(pid, local_iov, ABSL_ARRAYSIZE(local_iov), remote_iov,
|
if (result < 0) {
|
||||||
ABSL_ARRAYSIZE(remote_iov), 0) < 0) {
|
|
||||||
return absl::ErrnoToStatus(
|
return absl::ErrnoToStatus(
|
||||||
errno,
|
errno,
|
||||||
absl::StrFormat("process_vm_readv() failed for PID: %d at address: %#x",
|
absl::StrFormat("process_vm_readv() failed for PID: %d at address: %#x",
|
||||||
pid, reinterpret_cast<uintptr_t>(ptr)));
|
pid, ptr));
|
||||||
}
|
}
|
||||||
|
// Ensure only successfully read bytes are returned.
|
||||||
|
bytes.resize(result);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for whether there's a NUL byte in the buffer. If not, it's an
|
absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr) {
|
||||||
// incorrect path (or >PATH_MAX).
|
SAPI_ASSIGN_OR_RETURN(std::vector<uint8_t> bytes,
|
||||||
auto pos = path.find('\0');
|
ReadBytesFromPid(pid, ptr, PATH_MAX));
|
||||||
if (pos == std::string::npos) {
|
auto null_pos = absl::c_find(bytes, '\0');
|
||||||
return absl::FailedPreconditionError(absl::StrCat(
|
std::string path(bytes.begin(), null_pos);
|
||||||
"No NUL-byte inside the C string '", absl::CHexEscape(path), "'"));
|
if (null_pos == bytes.end()) {
|
||||||
|
return absl::FailedPreconditionError(
|
||||||
|
absl::StrFormat("path '%s' is too long", absl::CHexEscape(path)));
|
||||||
}
|
}
|
||||||
path.resize(pos);
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,9 @@ inline void CharPtrArrToVecString(char* const* arr,
|
||||||
// Returns the program name (via /proc/self/comm) for a given PID.
|
// Returns the program name (via /proc/self/comm) for a given PID.
|
||||||
std::string GetProgName(pid_t pid);
|
std::string GetProgName(pid_t pid);
|
||||||
|
|
||||||
|
// Given a resource descriptor FD and a PID, returns link of /proc/PID/fds/FD.
|
||||||
|
absl::StatusOr<std::string> GetResolvedFdLink(pid_t pid, uint32_t fd);
|
||||||
|
|
||||||
// Returns the command line (via /proc/self/cmdline) for a given PID. The
|
// Returns the command line (via /proc/self/cmdline) for a given PID. The
|
||||||
// argument separators '\0' are converted to spaces.
|
// argument separators '\0' are converted to spaces.
|
||||||
std::string GetCmdLine(pid_t pid);
|
std::string GetCmdLine(pid_t pid);
|
||||||
|
@ -95,12 +98,19 @@ absl::StatusOr<int> Communicate(const std::vector<std::string>& argv,
|
||||||
// Returns signal description.
|
// Returns signal description.
|
||||||
std::string GetSignalName(int signo);
|
std::string GetSignalName(int signo);
|
||||||
|
|
||||||
|
// Returns the socket address family as a string ("AF_INET", ...)
|
||||||
|
std::string GetAddressFamily(int addr_family);
|
||||||
|
|
||||||
// Returns rlimit resource name
|
// Returns rlimit resource name
|
||||||
std::string GetRlimitName(int resource);
|
std::string GetRlimitName(int resource);
|
||||||
|
|
||||||
// Returns ptrace event name
|
// Returns ptrace event name
|
||||||
std::string GetPtraceEventName(int event);
|
std::string GetPtraceEventName(int event);
|
||||||
|
|
||||||
|
// Reads `size` bytes from the given `ptr` address, or returns an error.
|
||||||
|
absl::StatusOr<std::vector<uint8_t>> ReadBytesFromPid(pid_t pid, uintptr_t ptr,
|
||||||
|
uint64_t size);
|
||||||
|
|
||||||
// Reads a path string (NUL-terminated, shorter than PATH_MAX) from another
|
// Reads a path string (NUL-terminated, shorter than PATH_MAX) from another
|
||||||
// process memory
|
// process memory
|
||||||
absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr);
|
absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user