1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384 |
- 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;
|