diff --git a/bin/cheribsdtest/cheribsdtest_registers.c b/bin/cheribsdtest/cheribsdtest_registers.c index 444b04fd346c..e8a8f52efbf1 100644 --- a/bin/cheribsdtest/cheribsdtest_registers.c +++ b/bin/cheribsdtest/cheribsdtest_registers.c @@ -74,7 +74,7 @@ static void check_initreg_code(void * __capability c) { - uintmax_t v; + uintmax_t v, expect; #if defined(__CHERI_PURE_CAPABILITY__) && !defined(__ARM_MORELLO_PURECAP_BENCHMARK_ABI) /* @@ -165,22 +165,24 @@ check_initreg_code(void * __capability c) if ((v & CHERI_PERM_SYSTEM_REGS) != 0) cheribsdtest_failure_errx("perms %jx (system_regs present)", v); - if ((v & CHERI_PERMS_SWALL) != - (CHERI_PERMS_SWALL & ~CHERI_PERM_SW_VMEM)) - cheribsdtest_failure_errx("swperms %jx (expected swperms %x)", - v & CHERI_PERMS_SWALL, - (CHERI_PERMS_SWALL & ~CHERI_PERM_SW_VMEM)); + expect = CHERI_PERMS_SWALL & ~CHERI_PERM_SW_VMEM; +#ifdef CHERIBSD_C18N_TESTS + expect &= ~CHERI_PERM_SYSCALL; +#endif + if ((v & CHERI_PERMS_SWALL) != expect) + cheribsdtest_failure_errx("swperms %jx (expected swperms %jx)", + v & CHERI_PERMS_SWALL, expect); /* Check that the raw permission bits match the kernel header: */ -#if defined(CHERIBSD_C18N_TESTS) && !defined(__ARM_MORELLO_PURECAP_BENCHMARK_ABI) - if (v != (CHERI_CAP_USER_CODE_PERMS & ~CHERI_PERM_EXECUTIVE)) - cheribsdtest_failure_errx("perms %jx (expected %jx)", v, - (uintmax_t)(CHERI_CAP_USER_CODE_PERMS & ~CHERI_PERM_EXECUTIVE)); -#else - if (v != CHERI_CAP_USER_CODE_PERMS) - cheribsdtest_failure_errx("perms %jx (expected %jx)", v, - (uintmax_t)CHERI_CAP_USER_CODE_PERMS); + expect = CHERI_CAP_USER_CODE_PERMS; +#ifdef CHERIBSD_C18N_TESTS + expect &= ~CHERI_PERM_SYSCALL; +#if defined(__aarch64__) && !defined(__ARM_MORELLO_PURECAP_BENCHMARK_ABI) + expect &= ~CHERI_PERM_EXECUTIVE; +#endif #endif + if (v != expect) + cheribsdtest_failure_errx("perms %jx (expected %jx)", v, expect); cheribsdtest_success(); } diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys index 2f1801671a98..76c76a8005b3 100644 --- a/lib/libsys/Makefile.sys +++ b/lib/libsys/Makefile.sys @@ -102,11 +102,13 @@ INTERPOSED = \ .ifdef CHERI_LIB_C18N # Pseudo implementations of system calls we don't currently fully support SRCS+= \ + mmap_c18n.c \ rfork_c18n.c \ thr_exit_c18n.c \ vfork_c18n.c PSEUDO+= \ + mmap \ rfork NOASM+= \ thr_exit.o \ diff --git a/lib/libsys/mmap_c18n.c b/lib/libsys/mmap_c18n.c new file mode 100644 index 000000000000..2945f3e5d234 --- /dev/null +++ b/lib/libsys/mmap_c18n.c @@ -0,0 +1,45 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Dapeng Gao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "libc_private.h" + +void * +mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) +{ + void *ret; + + ret = __sys_mmap(addr, len, prot, flags, fd, offset); +#if defined(__aarch64__) && !defined(__ARM_MORELLO_PURECAP_BENCHMARK_ABI) + ret = cheri_clearperm(ret, CHERI_PERM_EXECUTIVE); +#endif + ret = cheri_clearperm(ret, CHERI_PERM_SYSCALL); + return (ret); +} diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 08741050883c..1b26ed089340 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -248,9 +248,6 @@ map_object(int fd, const char *path, const struct stat *sb, const char* main_pat base_addr, mapsize, PROT_NONE | PROT_MAX(_PROT_ALL), base_flags); mapbase = mmap(base_addr, mapsize, PROT_NONE | PROT_MAX(_PROT_ALL), base_flags, -1, 0); -#ifdef CHERI_LIB_C18N - mapbase = cheri_clearperm(mapbase, c18n_code_perm_clear); -#endif if (mapbase == MAP_FAILED) { _rtld_error("%s: mmap of entire address space failed: %s", path, rtld_strerror(errno)); diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 5ac483d2b9fe..c13739c3c242 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -835,7 +835,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) ld_elf_hints_default = _PATH_ELF_HINTS_C18N; ld_path_libmap_conf = _PATH_LIBMAP_CONF_C18N; ld_standard_library_path = STANDARD_LIBRARY_PATH_C18N; - c18n_code_perm_clear = CHERI_PERM_EXECUTIVE; } #endif @@ -884,9 +883,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr)); assert(aux_info[AT_ENTRY] != NULL); imgentry = (dlfunc_t) aux_info[AT_ENTRY]->a_un.a_ptr; -#ifdef CHERI_LIB_C18N - imgentry = (dlfunc_t) cheri_clearperm(imgentry, c18n_code_perm_clear); -#endif dbg("Values from kernel:\n\tAT_PHDR=" PTR_FMT "\n" "\tAT_BASE=" PTR_FMT "\n\tAT_ENTRY=" PTR_FMT "\n", phdr, aux_info[AT_BASE]->a_un.a_ptr, (const void *)imgentry); @@ -6404,6 +6400,15 @@ c18n_assign_plt_compartments(Obj_Entry *obj) } } +static const void * +c18n_clear_pcc_perms(const char *name, const void *pcc) +{ + pcc = cheri_clearperm(pcc, CHERI_PERM_EXECUTIVE); + if (strcmp("libsys.so.7", name) != 0) + pcc = cheri_clearperm(pcc, CHERI_PERM_SYSCALL); + return (pcc); +} + static bool c18n_add_obj(Obj_Entry *obj, const char *name) { @@ -6427,6 +6432,12 @@ c18n_add_obj(Obj_Entry *obj, const char *name) return (false); } + /* Reduce the permission of each compartment's pcc. */ + obj->entry = c18n_clear_pcc_perms(name, obj->entry); + obj->text_rodata_cap = c18n_clear_pcc_perms(name, obj->text_rodata_cap); + for (unsigned long i = 0; i < obj->npcc_caps; ++i) + obj->pcc_caps[i] = c18n_clear_pcc_perms(name, obj->pcc_caps[i]); + c18n_setup_compartments(obj, name); c18n_assign_plt_compartments(obj); return (true); diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index eb88bfa5ba9b..436dc70d0737 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -124,9 +124,6 @@ uintptr_t sealer_pltgot, sealer_tramp; /* Enable compartmentalisation */ bool ld_compartment_enable; -/* Permission bit to be cleared for user code */ -uint64_t c18n_code_perm_clear; - /* Use utrace() to log compartmentalisation-related events */ const char *ld_compartment_utrace; diff --git a/libexec/rtld-elf/rtld_c18n.h b/libexec/rtld-elf/rtld_c18n.h index 2f8e3fe73de8..c1d5e35866a8 100644 --- a/libexec/rtld-elf/rtld_c18n.h +++ b/libexec/rtld-elf/rtld_c18n.h @@ -35,7 +35,6 @@ /* * Global symbols */ -extern size_t c18n_code_perm_clear; extern uintptr_t sealer_pltgot, sealer_tramp; extern const char *ld_compartment_utrace; extern const char *ld_compartment_policy; diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index cf02dafa9b11..66801a8fdbff 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -192,6 +192,11 @@ cpu_fetch_syscall_args(struct thread *td) if (__predict_false(sa->code >= p->p_sysent->sv_size)) sa->callp = &nosys_sysent; +#if __has_feature(capabilities) && !defined(CPU_CHERI_NO_SYSCALL_AUTHORIZE) + /* Constrain code that can originate system calls. */ + else if (__predict_false(!cheri_syscall_authorize(td))) + sa->callp = &nosys_sysent; +#endif else sa->callp = &p->p_sysent->sv_table[sa->code]; diff --git a/sys/cheri/cheri.h b/sys/cheri/cheri.h index f4f783b2e168..10b9396f5593 100644 --- a/sys/cheri/cheri.h +++ b/sys/cheri/cheri.h @@ -136,8 +136,7 @@ void * __capability cheri_sigcode_capability(struct thread *td); * CHERI context management functions. */ const char *cheri_exccode_string(uint8_t exccode); -int cheri_syscall_authorize(struct thread *td, u_int code, - int nargs, syscallarg_t *args); +int cheri_syscall_authorize(struct thread *td); /* * Functions to manage object types. @@ -164,8 +163,6 @@ bool vm_derive_capreg(struct proc *p, uintcap_t in, uintcap_t *out); */ SYSCTL_DECL(_security_cheri); SYSCTL_DECL(_security_cheri_stats); -extern u_int security_cheri_debugger_on_sandbox_syscall; -extern u_int security_cheri_syscall_violations; extern u_int security_cheri_bound_legacy_capabilities; extern u_int cheri_cloadtags_stride; #ifdef __aarch64__ diff --git a/sys/cheri/cheri_syscall.c b/sys/cheri/cheri_syscall.c index 2aa99029cb20..174a530363d4 100644 --- a/sys/cheri/cheri_syscall.c +++ b/sys/cheri/cheri_syscall.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011-2014, 2016 Robert N. M. Watson + * Copyright (c) 2025 Dapeng Gao * All rights reserved. * * This software was developed by SRI International and the University of @@ -28,50 +29,17 @@ * SUCH DAMAGE. */ -#include "opt_ddb.h" - #include -#include #include -#include -#include - -#include -#include #include #include /* - * Only allow most system calls from either ambient authority, or from - * sandboxes that have been explicitly delegated CHERI_PERM_SYSCALL via their - * code capability. Note that CHERI_PERM_SYSCALL effectively implies ambient - * authority, as the kernel does not [currently] interpret pointers/lengths - * via userspace $ddc. + * Only allow system calls from code that has the CHERI_PERM_SYSCALL permission. */ int -cheri_syscall_authorize(struct thread *td, u_int code, int nargs, - syscallarg_t *args) +cheri_syscall_authorize(struct thread *td) { - uintmax_t c_perms; - - /* - * Check whether userspace holds the rights defined in - * cheri_capability_set_user() in $pcc. Note that object type doesn't - * come into play here. - * - * XXXRW: Possibly ECAPMODE should be EPROT or ESANDBOX? - */ - c_perms = cheri_getperm(__USER_PCC); - if ((c_perms & CHERI_PERM_SYSCALL) == 0) { - atomic_add_int(&security_cheri_syscall_violations, 1); - -#ifdef DDB - if (security_cheri_debugger_on_sandbox_syscall) - kdb_enter(KDB_WHY_CHERI, - "Syscall rejected in CHERI sandbox"); -#endif - return (ECAPMODE); - } - return (0); + return ((cheri_getperm(__USER_PCC) & CHERI_PERM_SYSCALL) != 0); } diff --git a/sys/cheri/cheri_sysctl.c b/sys/cheri/cheri_sysctl.c index b6ed6bb26e76..ba023092cebb 100644 --- a/sys/cheri/cheri_sysctl.c +++ b/sys/cheri/cheri_sysctl.c @@ -57,20 +57,10 @@ SYSCTL_UINT(_security_cheri, OID_AUTO, capability_size, CTLFLAG_RD, SYSCTL_NODE(_security_cheri, OID_AUTO, stats, CTLFLAG_RD, 0, "CHERI statistics"); -/* XXXRW: Should possibly be u_long. */ -u_int security_cheri_syscall_violations; -SYSCTL_UINT(_security_cheri_stats, OID_AUTO, syscall_violations, CTLFLAG_RD, - &security_cheri_syscall_violations, 0, "Number of system calls blocked"); - /* * A set of sysctls that cause the kernel debugger to enter following a policy * violation or signal delivery due to CHERI or while in a sandbox. */ -u_int security_cheri_debugger_on_sandbox_syscall; -SYSCTL_UINT(_security_cheri, OID_AUTO, debugger_on_sandbox_syscall, CTLFLAG_RW, - &security_cheri_debugger_on_sandbox_syscall, 0, - "Enter KDB when a syscall is rejected while in a sandbox"); - u_int security_cheri_abort_on_memcpy_tag_loss; SYSCTL_UINT(_security_cheri, OID_AUTO, abort_on_memcpy_tag_loss, CTLFLAG_RW, &security_cheri_abort_on_memcpy_tag_loss, 0, diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index ecceb3df637d..5e17a74f53da 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -93,17 +93,6 @@ syscallenter(struct thread *td) goto retval; } -#if __has_feature(capabilities) && !defined(CPU_CHERI_NO_SYSCALL_AUTHORIZE) - /* - * Constrain code that can originate system calls if - * userspace sandboxing is available. - */ - error = cheri_syscall_authorize(td, sa->code, sa->callp->sy_narg, - sa->args); - if (error != 0) - goto retval; -#endif - if (__predict_false(traced)) { PROC_LOCK(p); if (p->p_ptevents & PTRACE_SCE)