From af89dfdd84376ef4f27d4993bb13a1c75e08cc5e Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 8 Aug 2024 21:53:40 +0100 Subject: [PATCH 1/3] cheribsdtest: style in vm_shm_open_anon_unix_surprise --- bin/cheribsdtest/cheribsdtest_vm.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/bin/cheribsdtest/cheribsdtest_vm.c b/bin/cheribsdtest/cheribsdtest_vm.c index 8e991c918fdd..6811401f19ac 100644 --- a/bin/cheribsdtest/cheribsdtest_vm.c +++ b/bin/cheribsdtest/cheribsdtest_vm.c @@ -177,14 +177,17 @@ CHERIBSDTEST(vm_shm_open_anon_unix_surprise, cheribsdtest_failure_errx("Fork failed; errno=%d", errno); if (pid == 0) { - void * __capability * map; + void * __capability *map; void * __capability c; int fd, tag; struct msghdr msg = { 0 }; struct cmsghdr * cmsg; char cmsgbuf[CMSG_SPACE(sizeof(fd))] = { 0 } ; char iovbuf[16]; - struct iovec iov = { .iov_base = iovbuf, .iov_len = sizeof(iovbuf) }; + struct iovec iov = { + .iov_base = iovbuf, + .iov_len = sizeof(iovbuf) + }; close(sv[1]); @@ -196,15 +199,13 @@ CHERIBSDTEST(vm_shm_open_anon_unix_surprise, CHERIBSDTEST_CHECK_SYSCALL(recvmsg(sv[0], &msg, 0)); /* Deconstruct cmsg */ - /* XXX Doesn't compile: cmsg = CMSG_FIRSTHDR(&msg); */ - cmsg = msg.msg_control; - memmove(&fd, CMSG_DATA(cmsg), sizeof(fd)); + cmsg = CMSG_FIRSTHDR(&msg); + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); CHERIBSDTEST_VERIFY2(fd >= 0, "fd read OK"); map = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), - PROT_READ, MAP_SHARED, fd, - 0)); + PROT_READ, MAP_SHARED, fd, 0)); c = *map; if (verbose) @@ -219,14 +220,17 @@ CHERIBSDTEST(vm_shm_open_anon_unix_surprise, exit(tag); } else { - void * __capability * map; + void * __capability *map; void * __capability c; int fd, res; struct msghdr msg = { 0 }; struct cmsghdr * cmsg; char cmsgbuf[CMSG_SPACE(sizeof(fd))] = { 0 }; char iovbuf[16] = { 0 }; - struct iovec iov = { .iov_base = iovbuf, .iov_len = sizeof(iovbuf) }; + struct iovec iov = { + .iov_base = iovbuf, + .iov_len = sizeof(iovbuf) + }; close(sv[0]); @@ -252,12 +256,11 @@ CHERIBSDTEST(vm_shm_open_anon_unix_surprise, msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); - /* XXX cmsg = CMSG_FIRSTHDR(&msg); */ - cmsg = msg.msg_control; + cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof fd); - memmove(CMSG_DATA(cmsg), &fd, sizeof(fd)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); msg.msg_controllen = cmsg->cmsg_len; /* Send! */ From 071b76c83f824ee973176ed40cb97a2087a44e32 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 28 Aug 2024 20:25:19 +0100 Subject: [PATCH 2/3] cheribsdtest: hoarding by unmapped shm object Add cheri_revoke_shm_anon_hoard_unmapped which: - creates and maps a shared memory object - stores a pointer to malloced memory in the mapped object - unmaps the object - frees the pointer and triggers revocation - remaps the object - checks that the stored pointer was revoked (it is not) --- bin/cheribsdtest/cheribsdtest_vm.c | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/bin/cheribsdtest/cheribsdtest_vm.c b/bin/cheribsdtest/cheribsdtest_vm.c index 6811401f19ac..d4b1bcc6288b 100644 --- a/bin/cheribsdtest/cheribsdtest_vm.c +++ b/bin/cheribsdtest/cheribsdtest_vm.c @@ -2623,6 +2623,40 @@ CHERIBSDTEST(cheri_revoke_cow_mapping, cheribsdtest_success(); } + +CHERIBSDTEST(cheri_revoke_shm_anon_hoard_unmapped, + "Capability is revoked within an unmapped shm object", + .ct_xfail_reason = "unmapped part of shm objects aren't revoked") +{ + int fd; + void * volatile to_revoke; + void * volatile *map; + + fd = CHERIBSDTEST_CHECK_SYSCALL(shm_open(SHM_ANON, O_RDWR, 0600)); + CHERIBSDTEST_CHECK_SYSCALL(ftruncate(fd, getpagesize())); + + map = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + + to_revoke = malloc(1); + *map = to_revoke; + CHERIBSDTEST_VERIFY(cheri_gettag(*map)); + + munmap(__DEVOLATILE(void *, map), getpagesize()); + + free(to_revoke); + malloc_revoke(); + CHERIBSDTEST_VERIFY(check_revoked(to_revoke)); + + map = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + + CHERIBSDTEST_VERIFY(to_revoke == *map); + CHERIBSDTEST_VERIFY(check_revoked(*map)); + + cheribsdtest_success(); +} + #endif /* CHERIBSDTEST_CHERI_REVOKE_TESTS */ #endif /* __CHERI_PURE_CAPABILITY__ */ From a9235c1b1fe5d648b860eceb04b53a0673dce424 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 28 Aug 2024 21:10:03 +0100 Subject: [PATCH 3/3] cheribsdtest: hoarding by closed shm object Add cheri_revoke_shm_anon_hoard_closed which: - creates and maps a shared memory object - stores a pointer to malloced memory in the mapped object - unmaps the object - send the shared object file descriptor to a child process - closes the file descriptor - frees the pointer and triggers revocation - receives the file descriptor back from the child process - remaps the object - checks that the stored pointer was revoked (it is not) This demostrates the futility of scanning the descriptor table for shared memory objects during revocation and the necessity to bind them to an address space. (Lest one think it's possible to walk the graph of sockets to find the graph of processes that might have a shared memory object to search, the child could be replaced by a completely independent hoarder daemon running on a unix domain socket in the file system.) --- bin/cheribsdtest/cheribsdtest_vm.c | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/bin/cheribsdtest/cheribsdtest_vm.c b/bin/cheribsdtest/cheribsdtest_vm.c index d4b1bcc6288b..e539256d1b87 100644 --- a/bin/cheribsdtest/cheribsdtest_vm.c +++ b/bin/cheribsdtest/cheribsdtest_vm.c @@ -2657,6 +2657,129 @@ CHERIBSDTEST(cheri_revoke_shm_anon_hoard_unmapped, cheribsdtest_success(); } +CHERIBSDTEST(cheri_revoke_shm_anon_hoard_closed, + "Capability is revoked within an unmapped and closed shm object", + .ct_xfail_reason = "unmapped part of shm objects aren't revoked") +{ + int sv[2]; + int pid; + + CHERIBSDTEST_CHECK_SYSCALL(socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) != 0); + + pid = fork(); + if (pid == -1) + cheribsdtest_failure_errx("Fork failed; errno=%d", errno); + + if (pid == 0) { + int fd; + struct msghdr msg = { 0 }; + struct cmsghdr * cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(fd))] = { 0 } ; + char iovbuf[16]; + struct iovec iov = { + .iov_base = iovbuf, + .iov_len = sizeof(iovbuf) + }; + + close(sv[1]); + + /* Read from socket */ + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + CHERIBSDTEST_CHECK_SYSCALL(recvmsg(sv[0], &msg, 0)); + + /* Deconstruct cmsg */ + cmsg = CMSG_FIRSTHDR(&msg); + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); + + CHERIBSDTEST_VERIFY2(fd >= 0, "fd read OK"); + + /* Send the fd back. */ + CHERIBSDTEST_CHECK_SYSCALL(sendmsg(sv[0], &msg, 0)); + + close(sv[0]); + close(fd); + + exit(0); + } else { + void * volatile to_revoke; + void * volatile * map; + int fd, res; + struct msghdr msg = { 0 }; + struct cmsghdr * cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(fd))] = { 0 }; + char iovbuf[16] = { 0 }; + struct iovec iov = { + .iov_base = iovbuf, + .iov_len = sizeof(iovbuf) + }; + + close(sv[0]); + + fd = CHERIBSDTEST_CHECK_SYSCALL(shm_open(SHM_ANON, O_RDWR, 0600)); + CHERIBSDTEST_CHECK_SYSCALL(ftruncate(fd, getpagesize())); + + map = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + + to_revoke = malloc(1); + *map = to_revoke; + CHERIBSDTEST_VERIFY(cheri_gettag(*map)); + + CHERIBSDTEST_CHECK_SYSCALL(munmap(__DEVOLATILE(void *, map), + getpagesize())); + + /* Construct control message */ + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof fd); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + msg.msg_controllen = cmsg->cmsg_len; + + /* Send! */ + CHERIBSDTEST_CHECK_SYSCALL(sendmsg(sv[1], &msg, 0)); + close(fd); + + /* Revoke the pointer */ + free(to_revoke); + malloc_revoke(); + CHERIBSDTEST_VERIFY(check_revoked(to_revoke)); + + /* Receive the fd back */ + msg.msg_controllen = sizeof(cmsgbuf); + CHERIBSDTEST_CHECK_SYSCALL(recvmsg(sv[1], &msg, 0)); + + /* Deconstruct cmsg */ + cmsg = CMSG_FIRSTHDR(&msg); + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); + + CHERIBSDTEST_VERIFY2(fd >= 0, "fd read OK"); + + map = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + + CHERIBSDTEST_VERIFY(to_revoke == *map); + CHERIBSDTEST_VERIFY(check_revoked(*map)); + + close(sv[1]); + close(fd); + + waitpid(pid, &res, 0); + if (res == 0) { + cheribsdtest_success(); + } else { + cheribsdtest_failure_errx("child failed"); + } + } +} + #endif /* CHERIBSDTEST_CHERI_REVOKE_TESTS */ #endif /* __CHERI_PURE_CAPABILITY__ */