From 824d894822a5ddfc5b2dbbb7e2ca8ba1c3a94794 Mon Sep 17 00:00:00 2001 From: Sandboxed API Team Date: Fri, 19 Jan 2024 16:27:34 -0800 Subject: [PATCH] Make sandbox2::SyscallTable::GetEntry public and add new helper GetEntries. PiperOrigin-RevId: 599967495 Change-Id: Iae524c2c9b2829cbdcd51117134223d08e993a01 --- sandboxed_api/sandbox2/BUILD.bazel | 5 +- sandboxed_api/sandbox2/syscall_defs.cc | 117 +++++++++++-------------- sandboxed_api/sandbox2/syscall_defs.h | 50 ++++++++++- 3 files changed, 105 insertions(+), 67 deletions(-) diff --git a/sandboxed_api/sandbox2/BUILD.bazel b/sandboxed_api/sandbox2/BUILD.bazel index fe94b11..71d7994 100644 --- a/sandboxed_api/sandbox2/BUILD.bazel +++ b/sandboxed_api/sandbox2/BUILD.bazel @@ -109,15 +109,18 @@ cc_library( srcs = [ "syscall.cc", "syscall_defs.cc", + ], + hdrs = [ + "syscall.h", "syscall_defs.h", ], - hdrs = ["syscall.h"], copts = sapi_platform_copts(), visibility = ["//visibility:public"], deps = [ ":util", "//sandboxed_api:config", "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", diff --git a/sandboxed_api/sandbox2/syscall_defs.cc b/sandboxed_api/sandbox2/syscall_defs.cc index af5a84d..7925c1f 100644 --- a/sandboxed_api/sandbox2/syscall_defs.cc +++ b/sandboxed_api/sandbox2/syscall_defs.cc @@ -8,6 +8,7 @@ #include #include "absl/algorithm/container.h" +#include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" @@ -18,56 +19,15 @@ namespace sandbox2 { -// Type of a given syscall argument. Used with argument conversion routines. -enum ArgType { - kGen = 1, - kInt, - kPath, - kHex, - kOct, - kSocketCall, - kSocketCallPtr, - kSignal, - kString, - kAddressFamily, - kSockaddr, - kSockmsghdr, - kCloneFlag, -}; - -// Single syscall definition -struct SyscallTable::Entry { - // Returns the number of arguments which given syscall takes. - int GetNumArgs() const { - if (num_args < 0 || num_args > syscalls::kMaxArgs) { - return syscalls::kMaxArgs; - } - return num_args; - } - - static std::string GetArgumentDescription(uint64_t value, ArgType type, - pid_t pid); - - static constexpr bool BySyscallNr(const SyscallTable::Entry& a, - const SyscallTable::Entry& b) { - return a.nr < b.nr; - } - - int nr; - absl::string_view name; - int num_args; - std::array arg_types; -}; - std::string SyscallTable::Entry::GetArgumentDescription(uint64_t value, - ArgType type, + syscalls::ArgType type, pid_t pid) { std::string ret = absl::StrFormat("%#x", value); switch (type) { - case kOct: + case syscalls::kOct: absl::StrAppendFormat(&ret, " [\\0%o]", value); break; - case kPath: + case syscalls::kPath: if (auto path_or = util::ReadCPathFromPid(pid, value); path_or.ok()) { absl::StrAppendFormat(&ret, " ['%s']", absl::CHexEscape(path_or.value())); @@ -75,7 +35,7 @@ std::string SyscallTable::Entry::GetArgumentDescription(uint64_t value, absl::StrAppend(&ret, " [unreadable path]"); } break; - case kInt: + case syscalls::kInt: absl::StrAppendFormat(&ret, " [%d]", value); break; default: @@ -85,14 +45,11 @@ std::string SyscallTable::Entry::GetArgumentDescription(uint64_t value, } absl::string_view SyscallTable::GetName(int syscall) const { - auto it = absl::c_lower_bound( - data_, syscall, [](const SyscallTable::Entry& entry, int syscall) { - return entry.nr < syscall; - }); - if (it == data_.end() || it->nr != syscall) { + auto entry = GetEntry(syscall); + if (!entry.ok()) { return ""; } - return it->name; + return entry->name; } namespace { @@ -108,32 +65,61 @@ constexpr SyscallTable::Entry MakeEntry(int nr, absl::string_view name, struct UnknownArguments {}; constexpr SyscallTable::Entry MakeEntry(int nr, absl::string_view name, UnknownArguments) { - return {nr, name, -1, {kGen, kGen, kGen, kGen, kGen, kGen}}; + return {nr, + name, + -1, + {syscalls::kGen, syscalls::kGen, syscalls::kGen, syscalls::kGen, + syscalls::kGen, syscalls::kGen}}; } } // namespace +absl::StatusOr SyscallTable::GetEntry(int syscall) const { + auto it = absl::c_lower_bound( + data_, syscall, [](const SyscallTable::Entry& entry, int syscall) { + return entry.nr < syscall; + }); + if (it == data_.end() || it->nr != syscall) { + return absl::NotFoundError(absl::StrCat("Syscall not found: ", syscall)); + } + return *it; +} + +absl::StatusOr SyscallTable::GetEntry( + absl::string_view name) const { + // Note: There's no uniqueness guarantee of syscall names in the table, but + // other than typos it's likely safe to assume uniqueness. + auto filter = [name](const SyscallTable::Entry& entry) { + return entry.name == name; + }; + auto it = absl::c_find_if(data_, filter); + if (it != data_.end()) { + return *it; + } else { + return absl::NotFoundError(absl::StrCat("Name not found: ", name)); + } +} + std::vector SyscallTable::GetArgumentsDescription( int syscall, const uint64_t values[], pid_t pid) const { static SyscallTable::Entry kInvalidEntry = MakeEntry(-1, "", UnknownArguments()); - auto it = absl::c_lower_bound( - data_, syscall, [](const SyscallTable::Entry& entry, int syscall) { - return entry.nr < syscall; - }); - const auto& entry = - it != data_.end() && it->nr == syscall ? *it : kInvalidEntry; + auto entry = GetEntry(syscall); + if (!entry.ok()) { + entry = kInvalidEntry; + } - int num_args = entry.GetNumArgs(); + int num_args = entry->GetNumArgs(); std::vector rv; rv.reserve(num_args); for (int i = 0; i < num_args; ++i) { rv.push_back(SyscallTable::Entry::GetArgumentDescription( - values[i], entry.arg_types[i], pid)); + values[i], entry->arg_types[i], pid)); } return rv; } +namespace syscalls { namespace { // TODO(C++20) Use std::is_sorted @@ -1894,19 +1880,20 @@ static_assert(IsSorted(kSyscallDataArm32, SyscallTable::Entry::BySyscallNr), "Syscalls should be sorted"); } // namespace +} // namespace syscalls SyscallTable SyscallTable::get(sapi::cpu::Architecture arch) { switch (arch) { case sapi::cpu::kX8664: - return SyscallTable(kSyscallDataX8664); + return SyscallTable(syscalls::kSyscallDataX8664); case sapi::cpu::kX86: - return SyscallTable(kSyscallDataX8632); + return SyscallTable(syscalls::kSyscallDataX8632); case sapi::cpu::kPPC64LE: - return SyscallTable(kSyscallDataPPC64LE); + return SyscallTable(syscalls::kSyscallDataPPC64LE); case sapi::cpu::kArm64: - return SyscallTable(kSyscallDataArm64); + return SyscallTable(syscalls::kSyscallDataArm64); case sapi::cpu::kArm: - return SyscallTable(kSyscallDataArm32); + return SyscallTable(syscalls::kSyscallDataArm32); default: return SyscallTable(); } diff --git a/sandboxed_api/sandbox2/syscall_defs.h b/sandboxed_api/sandbox2/syscall_defs.h index a5e7fc3..d3ff653 100644 --- a/sandboxed_api/sandbox2/syscall_defs.h +++ b/sandboxed_api/sandbox2/syscall_defs.h @@ -3,10 +3,12 @@ #include +#include #include #include #include +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "sandboxed_api/config.h" @@ -17,11 +19,51 @@ namespace syscalls { constexpr int kMaxArgs = 6; +// Type of a given syscall argument. Used with argument conversion routines. +enum ArgType { + kGen = 1, + kInt, + kPath, + kHex, + kOct, + kSocketCall, + kSocketCallPtr, + kSignal, + kString, + kAddressFamily, + kSockaddr, + kSockmsghdr, + kCloneFlag, +}; + } // namespace syscalls class SyscallTable { public: - struct Entry; + // Single syscall definition + struct Entry { + // Returns the number of arguments which given syscall takes. + int GetNumArgs() const { + if (num_args < 0 || num_args > syscalls::kMaxArgs) { + return syscalls::kMaxArgs; + } + return num_args; + } + + static std::string GetArgumentDescription(uint64_t value, + syscalls::ArgType type, + pid_t pid); + + static constexpr bool BySyscallNr(const SyscallTable::Entry& a, + const SyscallTable::Entry& b) { + return a.nr < b.nr; + } + + int nr; + absl::string_view name; + int num_args; + std::array arg_types; + }; // Returns the syscall table for the architecture. static SyscallTable get(sapi::cpu::Architecture arch); @@ -34,6 +76,12 @@ class SyscallTable { const uint64_t values[], pid_t pid) const; + absl::StatusOr GetEntry(int syscall) const; + // Returns the first entry matching the provided name. + absl::StatusOr GetEntry(std::string_view name) const; + + absl::Span GetEntries() const { return data_; } + private: constexpr SyscallTable() = default; explicit constexpr SyscallTable(absl::Span data) : data_(data) {}