From 95528d6cb2a1bcf20619f7849f3e964fc15174a0 Mon Sep 17 00:00:00 2001 From: Alexandre Lissy Date: Thu, 3 Jun 2021 20:04:08 +0000 Subject: [PATCH] Bug 1713776 - Allow faccessat2 r=gcp Differential Revision: https://phabricator.services.mozilla.com/D116597 --- dom/system/OSFileConstants.cpp | 1 + .../linux/system_headers/arm64_linux_syscalls.h | 271 ++++++++++++++++++++- .../linux/system_headers/arm_linux_syscalls.h | 208 +++++++++++++++- .../linux/system_headers/x86_32_linux_syscalls.h | 21 +- .../linux/system_headers/x86_64_linux_syscalls.h | 23 +- security/sandbox/linux/SandboxFilter.cpp | 24 ++ .../test/browser_content_sandbox_syscalls.js | 100 +++++++- 7 files changed, 633 insertions(+), 15 deletions(-) diff --git a/dom/system/OSFileConstants.cpp b/dom/system/OSFileConstants.cpp index d63619a3aa04..0feb121272ce 100644 --- a/dom/system/OSFileConstants.cpp +++ b/dom/system/OSFileConstants.cpp @@ -458,6 +458,7 @@ static const dom::ConstantSpec gLibcProperties[] = { #endif // defined(EOVERFLOW) INT_CONSTANT(EPERM), INT_CONSTANT(ERANGE), + INT_CONSTANT(ENOSYS), #if defined(ETIMEDOUT) // not defined with VC 9 INT_CONSTANT(ETIMEDOUT), #endif // defined(ETIMEDOUT) diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h index 3a8efced2c0f..17f22cd1c068 100644 --- a/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h +++ b/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h @@ -2,6 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/* Constructed by running: + * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/asm-generic/unistd.h?h=v5.8 + * | grep '^#define' | sed -e 's/__NR3264_/__NR_/g' | grep '__NR_' + * | awk '{ if ($2 != $3) { print "#if !defined(" $2 ")\n#define " $2 " " $3 "\n#endif\n"; } }' + * */ + #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_ #define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_ @@ -323,8 +329,8 @@ #define __NR_readlinkat 78 #endif -#if !defined(__NR_newfstatat) -#define __NR_newfstatat 79 +#if !defined(__NR_fstatat) +#define __NR_fstatat 79 #endif #if !defined(__NR_fstat) @@ -343,6 +349,10 @@ #define __NR_fdatasync 83 #endif +#if !defined(__NR_sync_file_range2) +#define __NR_sync_file_range2 84 +#endif + #if !defined(__NR_sync_file_range) #define __NR_sync_file_range 84 #endif @@ -983,6 +993,10 @@ #define __NR_recvmmsg 243 #endif +#if !defined(__NR_arch_specific_syscall) +#define __NR_arch_specific_syscall 244 +#endif + #if !defined(__NR_wait4) #define __NR_wait4 260 #endif @@ -1063,11 +1077,264 @@ #define __NR_memfd_create 279 #endif +#if !defined(__NR_bpf) +#define __NR_bpf 280 +#endif + +#if !defined(__NR_execveat) +#define __NR_execveat 281 +#endif + +#if !defined(__NR_userfaultfd) +#define __NR_userfaultfd 282 +#endif + +#if !defined(__NR_membarrier) +#define __NR_membarrier 283 +#endif + +#if !defined(__NR_mlock2) +#define __NR_mlock2 284 +#endif + +#if !defined(__NR_copy_file_range) +#define __NR_copy_file_range 285 +#endif + +#if !defined(__NR_preadv2) +#define __NR_preadv2 286 +#endif + +#if !defined(__NR_pwritev2) +#define __NR_pwritev2 287 +#endif + +#if !defined(__NR_pkey_mprotect) +#define __NR_pkey_mprotect 288 +#endif + +#if !defined(__NR_pkey_alloc) +#define __NR_pkey_alloc 289 +#endif + +#if !defined(__NR_pkey_free) +#define __NR_pkey_free 290 +#endif + #if !defined(__NR_statx) #define __NR_statx 291 #endif +#if !defined(__NR_io_pgetevents) +#define __NR_io_pgetevents 292 +#endif + #if !defined(__NR_rseq) #define __NR_rseq 293 #endif + +#if !defined(__NR_kexec_file_load) +#define __NR_kexec_file_load 294 +#endif + +#if !defined(__NR_clock_gettime64) +#define __NR_clock_gettime64 403 +#endif + +#if !defined(__NR_clock_settime64) +#define __NR_clock_settime64 404 +#endif + +#if !defined(__NR_clock_adjtime64) +#define __NR_clock_adjtime64 405 +#endif + +#if !defined(__NR_clock_getres_time64) +#define __NR_clock_getres_time64 406 +#endif + +#if !defined(__NR_clock_nanosleep_time64) +#define __NR_clock_nanosleep_time64 407 +#endif + +#if !defined(__NR_timer_gettime64) +#define __NR_timer_gettime64 408 +#endif + +#if !defined(__NR_timer_settime64) +#define __NR_timer_settime64 409 +#endif + +#if !defined(__NR_timerfd_gettime64) +#define __NR_timerfd_gettime64 410 +#endif + +#if !defined(__NR_timerfd_settime64) +#define __NR_timerfd_settime64 411 +#endif + +#if !defined(__NR_utimensat_time64) +#define __NR_utimensat_time64 412 +#endif + +#if !defined(__NR_pselect6_time64) +#define __NR_pselect6_time64 413 +#endif + +#if !defined(__NR_ppoll_time64) +#define __NR_ppoll_time64 414 +#endif + +#if !defined(__NR_io_pgetevents_time64) +#define __NR_io_pgetevents_time64 416 +#endif + +#if !defined(__NR_recvmmsg_time64) +#define __NR_recvmmsg_time64 417 +#endif + +#if !defined(__NR_mq_timedsend_time64) +#define __NR_mq_timedsend_time64 418 +#endif + +#if !defined(__NR_mq_timedreceive_time64) +#define __NR_mq_timedreceive_time64 419 +#endif + +#if !defined(__NR_semtimedop_time64) +#define __NR_semtimedop_time64 420 +#endif + +#if !defined(__NR_rt_sigtimedwait_time64) +#define __NR_rt_sigtimedwait_time64 421 +#endif + +#if !defined(__NR_futex_time64) +#define __NR_futex_time64 422 +#endif + +#if !defined(__NR_sched_rr_get_interval_time64) +#define __NR_sched_rr_get_interval_time64 423 +#endif + +#if !defined(__NR_pidfd_send_signal) +#define __NR_pidfd_send_signal 424 +#endif + +#if !defined(__NR_io_uring_setup) +#define __NR_io_uring_setup 425 +#endif + +#if !defined(__NR_io_uring_enter) +#define __NR_io_uring_enter 426 +#endif + +#if !defined(__NR_io_uring_register) +#define __NR_io_uring_register 427 +#endif + +#if !defined(__NR_open_tree) +#define __NR_open_tree 428 +#endif + +#if !defined(__NR_move_mount) +#define __NR_move_mount 429 +#endif + +#if !defined(__NR_fsopen) +#define __NR_fsopen 430 +#endif + +#if !defined(__NR_fsconfig) +#define __NR_fsconfig 431 +#endif + +#if !defined(__NR_fsmount) +#define __NR_fsmount 432 +#endif + +#if !defined(__NR_fspick) +#define __NR_fspick 433 +#endif + +#if !defined(__NR_pidfd_open) +#define __NR_pidfd_open 434 +#endif + +#if !defined(__NR_clone3) +#define __NR_clone3 435 +#endif + +#if !defined(__NR_openat2) +#define __NR_openat2 437 +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd 438 +#endif + +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 439 +#endif + +#if !defined(__NR_syscalls) +#define __NR_syscalls 440 +#endif + +#if !defined(__NR_newfstatat) +#define __NR_newfstatat __NR_fstatat +#endif + +#if !defined(__NR_fcntl64) +#define __NR_fcntl64 __NR_fcntl +#endif + +#if !defined(__NR_statfs64) +#define __NR_statfs64 __NR_statfs +#endif + +#if !defined(__NR_fstatfs64) +#define __NR_fstatfs64 __NR_fstatfs +#endif + +#if !defined(__NR_truncate64) +#define __NR_truncate64 __NR_truncate +#endif + +#if !defined(__NR_ftruncate64) +#define __NR_ftruncate64 __NR_ftruncate +#endif + +#if !defined(__NR_llseek) +#define __NR_llseek __NR_lseek +#endif + +#if !defined(__NR_sendfile64) +#define __NR_sendfile64 __NR_sendfile +#endif + +#if !defined(__NR_fstatat64) +#define __NR_fstatat64 __NR_fstatat +#endif + +#if !defined(__NR_fstat64) +#define __NR_fstat64 __NR_fstat +#endif + +#if !defined(__NR_mmap2) +#define __NR_mmap2 __NR_mmap +#endif + +#if !defined(__NR_fadvise64_64) +#define __NR_fadvise64_64 __NR_fadvise64 +#endif + +#if !defined(__NR_stat64) +#define __NR_stat64 __NR_stat +#endif + +#if !defined(__NR_lstat64) +#define __NR_lstat64 __NR_lstat +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_ diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h index 56bbbc4b5a47..5b7f4e511a61 100644 --- a/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h +++ b/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h @@ -2,7 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Generated from the Linux kernel's calls.S. +/* Constructed by running: + * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/arm/tools/syscall.tbl?h=v5.8 + * | grep -vE '^#|^$' + * | awk '{ if ($2 != "oabi") { print "#if !defined(__NR_" $3 ")\n#define __NR_" $3 " (__NR_SYSCALL_BASE+" $1 ")\n#endif\n"; } }' + * */ + #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_ #define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_ @@ -1205,10 +1210,6 @@ #define __NR_arm_sync_file_range (__NR_SYSCALL_BASE+341) #endif -#if !defined(__NR_sync_file_range2) -#define __NR_sync_file_range2 (__NR_SYSCALL_BASE+341) -#endif - #if !defined(__NR_tee) #define __NR_tee (__NR_SYSCALL_BASE+342) #endif @@ -1385,6 +1386,50 @@ #define __NR_memfd_create (__NR_SYSCALL_BASE+385) #endif +#if !defined(__NR_bpf) +#define __NR_bpf (__NR_SYSCALL_BASE+386) +#endif + +#if !defined(__NR_execveat) +#define __NR_execveat (__NR_SYSCALL_BASE+387) +#endif + +#if !defined(__NR_userfaultfd) +#define __NR_userfaultfd (__NR_SYSCALL_BASE+388) +#endif + +#if !defined(__NR_membarrier) +#define __NR_membarrier (__NR_SYSCALL_BASE+389) +#endif + +#if !defined(__NR_mlock2) +#define __NR_mlock2 (__NR_SYSCALL_BASE+390) +#endif + +#if !defined(__NR_copy_file_range) +#define __NR_copy_file_range (__NR_SYSCALL_BASE+391) +#endif + +#if !defined(__NR_preadv2) +#define __NR_preadv2 (__NR_SYSCALL_BASE+392) +#endif + +#if !defined(__NR_pwritev2) +#define __NR_pwritev2 (__NR_SYSCALL_BASE+393) +#endif + +#if !defined(__NR_pkey_mprotect) +#define __NR_pkey_mprotect (__NR_SYSCALL_BASE+394) +#endif + +#if !defined(__NR_pkey_alloc) +#define __NR_pkey_alloc (__NR_SYSCALL_BASE+395) +#endif + +#if !defined(__NR_pkey_free) +#define __NR_pkey_free (__NR_SYSCALL_BASE+396) +#endif + #if !defined(__NR_statx) #define __NR_statx (__NR_SYSCALL_BASE+397) #endif @@ -1392,6 +1437,159 @@ #if !defined(__NR_rseq) #define __NR_rseq (__NR_SYSCALL_BASE+398) #endif + +#if !defined(__NR_io_pgetevents) +#define __NR_io_pgetevents (__NR_SYSCALL_BASE+399) +#endif + +#if !defined(__NR_migrate_pages) +#define __NR_migrate_pages (__NR_SYSCALL_BASE+400) +#endif + +#if !defined(__NR_kexec_file_load) +#define __NR_kexec_file_load (__NR_SYSCALL_BASE+401) +#endif + +#if !defined(__NR_clock_gettime64) +#define __NR_clock_gettime64 (__NR_SYSCALL_BASE+403) +#endif + +#if !defined(__NR_clock_settime64) +#define __NR_clock_settime64 (__NR_SYSCALL_BASE+404) +#endif + +#if !defined(__NR_clock_adjtime64) +#define __NR_clock_adjtime64 (__NR_SYSCALL_BASE+405) +#endif + +#if !defined(__NR_clock_getres_time64) +#define __NR_clock_getres_time64 (__NR_SYSCALL_BASE+406) +#endif + +#if !defined(__NR_clock_nanosleep_time64) +#define __NR_clock_nanosleep_time64 (__NR_SYSCALL_BASE+407) +#endif + +#if !defined(__NR_timer_gettime64) +#define __NR_timer_gettime64 (__NR_SYSCALL_BASE+408) +#endif + +#if !defined(__NR_timer_settime64) +#define __NR_timer_settime64 (__NR_SYSCALL_BASE+409) +#endif + +#if !defined(__NR_timerfd_gettime64) +#define __NR_timerfd_gettime64 (__NR_SYSCALL_BASE+410) +#endif + +#if !defined(__NR_timerfd_settime64) +#define __NR_timerfd_settime64 (__NR_SYSCALL_BASE+411) +#endif + +#if !defined(__NR_utimensat_time64) +#define __NR_utimensat_time64 (__NR_SYSCALL_BASE+412) +#endif + +#if !defined(__NR_pselect6_time64) +#define __NR_pselect6_time64 (__NR_SYSCALL_BASE+413) +#endif + +#if !defined(__NR_ppoll_time64) +#define __NR_ppoll_time64 (__NR_SYSCALL_BASE+414) +#endif + +#if !defined(__NR_io_pgetevents_time64) +#define __NR_io_pgetevents_time64 (__NR_SYSCALL_BASE+416) +#endif + +#if !defined(__NR_recvmmsg_time64) +#define __NR_recvmmsg_time64 (__NR_SYSCALL_BASE+417) +#endif + +#if !defined(__NR_mq_timedsend_time64) +#define __NR_mq_timedsend_time64 (__NR_SYSCALL_BASE+418) +#endif + +#if !defined(__NR_mq_timedreceive_time64) +#define __NR_mq_timedreceive_time64 (__NR_SYSCALL_BASE+419) +#endif + +#if !defined(__NR_semtimedop_time64) +#define __NR_semtimedop_time64 (__NR_SYSCALL_BASE+420) +#endif + +#if !defined(__NR_rt_sigtimedwait_time64) +#define __NR_rt_sigtimedwait_time64 (__NR_SYSCALL_BASE+421) +#endif + +#if !defined(__NR_futex_time64) +#define __NR_futex_time64 (__NR_SYSCALL_BASE+422) +#endif + +#if !defined(__NR_sched_rr_get_interval_time64) +#define __NR_sched_rr_get_interval_time64 (__NR_SYSCALL_BASE+423) +#endif + +#if !defined(__NR_pidfd_send_signal) +#define __NR_pidfd_send_signal (__NR_SYSCALL_BASE+424) +#endif + +#if !defined(__NR_io_uring_setup) +#define __NR_io_uring_setup (__NR_SYSCALL_BASE+425) +#endif + +#if !defined(__NR_io_uring_enter) +#define __NR_io_uring_enter (__NR_SYSCALL_BASE+426) +#endif + +#if !defined(__NR_io_uring_register) +#define __NR_io_uring_register (__NR_SYSCALL_BASE+427) +#endif + +#if !defined(__NR_open_tree) +#define __NR_open_tree (__NR_SYSCALL_BASE+428) +#endif + +#if !defined(__NR_move_mount) +#define __NR_move_mount (__NR_SYSCALL_BASE+429) +#endif + +#if !defined(__NR_fsopen) +#define __NR_fsopen (__NR_SYSCALL_BASE+430) +#endif + +#if !defined(__NR_fsconfig) +#define __NR_fsconfig (__NR_SYSCALL_BASE+431) +#endif + +#if !defined(__NR_fsmount) +#define __NR_fsmount (__NR_SYSCALL_BASE+432) +#endif + +#if !defined(__NR_fspick) +#define __NR_fspick (__NR_SYSCALL_BASE+433) +#endif + +#if !defined(__NR_pidfd_open) +#define __NR_pidfd_open (__NR_SYSCALL_BASE+434) +#endif + +#if !defined(__NR_clone3) +#define __NR_clone3 (__NR_SYSCALL_BASE+435) +#endif + +#if !defined(__NR_openat2) +#define __NR_openat2 (__NR_SYSCALL_BASE+437) +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd (__NR_SYSCALL_BASE+438) +#endif + +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 (__NR_SYSCALL_BASE+439) +#endif + // ARM private syscalls. #if !defined(__ARM_NR_BASE) #define __ARM_NR_BASE (__NR_SYSCALL_BASE + 0xF0000) diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h index 7613c9bbcdc2..dc846ee7ad1a 100644 --- a/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h +++ b/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h @@ -2,7 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Generated from the Linux kernel's syscall_32.tbl. +/* Constructed by running: + * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/x86/entry/syscalls/syscall_32.tbl?h=v5.8 + * | grep -vE '^#|^$' + * | awk '{ if ($2 == "i386") { print "#if !defined(__NR_" $3 ")\n#define __NR_" $3 " " $1 "\n#endif\n"; } }' + * */ + #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_ #define SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_ @@ -1710,5 +1715,17 @@ #define __NR_clone3 435 #endif -#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_ +#if !defined(__NR_openat2) +#define __NR_openat2 437 +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd 438 +#endif +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 439 +#endif + + +#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_ diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h index 83c7b4fc3f82..ab51703464aa 100644 --- a/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h +++ b/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/* Constructed by running a vim macro over - linux-kernel/arch/x86/entry/syscalls/syscall_64.tbl - version 39a38bcba4ab6e5285b07675b0e42c96eec35e67 - which is close to Linux 5.4. -*/ +/* Constructed by running: + * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/x86/entry/syscalls/syscall_64.tbl?h=v5.8 + * | grep -vE '^#|^$' + * | awk '{ if ($2 != "x32") { print "#if !defined(__NR_" $3 ")\n#define __NR_" $3 " " $1 "\n#endif\n"; } }' + * */ + #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_ #define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_ @@ -1402,4 +1403,16 @@ #define __NR_clone3 435 #endif +#if !defined(__NR_openat2) +#define __NR_openat2 437 +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd 438 +#endif + +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 439 +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_ diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp index 4473da766a5e..5812bd99a60a 100644 --- a/security/sandbox/linux/SandboxFilter.cpp +++ b/security/sandbox/linux/SandboxFilter.cpp @@ -295,6 +295,9 @@ class SandboxPolicyCommon : public SandboxPolicyBase { // to handle the flags != 0 case is left to userspace; this is // impossible to do correctly in all cases, but that's not our // problem. + // + // Starting with kernel 5.8+ and glibc 2.33, there is faccessat2 that + // supports flags, handled below. if (fd != AT_FDCWD && path[0] != '/') { SANDBOX_LOG_ERROR("unsupported fd-relative faccessat(%d, \"%s\", %d)", fd, path, mode); @@ -303,6 +306,24 @@ class SandboxPolicyCommon : public SandboxPolicyBase { return broker->Access(path, mode); } + static intptr_t AccessAt2Trap(ArgsRef aArgs, void* aux) { + auto* broker = static_cast(aux); + auto fd = static_cast(aArgs.args[0]); + const auto* path = reinterpret_cast(aArgs.args[1]); + auto mode = static_cast(aArgs.args[2]); + auto flags = static_cast(aArgs.args[3]); + if (fd != AT_FDCWD && path[0] != '/') { + SANDBOX_LOG_ERROR( + "unsupported fd-relative faccessat2(%d, \"%s\", %d, %d)", fd, path, + mode, flags); + return BlockedSyscallTrap(aArgs, nullptr); + } + if ((flags & ~AT_EACCESS) == 0) { + return broker->Access(path, mode); + } + return ConvertError(ENOSYS); + } + static intptr_t StatAtTrap(ArgsRef aArgs, void* aux) { auto broker = static_cast(aux); auto fd = static_cast(aArgs.args[0]); @@ -630,6 +651,8 @@ class SandboxPolicyCommon : public SandboxPolicyBase { return Trap(OpenAtTrap, mBroker); case __NR_faccessat: return Trap(AccessAtTrap, mBroker); + case __NR_faccessat2: + return Trap(AccessAt2Trap, mBroker); CASES_FOR_fstatat: return Trap(StatAtTrap, mBroker); // Used by new libc and Rust's stdlib, if available. @@ -1244,6 +1267,7 @@ class ContentSandboxPolicy : public SandboxPolicyCommon { #endif case __NR_openat: case __NR_faccessat: + case __NR_faccessat2: CASES_FOR_fstatat: case __NR_fchmodat: case __NR_linkat: diff --git a/security/sandbox/test/browser_content_sandbox_syscalls.js b/security/sandbox/test/browser_content_sandbox_syscalls.js index adf65dc05e90..43ba70c3e34d 100644 --- a/security/sandbox/test/browser_content_sandbox_syscalls.js +++ b/security/sandbox/test/browser_content_sandbox_syscalls.js @@ -105,6 +105,28 @@ function callOpen(args) { return fd; } +// Verify faccessat2 +function callFaccessat2(args) { + const { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm"); + let { lib, dirfd, path, mode, flag } = args; + let libc = ctypes.open(lib); + let faccessat = libc.declare( + "faccessat", + ctypes.default_abi, + ctypes.int, + ctypes.int, // dirfd + ctypes.char.ptr, // path + ctypes.int, // mode + ctypes.int // flag + ); + let rv = faccessat(dirfd, path, mode, flag); + if (rv == -1) { + rv = ctypes.errno; + } + libc.close(); + return rv; +} + // open syscall flags function openWriteCreateFlags() { Assert.ok(isMac() || isLinux()); @@ -134,6 +156,43 @@ function getOSLib() { } } +// Reading a header might be weird, but the alternatives to read a stable +// version number we can easily check against are not much more fun +async function getKernelVersion() { + const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm"); + let header = await OS.File.read("/usr/include/linux/version.h", { + encoding: "utf-8", + }); + let hr = header.split("\n"); + for (let line in hr) { + let hrs = hr[line].split(" "); + if (hrs[0] === "#define" && hrs[1] === "LINUX_VERSION_CODE") { + return Number(hrs[2]); + } + } + throw Error("No LINUX_VERSION_CODE"); +} + +// This is how it is done in /usr/include/linux/version.h +function computeKernelVersion(major, minor, dot) { + return (major << 16) + (minor << 8) + dot; +} + +function getGlibcVersion() { + const { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm"); + let libc = ctypes.open(getOSLib()); + let gnu_get_libc_version = libc.declare( + "gnu_get_libc_version", + ctypes.default_abi, + ctypes.char.ptr + ); + let rv = gnu_get_libc_version().readString(); + libc.close(); + let ar = rv.split("."); + // return a number made of MAJORMINOR + return Number(ar[0] + ar[1]); +} + // Returns a harmless command to execute with execv function getOSExecCmd() { Assert.ok(!isWin()); @@ -290,11 +349,50 @@ add_task(async function() { ok(rv == 0, "calling sysctl('hw.ncpu') is permitted"); } - // verify we block PR_CAPBSET_READ with EINVAL if (isLinux()) { const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm"); + + // verify we block PR_CAPBSET_READ with EINVAL let option = OS.Constants.libc.PR_CAPBSET_READ; let rv = await SpecialPowers.spawn(browser, [{ lib, option }], callPrctl); ok(rv == OS.Constants.libc.EINVAL, "prctl(PR_CAPBSET_READ) is blocked"); + + const kernelVersion = await getKernelVersion(); + const glibcVersion = getGlibcVersion(); + // faccessat2 is only used with kernel 5.8+ by glibc 2.33+ + if (glibcVersion >= 233 && kernelVersion >= computeKernelVersion(5, 8, 0)) { + info("Linux v5.8+, glibc 2.33+, checking faccessat2"); + const dirfd = 0; + const path = "/"; + const mode = 0; + // the value 0x01 is just one we know should get rejected + let rv = await SpecialPowers.spawn( + browser, + [{ lib, dirfd, path, mode, flag: 0x01 }], + callFaccessat2 + ); + ok( + rv == OS.Constants.libc.ENOSYS, + "faccessat2 (flag=0x01) was blocked with ENOSYS" + ); + + rv = await SpecialPowers.spawn( + browser, + [{ lib, dirfd, path, mode, flag: OS.Constants.libc.AT_EACCESS }], + callFaccessat2 + ); + ok( + rv == OS.Constants.libc.EACCES, + "faccessat2 (flag=0x200) was allowed, errno=EACCES" + ); + } else { + info( + "Unsupported kernel (" + + kernelVersion + + " )/glibc (" + + glibcVersion + + "), skipping faccessat2" + ); + } } }); -- 2.11.4.GIT