1385 lines
52 KiB
Diff
1385 lines
52 KiB
Diff
|
From 4b438323d68840453b5ef826c3997568e2e0e8c7 Mon Sep 17 00:00:00 2001
|
||
|
From: Matthew Denton <mpdenton@chromium.org>
|
||
|
Date: Mon, 19 Jul 2021 14:03:13 +0000
|
||
|
Subject: [PATCH] Reland "Reland "Linux sandbox syscall broker: use struct
|
||
|
kernel_stat""
|
||
|
|
||
|
This reverts commit ff277a52ece0b216617d770f201ed66955fe70b9.
|
||
|
|
||
|
Reason for revert: reland
|
||
|
|
||
|
The fix included in the reland is that fstatat64() needs to be
|
||
|
allowed in the broker process's seccomp policy.
|
||
|
|
||
|
This CL also includes some extra tests that the kernel_stat structures
|
||
|
match the layout the kernel expects.
|
||
|
|
||
|
Bug: 1164975, 1199431
|
||
|
Test: trogdor Chromebook successfully boots and allows login.
|
||
|
|
||
|
Original change's description:
|
||
|
> Revert "Reland "Linux sandbox syscall broker: use struct kernel_stat""
|
||
|
>
|
||
|
> This reverts commit cffbc4432af79f720ae3c75dff380b853701bd64.
|
||
|
>
|
||
|
> Reason for revert: https://bugs.chromium.org/p/chromium/issues/detail?id=1199431
|
||
|
>
|
||
|
> Original change's description:
|
||
|
> > Reland "Linux sandbox syscall broker: use struct kernel_stat"
|
||
|
> >
|
||
|
> > This reverts commit 23030dc650cdfa22631f25bef937905f27f06a2c.
|
||
|
> >
|
||
|
> > Original change's description:
|
||
|
> > > Revert "Linux sandbox syscall broker: use struct kernel_stat"
|
||
|
> > >
|
||
|
> > > This reverts commit 784b0fcd8a3ca6bcd3acb9cfd624ec9cbbac2789.
|
||
|
> > >
|
||
|
> > > Reason for revert: Causing failure in
|
||
|
> > > Step "sandbox_linux_unittests" failing on builder "Linux ChromiumOS MSan Tests"
|
||
|
> > > See crbug.com/1198480
|
||
|
> > >
|
||
|
> > > Original change's description:
|
||
|
> > > > Linux sandbox syscall broker: use struct kernel_stat
|
||
|
> > > >
|
||
|
> > > > The struct stat used in libc is different (in size and field ordering)
|
||
|
> > > > from the structure assumed by the Linux kernel. So, when emulating
|
||
|
> > > > system calls, we need to use the struct definition the kernel expects.
|
||
|
> > > >
|
||
|
> > > > This CL adds linux_stat.h that includes definitions of the different
|
||
|
> > > > kernel structs.
|
||
|
> > > >
|
||
|
> > > > Change-Id: I53cad35c2251dff0f6b7ea77528cfa58ef3cab4a
|
||
|
> > > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2780876
|
||
|
> > > > Commit-Queue: Matthew Denton <mpdenton@chromium.org>
|
||
|
> > > > Reviewed-by: Robert Sesek <rsesek@chromium.org>
|
||
|
> > > > Cr-Commit-Position: refs/heads/master@{#871767}
|
||
|
> > >
|
||
|
> > > Change-Id: Icbec38f2103c8424dec79ab1870b97c3e83f9361
|
||
|
> > > No-Presubmit: true
|
||
|
> > > No-Tree-Checks: true
|
||
|
> > > No-Try: true
|
||
|
> > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2821812
|
||
|
> > > Auto-Submit: Victor Vianna <victorvianna@google.com>
|
||
|
> > > Owners-Override: Victor Vianna <victorvianna@google.com>
|
||
|
> > > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||
|
> > > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||
|
> > > Cr-Commit-Position: refs/heads/master@{#871882}
|
||
|
> >
|
||
|
> > Change-Id: I1f39bb5242961474def594ff7dbea52009f2cee4
|
||
|
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2824115
|
||
|
> > Auto-Submit: Matthew Denton <mpdenton@chromium.org>
|
||
|
> > Commit-Queue: Matthew Denton <mpdenton@chromium.org>
|
||
|
> > Reviewed-by: Robert Sesek <rsesek@chromium.org>
|
||
|
> > Cr-Commit-Position: refs/heads/master@{#872812}
|
||
|
>
|
||
|
> Fixed: 1199431
|
||
|
> Change-Id: Iebfc0c48201bf22ff9c54d8d5c8a43d26a880098
|
||
|
> No-Presubmit: true
|
||
|
> No-Tree-Checks: true
|
||
|
> No-Try: true
|
||
|
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2830459
|
||
|
> Auto-Submit: Kyle Horimoto <khorimoto@chromium.org>
|
||
|
> Commit-Queue: Matthew Denton <mpdenton@chromium.org>
|
||
|
> Commit-Queue: Kinuko Yasuda <kinuko@chromium.org>
|
||
|
> Reviewed-by: Matthew Denton <mpdenton@chromium.org>
|
||
|
> Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
|
||
|
> Owners-Override: Kinuko Yasuda <kinuko@chromium.org>
|
||
|
> Cr-Commit-Position: refs/heads/master@{#873173}
|
||
|
|
||
|
Change-Id: Ibe6a485070f33489aaa157b51b908c2d23d174d7
|
||
|
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2848936
|
||
|
Reviewed-by: Robert Sesek <rsesek@chromium.org>
|
||
|
Commit-Queue: Matthew Denton <mpdenton@chromium.org>
|
||
|
Cr-Commit-Position: refs/heads/master@{#902981}
|
||
|
---
|
||
|
sandbox/linux/BUILD.gn | 1 +
|
||
|
.../seccomp_broker_process_unittest.cc | 40 +++-
|
||
|
sandbox/linux/seccomp-bpf-helpers/DEPS | 1 -
|
||
|
...scall_parameters_restrictions_unittests.cc | 4 -
|
||
|
sandbox/linux/services/syscall_wrappers.cc | 50 ++++-
|
||
|
sandbox/linux/services/syscall_wrappers.h | 15 ++
|
||
|
.../services/syscall_wrappers_unittest.cc | 129 +++++++++++-
|
||
|
sandbox/linux/syscall_broker/DEPS | 3 +-
|
||
|
sandbox/linux/syscall_broker/broker_client.cc | 4 +-
|
||
|
sandbox/linux/syscall_broker/broker_client.h | 4 +-
|
||
|
sandbox/linux/syscall_broker/broker_host.cc | 23 ++-
|
||
|
.../syscall_broker/broker_process_unittest.cc | 74 +++----
|
||
|
.../remote_syscall_arg_handler_unittest.cc | 36 ++--
|
||
|
.../syscall_broker/syscall_dispatcher.cc | 67 ++++---
|
||
|
.../linux/syscall_broker/syscall_dispatcher.h | 27 ++-
|
||
|
sandbox/linux/system_headers/linux_stat.h | 188 ++++++++++++++++++
|
||
|
sandbox/linux/system_headers/linux_time.h | 26 +++
|
||
|
sandbox/linux/tests/test_utils.cc | 15 ++
|
||
|
sandbox/linux/tests/test_utils.h | 2 +
|
||
|
.../policy/linux/bpf_broker_policy_linux.cc | 4 +-
|
||
|
20 files changed, 595 insertions(+), 118 deletions(-)
|
||
|
create mode 100644 sandbox/linux/system_headers/linux_stat.h
|
||
|
|
||
|
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
|
||
|
index 2f778dd0bc..ccbbc91716 100644
|
||
|
--- a/sandbox/linux/BUILD.gn
|
||
|
+++ b/sandbox/linux/BUILD.gn
|
||
|
@@ -443,6 +443,7 @@ source_set("sandbox_services_headers") {
|
||
|
"system_headers/linux_ptrace.h",
|
||
|
"system_headers/linux_seccomp.h",
|
||
|
"system_headers/linux_signal.h",
|
||
|
+ "system_headers/linux_stat.h",
|
||
|
"system_headers/linux_syscalls.h",
|
||
|
"system_headers/linux_time.h",
|
||
|
"system_headers/linux_ucontext.h",
|
||
|
diff --git a/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc b/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
|
||
|
index 9da9c68911..8a941983b1 100644
|
||
|
--- a/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
|
||
|
+++ b/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
|
||
|
@@ -34,6 +34,7 @@
|
||
|
#include "sandbox/linux/syscall_broker/broker_file_permission.h"
|
||
|
#include "sandbox/linux/syscall_broker/broker_process.h"
|
||
|
#include "sandbox/linux/system_headers/linux_seccomp.h"
|
||
|
+#include "sandbox/linux/system_headers/linux_stat.h"
|
||
|
#include "sandbox/linux/system_headers/linux_syscalls.h"
|
||
|
#include "sandbox/linux/tests/scoped_temporary_file.h"
|
||
|
#include "sandbox/linux/tests/test_utils.h"
|
||
|
@@ -202,6 +203,26 @@ namespace {
|
||
|
// not accept this as a valid error number. E.g. bionic accepts up to 255, glibc
|
||
|
// and musl up to 4096.
|
||
|
const int kFakeErrnoSentinel = 254;
|
||
|
+
|
||
|
+void ConvertKernelStatToLibcStat(default_stat_struct& in_stat,
|
||
|
+ struct stat& out_stat) {
|
||
|
+ out_stat.st_dev = in_stat.st_dev;
|
||
|
+ out_stat.st_ino = in_stat.st_ino;
|
||
|
+ out_stat.st_mode = in_stat.st_mode;
|
||
|
+ out_stat.st_nlink = in_stat.st_nlink;
|
||
|
+ out_stat.st_uid = in_stat.st_uid;
|
||
|
+ out_stat.st_gid = in_stat.st_gid;
|
||
|
+ out_stat.st_rdev = in_stat.st_rdev;
|
||
|
+ out_stat.st_size = in_stat.st_size;
|
||
|
+ out_stat.st_blksize = in_stat.st_blksize;
|
||
|
+ out_stat.st_blocks = in_stat.st_blocks;
|
||
|
+ out_stat.st_atim.tv_sec = in_stat.st_atime_;
|
||
|
+ out_stat.st_atim.tv_nsec = in_stat.st_atime_nsec_;
|
||
|
+ out_stat.st_mtim.tv_sec = in_stat.st_mtime_;
|
||
|
+ out_stat.st_mtim.tv_nsec = in_stat.st_mtime_nsec_;
|
||
|
+ out_stat.st_ctim.tv_sec = in_stat.st_ctime_;
|
||
|
+ out_stat.st_ctim.tv_nsec = in_stat.st_ctime_nsec_;
|
||
|
+}
|
||
|
} // namespace
|
||
|
|
||
|
// There are a variety of ways to make syscalls in a sandboxed process. One is
|
||
|
@@ -217,6 +238,10 @@ class Syscaller {
|
||
|
|
||
|
virtual int Open(const char* filepath, int flags) = 0;
|
||
|
virtual int Access(const char* filepath, int mode) = 0;
|
||
|
+ // NOTE: we use struct stat instead of default_stat_struct, to make the libc
|
||
|
+ // syscaller simpler. Copying from default_stat_struct (the structure returned
|
||
|
+ // from a stat sycall) to struct stat (the structure exposed by a libc to its
|
||
|
+ // users) is simpler than going in the opposite direction.
|
||
|
virtual int Stat(const char* filepath,
|
||
|
bool follow_links,
|
||
|
struct stat* statbuf) = 0;
|
||
|
@@ -243,8 +268,12 @@ class IPCSyscaller : public Syscaller {
|
||
|
int Stat(const char* filepath,
|
||
|
bool follow_links,
|
||
|
struct stat* statbuf) override {
|
||
|
- return broker_->GetBrokerClientSignalBased()->Stat(filepath, follow_links,
|
||
|
- statbuf);
|
||
|
+ default_stat_struct buf;
|
||
|
+ int ret = broker_->GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ filepath, follow_links, &buf);
|
||
|
+ if (ret >= 0)
|
||
|
+ ConvertKernelStatToLibcStat(buf, *statbuf);
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
int Rename(const char* oldpath, const char* newpath) override {
|
||
|
@@ -300,10 +329,13 @@ class DirectSyscaller : public Syscaller {
|
||
|
int Stat(const char* filepath,
|
||
|
bool follow_links,
|
||
|
struct stat* statbuf) override {
|
||
|
- int ret = follow_links ? syscall(__NR_stat, filepath, statbuf)
|
||
|
- : syscall(__NR_lstat, filepath, statbuf);
|
||
|
+ struct kernel_stat buf;
|
||
|
+ int ret = syscall(__NR_newfstatat, AT_FDCWD, filepath, &buf,
|
||
|
+ follow_links ? 0 : AT_SYMLINK_NOFOLLOW);
|
||
|
if (ret < 0)
|
||
|
return -errno;
|
||
|
+
|
||
|
+ ConvertKernelStatToLibcStat(buf, *statbuf);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
diff --git a/sandbox/linux/seccomp-bpf-helpers/DEPS b/sandbox/linux/seccomp-bpf-helpers/DEPS
|
||
|
index 4419fd1da3..95d1bb6cbb 100644
|
||
|
--- a/sandbox/linux/seccomp-bpf-helpers/DEPS
|
||
|
+++ b/sandbox/linux/seccomp-bpf-helpers/DEPS
|
||
|
@@ -3,5 +3,4 @@ include_rules = [
|
||
|
"+sandbox/linux/seccomp-bpf",
|
||
|
"+sandbox/linux/services",
|
||
|
"+sandbox/linux/system_headers",
|
||
|
- "+third_party/lss/linux_syscall_support.h",
|
||
|
]
|
||
|
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
|
||
|
index 903e702eab..76c393032c 100644
|
||
|
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
|
||
|
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
|
||
|
@@ -37,10 +37,6 @@
|
||
|
#include "sandbox/linux/system_headers/linux_time.h"
|
||
|
#include "sandbox/linux/tests/unit_tests.h"
|
||
|
|
||
|
-#if !defined(OS_ANDROID)
|
||
|
-#include "third_party/lss/linux_syscall_support.h" // for MAKE_PROCESS_CPUCLOCK
|
||
|
-#endif
|
||
|
-
|
||
|
namespace sandbox {
|
||
|
|
||
|
namespace {
|
||
|
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
|
||
|
index fcfd2aa129..3bec18a14e 100644
|
||
|
--- a/sandbox/linux/services/syscall_wrappers.cc
|
||
|
+++ b/sandbox/linux/services/syscall_wrappers.cc
|
||
|
@@ -4,6 +4,7 @@
|
||
|
|
||
|
#include "sandbox/linux/services/syscall_wrappers.h"
|
||
|
|
||
|
+#include <fcntl.h>
|
||
|
#include <pthread.h>
|
||
|
#include <sched.h>
|
||
|
#include <setjmp.h>
|
||
|
@@ -14,11 +15,13 @@
|
||
|
#include <unistd.h>
|
||
|
#include <cstring>
|
||
|
|
||
|
+#include "base/check.h"
|
||
|
#include "base/compiler_specific.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "build/build_config.h"
|
||
|
#include "sandbox/linux/system_headers/capability.h"
|
||
|
#include "sandbox/linux/system_headers/linux_signal.h"
|
||
|
+#include "sandbox/linux/system_headers/linux_stat.h"
|
||
|
#include "sandbox/linux/system_headers/linux_syscalls.h"
|
||
|
|
||
|
namespace sandbox {
|
||
|
@@ -217,7 +220,7 @@ asm(
|
||
|
#undef STR
|
||
|
#undef XSTR
|
||
|
|
||
|
-#endif
|
||
|
+#endif // defined(ARCH_CPU_X86_FAMILY)
|
||
|
|
||
|
int sys_sigaction(int signum,
|
||
|
const struct sigaction* act,
|
||
|
@@ -241,7 +244,7 @@ int sys_sigaction(int signum,
|
||
|
#error "Unsupported architecture."
|
||
|
#endif
|
||
|
}
|
||
|
-#endif
|
||
|
+#endif // defined(ARCH_CPU_X86_FAMILY)
|
||
|
}
|
||
|
|
||
|
LinuxSigAction linux_oldact = {};
|
||
|
@@ -259,6 +262,47 @@ int sys_sigaction(int signum,
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
-#endif // defined(MEMORY_SANITIZER)
|
||
|
+#endif // !defined(OS_NACL_NONSFI)
|
||
|
+
|
||
|
+int sys_stat(const char* path, struct kernel_stat* stat_buf) {
|
||
|
+ int res;
|
||
|
+#if !defined(__NR_stat)
|
||
|
+ res = syscall(__NR_newfstatat, AT_FDCWD, path, stat_buf, 0);
|
||
|
+#else
|
||
|
+ res = syscall(__NR_stat, path, stat_buf);
|
||
|
+#endif
|
||
|
+ if (res == 0)
|
||
|
+ MSAN_UNPOISON(stat_buf, sizeof(*stat_buf));
|
||
|
+ return res;
|
||
|
+}
|
||
|
+
|
||
|
+int sys_lstat(const char* path, struct kernel_stat* stat_buf) {
|
||
|
+ int res;
|
||
|
+#if !defined(__NR_lstat)
|
||
|
+ res = syscall(__NR_newfstatat, AT_FDCWD, path, stat_buf, AT_SYMLINK_NOFOLLOW);
|
||
|
+#else
|
||
|
+ res = syscall(__NR_lstat, path, stat_buf);
|
||
|
+#endif
|
||
|
+ if (res == 0)
|
||
|
+ MSAN_UNPOISON(stat_buf, sizeof(*stat_buf));
|
||
|
+ return res;
|
||
|
+}
|
||
|
+
|
||
|
+int sys_fstatat64(int dirfd,
|
||
|
+ const char* pathname,
|
||
|
+ struct kernel_stat64* stat_buf,
|
||
|
+ int flags) {
|
||
|
+#if defined(__NR_fstatat64)
|
||
|
+ int res = syscall(__NR_fstatat64, dirfd, pathname, stat_buf, flags);
|
||
|
+ if (res == 0)
|
||
|
+ MSAN_UNPOISON(stat_buf, sizeof(*stat_buf));
|
||
|
+ return res;
|
||
|
+#else // defined(__NR_fstatat64)
|
||
|
+ // We should not reach here on 64-bit systems, as the *stat*64() are only
|
||
|
+ // necessary on 32-bit.
|
||
|
+ RAW_CHECK(false);
|
||
|
+ return -ENOSYS;
|
||
|
+#endif
|
||
|
+}
|
||
|
|
||
|
} // namespace sandbox
|
||
|
diff --git a/sandbox/linux/services/syscall_wrappers.h b/sandbox/linux/services/syscall_wrappers.h
|
||
|
index 1975bfbd88..b55340e4a2 100644
|
||
|
--- a/sandbox/linux/services/syscall_wrappers.h
|
||
|
+++ b/sandbox/linux/services/syscall_wrappers.h
|
||
|
@@ -17,6 +17,8 @@ struct sock_fprog;
|
||
|
struct rlimit64;
|
||
|
struct cap_hdr;
|
||
|
struct cap_data;
|
||
|
+struct kernel_stat;
|
||
|
+struct kernel_stat64;
|
||
|
|
||
|
namespace sandbox {
|
||
|
|
||
|
@@ -84,6 +86,19 @@ SANDBOX_EXPORT int sys_sigaction(int signum,
|
||
|
const struct sigaction* act,
|
||
|
struct sigaction* oldact);
|
||
|
|
||
|
+// Some architectures do not have stat() and lstat() syscalls. In that case,
|
||
|
+// these wrappers will use newfstatat(), which is available on all other
|
||
|
+// architectures, with the same capabilities as stat() and lstat().
|
||
|
+SANDBOX_EXPORT int sys_stat(const char* path, struct kernel_stat* stat_buf);
|
||
|
+SANDBOX_EXPORT int sys_lstat(const char* path, struct kernel_stat* stat_buf);
|
||
|
+
|
||
|
+// Takes care of unpoisoning |stat_buf| for MSAN. Check-fails if fstatat64() is
|
||
|
+// not a supported syscall on the current platform.
|
||
|
+SANDBOX_EXPORT int sys_fstatat64(int dirfd,
|
||
|
+ const char* pathname,
|
||
|
+ struct kernel_stat64* stat_buf,
|
||
|
+ int flags);
|
||
|
+
|
||
|
} // namespace sandbox
|
||
|
|
||
|
#endif // SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
|
||
|
diff --git a/sandbox/linux/services/syscall_wrappers_unittest.cc b/sandbox/linux/services/syscall_wrappers_unittest.cc
|
||
|
index 32820f60a8..64b9cea80f 100644
|
||
|
--- a/sandbox/linux/services/syscall_wrappers_unittest.cc
|
||
|
+++ b/sandbox/linux/services/syscall_wrappers_unittest.cc
|
||
|
@@ -5,15 +5,19 @@
|
||
|
#include "sandbox/linux/services/syscall_wrappers.h"
|
||
|
|
||
|
#include <stdint.h>
|
||
|
+#include <string.h>
|
||
|
#include <sys/syscall.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <unistd.h>
|
||
|
-#include <cstring>
|
||
|
|
||
|
+#include "base/logging.h"
|
||
|
+#include "base/memory/page_size.h"
|
||
|
#include "base/posix/eintr_wrapper.h"
|
||
|
#include "build/build_config.h"
|
||
|
#include "sandbox/linux/system_headers/linux_signal.h"
|
||
|
+#include "sandbox/linux/system_headers/linux_stat.h"
|
||
|
+#include "sandbox/linux/tests/scoped_temporary_file.h"
|
||
|
#include "sandbox/linux/tests/test_utils.h"
|
||
|
#include "sandbox/linux/tests/unit_tests.h"
|
||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
@@ -93,6 +97,129 @@ TEST(SyscallWrappers, LinuxSigSet) {
|
||
|
linux_sigset);
|
||
|
}
|
||
|
|
||
|
+TEST(SyscallWrappers, Stat) {
|
||
|
+ // Create a file to stat, with 12 bytes of data.
|
||
|
+ ScopedTemporaryFile tmp_file;
|
||
|
+ EXPECT_EQ(12, write(tmp_file.fd(), "blahblahblah", 12));
|
||
|
+
|
||
|
+ // To test we have the correct stat structures for each kernel/platform, we
|
||
|
+ // will right-align them on a page, with a guard page after.
|
||
|
+ char* two_pages = static_cast<char*>(TestUtils::MapPagesOrDie(2));
|
||
|
+ TestUtils::MprotectLastPageOrDie(two_pages, 2);
|
||
|
+ char* page1_end = two_pages + base::GetPageSize();
|
||
|
+
|
||
|
+ // First, check that calling stat with |stat_buf| pointing to the last byte on
|
||
|
+ // a page causes EFAULT.
|
||
|
+ int res = sys_stat(tmp_file.full_file_name(),
|
||
|
+ reinterpret_cast<struct kernel_stat*>(page1_end - 1));
|
||
|
+ ASSERT_EQ(res, -1);
|
||
|
+ ASSERT_EQ(errno, EFAULT);
|
||
|
+
|
||
|
+ // Now, check that we have the correctly sized stat structure.
|
||
|
+ struct kernel_stat* sb = reinterpret_cast<struct kernel_stat*>(
|
||
|
+ page1_end - sizeof(struct kernel_stat));
|
||
|
+ // Memset to c's so we can check the kernel zero'd the padding...
|
||
|
+ memset(sb, 'c', sizeof(struct kernel_stat));
|
||
|
+ res = sys_stat(tmp_file.full_file_name(), sb);
|
||
|
+ ASSERT_EQ(res, 0);
|
||
|
+
|
||
|
+ // Following fields may never be consistent but should be non-zero.
|
||
|
+ // Don't trust the platform to define fields with any particular sign.
|
||
|
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_dev));
|
||
|
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_ino));
|
||
|
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_mode));
|
||
|
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_blksize));
|
||
|
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_blocks));
|
||
|
+
|
||
|
+// We are the ones that made the file.
|
||
|
+// Note: normally gid and uid overflow on backwards-compatible 32-bit systems
|
||
|
+// and we end up with dummy uids and gids in place here.
|
||
|
+#if defined(ARCH_CPU_64_BITS)
|
||
|
+ EXPECT_EQ(geteuid(), sb->st_uid);
|
||
|
+ EXPECT_EQ(getegid(), sb->st_gid);
|
||
|
+#endif
|
||
|
+
|
||
|
+ // Wrote 12 bytes above which should fit in one block.
|
||
|
+ EXPECT_EQ(12u, sb->st_size);
|
||
|
+
|
||
|
+ // Can't go backwards in time, 1500000000 was some time ago.
|
||
|
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_atime_));
|
||
|
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_mtime_));
|
||
|
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_ctime_));
|
||
|
+
|
||
|
+ // Checking the padding for good measure.
|
||
|
+#if defined(__x86_64__)
|
||
|
+ EXPECT_EQ(0u, sb->__pad0);
|
||
|
+ EXPECT_EQ(0u, sb->__unused4[0]);
|
||
|
+ EXPECT_EQ(0u, sb->__unused4[1]);
|
||
|
+ EXPECT_EQ(0u, sb->__unused4[2]);
|
||
|
+#elif defined(__aarch64__)
|
||
|
+ EXPECT_EQ(0u, sb->__pad1);
|
||
|
+ EXPECT_EQ(0, sb->__pad2);
|
||
|
+ EXPECT_EQ(0u, sb->__unused4);
|
||
|
+ EXPECT_EQ(0u, sb->__unused5);
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+TEST(SyscallWrappers, LStat) {
|
||
|
+ // Create a file to stat, with 12 bytes of data.
|
||
|
+ ScopedTemporaryFile tmp_file;
|
||
|
+ EXPECT_EQ(12, write(tmp_file.fd(), "blahblahblah", 12));
|
||
|
+
|
||
|
+ // Also create a symlink.
|
||
|
+ std::string symlink_name;
|
||
|
+ {
|
||
|
+ ScopedTemporaryFile tmp_file2;
|
||
|
+ symlink_name = tmp_file2.full_file_name();
|
||
|
+ }
|
||
|
+ int rc = symlink(tmp_file.full_file_name(), symlink_name.c_str());
|
||
|
+ if (rc != 0) {
|
||
|
+ PLOG(ERROR) << "Couldn't symlink " << symlink_name << " to target "
|
||
|
+ << tmp_file.full_file_name();
|
||
|
+ GTEST_FAIL();
|
||
|
+ }
|
||
|
+
|
||
|
+ struct kernel_stat lstat_info;
|
||
|
+ rc = sys_lstat(symlink_name.c_str(), &lstat_info);
|
||
|
+ if (rc < 0 && errno == EOVERFLOW) {
|
||
|
+ GTEST_SKIP();
|
||
|
+ }
|
||
|
+ if (rc != 0) {
|
||
|
+ PLOG(ERROR) << "Couldn't sys_lstat " << symlink_name;
|
||
|
+ GTEST_FAIL();
|
||
|
+ }
|
||
|
+
|
||
|
+ struct kernel_stat stat_info;
|
||
|
+ rc = sys_stat(symlink_name.c_str(), &stat_info);
|
||
|
+ if (rc < 0 && errno == EOVERFLOW) {
|
||
|
+ GTEST_SKIP();
|
||
|
+ }
|
||
|
+ if (rc != 0) {
|
||
|
+ PLOG(ERROR) << "Couldn't sys_stat " << symlink_name;
|
||
|
+ GTEST_FAIL();
|
||
|
+ }
|
||
|
+
|
||
|
+ struct kernel_stat tmp_file_stat_info;
|
||
|
+ rc = sys_stat(tmp_file.full_file_name(), &tmp_file_stat_info);
|
||
|
+ if (rc < 0 && errno == EOVERFLOW) {
|
||
|
+ GTEST_SKIP();
|
||
|
+ }
|
||
|
+ if (rc != 0) {
|
||
|
+ PLOG(ERROR) << "Couldn't sys_stat " << tmp_file.full_file_name();
|
||
|
+ GTEST_FAIL();
|
||
|
+ }
|
||
|
+
|
||
|
+ // lstat should produce information about a symlink.
|
||
|
+ ASSERT_TRUE(S_ISLNK(lstat_info.st_mode));
|
||
|
+
|
||
|
+ // stat-ing symlink_name and tmp_file should produce the same inode.
|
||
|
+ ASSERT_EQ(stat_info.st_ino, tmp_file_stat_info.st_ino);
|
||
|
+
|
||
|
+ // lstat-ing symlink_name should give a different inode than stat-ing
|
||
|
+ // symlink_name.
|
||
|
+ ASSERT_NE(stat_info.st_ino, lstat_info.st_ino);
|
||
|
+}
|
||
|
+
|
||
|
} // namespace
|
||
|
|
||
|
} // namespace sandbox
|
||
|
diff --git a/sandbox/linux/syscall_broker/DEPS b/sandbox/linux/syscall_broker/DEPS
|
||
|
index c477f7d363..149c463b06 100644
|
||
|
--- a/sandbox/linux/syscall_broker/DEPS
|
||
|
+++ b/sandbox/linux/syscall_broker/DEPS
|
||
|
@@ -1,4 +1,5 @@
|
||
|
include_rules = [
|
||
|
- "+sandbox/linux/system_headers",
|
||
|
"+sandbox/linux/bpf_dsl",
|
||
|
+ "+sandbox/linux/services",
|
||
|
+ "+sandbox/linux/system_headers",
|
||
|
]
|
||
|
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc
|
||
|
index 6b1b5be433..e24f659fcf 100644
|
||
|
--- a/sandbox/linux/syscall_broker/broker_client.cc
|
||
|
+++ b/sandbox/linux/syscall_broker/broker_client.cc
|
||
|
@@ -166,7 +166,7 @@ int BrokerClient::Rmdir(const char* path) const {
|
||
|
|
||
|
int BrokerClient::Stat(const char* pathname,
|
||
|
bool follow_links,
|
||
|
- struct stat* sb) const {
|
||
|
+ struct kernel_stat* sb) const {
|
||
|
if (!pathname || !sb)
|
||
|
return -EFAULT;
|
||
|
|
||
|
@@ -181,7 +181,7 @@ int BrokerClient::Stat(const char* pathname,
|
||
|
|
||
|
int BrokerClient::Stat64(const char* pathname,
|
||
|
bool follow_links,
|
||
|
- struct stat64* sb) const {
|
||
|
+ struct kernel_stat64* sb) const {
|
||
|
if (!pathname || !sb)
|
||
|
return -EFAULT;
|
||
|
|
||
|
diff --git a/sandbox/linux/syscall_broker/broker_client.h b/sandbox/linux/syscall_broker/broker_client.h
|
||
|
index 05e14c83f2..26ca78101c 100644
|
||
|
--- a/sandbox/linux/syscall_broker/broker_client.h
|
||
|
+++ b/sandbox/linux/syscall_broker/broker_client.h
|
||
|
@@ -61,10 +61,10 @@ class SANDBOX_EXPORT BrokerClient : public SyscallDispatcher {
|
||
|
int Rmdir(const char* path) const override;
|
||
|
int Stat(const char* pathname,
|
||
|
bool follow_links,
|
||
|
- struct stat* sb) const override;
|
||
|
+ struct kernel_stat* sb) const override;
|
||
|
int Stat64(const char* pathname,
|
||
|
bool follow_links,
|
||
|
- struct stat64* sb) const override;
|
||
|
+ struct kernel_stat64* sb) const override;
|
||
|
int Unlink(const char* unlink) const override;
|
||
|
|
||
|
private:
|
||
|
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
|
||
|
index 1cd03a18df..1cdc01a888 100644
|
||
|
--- a/sandbox/linux/syscall_broker/broker_host.cc
|
||
|
+++ b/sandbox/linux/syscall_broker/broker_host.cc
|
||
|
@@ -20,9 +20,11 @@
|
||
|
#include "base/files/scoped_file.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "base/posix/eintr_wrapper.h"
|
||
|
+#include "sandbox/linux/services/syscall_wrappers.h"
|
||
|
#include "sandbox/linux/syscall_broker/broker_command.h"
|
||
|
#include "sandbox/linux/syscall_broker/broker_permission_list.h"
|
||
|
#include "sandbox/linux/syscall_broker/broker_simple_message.h"
|
||
|
+#include "sandbox/linux/system_headers/linux_stat.h"
|
||
|
#include "sandbox/linux/system_headers/linux_syscalls.h"
|
||
|
|
||
|
namespace sandbox {
|
||
|
@@ -193,10 +195,12 @@ void StatFileForIPC(const BrokerCommandSet& allowed_command_set,
|
||
|
RAW_CHECK(reply->AddIntToMessage(-permission_list.denied_errno()));
|
||
|
return;
|
||
|
}
|
||
|
+
|
||
|
if (command_type == COMMAND_STAT) {
|
||
|
- struct stat sb;
|
||
|
- int sts =
|
||
|
- follow_links ? stat(file_to_access, &sb) : lstat(file_to_access, &sb);
|
||
|
+ struct kernel_stat sb;
|
||
|
+
|
||
|
+ int sts = follow_links ? sandbox::sys_stat(file_to_access, &sb)
|
||
|
+ : sandbox::sys_lstat(file_to_access, &sb);
|
||
|
if (sts < 0) {
|
||
|
RAW_CHECK(reply->AddIntToMessage(-errno));
|
||
|
return;
|
||
|
@@ -205,10 +209,12 @@ void StatFileForIPC(const BrokerCommandSet& allowed_command_set,
|
||
|
RAW_CHECK(
|
||
|
reply->AddDataToMessage(reinterpret_cast<char*>(&sb), sizeof(sb)));
|
||
|
} else {
|
||
|
+#if defined(__NR_fstatat64)
|
||
|
DCHECK(command_type == COMMAND_STAT64);
|
||
|
- struct stat64 sb;
|
||
|
- int sts = follow_links ? stat64(file_to_access, &sb)
|
||
|
- : lstat64(file_to_access, &sb);
|
||
|
+ struct kernel_stat64 sb;
|
||
|
+
|
||
|
+ int sts = sandbox::sys_fstatat64(AT_FDCWD, file_to_access, &sb,
|
||
|
+ follow_links ? 0 : AT_SYMLINK_NOFOLLOW);
|
||
|
if (sts < 0) {
|
||
|
RAW_CHECK(reply->AddIntToMessage(-errno));
|
||
|
return;
|
||
|
@@ -216,6 +222,11 @@ void StatFileForIPC(const BrokerCommandSet& allowed_command_set,
|
||
|
RAW_CHECK(reply->AddIntToMessage(0));
|
||
|
RAW_CHECK(
|
||
|
reply->AddDataToMessage(reinterpret_cast<char*>(&sb), sizeof(sb)));
|
||
|
+#else // defined(__NR_fstatat64)
|
||
|
+ // We should not reach here on 64-bit systems, as the *stat*64() are only
|
||
|
+ // necessary on 32-bit.
|
||
|
+ RAW_CHECK(false);
|
||
|
+#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc
|
||
|
index 55ba6bccb2..c65f25a78a 100644
|
||
|
--- a/sandbox/linux/syscall_broker/broker_process_unittest.cc
|
||
|
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc
|
||
|
@@ -811,7 +811,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
const char* bad_leading_path5 = "/mbogo/fictitioux";
|
||
|
const char* bad_leading_path6 = "/mbogo/fictitiousa";
|
||
|
|
||
|
- struct stat sb;
|
||
|
+ default_stat_struct sb;
|
||
|
|
||
|
{
|
||
|
// Actual file with permissions to see file but command not allowed.
|
||
|
@@ -824,7 +824,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
tempfile_name, follow_links, &sb));
|
||
|
}
|
||
|
|
||
|
@@ -840,7 +840,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
nonesuch_name, follow_links, &sb));
|
||
|
}
|
||
|
{
|
||
|
@@ -852,7 +852,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
tempfile_name, follow_links, &sb));
|
||
|
}
|
||
|
{
|
||
|
@@ -864,38 +864,39 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
ASSERT_TRUE(open_broker.Init(base::BindOnce(&NoOpCallback)));
|
||
|
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
- nonesuch_name, follow_links, &sb));
|
||
|
+ EXPECT_EQ(-ENOENT,
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ nonesuch_name, follow_links, &sb));
|
||
|
|
||
|
// Gets denied all the way back to root since no create permission.
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
leading_path1, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
leading_path2, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
leading_path3, follow_links, &sb));
|
||
|
|
||
|
// Not fooled by substrings.
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path1, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path2, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path3, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path4, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path5, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path6, follow_links, &sb));
|
||
|
}
|
||
|
{
|
||
|
@@ -907,37 +908,41 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
ASSERT_TRUE(open_broker.Init(base::BindOnce(&NoOpCallback)));
|
||
|
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
- nonesuch_name, follow_links, &sb));
|
||
|
+ EXPECT_EQ(-ENOENT,
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ nonesuch_name, follow_links, &sb));
|
||
|
|
||
|
// Gets ENOENT all the way back to root since it has create permission.
|
||
|
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
- leading_path1, follow_links, &sb));
|
||
|
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
- leading_path2, follow_links, &sb));
|
||
|
+ EXPECT_EQ(-ENOENT,
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ leading_path1, follow_links, &sb));
|
||
|
+ EXPECT_EQ(-ENOENT,
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ leading_path2, follow_links, &sb));
|
||
|
|
||
|
// But can always get the root.
|
||
|
- EXPECT_EQ(0, open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
- leading_path3, follow_links, &sb));
|
||
|
+ EXPECT_EQ(0,
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ leading_path3, follow_links, &sb));
|
||
|
|
||
|
// Not fooled by substrings.
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path1, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path2, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path3, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path4, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path5, follow_links, &sb));
|
||
|
EXPECT_EQ(-kFakeErrnoSentinel,
|
||
|
- open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
bad_leading_path6, follow_links, &sb));
|
||
|
}
|
||
|
{
|
||
|
@@ -949,8 +954,9 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
ASSERT_TRUE(open_broker.Init(base::BindOnce(&NoOpCallback)));
|
||
|
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
- EXPECT_EQ(0, open_broker.GetBrokerClientSignalBased()->Stat(
|
||
|
- tempfile_name, follow_links, &sb));
|
||
|
+ EXPECT_EQ(0,
|
||
|
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
|
||
|
+ tempfile_name, follow_links, &sb));
|
||
|
|
||
|
// Following fields may never be consistent but should be non-zero.
|
||
|
// Don't trust the platform to define fields with any particular sign.
|
||
|
@@ -968,9 +974,9 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
|
||
|
EXPECT_EQ(12, sb.st_size);
|
||
|
|
||
|
// Can't go backwards in time, 1500000000 was some time ago.
|
||
|
- EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_atime));
|
||
|
- EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_mtime));
|
||
|
- EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_ctime));
|
||
|
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_atime_));
|
||
|
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_mtime_));
|
||
|
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_ctime_));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc b/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc
|
||
|
index fffa9bb708..f517a9867c 100644
|
||
|
--- a/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc
|
||
|
+++ b/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc
|
||
|
@@ -16,6 +16,7 @@
|
||
|
#include "base/memory/page_size.h"
|
||
|
#include "base/posix/unix_domain_socket.h"
|
||
|
#include "base/test/bind.h"
|
||
|
+#include "sandbox/linux/tests/test_utils.h"
|
||
|
#include "sandbox/linux/tests/unit_tests.h"
|
||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
|
||
|
@@ -52,19 +53,6 @@ void VerifyCorrectString(std::string str, size_t size) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-void* MapPagesOrDie(size_t num_pages) {
|
||
|
- void* addr = mmap(nullptr, num_pages * base::GetPageSize(),
|
||
|
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||
|
- PCHECK(addr);
|
||
|
- return addr;
|
||
|
-}
|
||
|
-
|
||
|
-void MprotectLastPageOrDie(char* addr, size_t num_pages) {
|
||
|
- size_t last_page_offset = (num_pages - 1) * base::GetPageSize();
|
||
|
- PCHECK(mprotect(addr + last_page_offset, base::GetPageSize(), PROT_NONE) >=
|
||
|
- 0);
|
||
|
-}
|
||
|
-
|
||
|
pid_t ForkWaitingChild(base::OnceCallback<void(int)>
|
||
|
after_parent_signals_callback = base::DoNothing(),
|
||
|
base::ScopedFD* parent_sync_fd = nullptr) {
|
||
|
@@ -105,13 +93,13 @@ void ReadTest(const ReadTestConfig& test_config) {
|
||
|
size_t total_pages = (test_config.start_at + test_config.total_size +
|
||
|
base::GetPageSize() - 1) /
|
||
|
base::GetPageSize();
|
||
|
- char* mmap_addr = static_cast<char*>(MapPagesOrDie(total_pages));
|
||
|
+ char* mmap_addr = static_cast<char*>(TestUtils::MapPagesOrDie(total_pages));
|
||
|
char* addr = mmap_addr + test_config.start_at;
|
||
|
FillBufferWithPath(addr, test_config.total_size,
|
||
|
test_config.include_null_byte);
|
||
|
|
||
|
if (test_config.last_page_inaccessible)
|
||
|
- MprotectLastPageOrDie(mmap_addr, total_pages);
|
||
|
+ TestUtils::MprotectLastPageOrDie(mmap_addr, total_pages);
|
||
|
|
||
|
pid_t pid = ForkWaitingChild();
|
||
|
munmap(mmap_addr, base::GetPageSize() * total_pages);
|
||
|
@@ -212,7 +200,7 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, ReadChunkPlus1EndingOnePastPage) {
|
||
|
}
|
||
|
|
||
|
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, ReadChildExited) {
|
||
|
- void* addr = MapPagesOrDie(1);
|
||
|
+ void* addr = TestUtils::MapPagesOrDie(1);
|
||
|
FillBufferWithPath(static_cast<char*>(addr), strlen(kPathPart) + 1, true);
|
||
|
|
||
|
base::ScopedFD parent_sync, child_sync;
|
||
|
@@ -240,10 +228,10 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, ReadChildExited) {
|
||
|
}
|
||
|
|
||
|
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, BasicWrite) {
|
||
|
- void* read_from = MapPagesOrDie(1);
|
||
|
+ void* read_from = TestUtils::MapPagesOrDie(1);
|
||
|
const size_t write_size = base::GetPageSize();
|
||
|
FillBufferWithPath(static_cast<char*>(read_from), write_size, false);
|
||
|
- char* write_to = static_cast<char*>(MapPagesOrDie(1));
|
||
|
+ char* write_to = static_cast<char*>(TestUtils::MapPagesOrDie(1));
|
||
|
base::ScopedFD parent_signal_fd;
|
||
|
const std::vector<int> empty_fd_vec;
|
||
|
|
||
|
@@ -278,8 +266,8 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, BasicWrite) {
|
||
|
}
|
||
|
|
||
|
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WriteToInvalidAddress) {
|
||
|
- char* write_to = static_cast<char*>(MapPagesOrDie(1));
|
||
|
- MprotectLastPageOrDie(write_to, 1);
|
||
|
+ char* write_to = static_cast<char*>(TestUtils::MapPagesOrDie(1));
|
||
|
+ TestUtils::MprotectLastPageOrDie(write_to, 1);
|
||
|
base::ScopedFD parent_signal_fd;
|
||
|
const std::vector<int> empty_fd_vec;
|
||
|
|
||
|
@@ -295,11 +283,11 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WriteToInvalidAddress) {
|
||
|
}
|
||
|
|
||
|
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WritePartiallyToInvalidAddress) {
|
||
|
- char* read_from = static_cast<char*>(MapPagesOrDie(2));
|
||
|
+ char* read_from = static_cast<char*>(TestUtils::MapPagesOrDie(2));
|
||
|
const size_t write_size = base::GetPageSize();
|
||
|
FillBufferWithPath(static_cast<char*>(read_from), write_size, false);
|
||
|
- char* write_to = static_cast<char*>(MapPagesOrDie(2));
|
||
|
- MprotectLastPageOrDie(write_to, 2);
|
||
|
+ char* write_to = static_cast<char*>(TestUtils::MapPagesOrDie(2));
|
||
|
+ TestUtils::MprotectLastPageOrDie(write_to, 2);
|
||
|
write_to += base::GetPageSize() / 2;
|
||
|
base::ScopedFD parent_signal_fd;
|
||
|
const std::vector<int> empty_fd_vec;
|
||
|
@@ -314,7 +302,7 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WritePartiallyToInvalidAddress) {
|
||
|
}
|
||
|
|
||
|
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WriteChildExited) {
|
||
|
- char* addr = static_cast<char*>(MapPagesOrDie(1));
|
||
|
+ char* addr = static_cast<char*>(TestUtils::MapPagesOrDie(1));
|
||
|
FillBufferWithPath(static_cast<char*>(addr), strlen(kPathPart) + 1, true);
|
||
|
|
||
|
base::ScopedFD parent_sync, child_sync;
|
||
|
diff --git a/sandbox/linux/syscall_broker/syscall_dispatcher.cc b/sandbox/linux/syscall_broker/syscall_dispatcher.cc
|
||
|
index b9ee93c14a..8a42397ef8 100644
|
||
|
--- a/sandbox/linux/syscall_broker/syscall_dispatcher.cc
|
||
|
+++ b/sandbox/linux/syscall_broker/syscall_dispatcher.cc
|
||
|
@@ -19,8 +19,18 @@ namespace syscall_broker {
|
||
|
#define BROKER_UNPOISON_STRING(x)
|
||
|
#endif
|
||
|
|
||
|
+int SyscallDispatcher::DefaultStatForTesting(const char* pathname,
|
||
|
+ bool follow_links,
|
||
|
+ default_stat_struct* sb) {
|
||
|
+#if defined(__NR_fstatat64)
|
||
|
+ return Stat64(pathname, follow_links, sb);
|
||
|
+#elif defined(__NR_newfstatat)
|
||
|
+ return Stat(pathname, follow_links, sb);
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
int SyscallDispatcher::PerformStatat(const arch_seccomp_data& args,
|
||
|
- bool arch64) {
|
||
|
+ bool stat64) {
|
||
|
if (static_cast<int>(args.args[0]) != AT_FDCWD)
|
||
|
return -EPERM;
|
||
|
// Only allow the AT_SYMLINK_NOFOLLOW flag which is used by some libc
|
||
|
@@ -30,13 +40,29 @@ int SyscallDispatcher::PerformStatat(const arch_seccomp_data& args,
|
||
|
|
||
|
const bool follow_links =
|
||
|
!(static_cast<int>(args.args[3]) & AT_SYMLINK_NOFOLLOW);
|
||
|
- if (arch64) {
|
||
|
+ if (stat64) {
|
||
|
return Stat64(reinterpret_cast<const char*>(args.args[1]), follow_links,
|
||
|
- reinterpret_cast<struct stat64*>(args.args[2]));
|
||
|
+ reinterpret_cast<struct kernel_stat64*>(args.args[2]));
|
||
|
}
|
||
|
|
||
|
return Stat(reinterpret_cast<const char*>(args.args[1]), follow_links,
|
||
|
- reinterpret_cast<struct stat*>(args.args[2]));
|
||
|
+ reinterpret_cast<struct kernel_stat*>(args.args[2]));
|
||
|
+}
|
||
|
+
|
||
|
+int SyscallDispatcher::PerformUnlinkat(const arch_seccomp_data& args) {
|
||
|
+ if (static_cast<int>(args.args[0]) != AT_FDCWD)
|
||
|
+ return -EPERM;
|
||
|
+
|
||
|
+ int flags = static_cast<int>(args.args[2]);
|
||
|
+
|
||
|
+ if (flags == AT_REMOVEDIR) {
|
||
|
+ return Rmdir(reinterpret_cast<const char*>(args.args[1]));
|
||
|
+ }
|
||
|
+
|
||
|
+ if (flags != 0)
|
||
|
+ return -EPERM;
|
||
|
+
|
||
|
+ return Unlink(reinterpret_cast<const char*>(args.args[1]));
|
||
|
}
|
||
|
|
||
|
int SyscallDispatcher::DispatchSyscall(const arch_seccomp_data& args) {
|
||
|
@@ -127,59 +153,42 @@ int SyscallDispatcher::DispatchSyscall(const arch_seccomp_data& args) {
|
||
|
#if defined(__NR_stat)
|
||
|
case __NR_stat:
|
||
|
return Stat(reinterpret_cast<const char*>(args.args[0]), true,
|
||
|
- reinterpret_cast<struct stat*>(args.args[1]));
|
||
|
+ reinterpret_cast<struct kernel_stat*>(args.args[1]));
|
||
|
#endif
|
||
|
#if defined(__NR_stat64)
|
||
|
case __NR_stat64:
|
||
|
return Stat64(reinterpret_cast<const char*>(args.args[0]), true,
|
||
|
- reinterpret_cast<struct stat64*>(args.args[1]));
|
||
|
+ reinterpret_cast<struct kernel_stat64*>(args.args[1]));
|
||
|
#endif
|
||
|
#if defined(__NR_lstat)
|
||
|
case __NR_lstat:
|
||
|
// See https://crbug.com/847096
|
||
|
BROKER_UNPOISON_STRING(reinterpret_cast<const char*>(args.args[0]));
|
||
|
return Stat(reinterpret_cast<const char*>(args.args[0]), false,
|
||
|
- reinterpret_cast<struct stat*>(args.args[1]));
|
||
|
+ reinterpret_cast<struct kernel_stat*>(args.args[1]));
|
||
|
#endif
|
||
|
#if defined(__NR_lstat64)
|
||
|
case __NR_lstat64:
|
||
|
// See https://crbug.com/847096
|
||
|
BROKER_UNPOISON_STRING(reinterpret_cast<const char*>(args.args[0]));
|
||
|
return Stat64(reinterpret_cast<const char*>(args.args[0]), false,
|
||
|
- reinterpret_cast<struct stat64*>(args.args[1]));
|
||
|
-#endif
|
||
|
-#if defined(__NR_fstatat)
|
||
|
- case __NR_fstatat:
|
||
|
- return PerformStatat(args, /*arch64=*/false);
|
||
|
+ reinterpret_cast<struct kernel_stat64*>(args.args[1]));
|
||
|
#endif
|
||
|
#if defined(__NR_fstatat64)
|
||
|
case __NR_fstatat64:
|
||
|
- return PerformStatat(args, /*arch64=*/true);
|
||
|
+ return PerformStatat(args, /*stat64=*/true);
|
||
|
#endif
|
||
|
#if defined(__NR_newfstatat)
|
||
|
case __NR_newfstatat:
|
||
|
- return PerformStatat(args, /*arch64=*/false);
|
||
|
+ return PerformStatat(args, /*stat64=*/false);
|
||
|
#endif
|
||
|
#if defined(__NR_unlink)
|
||
|
case __NR_unlink:
|
||
|
return Unlink(reinterpret_cast<const char*>(args.args[0]));
|
||
|
#endif
|
||
|
#if defined(__NR_unlinkat)
|
||
|
- case __NR_unlinkat: {
|
||
|
- if (static_cast<int>(args.args[0]) != AT_FDCWD)
|
||
|
- return -EPERM;
|
||
|
-
|
||
|
- int flags = static_cast<int>(args.args[2]);
|
||
|
-
|
||
|
- if (flags == AT_REMOVEDIR) {
|
||
|
- return Rmdir(reinterpret_cast<const char*>(args.args[1]));
|
||
|
- }
|
||
|
-
|
||
|
- if (flags != 0)
|
||
|
- return -EPERM;
|
||
|
-
|
||
|
- return Unlink(reinterpret_cast<const char*>(args.args[1]));
|
||
|
- }
|
||
|
+ case __NR_unlinkat:
|
||
|
+ return PerformUnlinkat(args);
|
||
|
#endif // defined(__NR_unlinkat)
|
||
|
default:
|
||
|
RAW_CHECK(false);
|
||
|
diff --git a/sandbox/linux/syscall_broker/syscall_dispatcher.h b/sandbox/linux/syscall_broker/syscall_dispatcher.h
|
||
|
index d8b8874ad9..1d6653caf3 100644
|
||
|
--- a/sandbox/linux/syscall_broker/syscall_dispatcher.h
|
||
|
+++ b/sandbox/linux/syscall_broker/syscall_dispatcher.h
|
||
|
@@ -9,13 +9,15 @@
|
||
|
#include <cstddef>
|
||
|
|
||
|
#include "sandbox/linux/system_headers/linux_seccomp.h"
|
||
|
+#include "sandbox/linux/system_headers/linux_stat.h"
|
||
|
+#include "sandbox/sandbox_export.h"
|
||
|
|
||
|
namespace sandbox {
|
||
|
namespace syscall_broker {
|
||
|
|
||
|
// An abstract class that defines all the system calls we perform for the
|
||
|
// sandboxed process.
|
||
|
-class SyscallDispatcher {
|
||
|
+class SANDBOX_EXPORT SyscallDispatcher {
|
||
|
public:
|
||
|
// Emulates access()/faccessat().
|
||
|
// X_OK will always return an error in practice since the broker process
|
||
|
@@ -40,19 +42,34 @@ class SyscallDispatcher {
|
||
|
virtual int Rmdir(const char* path) const = 0;
|
||
|
|
||
|
// Emulates stat()/stat64()/lstat()/lstat64()/fstatat()/newfstatat().
|
||
|
+ // Stat64 is only available on 32-bit systems.
|
||
|
virtual int Stat(const char* pathname,
|
||
|
bool follow_links,
|
||
|
- struct stat* sb) const = 0;
|
||
|
+ struct kernel_stat* sb) const = 0;
|
||
|
virtual int Stat64(const char* pathname,
|
||
|
bool follow_links,
|
||
|
- struct stat64* sb) const = 0;
|
||
|
+ struct kernel_stat64* sb) const = 0;
|
||
|
|
||
|
// Emulates unlink()/unlinkat().
|
||
|
virtual int Unlink(const char* unlink) const = 0;
|
||
|
|
||
|
+ // Different architectures use a different syscall from the stat family by
|
||
|
+ // default in glibc. E.g. 32-bit systems use *stat*64() and fill out struct
|
||
|
+ // kernel_stat64, whereas 64-bit systems use *stat*() and fill out struct
|
||
|
+ // kernel_stat. Some tests want to call the SyscallDispatcher directly, and
|
||
|
+ // should be using the default stat in order to test against glibc.
|
||
|
+ int DefaultStatForTesting(const char* pathname,
|
||
|
+ bool follow_links,
|
||
|
+ default_stat_struct* sb);
|
||
|
+
|
||
|
// Validates the args passed to a *statat*() syscall and performs the syscall
|
||
|
- // using Stat() or Stat64().
|
||
|
- int PerformStatat(const arch_seccomp_data& args, bool arch64);
|
||
|
+ // using Stat(), or on 32-bit systems it uses Stat64() for the *statat64()
|
||
|
+ // syscalls.
|
||
|
+ int PerformStatat(const arch_seccomp_data& args, bool stat64);
|
||
|
+
|
||
|
+ // Validates the args passed to an unlinkat() syscall and performs the syscall
|
||
|
+ // using either Unlink() or Rmdir().
|
||
|
+ int PerformUnlinkat(const arch_seccomp_data& args);
|
||
|
|
||
|
// Reads the syscall number and arguments, imposes some policy (e.g. the *at()
|
||
|
// system calls must only allow AT_FDCWD as the first argument), and
|
||
|
diff --git a/sandbox/linux/system_headers/linux_stat.h b/sandbox/linux/system_headers/linux_stat.h
|
||
|
new file mode 100644
|
||
|
index 0000000000..35788eb22a
|
||
|
--- /dev/null
|
||
|
+++ b/sandbox/linux/system_headers/linux_stat.h
|
||
|
@@ -0,0 +1,188 @@
|
||
|
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||
|
+// Use of this source code is governed by a BSD-style license that can be
|
||
|
+// found in the LICENSE file.
|
||
|
+
|
||
|
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_STAT_H_
|
||
|
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_STAT_H_
|
||
|
+
|
||
|
+#include <stdint.h>
|
||
|
+
|
||
|
+#include "build/build_config.h"
|
||
|
+#include "sandbox/linux/system_headers/linux_syscalls.h"
|
||
|
+
|
||
|
+#if defined(ARCH_CPU_MIPS_FAMILY)
|
||
|
+#if defined(ARCH_CPU_64_BITS)
|
||
|
+struct kernel_stat {
|
||
|
+#else
|
||
|
+struct kernel_stat64 {
|
||
|
+#endif
|
||
|
+ unsigned st_dev;
|
||
|
+ unsigned __pad0[3];
|
||
|
+ unsigned long long st_ino;
|
||
|
+ unsigned st_mode;
|
||
|
+ unsigned st_nlink;
|
||
|
+ unsigned st_uid;
|
||
|
+ unsigned st_gid;
|
||
|
+ unsigned st_rdev;
|
||
|
+ unsigned __pad1[3];
|
||
|
+ long long st_size;
|
||
|
+ unsigned st_atime_;
|
||
|
+ unsigned st_atime_nsec_;
|
||
|
+ unsigned st_mtime_;
|
||
|
+ unsigned st_mtime_nsec_;
|
||
|
+ unsigned st_ctime_;
|
||
|
+ unsigned st_ctime_nsec_;
|
||
|
+ unsigned st_blksize;
|
||
|
+ unsigned __pad2;
|
||
|
+ unsigned long long st_blocks;
|
||
|
+};
|
||
|
+#else
|
||
|
+struct kernel_stat64 {
|
||
|
+ unsigned long long st_dev;
|
||
|
+ unsigned char __pad0[4];
|
||
|
+ unsigned __st_ino;
|
||
|
+ unsigned st_mode;
|
||
|
+ unsigned st_nlink;
|
||
|
+ unsigned st_uid;
|
||
|
+ unsigned st_gid;
|
||
|
+ unsigned long long st_rdev;
|
||
|
+ unsigned char __pad3[4];
|
||
|
+ long long st_size;
|
||
|
+ unsigned st_blksize;
|
||
|
+ unsigned long long st_blocks;
|
||
|
+ unsigned st_atime_;
|
||
|
+ unsigned st_atime_nsec_;
|
||
|
+ unsigned st_mtime_;
|
||
|
+ unsigned st_mtime_nsec_;
|
||
|
+ unsigned st_ctime_;
|
||
|
+ unsigned st_ctime_nsec_;
|
||
|
+ unsigned long long st_ino;
|
||
|
+};
|
||
|
+#endif
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__)
|
||
|
+struct kernel_stat {
|
||
|
+ /* The kernel headers suggest that st_dev and st_rdev should be 32bit
|
||
|
+ * quantities encoding 12bit major and 20bit minor numbers in an interleaved
|
||
|
+ * format. In reality, we do not see useful data in the top bits. So,
|
||
|
+ * we'll leave the padding in here, until we find a better solution.
|
||
|
+ */
|
||
|
+ unsigned short st_dev;
|
||
|
+ short pad1;
|
||
|
+ unsigned st_ino;
|
||
|
+ unsigned short st_mode;
|
||
|
+ unsigned short st_nlink;
|
||
|
+ unsigned short st_uid;
|
||
|
+ unsigned short st_gid;
|
||
|
+ unsigned short st_rdev;
|
||
|
+ short pad2;
|
||
|
+ unsigned st_size;
|
||
|
+ unsigned st_blksize;
|
||
|
+ unsigned st_blocks;
|
||
|
+ unsigned st_atime_;
|
||
|
+ unsigned st_atime_nsec_;
|
||
|
+ unsigned st_mtime_;
|
||
|
+ unsigned st_mtime_nsec_;
|
||
|
+ unsigned st_ctime_;
|
||
|
+ unsigned st_ctime_nsec_;
|
||
|
+ unsigned __unused4;
|
||
|
+ unsigned __unused5;
|
||
|
+};
|
||
|
+#elif defined(__x86_64__)
|
||
|
+struct kernel_stat {
|
||
|
+ uint64_t st_dev;
|
||
|
+ uint64_t st_ino;
|
||
|
+ uint64_t st_nlink;
|
||
|
+ unsigned st_mode;
|
||
|
+ unsigned st_uid;
|
||
|
+ unsigned st_gid;
|
||
|
+ unsigned __pad0;
|
||
|
+ uint64_t st_rdev;
|
||
|
+ int64_t st_size;
|
||
|
+ int64_t st_blksize;
|
||
|
+ int64_t st_blocks;
|
||
|
+ uint64_t st_atime_;
|
||
|
+ uint64_t st_atime_nsec_;
|
||
|
+ uint64_t st_mtime_;
|
||
|
+ uint64_t st_mtime_nsec_;
|
||
|
+ uint64_t st_ctime_;
|
||
|
+ uint64_t st_ctime_nsec_;
|
||
|
+ int64_t __unused4[3];
|
||
|
+};
|
||
|
+#elif (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
|
||
|
+struct kernel_stat {
|
||
|
+ unsigned st_dev;
|
||
|
+ int st_pad1[3];
|
||
|
+ unsigned st_ino;
|
||
|
+ unsigned st_mode;
|
||
|
+ unsigned st_nlink;
|
||
|
+ unsigned st_uid;
|
||
|
+ unsigned st_gid;
|
||
|
+ unsigned st_rdev;
|
||
|
+ int st_pad2[2];
|
||
|
+ long st_size;
|
||
|
+ int st_pad3;
|
||
|
+ long st_atime_;
|
||
|
+ long st_atime_nsec_;
|
||
|
+ long st_mtime_;
|
||
|
+ long st_mtime_nsec_;
|
||
|
+ long st_ctime_;
|
||
|
+ long st_ctime_nsec_;
|
||
|
+ int st_blksize;
|
||
|
+ int st_blocks;
|
||
|
+ int st_pad4[14];
|
||
|
+};
|
||
|
+#elif defined(__aarch64__)
|
||
|
+struct kernel_stat {
|
||
|
+ unsigned long st_dev;
|
||
|
+ unsigned long st_ino;
|
||
|
+ unsigned int st_mode;
|
||
|
+ unsigned int st_nlink;
|
||
|
+ unsigned int st_uid;
|
||
|
+ unsigned int st_gid;
|
||
|
+ unsigned long st_rdev;
|
||
|
+ unsigned long __pad1;
|
||
|
+ long st_size;
|
||
|
+ int st_blksize;
|
||
|
+ int __pad2;
|
||
|
+ long st_blocks;
|
||
|
+ long st_atime_;
|
||
|
+ unsigned long st_atime_nsec_;
|
||
|
+ long st_mtime_;
|
||
|
+ unsigned long st_mtime_nsec_;
|
||
|
+ long st_ctime_;
|
||
|
+ unsigned long st_ctime_nsec_;
|
||
|
+ unsigned int __unused4;
|
||
|
+ unsigned int __unused5;
|
||
|
+};
|
||
|
+#endif
|
||
|
+
|
||
|
+// On 32-bit systems, we default to the 64-bit stat struct like libc
|
||
|
+// implementations do. Otherwise we default to the normal stat struct which is
|
||
|
+// already 64-bit.
|
||
|
+// These defines make it easy to call the right syscall to fill out a 64-bit
|
||
|
+// stat struct, which is the default in libc implementations but requires
|
||
|
+// different syscall names on 32 and 64-bit platforms.
|
||
|
+#if defined(__NR_fstatat64)
|
||
|
+
|
||
|
+namespace sandbox {
|
||
|
+using default_stat_struct = struct kernel_stat64;
|
||
|
+} // namespace sandbox
|
||
|
+
|
||
|
+#define __NR_fstatat_default __NR_fstatat64
|
||
|
+#define __NR_fstat_default __NR_fstat64
|
||
|
+
|
||
|
+#elif defined(__NR_newfstatat)
|
||
|
+
|
||
|
+namespace sandbox {
|
||
|
+using default_stat_struct = struct kernel_stat;
|
||
|
+} // namespace sandbox
|
||
|
+
|
||
|
+#define __NR_fstatat_default __NR_newfstatat
|
||
|
+#define __NR_fstat_default __NR_fstat
|
||
|
+
|
||
|
+#else
|
||
|
+#error "one of fstatat64 and newfstatat must be defined"
|
||
|
+#endif
|
||
|
+
|
||
|
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_STAT_H_
|
||
|
diff --git a/sandbox/linux/system_headers/linux_time.h b/sandbox/linux/system_headers/linux_time.h
|
||
|
index 780f24dddd..f18c806611 100644
|
||
|
--- a/sandbox/linux/system_headers/linux_time.h
|
||
|
+++ b/sandbox/linux/system_headers/linux_time.h
|
||
|
@@ -11,6 +11,32 @@
|
||
|
#define CPUCLOCK_CLOCK_MASK 3
|
||
|
#endif
|
||
|
|
||
|
+#if !defined(CPUCLOCK_PROF)
|
||
|
+#define CPUCLOCK_PROF 0
|
||
|
+#endif
|
||
|
+
|
||
|
+#if !defined(CPUCLOCK_VIRT)
|
||
|
+#define CPUCLOCK_VIRT 1
|
||
|
+#endif
|
||
|
+
|
||
|
+#if !defined(CPUCLOCK_SCHED)
|
||
|
+#define CPUCLOCK_SCHED 2
|
||
|
+#endif
|
||
|
+
|
||
|
+#if !defined(CPUCLOCK_PERTHREAD_MASK)
|
||
|
+#define CPUCLOCK_PERTHREAD_MASK 4
|
||
|
+#endif
|
||
|
+
|
||
|
+#if !defined(MAKE_PROCESS_CPUCLOCK)
|
||
|
+#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
|
||
|
+ ((int)(~(unsigned)(pid) << 3) | (int)(clock))
|
||
|
+#endif
|
||
|
+
|
||
|
+#if !defined(MAKE_THREAD_CPUCLOCK)
|
||
|
+#define MAKE_THREAD_CPUCLOCK(tid, clock) \
|
||
|
+ ((int)(~(unsigned)(tid) << 3) | (int)((clock) | CPUCLOCK_PERTHREAD_MASK))
|
||
|
+#endif
|
||
|
+
|
||
|
#if !defined(CLOCKFD)
|
||
|
#define CLOCKFD 3
|
||
|
#endif
|
||
|
diff --git a/sandbox/linux/tests/test_utils.cc b/sandbox/linux/tests/test_utils.cc
|
||
|
index 847c20b20c..cf6041a4b4 100644
|
||
|
--- a/sandbox/linux/tests/test_utils.cc
|
||
|
+++ b/sandbox/linux/tests/test_utils.cc
|
||
|
@@ -5,12 +5,14 @@
|
||
|
#include "sandbox/linux/tests/test_utils.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
+#include <sys/mman.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "base/check_op.h"
|
||
|
+#include "base/memory/page_size.h"
|
||
|
#include "base/posix/eintr_wrapper.h"
|
||
|
|
||
|
namespace sandbox {
|
||
|
@@ -39,4 +41,17 @@ void TestUtils::HandlePostForkReturn(pid_t pid) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+void* TestUtils::MapPagesOrDie(size_t num_pages) {
|
||
|
+ void* addr = mmap(nullptr, num_pages * base::GetPageSize(),
|
||
|
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||
|
+ PCHECK(addr);
|
||
|
+ return addr;
|
||
|
+}
|
||
|
+
|
||
|
+void TestUtils::MprotectLastPageOrDie(char* addr, size_t num_pages) {
|
||
|
+ size_t last_page_offset = (num_pages - 1) * base::GetPageSize();
|
||
|
+ PCHECK(mprotect(addr + last_page_offset, base::GetPageSize(), PROT_NONE) >=
|
||
|
+ 0);
|
||
|
+}
|
||
|
+
|
||
|
} // namespace sandbox
|
||
|
diff --git a/sandbox/linux/tests/test_utils.h b/sandbox/linux/tests/test_utils.h
|
||
|
index 7cf9749fe4..43b028b1e3 100644
|
||
|
--- a/sandbox/linux/tests/test_utils.h
|
||
|
+++ b/sandbox/linux/tests/test_utils.h
|
||
|
@@ -19,6 +19,8 @@ class TestUtils {
|
||
|
// makes sure that if fork() succeeded the child exits
|
||
|
// and the parent waits for it.
|
||
|
static void HandlePostForkReturn(pid_t pid);
|
||
|
+ static void* MapPagesOrDie(size_t num_pages);
|
||
|
+ static void MprotectLastPageOrDie(char* addr, size_t num_pages);
|
||
|
|
||
|
private:
|
||
|
DISALLOW_IMPLICIT_CONSTRUCTORS(TestUtils);
|
||
|
diff --git a/sandbox/policy/linux/bpf_broker_policy_linux.cc b/sandbox/policy/linux/bpf_broker_policy_linux.cc
|
||
|
index 2963bb9ca8..6dc8c0581b 100644
|
||
|
--- a/sandbox/policy/linux/bpf_broker_policy_linux.cc
|
||
|
+++ b/sandbox/policy/linux/bpf_broker_policy_linux.cc
|
||
|
@@ -93,8 +93,8 @@ ResultExpr BrokerProcessPolicy::EvaluateSyscall(int sysno) const {
|
||
|
return Allow();
|
||
|
break;
|
||
|
#endif
|
||
|
-#if defined(__NR_fstatat)
|
||
|
- case __NR_fstatat:
|
||
|
+#if defined(__NR_fstatat64)
|
||
|
+ case __NR_fstatat64:
|
||
|
if (allowed_command_set_.test(syscall_broker::COMMAND_STAT))
|
||
|
return Allow();
|
||
|
break;
|