Add support for ARM32 (hard float target)

This change enables support for 32-bit ARM, as used by embedded controllers and older phones.
Note: This does not support 32-bit sandboxees on AArch64. Both sandboxee and host code must have the same bitness.
PiperOrigin-RevId: 347835193
Change-Id: I6395882677530f9862f118d2dc10230a61049836
pull/75/head
Anton D. Kachalov 2020-12-16 09:17:53 -08:00 committed by Copybara-Service
parent 324ab5974c
commit d0c8224e61
20 changed files with 576 additions and 77 deletions

View File

@ -83,6 +83,23 @@ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
list(APPEND _unwind_ptrace_srcs
${_unwind_src}/src/aarch64/Ginit_remote.c
)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
set(_unwind_cpu "arm")
list(APPEND _unwind_platform_srcs
${_unwind_src}/src/arm/Gcreate_addr_space.c
${_unwind_src}/src/arm/Gex_tables.c
${_unwind_src}/src/arm/Gglobal.c
${_unwind_src}/src/arm/Ginit.c
${_unwind_src}/src/arm/Gis_signal_frame.c
${_unwind_src}/src/arm/Gregs.c
${_unwind_src}/src/arm/Gresume.c
${_unwind_src}/src/arm/Gstash_frame.c
${_unwind_src}/src/arm/Gstep.c
${_unwind_src}/src/arm/is_fpreg.c
)
list(APPEND _unwind_ptrace_srcs
${_unwind_src}/src/arm/Ginit_remote.c
)
endif()
add_library(unwind_ptrace_wrapped STATIC
@ -165,6 +182,7 @@ add_library(unwind::unwind_ptrace_wrapped ALIAS unwind_ptrace_wrapped)
target_include_directories(unwind_ptrace_wrapped PUBLIC
${_unwind_src}/include
${_unwind_src}/include/tdep
${_unwind_src}/include/tdep-${_unwind_cpu}
${_unwind_src}/src
)
target_compile_options(unwind_ptrace_wrapped PRIVATE

View File

@ -55,15 +55,14 @@ ffi_type* GetFFIType(size_t size, v::Type type) {
case v::Type::kFd:
return &ffi_type_sint;
case v::Type::kFloat:
switch (size) {
case sizeof(float):
return &ffi_type_float;
case sizeof(double):
return &ffi_type_double;
case sizeof(long double):
return &ffi_type_longdouble;
default:
LOG(FATAL) << "Unknown floating-point size: " << size;
if (size == sizeof(float)) {
return &ffi_type_float;
} else if (size == sizeof(double)) {
return &ffi_type_double;
} else if (size == sizeof(long double)) {
return &ffi_type_longdouble;
} else {
LOG(FATAL) << "Unknown floating-point size: " << size;
}
case v::Type::kInt:
switch (size) {

View File

@ -32,6 +32,11 @@
// Spellings for AArch64
#elif defined(__aarch64__) || defined(_M_ARM64)
#define SAPI_ARM64 1
// 32-bit ARM
#elif defined(__arm__) || defined(_M_ARM)
#define SAPI_ARM 1
#endif
namespace sandbox2 {
@ -48,6 +53,7 @@ enum Architecture : uint16_t {
kX86,
kPPC64LE,
kArm64,
kArm,
};
} // namespace cpu
@ -63,6 +69,8 @@ constexpr cpu::Architecture Architecture() {
return cpu::kPPC64LE;
#elif defined(SAPI_ARM64)
return cpu::kArm64;
#elif defined(SAPI_ARM)
return cpu::kArm;
#else
return cpu::kUnknown;
#endif
@ -74,11 +82,15 @@ constexpr bool IsPPC64LE() { return Architecture() == cpu::kPPC64LE; }
constexpr bool IsArm64() { return Architecture() == cpu::kArm64; }
constexpr bool IsArm() { return Architecture() == cpu::kArm; }
constexpr bool Is64Bit() { return sizeof(uintptr_t) == 8; }
} // namespace host_cpu
static_assert(host_cpu::Architecture() != cpu::kUnknown,
"Host CPU architecture is not supported: One of x86-64, POWER64 "
"(little endian) or AArch64 is required.");
"(little endian), Arm or AArch64 is required.");
} // namespace sandbox2

View File

@ -115,6 +115,7 @@ absl::Status ValidateInterpreter(absl::string_view interpreter) {
"/lib64/ld-linux-x86-64.so.2",
"/lib64/ld64.so.2", // PPC64
"/lib/ld-linux-aarch64.so.1", // AArch64
"/lib/ld-linux-armhf.so.3", // Arm
};
if (!allowed_interpreters.contains(interpreter)) {

View File

@ -55,6 +55,12 @@ constexpr int kRegSyscall = 8;
constexpr int kRegArg0 = 0;
constexpr int kRegArg1 = 1;
constexpr int kRegArg2 = 2;
#elif defined(SAPI_ARM)
constexpr int kRegResult = 0;
constexpr int kRegSyscall = 8;
constexpr int kRegArg0 = 0;
constexpr int kRegArg1 = 1;
constexpr int kRegArg2 = 2;
#endif
int NetworkProxyClient::ConnectHandler(int sockfd, const struct sockaddr* addr,
@ -173,6 +179,8 @@ void NetworkProxyHandler::ProcessSeccompTrap(int nr, siginfo_t* info,
auto* registers = ctx->uc_mcontext.gp_regs;
#elif defined(SAPI_ARM64)
auto* registers = ctx->uc_mcontext.regs;
#elif defined(SAPI_ARM)
auto* registers = &ctx->uc_mcontext.arm_r0;
#endif
int syscall = registers[kRegSyscall];

View File

@ -145,6 +145,8 @@ std::vector<sock_filter> Policy::GetTrackingPolicy() const {
JEQ32(AUDIT_ARCH_PPC64LE, TRACE(cpu::kPPC64LE)),
#elif defined(SAPI_ARM64)
JEQ32(AUDIT_ARCH_AARCH64, TRACE(cpu::kArm64)),
#elif defined(SAPI_ARM)
JEQ32(AUDIT_ARCH_ARM, TRACE(cpu::kArm)),
#endif
TRACE(cpu::kUnknown),
};

View File

@ -280,25 +280,53 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
std::vector<std::string> args = {path};
auto executor = absl::make_unique<Executor>(path, args);
auto policy =
PolicyBuilder()
auto policy = PolicyBuilder()
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.AllowStaticStartup()
.AllowTcMalloc()
.AllowExit()
.AddPolicyOnSyscalls(
{__NR_getuid, __NR_getgid, __NR_geteuid, __NR_getegid}, {ALLOW})
.AddPolicyOnSyscalls({__NR_getresuid, __NR_getresgid}, {ERRNO(42)})
.AddPolicyOnSyscalls({__NR_read, __NR_write}, {ERRNO(43)})
.AddPolicyOnSyscall(__NR_umask, {DENY})
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.AllowStaticStartup()
.AllowTcMalloc()
.AllowExit()
.AddPolicyOnSyscalls(
{
__NR_getuid,
__NR_getgid,
__NR_geteuid,
__NR_getegid,
#ifdef __NR_getuid32
__NR_getuid32,
#endif
#ifdef __NR_getgid32
__NR_getgid32,
#endif
#ifdef __NR_geteuid32
__NR_geteuid32,
#endif
#ifdef __NR_getegid32
__NR_getegid32,
#endif
},
{ALLOW})
.AddPolicyOnSyscalls(
{
__NR_getresuid,
__NR_getresgid,
#ifdef __NR_getresuid32
__NR_getresuid32,
#endif
#ifdef __NR_getresgid32
__NR_getresgid32,
#endif
},
{ERRNO(42)})
.AddPolicyOnSyscalls({__NR_read, __NR_write}, {ERRNO(43)})
.AddPolicyOnSyscall(__NR_umask, {DENY})
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
.BuildOrDie();
.BuildOrDie();
Sandbox2 s2(std::move(executor), std::move(policy));
auto result = s2.Run();

View File

@ -428,7 +428,9 @@ PolicyBuilder& PolicyBuilder::AllowGetPIDs() {
PolicyBuilder& PolicyBuilder::AllowGetRlimit() {
return AllowSyscalls({
#ifdef __NR_getrlimit
__NR_getrlimit,
#endif
#ifdef __NR_ugetrlimit
__NR_ugetrlimit,
#endif
@ -437,7 +439,9 @@ PolicyBuilder& PolicyBuilder::AllowGetRlimit() {
PolicyBuilder& PolicyBuilder::AllowSetRlimit() {
return AllowSyscalls({
#ifdef __NR_setrlimit
__NR_setrlimit,
#endif
#ifdef __NR_usetrlimit
__NR_usetrlimit,
#endif
@ -504,13 +508,16 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
AllowGetRlimit();
AllowSyscalls({
// These syscalls take a pointer, so no restriction.
__NR_uname,
__NR_brk,
__NR_set_tid_address,
__NR_uname, __NR_brk, __NR_set_tid_address,
// This syscall takes a pointer and a length.
// We could restrict length, but it might change, so not worth it.
__NR_set_robust_list,
#if defined(__ARM_NR_set_tls)
// libc sets the TLS during startup
__ARM_NR_set_tls,
#endif
// This syscall takes a pointer and a length.
// We could restrict length, but it might change, so not worth it.
__NR_set_robust_list,
});
AllowFutexOp(FUTEX_WAIT_BITSET);
@ -543,6 +550,13 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
BlockSyscallWithErrno(__NR_readlink, ENOENT);
#endif
if constexpr (host_cpu::IsArm()) {
AddPolicyOnSyscall(__NR_mprotect, {
ARG_32(2),
JEQ32(PROT_READ, ALLOW),
});
}
return *this;
}

View File

@ -93,8 +93,8 @@ TEST_F(PolicyBuilderTest, Testpolicy_size) {
builder.AllowSyscall(__NR_chroot); assert_increased();
builder.AllowSyscall(__NR_chroot); assert_same();
builder.AllowSyscall(__NR_mmap); assert_increased();
builder.AllowSyscall(__NR_mmap); assert_same();
builder.AllowSyscall(__NR_umask); assert_increased();
builder.AllowSyscall(__NR_umask); assert_same();
builder.AllowSyscall(__NR_chroot); assert_same();
builder.AllowSyscall(__NR_chroot); assert_same();
@ -120,8 +120,8 @@ TEST_F(PolicyBuilderTest, Testpolicy_size) {
builder.AddPolicyOnSyscalls({ }, { ALLOW }); assert_increased();
// This might change in the future if we implement an optimization.
builder.AddPolicyOnSyscall(__NR_mmap, { ALLOW }); assert_increased();
builder.AddPolicyOnSyscall(__NR_mmap, { ALLOW }); assert_increased();
builder.AddPolicyOnSyscall(__NR_umask, { ALLOW }); assert_increased();
builder.AddPolicyOnSyscall(__NR_umask, { ALLOW }); assert_increased();
// None of the namespace functions should alter the seccomp policy.
builder.AddFile("/usr/bin/find"); assert_same();

View File

@ -42,7 +42,8 @@ absl::Status Regs::Fetch() {
") failed: ", StrError(errno)));
}
#endif
if constexpr (host_cpu::IsPPC64LE() || host_cpu::IsArm64()) {
if constexpr (host_cpu::IsPPC64LE() || host_cpu::IsArm64() ||
host_cpu::IsArm()) {
iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
if (ptrace(PTRACE_GETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
@ -85,7 +86,8 @@ absl::Status Regs::Store() {
") failed: ", StrError(errno)));
}
#endif
if constexpr (host_cpu::IsPPC64LE() || host_cpu::IsArm64()) {
if constexpr (host_cpu::IsPPC64LE() || host_cpu::IsArm64() ||
host_cpu::IsArm()) {
iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
if (ptrace(PTRACE_SETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
@ -108,7 +110,7 @@ absl::Status Regs::Store() {
return absl::OkStatus();
}
absl::Status Regs::SkipSyscallReturnValue(uint64_t value) {
absl::Status Regs::SkipSyscallReturnValue(uintptr_t value) {
#if defined(SAPI_X86_64)
user_regs_.orig_rax = -1;
user_regs_.rax = value;
@ -118,6 +120,9 @@ absl::Status Regs::SkipSyscallReturnValue(uint64_t value) {
#elif defined(SAPI_ARM64)
user_regs_.regs[0] = -1;
syscall_number_ = value;
#elif defined(SAPI_ARM)
user_regs_.orig_x0 = -1;
user_regs_.regs[7] = value;
#endif
return Store();
}
@ -168,6 +173,16 @@ Syscall Regs::ToSyscall(cpu::Architecture syscall_arch) const {
auto ip = user_regs_.pc;
return Syscall(syscall_arch, syscall_number_, args, pid_, sp, ip);
}
#elif defined(SAPI_ARM)
if (ABSL_PREDICT_TRUE(syscall_arch == cpu::kArm)) {
Syscall::Args args = {
user_regs_.orig_x0, user_regs_.regs[1], user_regs_.regs[2],
user_regs_.regs[3], user_regs_.regs[4], user_regs_.regs[5],
};
auto sp = user_regs_.regs[13];
auto ip = user_regs_.pc;
return Syscall(syscall_arch, user_regs_.regs[7], args, pid_, sp, ip);
}
#endif
return Syscall(pid_);
}
@ -231,6 +246,14 @@ void Regs::StoreRegisterValuesInProtobuf(RegisterValues* values) const {
regs->set_sp(user_regs_.sp);
regs->set_pc(user_regs_.pc);
regs->set_pstate(user_regs_.pstate);
#elif defined(SAPI_ARM)
RegisterArm* regs = values->mutable_register_arm();
for (int i = 0; i < ABSL_ARRAYSIZE(user_regs_.regs); ++i) {
regs->add_regs(user_regs_.regs[i]);
}
regs->set_pc(user_regs_.pc);
regs->set_cpsr(user_regs_.cpsr);
regs->set_orig_x0(user_regs_.orig_x0);
#endif
}

View File

@ -43,7 +43,7 @@ class Regs {
absl::Status Store();
// Causes the process to skip current syscall and return given value instead
absl::Status SkipSyscallReturnValue(uint64_t value);
absl::Status SkipSyscallReturnValue(uintptr_t value);
// Converts raw register values obtained on syscall entry to syscall info
Syscall ToSyscall(cpu::Architecture syscall_arch) const;
@ -110,6 +110,11 @@ class Regs {
uint64_t sp;
uint64_t pc;
uint64_t pstate;
#elif defined(SAPI_ARM)
uint32_t regs[15];
uint32_t pc;
uint32_t cpsr;
uint32_t orig_x0;
#else
static_assert(false, "Host CPU architecture not supported, see config.h");
#endif

View File

@ -85,6 +85,9 @@ std::unique_ptr<Policy> StackTracePeer::GetPolicy(pid_t target_pid,
// libunwind
.AllowSyscall(__NR_fstat)
#ifdef __NR_fstat64
.AllowSyscall(__NR_fstat64)
#endif
.AllowSyscall(__NR_lseek)
#ifdef __NR__llseek
.AllowSyscall(__NR__llseek) // Newer glibc on PPC

View File

@ -44,6 +44,8 @@ std::string Syscall::GetArchDescription(cpu::Architecture arch) {
return "[PPC-64]";
case cpu::kArm64:
return "[Arm-64]";
case cpu::kArm:
return "[Arm-32]";
default:
LOG(ERROR) << "Unknown CPU architecture: " << arch;
return absl::StrFormat("[UNKNOWN_ARCH:%d]", arch);
@ -58,6 +60,8 @@ uint32_t Syscall::GetHostAuditArch() {
return AUDIT_ARCH_PPC64LE;
case cpu::kArm64:
return AUDIT_ARCH_AARCH64;
case cpu::kArm:
return AUDIT_ARCH_ARM;
default:
// The static_assert() in config.h should prevent us from ever getting
// here.

View File

@ -1524,6 +1524,368 @@ constexpr std::array kSyscallDataArm64 = {
static_assert(IsSorted(kSyscallDataArm64, SyscallTable::Entry::BySyscallNr),
"Syscalls should be sorted");
constexpr std::array kSyscallDataArm32 = {
// clang-format off
MakeEntry(0, "restart_syscall", kGen, kGen, kGen, kGen),
MakeEntry(1, "exit", kHex, kHex, kHex, kHex),
MakeEntry(2, "fork", kGen, kGen, kGen, kGen),
MakeEntry(3, "read", kInt, kHex, kInt),
MakeEntry(4, "write", kHex, kHex, kHex, kHex),
MakeEntry(5, "open", kPath, kHex, kOct),
MakeEntry(6, "close", kHex, kHex, kHex, kHex),
MakeEntry(8, "creat", kPath, kHex, kHex, kHex),
MakeEntry(9, "link", kPath, kPath),
MakeEntry(10, "unlink", kPath),
MakeEntry(11, "execve", kPath, kHex, kHex),
MakeEntry(12, "chdir", kPath),
MakeEntry(14, "mknod", kPath, kOct, kHex),
MakeEntry(15, "chmod", kPath, kOct),
MakeEntry(16, "lchown", kPath, kInt, kInt),
MakeEntry(19, "lseek", kGen, kGen, kGen, kGen),
MakeEntry(20, "getpid", kGen, kGen, kGen, kGen),
MakeEntry(21, "mount", kHex, kHex, kHex, kHex),
MakeEntry(23, "setuid", kGen, kGen, kGen, kGen),
MakeEntry(24, "getuid", kGen, kGen, kGen, kGen),
MakeEntry(26, "ptrace", kGen, kGen, kGen),
MakeEntry(29, "pause", kGen, kGen, kGen, kGen),
MakeEntry(33, "access", kPath, kHex),
MakeEntry(34, "nice", kHex, kHex, kHex, kHex),
MakeEntry(36, "sync", kGen, kGen, kGen, kGen),
MakeEntry(37, "kill", kHex, kHex, kHex, kHex),
MakeEntry(38, "rename", kPath, kPath),
MakeEntry(39, "mkdir", kPath, kHex, kHex, kHex),
MakeEntry(40, "rmdir", kHex, kHex, kHex, kHex),
MakeEntry(41, "dup", kGen, kGen, kGen, kGen),
MakeEntry(42, "pipe", kGen, kGen, kGen, kGen),
MakeEntry(43, "times", kGen, kGen, kGen, kGen),
MakeEntry(45, "brk", kHex),
MakeEntry(46, "setgid", kGen, kGen, kGen, kGen),
MakeEntry(47, "getgid", kGen, kGen, kGen, kGen),
MakeEntry(49, "geteuid", kGen, kGen, kGen, kGen),
MakeEntry(50, "getegid", kGen, kGen, kGen, kGen),
MakeEntry(51, "acct", kHex, kHex, kHex, kHex),
MakeEntry(52, "umount2", kHex, kHex, kHex, kHex),
MakeEntry(54, "ioctl", kGen, kGen, kGen, kGen),
MakeEntry(55, "fcntl", kGen, kGen, kGen, kGen),
MakeEntry(57, "setpgid", kGen, kGen, kGen, kGen),
MakeEntry(60, "umask", kHex),
MakeEntry(61, "chroot", kHex, kHex, kHex, kHex),
MakeEntry(62, "ustat", kGen, kGen, kGen, kGen),
MakeEntry(63, "dup2", kGen, kGen),
MakeEntry(64, "getppid", kGen, kGen, kGen, kGen),
MakeEntry(65, "getpgrp", kGen, kGen, kGen, kGen),
MakeEntry(66, "setsid", kGen, kGen, kGen, kGen),
MakeEntry(67, "sigaction", kHex, kHex, kHex, kHex),
MakeEntry(70, "setreuid", kGen, kGen, kGen, kGen),
MakeEntry(71, "setregid", kGen, kGen, kGen, kGen),
MakeEntry(72, "sigsuspend", kHex, kHex, kHex, kHex),
MakeEntry(73, "sigpending", kHex, kHex, kHex, kHex),
MakeEntry(74, "sethostname", kGen, kGen, kGen, kGen),
MakeEntry(75, "setrlimit", kGen, kGen, kGen, kGen),
MakeEntry(77, "getrusage", kGen, kGen, kGen, kGen),
MakeEntry(78, "gettimeofday", kHex, kHex),
MakeEntry(79, "settimeofday", kHex, kHex),
MakeEntry(80, "getgroups", kGen, kGen, kGen, kGen),
MakeEntry(81, "setgroups", kGen, kGen, kGen, kGen),
MakeEntry(83, "symlink", kPath, kPath),
MakeEntry(85, "readlink", kPath, kGen, kInt),
MakeEntry(86, "uselib", kPath),
MakeEntry(87, "swapon", kHex, kHex, kHex, kHex),
MakeEntry(88, "reboot", kGen, kGen, kGen, kGen),
MakeEntry(91, "munmap", kHex, kHex),
MakeEntry(92, "truncate", kPath, kHex, kHex, kHex),
MakeEntry(93, "ftruncate", kGen, kGen, kGen, kGen),
MakeEntry(94, "fchmod", kGen, kGen, kGen, kGen),
MakeEntry(95, "fchown", kGen, kGen, kGen, kGen),
MakeEntry(96, "getpriority", kGen, kGen, kGen, kGen),
MakeEntry(97, "setpriority", kGen, kGen, kGen, kGen),
MakeEntry(99, "statfs", kPath, kGen, kGen, kGen),
MakeEntry(100, "fstatfs", kGen, kGen, kGen, kGen),
MakeEntry(103, "syslog", kGen, kGen, kGen, kGen),
MakeEntry(104, "setitimer", kGen, kGen, kGen, kGen),
MakeEntry(105, "getitimer", kGen, kGen, kGen, kGen),
MakeEntry(106, "stat", kPath, kGen),
MakeEntry(107, "lstat", kPath, kGen),
MakeEntry(108, "fstat", kHex, kHex, kHex, kHex),
MakeEntry(111, "vhangup", kGen, kGen, kGen, kGen),
MakeEntry(114, "wait4", kHex, kHex, kHex, kHex),
MakeEntry(115, "swapoff", kHex, kHex, kHex, kHex),
MakeEntry(116, "sysinfo", kGen, kGen, kGen, kGen),
MakeEntry(118, "fsync", kGen, kGen, kGen, kGen),
MakeEntry(119, "sigreturn", kHex, kHex, kHex, kHex),
MakeEntry(120, "clone", kCloneFlag, kHex, kHex, kHex),
MakeEntry(121, "setdomainname", kGen, kGen, kGen, kGen),
MakeEntry(122, "uname", kGen, kGen, kGen, kGen),
MakeEntry(124, "adjtimex", kGen, kGen, kGen, kGen),
MakeEntry(125, "mprotect", kHex, kHex, kHex),
MakeEntry(126, "sigprocmask", kHex, kHex, kHex, kHex),
MakeEntry(128, "init_module", kGen, kGen, kGen, kGen),
MakeEntry(129, "delete_module", kGen, kGen, kGen, kGen),
MakeEntry(131, "quotactl", kHex, kHex, kHex, kHex),
MakeEntry(132, "getpgid", kGen, kGen, kGen, kGen),
MakeEntry(133, "fchdir", kGen, kGen, kGen, kGen),
MakeEntry(134, "bdflush", kHex, kHex, kHex, kHex),
MakeEntry(135, "sysfs", kGen, kGen, kGen, kGen),
MakeEntry(136, "personality", kGen, kGen, kGen, kGen),
MakeEntry(138, "setfsuid", kGen, kGen, kGen, kGen),
MakeEntry(139, "setfsgid", kGen, kGen, kGen, kGen),
MakeEntry(140, "_llseek", kHex, kHex, kHex, kHex),
MakeEntry(141, "getdents", kGen, kGen, kGen, kGen),
MakeEntry(142, "_newselect", kHex, kHex, kHex, kHex),
MakeEntry(143, "flock", kGen, kGen, kGen, kGen),
MakeEntry(144, "msync", kGen, kGen, kGen, kGen),
MakeEntry(145, "readv", kGen, kGen, kGen, kGen),
MakeEntry(146, "writev", kGen, kGen, kGen, kGen),
MakeEntry(147, "getsid", kGen, kGen, kGen, kGen),
MakeEntry(148, "fdatasync", kGen, kGen, kGen, kGen),
MakeEntry(149, "_sysctl", kGen, kGen, kGen, kGen),
MakeEntry(150, "mlock", kGen, kGen, kGen, kGen),
MakeEntry(151, "munlock", kGen, kGen, kGen, kGen),
MakeEntry(152, "mlockall", kGen, kGen, kGen, kGen),
MakeEntry(153, "munlockall", kGen, kGen, kGen, kGen),
MakeEntry(154, "sched_setparam", kGen, kGen, kGen, kGen),
MakeEntry(155, "sched_getparam", kGen, kGen, kGen, kGen),
MakeEntry(156, "sched_setscheduler", kGen, kGen, kGen, kGen),
MakeEntry(157, "sched_getscheduler", kGen, kGen, kGen, kGen),
MakeEntry(158, "sched_yield", kGen, kGen, kGen, kGen),
MakeEntry(159, "sched_get_priority_max", kGen, kGen, kGen, kGen),
MakeEntry(160, "sched_get_priority_min", kGen, kGen, kGen, kGen),
MakeEntry(161, "sched_rr_get_interval", kGen, kGen, kGen, kGen),
MakeEntry(162, "nanosleep", kHex, kHex),
MakeEntry(163, "mremap", kGen, kGen, kGen, kGen),
MakeEntry(164, "setresuid", kGen, kGen, kGen, kGen),
MakeEntry(165, "getresuid", kGen, kGen, kGen, kGen),
MakeEntry(168, "poll", kGen, kGen, kGen, kGen),
MakeEntry(169, "nfsservctl", kGen, kGen, kGen, kGen),
MakeEntry(170, "setresgid", kGen, kGen, kGen, kGen),
MakeEntry(171, "getresgid", kGen, kGen, kGen, kGen),
MakeEntry(172, "prctl", kHex, kHex, kHex, kHex),
MakeEntry(173, "rt_sigreturn", kGen, kGen, kGen, kGen),
MakeEntry(174, "rt_sigaction", kHex, kHex, kHex, kHex),
MakeEntry(175, "rt_sigprocmask", kGen, kGen, kGen, kGen),
MakeEntry(176, "rt_sigpending", kGen, kGen, kGen, kGen),
MakeEntry(177, "rt_sigtimedwait", kGen, kGen, kGen, kGen),
MakeEntry(178, "rt_sigqueueinfo", kGen, kGen, kGen, kGen),
MakeEntry(179, "rt_sigsuspend", kGen, kGen, kGen, kGen),
MakeEntry(180, "pread64", kGen, kGen, kGen, kGen),
MakeEntry(181, "pwrite64", kGen, kGen, kGen, kGen),
MakeEntry(182, "chown", kHex, kHex, kHex, kHex),
MakeEntry(183, "getcwd", kGen, kGen, kGen, kGen),
MakeEntry(184, "capget", kGen, kGen, kGen, kGen),
MakeEntry(185, "capset", kGen, kGen, kGen, kGen),
MakeEntry(186, "sigaltstack", kGen, kGen, kGen, kGen),
MakeEntry(187, "sendfile", kGen, kGen, kGen, kGen),
MakeEntry(190, "vfork", kGen, kGen, kGen, kGen),
MakeEntry(191, "ugetrlimit", kHex, kHex, kHex, kHex),
MakeEntry(192, "mmap2", kHex, kHex, kHex, kHex),
MakeEntry(193, "truncate64", kHex, kHex, kHex, kHex),
MakeEntry(194, "ftruncate64", kHex, kHex, kHex, kHex),
MakeEntry(195, "stat64", kHex, kHex, kHex, kHex),
MakeEntry(196, "lstat64", kHex, kHex, kHex, kHex),
MakeEntry(197, "fstat64", kHex, kHex, kHex, kHex),
MakeEntry(198, "lchown32", kHex, kHex, kHex, kHex),
MakeEntry(199, "getuid32", kHex, kHex, kHex, kHex),
MakeEntry(200, "getgid32", kHex, kHex, kHex, kHex),
MakeEntry(201, "geteuid32", kHex, kHex, kHex, kHex),
MakeEntry(202, "getegid32", kHex, kHex, kHex, kHex),
MakeEntry(203, "setreuid32", kHex, kHex, kHex, kHex),
MakeEntry(204, "setregid32", kHex, kHex, kHex, kHex),
MakeEntry(205, "getgroups32", kHex, kHex, kHex, kHex),
MakeEntry(206, "setgroups32", kHex, kHex, kHex, kHex),
MakeEntry(207, "fchown32", kHex, kHex, kHex, kHex),
MakeEntry(208, "setresuid32", kHex, kHex, kHex, kHex),
MakeEntry(209, "getresuid32", kHex, kHex, kHex, kHex),
MakeEntry(210, "setresgid32", kHex, kHex, kHex, kHex),
MakeEntry(211, "getresgid32", kHex, kHex, kHex, kHex),
MakeEntry(212, "chown32", kHex, kHex, kHex, kHex),
MakeEntry(213, "setuid32", kHex, kHex, kHex, kHex),
MakeEntry(214, "setgid32", kHex, kHex, kHex, kHex),
MakeEntry(215, "setfsuid32", kHex, kHex, kHex, kHex),
MakeEntry(216, "setfsgid32", kHex, kHex, kHex, kHex),
MakeEntry(217, "getdents64", kGen, kGen, kGen, kGen),
MakeEntry(218, "pivot_root", kHex, kHex, kHex, kHex),
MakeEntry(219, "mincore", kGen, kGen, kGen, kGen),
MakeEntry(220, "madvise", kGen, kGen, kGen, kGen),
MakeEntry(221, "fcntl64", kHex, kHex, kHex, kHex),
MakeEntry(224, "gettid", kGen, kGen, kGen, kGen),
MakeEntry(225, "readahead", kGen, kGen, kGen, kGen),
MakeEntry(226, "setxattr", kHex, kHex, kHex, kHex),
MakeEntry(227, "lsetxattr", kHex, kHex, kHex, kHex),
MakeEntry(228, "fsetxattr", kGen, kGen, kGen, kGen),
MakeEntry(229, "getxattr", kHex, kHex, kHex, kHex),
MakeEntry(230, "lgetxattr", kHex, kHex, kHex, kHex),
MakeEntry(231, "fgetxattr", kGen, kGen, kGen, kGen),
MakeEntry(232, "listxattr", kHex, kHex, kHex, kHex),
MakeEntry(233, "llistxattr", kHex, kHex, kHex, kHex),
MakeEntry(234, "flistxattr", kGen, kGen, kGen, kGen),
MakeEntry(235, "removexattr", kHex, kHex, kHex, kHex),
MakeEntry(236, "lremovexattr", kGen, kGen, kGen, kGen),
MakeEntry(237, "fremovexattr", kGen, kGen, kGen, kGen),
MakeEntry(238, "tkill", kHex, kHex, kHex, kHex),
MakeEntry(239, "sendfile64", kHex, kHex, kHex, kHex),
MakeEntry(240, "futex", kGen, kGen, kGen, kGen),
MakeEntry(241, "sched_setaffinity", kGen, kGen, kGen, kGen),
MakeEntry(242, "sched_getaffinity", kGen, kGen, kGen, kGen),
MakeEntry(243, "io_setup", kGen, kGen, kGen, kGen),
MakeEntry(244, "io_destroy", kGen, kGen, kGen, kGen),
MakeEntry(245, "io_getevents", kGen, kGen, kGen, kGen),
MakeEntry(246, "io_submit", kGen, kGen, kGen, kGen),
MakeEntry(247, "io_cancel", kGen, kGen, kGen, kGen),
MakeEntry(248, "exit_group", kHex, kHex, kHex, kHex),
MakeEntry(249, "lookup_dcookie", kGen, kGen, kGen, kGen),
MakeEntry(250, "epoll_create", kGen, kGen, kGen, kGen),
MakeEntry(251, "epoll_ctl", kGen, kGen, kGen, kGen),
MakeEntry(252, "epoll_wait", kGen, kGen, kGen, kGen),
MakeEntry(253, "remap_file_pages", kGen, kGen, kGen, kGen),
MakeEntry(256, "set_tid_address", kHex),
MakeEntry(257, "timer_create", kGen, kGen, kGen, kGen),
MakeEntry(258, "timer_settime", kGen, kGen, kGen, kGen),
MakeEntry(259, "timer_gettime", kGen, kGen, kGen, kGen),
MakeEntry(260, "timer_getoverrun", kGen, kGen, kGen, kGen),
MakeEntry(261, "timer_delete", kGen, kGen, kGen, kGen),
MakeEntry(262, "clock_settime", kGen, kGen, kGen, kGen),
MakeEntry(263, "clock_gettime", kGen, kGen, kGen, kGen),
MakeEntry(264, "clock_getres", kGen, kGen, kGen, kGen),
MakeEntry(265, "clock_nanosleep", kGen, kGen, kGen, kGen),
MakeEntry(266, "statfs64", kHex, kHex, kHex, kHex),
MakeEntry(267, "fstatfs64", kHex, kHex, kHex, kHex),
MakeEntry(268, "tgkill", kHex, kHex, kHex, kHex),
MakeEntry(269, "utimes", kGen, kGen, kGen, kGen),
MakeEntry(271, "pciconfig_iobase", kHex, kHex, kHex, kHex),
MakeEntry(272, "pciconfig_read", kHex, kHex, kHex, kHex),
MakeEntry(273, "pciconfig_write", kHex, kHex, kHex, kHex),
MakeEntry(274, "mq_open", kGen, kGen, kGen, kGen),
MakeEntry(275, "mq_unlink", kGen, kGen, kGen, kGen),
MakeEntry(276, "mq_timedsend", kGen, kGen, kGen, kGen),
MakeEntry(277, "mq_timedreceive", kGen, kGen, kGen, kGen),
MakeEntry(278, "mq_notify", kGen, kGen, kGen, kGen),
MakeEntry(279, "mq_getsetattr", kGen, kGen, kGen, kGen),
MakeEntry(280, "waitid", kGen, kGen, kGen, kGen),
MakeEntry(281, "socket", kAddressFamily, kInt, kInt),
MakeEntry(282, "bind", kGen, kGen, kGen, kGen),
MakeEntry(283, "connect", kInt, kSockaddr, kInt),
MakeEntry(284, "listen", kGen, kGen, kGen, kGen),
MakeEntry(285, "accept", kGen, kGen, kGen, kGen),
MakeEntry(286, "getsockname", kGen, kGen, kGen, kGen),
MakeEntry(287, "getpeername", kGen, kGen, kGen, kGen),
MakeEntry(288, "socketpair", kGen, kGen, kGen, kGen),
MakeEntry(289, "send", kHex, kHex, kHex, kHex),
MakeEntry(290, "sendto", kInt, kGen, kInt, kHex),
MakeEntry(291, "recv", kHex, kHex, kHex, kHex),
MakeEntry(292, "recvfrom", kGen, kGen, kGen, kGen),
MakeEntry(293, "shutdown", kGen, kGen, kGen, kGen),
MakeEntry(294, "setsockopt", kGen, kGen, kGen, kGen),
MakeEntry(295, "getsockopt", kGen, kGen, kGen, kGen),
MakeEntry(296, "sendmsg", kInt, kSockmsghdr, kHex),
MakeEntry(297, "recvmsg", kGen, kGen, kGen, kGen),
MakeEntry(298, "semop", UnknownArguments()),
MakeEntry(299, "semget", UnknownArguments()),
MakeEntry(300, "semctl", UnknownArguments()),
MakeEntry(301, "msgsnd", UnknownArguments()),
MakeEntry(302, "msgrcv", UnknownArguments()),
MakeEntry(303, "msgget", UnknownArguments()),
MakeEntry(304, "msgctl", UnknownArguments()),
MakeEntry(305, "shmat", UnknownArguments()),
MakeEntry(306, "shmdt", UnknownArguments()),
MakeEntry(307, "shmget", UnknownArguments()),
MakeEntry(308, "shmctl", UnknownArguments()),
MakeEntry(309, "add_key", kGen, kGen, kGen, kGen),
MakeEntry(310, "request_key", kGen, kGen, kGen, kGen),
MakeEntry(311, "keyctl", kGen, kGen, kGen, kGen),
MakeEntry(312, "semtimedop", UnknownArguments()),
MakeEntry(313, "vserver", kHex, kHex, kHex, kHex),
MakeEntry(314, "ioprio_set", kGen, kGen, kGen, kGen),
MakeEntry(315, "ioprio_get", kGen, kGen, kGen, kGen),
MakeEntry(316, "inotify_init", kGen, kGen, kGen, kGen),
MakeEntry(317, "inotify_add_watch", kGen, kGen, kGen, kGen),
MakeEntry(318, "inotify_rm_watch", kGen, kGen, kGen, kGen),
MakeEntry(319, "mbind", kGen, kGen, kGen, kGen),
MakeEntry(320, "get_mempolicy", kGen, kGen, kGen, kGen),
MakeEntry(321, "set_mempolicy", kGen, kGen, kGen, kGen),
MakeEntry(322, "openat", kGen, kPath, kOct, kHex),
MakeEntry(323, "mkdirat", kGen, kPath),
MakeEntry(324, "mknodat", kGen, kPath),
MakeEntry(325, "fchownat", kGen, kPath),
MakeEntry(326, "futimesat", kGen, kPath),
MakeEntry(327, "fstatat64", kHex, kHex, kHex, kHex),
MakeEntry(328, "unlinkat", kGen, kPath),
MakeEntry(329, "renameat", kGen, kPath, kGen, kPath),
MakeEntry(330, "linkat", kGen, kPath, kGen, kPath),
MakeEntry(331, "symlinkat", kPath, kGen, kPath),
MakeEntry(332, "readlinkat", kGen, kPath),
MakeEntry(333, "fchmodat", kGen, kPath),
MakeEntry(334, "faccessat", kGen, kPath),
MakeEntry(335, "pselect6", kGen, kGen, kGen, kGen),
MakeEntry(336, "ppoll", kGen, kGen, kGen, kGen),
MakeEntry(337, "unshare", kGen, kGen, kGen, kGen),
MakeEntry(338, "set_robust_list", kGen, kGen),
MakeEntry(339, "get_robust_list", kGen, kGen, kGen, kGen),
MakeEntry(340, "splice", kGen, kGen, kGen, kGen),
MakeEntry(342, "tee", kGen, kGen, kGen, kGen),
MakeEntry(343, "vmsplice", kGen, kGen, kGen, kGen),
MakeEntry(344, "move_pages", kGen, kGen, kGen, kGen),
MakeEntry(345, "getcpu", kHex, kHex, kHex),
MakeEntry(346, "epoll_pwait", kGen, kGen, kGen, kGen),
MakeEntry(347, "kexec_load", kGen, kGen, kGen, kGen),
MakeEntry(348, "utimensat", kGen, kGen, kGen, kGen),
MakeEntry(349, "signalfd", kGen, kGen, kGen, kGen),
MakeEntry(350, "timerfd_create", kGen, kGen, kGen, kGen),
MakeEntry(351, "eventfd", kGen, kGen, kGen, kGen),
MakeEntry(352, "fallocate", kGen, kGen, kGen, kGen),
MakeEntry(353, "timerfd_settime", kGen, kGen, kGen, kGen),
MakeEntry(354, "timerfd_gettime", kGen, kGen, kGen, kGen),
MakeEntry(355, "signalfd4", kGen, kGen, kGen, kGen),
MakeEntry(356, "eventfd2", kGen, kGen, kGen, kGen),
MakeEntry(357, "epoll_create1", kGen, kGen, kGen, kGen),
MakeEntry(358, "dup3", kGen, kGen, kGen),
MakeEntry(359, "pipe2", kGen, kGen, kGen, kGen),
MakeEntry(360, "inotify_init1", kGen, kGen, kGen, kGen),
MakeEntry(361, "preadv", kGen, kGen, kGen, kGen),
MakeEntry(362, "pwritev", kGen, kGen, kGen, kGen),
MakeEntry(363, "rt_tgsigqueueinfo", kGen, kGen, kGen, kGen),
MakeEntry(364, "perf_event_open", kGen, kGen, kGen, kGen),
MakeEntry(365, "recvmmsg", kHex, kHex, kHex, kHex),
MakeEntry(366, "accept4", kGen, kGen, kGen, kGen),
MakeEntry(367, "fanotify_init", kHex, kHex, kHex, kHex),
MakeEntry(368, "fanotify_mark", kHex, kHex, kHex, kHex),
MakeEntry(369, "prlimit64", kHex, kHex, kHex, kHex),
MakeEntry(370, "name_to_handle_at", kHex, kHex, kHex, kHex),
MakeEntry(371, "open_by_handle_at", kHex, kHex, kHex, kHex),
MakeEntry(372, "clock_adjtime", kHex, kHex, kHex, kHex),
MakeEntry(373, "syncfs", kHex, kHex, kHex, kHex),
MakeEntry(374, "sendmmsg", kHex, kHex, kHex, kHex),
MakeEntry(375, "setns", kHex, kHex, kHex, kHex),
MakeEntry(376, "process_vm_readv", kHex, kHex, kHex, kHex),
MakeEntry(377, "process_vm_writev", kHex, kHex, kHex, kHex),
MakeEntry(378, "kcmp", kHex, kHex, kHex, kHex),
MakeEntry(379, "finit_module", kHex, kHex, kHex, kHex),
MakeEntry(380, "sched_setattr", kGen, kGen, kGen, kGen),
MakeEntry(381, "sched_getattr", kGen, kGen, kGen, kGen),
MakeEntry(382, "renameat2", kGen, kPath, kGen, kPath),
MakeEntry(383, "seccomp", kGen, kGen, kGen, kGen),
MakeEntry(384, "getrandom", kGen, kGen, kGen, kGen),
MakeEntry(385, "memfd_create", kGen, kGen, kGen, kGen),
MakeEntry(386, "bpf", kHex, kHex, kHex, kHex),
MakeEntry(387, "execveat", kHex, kHex, kHex, kHex),
MakeEntry(388, "userfaultfd", kHex),
MakeEntry(389, "membarrier", kHex, kHex),
MakeEntry(390, "mlock2", kHex, kHex, kHex, kHex),
MakeEntry(391, "copy_file_range", kHex, kHex, kHex, kHex),
MakeEntry(392, "preadv2", kHex, kHex, kHex, kHex),
MakeEntry(393, "pwritev2", kHex, kHex, kHex, kHex),
MakeEntry(400, "migrate_pages", kGen, kGen, kGen, kGen),
MakeEntry(401, "kexec_file_load", kGen, kGen, kGen, kGen),
MakeEntry(0xf0001, "ARM_breakpoint", kHex, kHex, kHex, kHex),
MakeEntry(0xf0002, "ARM_cacheflush", kHex, kHex, kHex, kHex),
MakeEntry(0xf0003, "ARM_usr26", kHex, kHex, kHex, kHex),
MakeEntry(0xf0004, "ARM_usr32", kHex, kHex, kHex, kHex),
MakeEntry(0xf0005, "ARM_set_tls", kHex, kHex, kHex, kHex),
// clang-format on
};
static_assert(IsSorted(kSyscallDataArm32, SyscallTable::Entry::BySyscallNr),
"Syscalls should be sorted");
} // namespace
SyscallTable SyscallTable::get(cpu::Architecture arch) {
@ -1536,6 +1898,8 @@ SyscallTable SyscallTable::get(cpu::Architecture arch) {
return SyscallTable(kSyscallDataPPC64LE);
case cpu::kArm64:
return SyscallTable(kSyscallDataArm64);
case cpu::kArm:
return SyscallTable(kSyscallDataArm32);
default:
return SyscallTable();
}

View File

@ -18,7 +18,10 @@
#include <syscall.h>
#include <unistd.h>
#include <cstdint>
int main(int argc, char** argv) {
syscall(__NR_personality, 1ULL, 2ULL, 3ULL, 4ULL, 5ULL, 6ULL);
syscall(__NR_personality, uintptr_t{1}, uintptr_t{2}, uintptr_t{3},
uintptr_t{4}, uintptr_t{5}, uintptr_t{6});
return 22;
}

View File

@ -127,9 +127,9 @@ ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
ABSL_ATTRIBUTE_NOINLINE
pid_t CloneAndJump(int flags, jmp_buf* env_ptr) {
uint8_t stack_buf[PTHREAD_STACK_MIN] ABSL_CACHELINE_ALIGNED;
static_assert(
host_cpu::IsX8664() || host_cpu::IsPPC64LE() || host_cpu::IsArm64(),
"Host CPU architecture not supported, see config.h");
static_assert(host_cpu::IsX8664() || host_cpu::IsPPC64LE() ||
host_cpu::IsArm64() || host_cpu::IsArm(),
"Host CPU architecture not supported, see config.h");
// Stack grows down.
void* stack = stack_buf + sizeof(stack_buf);
int r;

View File

@ -137,6 +137,7 @@ cc_library(
copts = sapi_platform_copts(),
deps = [
":strerror",
"//sandboxed_api/sandbox2:config",
"//sandboxed_api/sandbox2:util",
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:status",

View File

@ -24,6 +24,7 @@
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/util.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/raw_logging.h"
@ -31,15 +32,20 @@
namespace sandbox2 {
constexpr int kElfHeaderSize =
sizeof(Elf64_Ehdr); // Maximum size for 64-bit binaries
using ElfEhdr = std::conditional_t<host_cpu::Is64Bit(), Elf64_Ehdr, Elf32_Ehdr>;
using ElfShdr = std::conditional_t<host_cpu::Is64Bit(), Elf64_Shdr, Elf32_Shdr>;
using ElfPhdr = std::conditional_t<host_cpu::Is64Bit(), Elf64_Phdr, Elf32_Phdr>;
using ElfDyn = std::conditional_t<host_cpu::Is64Bit(), Elf64_Dyn, Elf32_Dyn>;
using ElfSym = std::conditional_t<host_cpu::Is64Bit(), Elf64_Sym, Elf32_Sym>;
constexpr int kElfHeaderSize = sizeof(ElfEhdr); // Maximum size for binaries
constexpr char kElfMagic[] =
"\x7F"
"ELF";
constexpr int kEiClassOffset = 0x04;
constexpr int kEiClass64 = 2; // 64-bit binary
constexpr int kEiClass = host_cpu::Is64Bit() ? ELFCLASS64 : ELFCLASS32;
constexpr int kEiDataOffset = 0x05;
constexpr int kEiDataLittle = 1; // Little Endian
@ -134,29 +140,29 @@ class ElfParser {
// Reads elf header.
absl::Status ReadFileHeader();
// Reads a single elf program header.
absl::StatusOr<Elf64_Phdr> ReadProgramHeader(absl::string_view src);
absl::StatusOr<ElfPhdr> ReadProgramHeader(absl::string_view src);
// Reads all elf program headers.
absl::Status ReadProgramHeaders();
// Reads a single elf section header.
absl::StatusOr<Elf64_Shdr> ReadSectionHeader(absl::string_view src);
absl::StatusOr<ElfShdr> ReadSectionHeader(absl::string_view src);
// Reads all elf section headers.
absl::Status ReadSectionHeaders();
// Reads contents of an elf section.
absl::StatusOr<std::string> ReadSectionContents(int idx);
absl::StatusOr<std::string> ReadSectionContents(
const Elf64_Shdr& section_header);
const ElfShdr& section_header);
// Reads all symbols from symtab section.
absl::Status ReadSymbolsFromSymtab(const Elf64_Shdr& symtab);
absl::Status ReadSymbolsFromSymtab(const ElfShdr& symtab);
// Reads all imported libraries from dynamic section.
absl::Status ReadImportedLibrariesFromDynamic(const Elf64_Shdr& dynamic);
absl::Status ReadImportedLibrariesFromDynamic(const ElfShdr& dynamic);
ElfFile result_;
FILE* elf_ = nullptr;
size_t file_size_ = 0;
bool elf_little_ = false;
Elf64_Ehdr file_header_;
std::vector<Elf64_Phdr> program_headers_;
std::vector<Elf64_Shdr> section_headers_;
ElfEhdr file_header_;
std::vector<ElfPhdr> program_headers_;
std::vector<ElfShdr> section_headers_;
int symbol_entries_read = 0;
int dynamic_entries_read = 0;
@ -191,7 +197,7 @@ absl::Status ElfParser::ReadFileHeader() {
return absl::FailedPreconditionError("magic not found, not an ELF");
}
if (header[kEiClassOffset] != kEiClass64) {
if (header[kEiClassOffset] != kEiClass) {
return absl::FailedPreconditionError("invalid ELF class");
}
const auto elf_data = header[kEiDataOffset];
@ -220,13 +226,13 @@ absl::Status ElfParser::ReadFileHeader() {
return absl::OkStatus();
}
absl::StatusOr<Elf64_Shdr> ElfParser::ReadSectionHeader(absl::string_view src) {
if (src.size() < sizeof(Elf64_Shdr)) {
absl::StatusOr<ElfShdr> ElfParser::ReadSectionHeader(absl::string_view src) {
if (src.size() < sizeof(ElfShdr)) {
return absl::FailedPreconditionError(
absl::StrCat("invalid section header data: got ", src.size(),
" bytes, ", sizeof(Elf64_Shdr), " bytes expected."));
" bytes, ", sizeof(ElfShdr), " bytes expected."));
}
Elf64_Shdr rv;
ElfShdr rv;
LOAD_MEMBER(rv, sh_name, src.data());
LOAD_MEMBER(rv, sh_type, src.data());
LOAD_MEMBER(rv, sh_flags, src.data());
@ -245,10 +251,10 @@ absl::Status ElfParser::ReadSectionHeaders() {
return absl::FailedPreconditionError(
absl::StrCat("invalid section header offset: ", file_header_.e_shoff));
}
if (file_header_.e_shentsize != sizeof(Elf64_Shdr)) {
if (file_header_.e_shentsize != sizeof(ElfShdr)) {
return absl::FailedPreconditionError(absl::StrCat(
"section header entry size incorrect: ", file_header_.e_shentsize,
" bytes, ", sizeof(Elf64_Shdr), " expected."));
" bytes, ", sizeof(ElfShdr), " expected."));
}
if (file_header_.e_shnum > kMaxSectionHeaderEntries) {
return absl::FailedPreconditionError(
@ -276,7 +282,7 @@ absl::StatusOr<std::string> ElfParser::ReadSectionContents(int idx) {
}
absl::StatusOr<std::string> ElfParser::ReadSectionContents(
const Elf64_Shdr& section_header) {
const ElfShdr& section_header) {
auto offset = section_header.sh_offset;
if (offset > file_size_) {
return absl::FailedPreconditionError(
@ -293,13 +299,13 @@ absl::StatusOr<std::string> ElfParser::ReadSectionContents(
return rv;
}
absl::StatusOr<Elf64_Phdr> ElfParser::ReadProgramHeader(absl::string_view src) {
if (src.size() < sizeof(Elf64_Phdr)) {
absl::StatusOr<ElfPhdr> ElfParser::ReadProgramHeader(absl::string_view src) {
if (src.size() < sizeof(ElfPhdr)) {
return absl::FailedPreconditionError(
absl::StrCat("invalid program header data: got ", src.size(),
" bytes, ", sizeof(Elf64_Phdr), " bytes expected."));
" bytes, ", sizeof(ElfPhdr), " bytes expected."));
}
Elf64_Phdr rv;
ElfPhdr rv;
LOAD_MEMBER(rv, p_type, src.data());
LOAD_MEMBER(rv, p_flags, src.data());
LOAD_MEMBER(rv, p_offset, src.data());
@ -316,10 +322,10 @@ absl::Status ElfParser::ReadProgramHeaders() {
return absl::FailedPreconditionError(
absl::StrCat("invalid program header offset: ", file_header_.e_phoff));
}
if (file_header_.e_phentsize != sizeof(Elf64_Phdr)) {
if (file_header_.e_phentsize != sizeof(ElfPhdr)) {
return absl::FailedPreconditionError(absl::StrCat(
"section header entry size incorrect: ", file_header_.e_phentsize,
" bytes, ", sizeof(Elf64_Phdr), " expected."));
" bytes, ", sizeof(ElfPhdr), " expected."));
}
if (file_header_.e_phnum > kMaxProgramHeaderEntries) {
return absl::FailedPreconditionError(
@ -338,11 +344,11 @@ absl::Status ElfParser::ReadProgramHeaders() {
return absl::OkStatus();
}
absl::Status ElfParser::ReadSymbolsFromSymtab(const Elf64_Shdr& symtab) {
absl::Status ElfParser::ReadSymbolsFromSymtab(const ElfShdr& symtab) {
if (symtab.sh_type != SHT_SYMTAB) {
return absl::FailedPreconditionError("invalid symtab type");
}
if (symtab.sh_entsize != sizeof(Elf64_Sym)) {
if (symtab.sh_entsize != sizeof(ElfSym)) {
return absl::InternalError(
absl::StrCat("invalid symbol entry size: ", symtab.sh_entsize));
}
@ -366,7 +372,7 @@ absl::Status ElfParser::ReadSymbolsFromSymtab(const Elf64_Shdr& symtab) {
result_.symbols_.reserve(result_.symbols_.size() + symbol_entries);
for (absl::string_view src = symbols; !src.empty();
src = src.substr(symtab.sh_entsize)) {
Elf64_Sym symbol;
ElfSym symbol;
LOAD_MEMBER(symbol, st_name, src.data());
LOAD_MEMBER(symbol, st_info, src.data());
LOAD_MEMBER(symbol, st_other, src.data());
@ -396,11 +402,11 @@ absl::Status ElfParser::ReadSymbolsFromSymtab(const Elf64_Shdr& symtab) {
}
absl::Status ElfParser::ReadImportedLibrariesFromDynamic(
const Elf64_Shdr& dynamic) {
const ElfShdr& dynamic) {
if (dynamic.sh_type != SHT_DYNAMIC) {
return absl::FailedPreconditionError("invalid dynamic type");
}
if (dynamic.sh_entsize != sizeof(Elf64_Dyn)) {
if (dynamic.sh_entsize != sizeof(ElfDyn)) {
return absl::InternalError(
absl::StrCat("invalid dynamic entry size: ", dynamic.sh_entsize));
}
@ -435,7 +441,7 @@ absl::Status ElfParser::ReadImportedLibrariesFromDynamic(
SAPI_ASSIGN_OR_RETURN(std::string dynamic_entries, ReadSectionContents(dynamic));
for (absl::string_view src = dynamic_entries; !src.empty();
src = src.substr(dynamic.sh_entsize)) {
Elf64_Dyn dyn;
ElfDyn dyn;
LOAD_MEMBER(dyn, d_tag, src.data());
LOAD_MEMBER(dyn, d_un.d_val, src.data());
if (dyn.d_tag != DT_NEEDED) {
@ -478,7 +484,7 @@ absl::StatusOr<ElfFile> ElfParser::Parse(FILE* elf, uint32_t features) {
std::string interpreter;
auto it = std::find_if(
program_headers_.begin(), program_headers_.end(),
[](const Elf64_Phdr& hdr) { return hdr.p_type == PT_INTERP; });
[](const ElfPhdr& hdr) { return hdr.p_type == PT_INTERP; });
// No interpreter usually means that the executable was statically linked.
if (it != program_headers_.end()) {
if (it->p_filesz > kMaxInterpreterSize) {

View File

@ -15,6 +15,7 @@
#ifndef SANDBOXED_API_SANDBOX2_UTIL_MINIELF_H_
#define SANDBOXED_API_SANDBOX2_UTIL_MINIELF_H_
#include <cstdint>
#include <cstdio>
#include <memory>
#include <string>
@ -25,11 +26,10 @@
namespace sandbox2 {
// Minimal implementation of an ELF file parser to read the program interpreter.
// Only understands 64-bit ELFs.
class ElfFile {
public:
struct Symbol {
uint64_t address;
uintptr_t address;
std::string name;
};

View File

@ -83,12 +83,20 @@ message RegisterAarch64 {
uint64 pstate = 4;
}
message RegisterArm {
repeated uint32 regs = 1;
uint32 pc = 2;
uint32 cpsr = 3;
uint32 orig_x0 = 4;
}
message RegisterValues {
// Architecture architecture = 1;
oneof register_values {
RegisterX8664 register_x86_64 = 2;
RegisterPowerpc64 register_powerpc64 = 3;
RegisterAarch64 register_aarch64 = 4;
RegisterArm register_arm = 5;
}
}