From 08f323e5b59d096287f6aeb2a3ce973e9ec3441e Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 6 Feb 2025 14:33:53 +0000 Subject: [PATCH] caprevoke: Avoid crashing if the revoker encounters a kernel capability Kernel bugs, especially in ioctl handlers, can lead to a kernel capability being leaked to userspace. When the revoker encounters such a capability it ends up accessing memory beyond the end of the bitmap, which may trigger a panic, e.g., if the vm_cheri_revoke_tlb_fault() fault handler is invoked in FAST_COPYIN mode. Such bugs ought to be fixed, of course, but panicking the system is not really desireable, especially since the resulting crash dump doesn't help much in determining how the capability was leaked in the first place. Explicitly check for out-of-bounds capabilities before accessing the shadow bitmap and print a warning to the console instead. --- sys/arm64/arm64/cheri_revoke_machdep_tests.c | 10 ++++++++++ sys/riscv/riscv/cheri_revoke_machdep_tests.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/sys/arm64/arm64/cheri_revoke_machdep_tests.c b/sys/arm64/arm64/cheri_revoke_machdep_tests.c index 594f2e5f992f..50c500aa9398 100644 --- a/sys/arm64/arm64/cheri_revoke_machdep_tests.c +++ b/sys/arm64/arm64/cheri_revoke_machdep_tests.c @@ -53,6 +53,11 @@ vm_cheri_revoke_test_mem_map(const uint8_t * __capability crshadow, const uint8_t * __capability bmloc; ptraddr_t va = cheri_getbase(cut); + if (__predict_false(va >= VM_MAX_USER_ADDRESS)) { + printf("%s: kernel capability leaked to userspace: %#lp\n", + __func__, (void * __capability)cut); + return (0); + } bmloc = crshadow - VM_CHERI_REVOKE_BSZ_OTYPE - (va / VM_CHERI_REVOKE_GSZ_MEM_MAP / 8); @@ -90,6 +95,11 @@ vm_cheri_revoke_test_mem_nomap(const uint8_t * __capability crshadow, const uint8_t * __capability bmloc; ptraddr_t va = cheri_getbase(cut); + if (__predict_false(va >= VM_MAX_USER_ADDRESS)) { + printf("%s: kernel capability leaked to userspace: %#lp\n", + __func__, (void * __capability)cut); + return (0); + } bmloc = crshadow + (va / VM_CHERI_REVOKE_GSZ_MEM_NOMAP / 8); diff --git a/sys/riscv/riscv/cheri_revoke_machdep_tests.c b/sys/riscv/riscv/cheri_revoke_machdep_tests.c index cb9bf070c7b3..7d1f0c968a07 100644 --- a/sys/riscv/riscv/cheri_revoke_machdep_tests.c +++ b/sys/riscv/riscv/cheri_revoke_machdep_tests.c @@ -53,6 +53,11 @@ vm_cheri_revoke_test_mem_map(const uint8_t * __capability crshadow, const uint8_t * __capability bmloc; ptraddr_t va = cheri_getbase(cut); + if (__predict_false(va >= VM_MAX_USER_ADDRESS)) { + printf("%s: kernel capability leaked to userspace: %#lp\n", + __func__, (void * __capability)cut); + return (0); + } bmloc = crshadow - VM_CHERI_REVOKE_BSZ_OTYPE - (va / VM_CHERI_REVOKE_GSZ_MEM_MAP / 8); @@ -91,6 +96,11 @@ vm_cheri_revoke_test_mem_nomap(const uint8_t * __capability crshadow, const uint8_t * __capability bmloc; ptraddr_t va = cheri_getbase(cut); + if (__predict_false(va >= VM_MAX_USER_ADDRESS)) { + printf("%s: kernel capability leaked to userspace: %#lp\n", + __func__, (void * __capability)cut); + return (0); + } bmloc = crshadow + (va / VM_CHERI_REVOKE_GSZ_MEM_NOMAP / 8);