Skip to content

Commit

Permalink
cheribsdtest: hoarding by closed shm object
Browse files Browse the repository at this point in the history
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.)
  • Loading branch information
brooksdavis authored and bsdjhb committed Sep 3, 2024
1 parent 214ed34 commit 37d2591
Showing 1 changed file with 123 additions and 0 deletions.
123 changes: 123 additions & 0 deletions bin/cheribsdtest/cheribsdtest_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */

0 comments on commit 37d2591

Please sign in to comment.