From 17a058a4be24365e58880d1f6022433d570db748 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 2 Jan 2025 17:02:52 +0000 Subject: [PATCH 1/7] vmm: Set bounds in _vm_gpa_hold() --- sys/arm64/vmm/vmm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sys/arm64/vmm/vmm.c b/sys/arm64/vmm/vmm.c index 327e03c584c5..824ab9af0611 100644 --- a/sys/arm64/vmm/vmm.c +++ b/sys/arm64/vmm/vmm.c @@ -1570,8 +1570,9 @@ _vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, void * __capability gpap; #if __has_feature(capabilities) - gpap = cheri_setaddress(vmm_gpa_root_cap, - trunc_page(gpa)); + gpap = cheri_setboundsexact( + cheri_setaddress(vmm_gpa_root_cap, trunc_page(gpa)), + PAGE_SIZE); #else gpap = (void *)trunc_page(gpa); #endif @@ -1583,7 +1584,7 @@ _vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, if (count == 1) { *cookie = m; - return (cheri_kern_setbounds( + return (cheri_kern_setboundsexact( (void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff), len)); } else { *cookie = NULL; From 572c912bbfb9f6f7817a275b1b0ab893a25c06e9 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 2 Jan 2025 15:46:53 +0000 Subject: [PATCH 2/7] vmm: Add an ioctl to fetch a capability tag from the guest PA space This is needed by the gdb stub when loading a capability from guest memory. The capability itself is fetched via a mapping of the guest address space, but this mapping necessarily clears tags, as otherwise it'd be subject to revocation sweeps. --- sys/arm64/include/vmm.h | 7 +++++++ sys/arm64/include/vmm_dev.h | 16 ++++++++++++++++ sys/arm64/vmm/vmm.c | 20 ++++++++++++++++++++ sys/dev/vmm/vmm_dev.c | 13 +++++++++++++ 4 files changed, 56 insertions(+) diff --git a/sys/arm64/include/vmm.h b/sys/arm64/include/vmm.h index 2882ad082178..ec97a22ecbff 100644 --- a/sys/arm64/include/vmm.h +++ b/sys/arm64/include/vmm.h @@ -178,6 +178,9 @@ struct vm_object; struct vm_guest_paging; struct vm_vgic_descr; struct pmap; +#if __has_feature(capabilities) +struct vm_cheri_capability_tag; +#endif struct vm_eventinfo { void *rptr; /* rendezvous cookie */ @@ -222,6 +225,10 @@ void *vm_gpa_hold_global(struct vm *vm, vm_paddr_t gpa, size_t len, int prot, void **cookie); void vm_gpa_release(void *cookie); bool vm_mem_allocated(struct vcpu *vcpu, vm_paddr_t gpa); +#if __has_feature(capabilities) +int vm_get_cheri_capability_tag(struct vm *vm, + struct vm_cheri_capability_tag *vt); +#endif int vm_gla2gpa_nofault(struct vcpu *vcpu, struct vm_guest_paging *paging, uint64_t gla, int prot, uint64_t *gpa, int *is_fault); diff --git a/sys/arm64/include/vmm_dev.h b/sys/arm64/include/vmm_dev.h index 17f9cbfcccf4..30b90db9b4c7 100644 --- a/sys/arm64/include/vmm_dev.h +++ b/sys/arm64/include/vmm_dev.h @@ -159,6 +159,13 @@ struct vm_cpu_topology { uint16_t maxcpus; }; +#if __has_feature(capabilities) +struct vm_cheri_capability_tag { + vm_paddr_t gpa; /* input, must be aligned */ + uint8_t tag; /* output */ +}; +#endif + enum { /* general routines */ IOCNUM_ABIVERS = 0, @@ -206,6 +213,10 @@ enum { /* vm_attach_vgic */ IOCNUM_GET_VGIC_VERSION = 110, IOCNUM_ATTACH_VGIC = 111, + +#if __has_feature(capabilities) + IOCNUM_GET_CHERI_CAPABILITY_TAG = 200, +#endif }; #define VM_RUN \ @@ -266,4 +277,9 @@ enum { _IOR('v', IOCNUM_GET_VGIC_VERSION, struct vm_vgic_version) #define VM_ATTACH_VGIC \ _IOW('v', IOCNUM_ATTACH_VGIC, struct vm_vgic_descr) +#if __has_feature(capabilities) +#define VM_GET_CHERI_CAPABILITY_TAG \ + _IOWR('v', IOCNUM_GET_CHERI_CAPABILITY_TAG, \ + struct vm_cheri_capability_tag) +#endif #endif diff --git a/sys/arm64/vmm/vmm.c b/sys/arm64/vmm/vmm.c index 824ab9af0611..c16ae93cca65 100644 --- a/sys/arm64/vmm/vmm.c +++ b/sys/arm64/vmm/vmm.c @@ -1690,6 +1690,26 @@ vm_deassert_irq(struct vm *vm, uint32_t irq) return (vgic_inject_irq(vm->cookie, -1, irq, false)); } +#if __has_feature(capabilities) +int +vm_get_cheri_capability_tag(struct vm *vm, struct vm_cheri_capability_tag *vt) +{ + uintcap_t *cap; + void *cookie; + + if (!__is_aligned(vt->gpa, sizeof(*cap))) + return (EINVAL); + + cap = vm_gpa_hold_global(vm, vt->gpa, sizeof(*cap), VM_PROT_READ, + &cookie); + if (cap == NULL) + return (EFAULT); + vt->tag = cheri_gettag(*cap); + vm_gpa_release(cookie); + return (0); +} +#endif + int vm_raise_msi(struct vm *vm, uint64_t msg, uint64_t addr, int bus, int slot, int func) diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c index 56e6d11e017c..4dc9cbd7288c 100644 --- a/sys/dev/vmm/vmm_dev.c +++ b/sys/dev/vmm/vmm_dev.c @@ -375,6 +375,10 @@ static const struct vmmdev_ioctl vmmdev_ioctls[] = { VMMDEV_IOCTL(VM_GET_CPUS, 0), VMMDEV_IOCTL(VM_GET_TOPOLOGY, 0), VMMDEV_IOCTL(VM_SET_TOPOLOGY, 0), + +#if __has_feature(capabilities) + VMMDEV_IOCTL(VM_GET_CHERI_CAPABILITY_TAG, VMMDEV_IOCTL_SLOCK_MEMSEGS), +#endif }; static int @@ -648,6 +652,15 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, error = 0; break; } +#if __has_feature(capabilities) + case VM_GET_CHERI_CAPABILITY_TAG: { + struct vm_cheri_capability_tag *vt; + + vt = (struct vm_cheri_capability_tag *)data; + error = vm_get_cheri_capability_tag(sc->vm, vt); + break; + } +#endif default: error = vmmdev_machdep_ioctl(sc->vm, vcpu, cmd, data, fflag, td); From 9110b7e072486944ef0f7ba10a711cea3ec0ea5a Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 2 Jan 2025 15:50:03 +0000 Subject: [PATCH 3/7] libvmmapi: Add a wrapper for the VM_GET_CAPABILITY_TAG ioctl --- lib/libvmmapi/aarch64/vmmapi_machdep.c | 3 +++ lib/libvmmapi/vmmapi.c | 17 +++++++++++++++++ lib/libvmmapi/vmmapi.h | 8 ++++++++ 3 files changed, 28 insertions(+) diff --git a/lib/libvmmapi/aarch64/vmmapi_machdep.c b/lib/libvmmapi/aarch64/vmmapi_machdep.c index fb2556af3be2..8ce867a26dfc 100644 --- a/lib/libvmmapi/aarch64/vmmapi_machdep.c +++ b/lib/libvmmapi/aarch64/vmmapi_machdep.c @@ -53,6 +53,9 @@ const char *vm_capstrmap[] = { const cap_ioctl_t vm_ioctl_cmds[] = { VM_COMMON_IOCTLS, VM_MD_IOCTLS, +#if __has_feature(capabilities) + VM_GET_CHERI_CAPABILITY_TAG, +#endif }; size_t vm_ioctl_ncmds = nitems(vm_ioctl_cmds); diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index d8c49665faed..8ce4a1223c5d 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -1122,6 +1122,23 @@ vm_restore_time(struct vmctx *ctx) } #endif +#if __has_feature(capabilities) +int +vm_get_cheri_capability_tag(struct vmctx *ctx, vm_paddr_t gpa, uint8_t *tag) +{ + struct vm_cheri_capability_tag vt; + int error; + + bzero(&vt, sizeof(vt)); + vt.gpa = gpa; + + error = ioctl(ctx->fd, VM_GET_CHERI_CAPABILITY_TAG, &vt); + if (error == 0) + *tag = vt.tag; + return (error); +} +#endif + int vm_set_topology(struct vmctx *ctx, uint16_t sockets, uint16_t cores, uint16_t threads, uint16_t maxcpus) diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index ea340f475a79..d0fe29e40c08 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -284,6 +284,14 @@ void vm_setup_freebsd_gdt(uint64_t *gdtr); int vm_snapshot_req(struct vmctx *ctx, struct vm_snapshot_meta *meta); int vm_restore_time(struct vmctx *ctx); +#if __has_feature(capabilities) +/* + * CHERI interfaces + */ +int vm_get_cheri_capability_tag(struct vmctx *ctx, vm_paddr_t gpa, + uint8_t *tag); +#endif + /* * Deprecated interfaces, do not use them in new code. */ From d72451fb1f3d3cd90c51681bee68b5163fd0386c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 2 Jan 2025 15:50:18 +0000 Subject: [PATCH 4/7] bhyve: Fix fetching of capability tags The mapping of the guest address space clears tags, so we need to fetch them out of band. --- usr.sbin/bhyve/gdb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/gdb.c b/usr.sbin/bhyve/gdb.c index 18cd17624924..370cab3a11a1 100644 --- a/usr.sbin/bhyve/gdb.c +++ b/usr.sbin/bhyve/gdb.c @@ -1963,12 +1963,16 @@ gdb_query(const uint8_t *data, size_t len) return; } + error = vm_get_cheri_capability_tag(ctx, gpa, &capbuf[0]); + if (error != 0) { + send_error(errno); + return; + } cap = paddr_guest2host(ctx, gpa, sizeof(uintcap_t)); if (cap == NULL) { send_error(EFAULT); return; } - capbuf[0] = cheri_gettag(*cap); memcpy(&capbuf[1], cap, sizeof(uintcap_t)); start_packet(); From a6c438959a108c20cff212df4af60ee49af054d4 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Fri, 3 Jan 2025 18:21:46 +0000 Subject: [PATCH 5/7] arm64/vmm: Avoid returning valid capabilities from VM_GET_REGISTER The VM_GET_REGISTER and VM_GET_REGISTER_SET ioctls return guest register values; on arm64 they are used only by bhyve's gdb stub. The ioctls may return valid capabilities, which is a mistake since they belong to a different address space. Modify the ioctl handlers to strip capability tags before returning to userspace. Since the gdb stub still wants the tag values, provide two new ioctls for this purpose: VM_GET_REGISTER_CHERI_CAPABILITY_TAG and VM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET. They are not atomic, but for practical purposes the target vCPU will be stopped anyway, and this lets us side-step compatibility concerns. --- sys/arm64/include/vmm.h | 4 +++ sys/arm64/include/vmm_dev.h | 25 +++++++++++++++ sys/arm64/vmm/vmm.c | 17 ++++++++++ sys/dev/vmm/vmm_dev.c | 63 +++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/sys/arm64/include/vmm.h b/sys/arm64/include/vmm.h index ec97a22ecbff..c435fefdfdd0 100644 --- a/sys/arm64/include/vmm.h +++ b/sys/arm64/include/vmm.h @@ -239,6 +239,10 @@ void vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores, int vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores, uint16_t threads, uint16_t maxcpus); int vm_get_register(struct vcpu *vcpu, int reg, uintcap_t *retval); +#if __has_feature(capabilities) +int vm_get_register_cheri_capability_tag(struct vcpu *vcpu, int reg, + uint8_t *tagp); +#endif int vm_set_register(struct vcpu *vcpu, int reg, uintcap_t val); int vm_run(struct vcpu *vcpu); int vm_suspend(struct vm *vm, enum vm_suspend_how how); diff --git a/sys/arm64/include/vmm_dev.h b/sys/arm64/include/vmm_dev.h index 30b90db9b4c7..6c45fe6fd425 100644 --- a/sys/arm64/include/vmm_dev.h +++ b/sys/arm64/include/vmm_dev.h @@ -57,6 +57,14 @@ struct vm_register { kuintcap_t regval; }; +#if __has_feature(capabilities) +struct vm_register_cheri_capability_tag { + int cpuid; + int regnum; /* enum vm_reg_name */ + uint8_t tag; +}; +#endif + struct vm_register_set { int cpuid; unsigned int count; @@ -64,6 +72,15 @@ struct vm_register_set { uintcap_t * __kerncap regvals; }; +#if __has_feature(capabilities) +struct vm_register_cheri_capability_tag_set { + int cpuid; + unsigned int count; + const int * __kerncap regnums; /* enum vm_reg_name */ + uint8_t * __kerncap tags; +}; +#endif + struct vm_run { int cpuid; cpuset_t * __kerncap cpuset; /* CPU set storage */ @@ -216,6 +233,8 @@ enum { #if __has_feature(capabilities) IOCNUM_GET_CHERI_CAPABILITY_TAG = 200, + IOCNUM_GET_REGISTER_CHERI_CAPABILITY_TAG = 201, + IOCNUM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET = 202, #endif }; @@ -281,5 +300,11 @@ enum { #define VM_GET_CHERI_CAPABILITY_TAG \ _IOWR('v', IOCNUM_GET_CHERI_CAPABILITY_TAG, \ struct vm_cheri_capability_tag) +#define VM_GET_REGISTER_CHERI_CAPABILITY_TAG \ + _IOWR('v', IOCNUM_GET_REGISTER_CHERI_CAPABILITY_TAG, \ + struct vm_register_cheri_capability_tag) +#define VM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET \ + _IOW('v', IOCNUM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET, \ + struct vm_register_cheri_capability_tag_set) #endif #endif diff --git a/sys/arm64/vmm/vmm.c b/sys/arm64/vmm/vmm.c index c16ae93cca65..ef740550a8a5 100644 --- a/sys/arm64/vmm/vmm.c +++ b/sys/arm64/vmm/vmm.c @@ -1634,6 +1634,23 @@ vm_get_register(struct vcpu *vcpu, int reg, uintcap_t *retval) return (vmmops_getreg(vcpu->cookie, reg, retval)); } +#if __has_feature(capabilities) +int +vm_get_register_cheri_capability_tag(struct vcpu *vcpu, int reg, uint8_t *tagp) +{ + uintcap_t val; + int error; + + if (reg >= VM_REG_LAST) + return (EINVAL); + + error = vmmops_getreg(vcpu->cookie, reg, &val); + if (error == 0) + *tagp = cheri_gettag(val); + return (error); +} +#endif + int vm_set_register(struct vcpu *vcpu, int reg, uintcap_t val) { diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c index 4dc9cbd7288c..7c94ca3c8a6f 100644 --- a/sys/dev/vmm/vmm_dev.c +++ b/sys/dev/vmm/vmm_dev.c @@ -303,10 +303,31 @@ vm_get_register_set(struct vcpu *vcpu, unsigned int count, int *regnum, error = vm_get_register(vcpu, regnum[i], ®val[i]); if (error) break; +#if __has_feature(capabilities) + regval[i] = cheri_cleartag(regval[i]); +#endif } return (error); } +#if __has_feature(capabilities) +static int +vm_get_register_cheri_capability_tag_set(struct vcpu *vcpu, unsigned int count, + int *regnum, uint8_t *tags) +{ + int error, i; + + error = 0; + for (i = 0; i < count; i++) { + error = vm_get_register_cheri_capability_tag(vcpu, regnum[i], + &tags[i]); + if (error) + break; + } + return (error); +} +#endif + static int vm_set_register_set(struct vcpu *vcpu, unsigned int count, int *regnum, uintcap_t *regval) @@ -378,6 +399,10 @@ static const struct vmmdev_ioctl vmmdev_ioctls[] = { #if __has_feature(capabilities) VMMDEV_IOCTL(VM_GET_CHERI_CAPABILITY_TAG, VMMDEV_IOCTL_SLOCK_MEMSEGS), + VMMDEV_IOCTL(VM_GET_REGISTER_CHERI_CAPABILITY_TAG, + VMMDEV_IOCTL_LOCK_ONE_VCPU), + VMMDEV_IOCTL(VM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET, + VMMDEV_IOCTL_LOCK_ONE_VCPU), #endif }; @@ -522,6 +547,10 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, vmreg = (struct vm_register *)data; error = vm_get_register(vcpu, vmreg->regnum, &vmreg->regval); +#if __has_feature(capabilities) + if (error == 0) + vmreg->regval = cheri_cleartag(vmreg->regval); +#endif break; } case VM_SET_REGISTER: { @@ -660,6 +689,40 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, error = vm_get_cheri_capability_tag(sc->vm, vt); break; } + case VM_GET_REGISTER_CHERI_CAPABILITY_TAG: { + struct vm_register_cheri_capability_tag *vrct; + + vrct = (struct vm_register_cheri_capability_tag *)data; + error = vm_get_register_cheri_capability_tag(vcpu, vrct->regnum, + &vrct->tag); + break; + } + case VM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET: { + struct vm_register_cheri_capability_tag_set *vmtagset; + uint8_t *tags; + int *regnums; + + vmtagset = (struct vm_register_cheri_capability_tag_set *)data; + if (vmtagset->count > VM_REG_LAST) { + error = EINVAL; + break; + } + tags = malloc(sizeof(tags[0]) * vmtagset->count, M_VMMDEV, + M_WAITOK); + regnums = malloc(sizeof(regnums[0]) * vmtagset->count, M_VMMDEV, + M_WAITOK); + error = copyin(vmtagset->regnums, regnums, sizeof(regnums[0]) * + vmtagset->count); + if (error == 0) + error = vm_get_register_cheri_capability_tag_set(vcpu, + vmtagset->count, regnums, tags); + if (error == 0) + error = copyout(tags, vmtagset->tags, + sizeof(tags[0]) * vmtagset->count); + free(tags, M_VMMDEV); + free(regnums, M_VMMDEV); + break; + } #endif default: error = vmmdev_machdep_ioctl(sc->vm, vcpu, cmd, data, fflag, From ecb1b9448125c7735d6d840a92034275946b106b Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Fri, 3 Jan 2025 18:33:15 +0000 Subject: [PATCH 6/7] libvmmapi: Provide wrappers for fetching register capability tags --- lib/libvmmapi/aarch64/vmmapi_machdep.c | 2 ++ lib/libvmmapi/vmmapi.c | 36 ++++++++++++++++++++++++++ lib/libvmmapi/vmmapi.h | 8 ++++++ 3 files changed, 46 insertions(+) diff --git a/lib/libvmmapi/aarch64/vmmapi_machdep.c b/lib/libvmmapi/aarch64/vmmapi_machdep.c index 8ce867a26dfc..c9b463ba4c1f 100644 --- a/lib/libvmmapi/aarch64/vmmapi_machdep.c +++ b/lib/libvmmapi/aarch64/vmmapi_machdep.c @@ -55,6 +55,8 @@ const cap_ioctl_t vm_ioctl_cmds[] = { VM_MD_IOCTLS, #if __has_feature(capabilities) VM_GET_CHERI_CAPABILITY_TAG, + VM_GET_REGISTER_CHERI_CAPABILITY_TAG, + VM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET, #endif }; size_t vm_ioctl_ncmds = nitems(vm_ioctl_cmds); diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index 8ce4a1223c5d..d5e595665e41 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -650,6 +650,23 @@ vm_get_register(struct vcpu *vcpu, int reg, uintcap_t *ret_val) return (error); } +#if __has_feature(capabilities) +int +vm_get_register_cheri_capability_tag(struct vcpu *vcpu, int reg, uint8_t *tagp) +{ + struct vm_register_cheri_capability_tag vmreg; + int error; + + bzero(&vmreg, sizeof(vmreg)); + vmreg.regnum = reg; + + error = vcpu_ioctl(vcpu, VM_GET_REGISTER_CHERI_CAPABILITY_TAG, &vmreg); + if (error == 0) + *tagp = vmreg.tag; + return (error); +} +#endif + int vm_set_register_set(struct vcpu *vcpu, unsigned int count, const int *regnums, uintcap_t *regvals) @@ -682,6 +699,25 @@ vm_get_register_set(struct vcpu *vcpu, unsigned int count, return (error); } +#if __has_feature(capabilities) +int +vm_get_register_cheri_capability_tag_set(struct vcpu *vcpu, unsigned int count, + const int *regnums, uint8_t *tags) +{ + struct vm_register_cheri_capability_tag_set vmtagset; + int error; + + bzero(&vmtagset, sizeof(vmtagset)); + vmtagset.count = count; + vmtagset.regnums = regnums; + vmtagset.tags = tags; + + error = vcpu_ioctl(vcpu, VM_GET_REGISTER_CHERI_CAPABILITY_TAG_SET, + &vmtagset); + return (error); +} +#endif + int vm_run(struct vcpu *vcpu, struct vm_run *vmrun) { diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index d0fe29e40c08..99d50293085f 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -152,10 +152,18 @@ int vm_get_seg_desc(struct vcpu *vcpu, int reg, struct seg_desc *seg_desc); #endif int vm_set_register(struct vcpu *vcpu, int reg, uintcap_t val); int vm_get_register(struct vcpu *vcpu, int reg, uintcap_t *retval); +#if __has_feature(capabilities) +int vm_get_register_cheri_capability_tag(struct vcpu *vcpu, int reg, + uint8_t *tagp); +#endif int vm_set_register_set(struct vcpu *vcpu, unsigned int count, const int *regnums, uintcap_t *regvals); int vm_get_register_set(struct vcpu *vcpu, unsigned int count, const int *regnums, uintcap_t *regvals); +#if __has_feature(capabilities) +int vm_get_register_cheri_capability_tag_set(struct vcpu *vcpu, + unsigned int count, const int *regnums, uint8_t *tags); +#endif int vm_run(struct vcpu *vcpu, struct vm_run *vmrun); int vm_suspend(struct vmctx *ctx, enum vm_suspend_how how); int vm_reinit(struct vmctx *ctx); From 6ca3b56e8ecc71f6e3972ad4952c644d09c09a9c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Fri, 3 Jan 2025 18:33:31 +0000 Subject: [PATCH 7/7] gdb: Update handling of register capability tags The vm_get_register() and vm_get_register_set() functions now always return capabilities with tags cleared. Use new libvmmapi functions to fetch tags where necessary. --- usr.sbin/bhyve/gdb.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/usr.sbin/bhyve/gdb.c b/usr.sbin/bhyve/gdb.c index 370cab3a11a1..0bc91682cae8 100644 --- a/usr.sbin/bhyve/gdb.c +++ b/usr.sbin/bhyve/gdb.c @@ -746,15 +746,9 @@ append_unsigned_native(uintmax_t value, size_t len) } static void -append_cap_native(uintcap_t value) +append_cap_native(uintcap_t value, uint8_t tag) { -#if __has_feature(capabilities) - uint8_t tag; - - tag = cheri_gettag(value); - append_byte(tag); -#endif for (size_t i = 0; i < sizeof(value); i++) append_byte(((uint8_t *)&value)[i]); } @@ -1253,6 +1247,7 @@ gdb_read_regs(void) { uintcap_t regvals[nitems(gdb_regset)]; int regnums[nitems(gdb_regset)]; + uint8_t tags[nitems(gdb_regset)]; for (size_t i = 0; i < nitems(gdb_regset); i++) regnums[i] = gdb_regset[i].id; @@ -1261,6 +1256,15 @@ gdb_read_regs(void) send_error(errno); return; } +#if __has_feature(capabilities) + if (vm_get_register_cheri_capability_tag_set(vcpus[cur_vcpu], + nitems(gdb_regset), regnums, tags) == -1) { + send_error(errno); + return; + } +#else + memset(tags, 0, sizeof(tags)); +#endif start_packet(); for (size_t i = 0; i < nitems(gdb_regset); i++) { @@ -1271,7 +1275,7 @@ gdb_read_regs(void) if (gdb_regset[i].size <= 8) append_unsigned_native(regvals[i], gdb_regset[i].size); else - append_cap_native(regvals[i]); + append_cap_native(regvals[i], tags[i]); } finish_packet(); } @@ -1281,6 +1285,7 @@ gdb_read_one_reg(const uint8_t *data, size_t len) { uintcap_t regval; uintmax_t reg; + uint8_t tag; reg = parse_integer(data, len); if (reg >= nitems(gdb_regset)) { @@ -1293,12 +1298,21 @@ gdb_read_one_reg(const uint8_t *data, size_t len) send_error(errno); return; } +#if __has_feature(capabilities) + if (vm_get_register_cheri_capability_tag(vcpus[cur_vcpu], + gdb_regset[reg].id, &tag) == -1) { + send_error(errno); + return; + } +#else + tag = 0; +#endif start_packet(); if (gdb_regset[reg].size <= 8) append_unsigned_native(regval, gdb_regset[reg].size); else - append_cap_native(regval); + append_cap_native(regval, tag); finish_packet(); }