Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for CheriBSD #55

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ add_library(wrap OBJECT wrap.c)
set_property(TARGET wrap PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(wrap PUBLIC Threads::Threads)
target_include_directories(wrap
PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>)

macro(add_compat_target _name _condition)
Expand All @@ -51,6 +52,8 @@ include(CheckSymbolExists)
# supports native timerfd descriptors. Prefer them if available.
check_symbol_exists(eventfd "sys/eventfd.h" HAVE_EVENTFD)
check_symbol_exists(timerfd_create "sys/timerfd.h" HAVE_TIMERFD)
# Presence of a variadic version of fcntl allows for safer interposing.
check_symbol_exists(vfcntl "fcntl.h;stdarg.h" HAVE_VFCNTL)

check_symbol_exists(kqueue1 "sys/types.h;sys/event.h;sys/time.h" HAVE_KQUEUE1)
add_compat_target(kqueue1 "NOT;HAVE_KQUEUE1")
Expand Down Expand Up @@ -117,9 +120,9 @@ target_link_libraries(
$<BUILD_INTERFACE:compat_enable_sigops>
$<BUILD_INTERFACE:rwlock>
$<BUILD_INTERFACE:wrap>)
if(HAVE_TIMERFD)
target_compile_definitions(epoll-shim PRIVATE HAVE_TIMERFD)
endif()
configure_file(
epoll_shim_config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/epoll_shim_config.h)
target_compile_definitions(epoll-shim PRIVATE EPOLL_SHIM_DISABLE_WRAPPER_MACROS)
target_include_directories(
epoll-shim
Expand Down
3 changes: 3 additions & 0 deletions src/epoll_shim_config.h.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#cmakedefine01 HAVE_TIMERFD
#cmakedefine01 HAVE_VFCNTL

23 changes: 14 additions & 9 deletions src/epoll_shim_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <time.h>
#include <unistd.h>

#include "epoll_shim_config.h"
#include "epoll_shim_export.h"
#include "errno_return.h"
#include "timespec_util.h"
Expand Down Expand Up @@ -427,7 +428,7 @@ epoll_shim_ctx_drop_desc(EpollShimCtx *epoll_shim_ctx, /**/
rwlock_unlock_write(&epoll_shim_ctx->rwlock);
}

#ifndef HAVE_TIMERFD
#if !HAVE_TIMERFD
static void
trigger_realtime_change_notification(FileDescription *desc, int kq, void *arg)
{
Expand Down Expand Up @@ -792,30 +793,34 @@ epoll_shim_ppoll(struct pollfd *fds, nfds_t nfds, struct timespec const *tmo_p,
EPOLL_SHIM_EXPORT
int
epoll_shim_fcntl(int fd, int cmd, ...)
{
va_list ap;
va_start(ap, cmd);
int result = epoll_shim_vfcntl(fd, cmd, ap);
va_end(ap);
return result;
}

EPOLL_SHIM_EXPORT
int
epoll_shim_vfcntl(int fd, int cmd, va_list ap)
{
ERRNO_SAVE;

EpollShimCtx *epoll_shim_ctx;
FileDescription *desc;
va_list ap;

if (fd < 0 || (cmd != F_SETFL && cmd != F_GETFL) ||
epoll_shim_ctx_global(&epoll_shim_ctx) != 0 ||
(desc = epoll_shim_ctx_find_desc(epoll_shim_ctx, fd)) == NULL) {
va_start(ap, cmd);
void *arg = va_arg(ap, void *);
va_end(ap);

ERRNO_RETURN(0, -1, real_fcntl(fd, cmd, arg));
ERRNO_RETURN(0, -1, real_vfcntl(fd, cmd, ap));
}

errno_t ec;
int result = 0;

if (cmd == F_SETFL) {
va_start(ap, cmd);
int arg = va_arg(ap, int);
va_end(ap);

(void)pthread_mutex_lock(&desc->mutex);
{
Expand Down
2 changes: 2 additions & 0 deletions src/epoll_shim_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <sys/tree.h>

#include <stdatomic.h>
#include <stdarg.h>

#include <signal.h>
#include <unistd.h>
Expand Down Expand Up @@ -83,5 +84,6 @@ int epoll_shim_ppoll(struct pollfd *, nfds_t, struct timespec const *,
sigset_t const *);

int epoll_shim_fcntl(int fd, int cmd, ...);
int epoll_shim_vfcntl(int fd, int cmd, va_list);

#endif
12 changes: 2 additions & 10 deletions src/epoll_shim_interpose.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@
#include <unistd.h>

#include "epoll_shim_interpose_export.h"

int epoll_shim_close(int fd);
ssize_t epoll_shim_read(int fd, void *buf, size_t nbytes);
ssize_t epoll_shim_write(int fd, void const *buf, size_t nbytes);
int epoll_shim_poll(struct pollfd *, nfds_t, int);
int epoll_shim_ppoll(struct pollfd *, nfds_t, struct timespec const *,
sigset_t const *);
int epoll_shim_fcntl(int fd, int cmd, ...);
#include "epoll_shim_ctx.h"

EPOLL_SHIM_INTERPOSE_EXPORT
ssize_t
Expand Down Expand Up @@ -65,8 +58,7 @@ fcntl(int fd, int cmd, ...)
va_list ap;

va_start(ap, cmd);
void *arg = va_arg(ap, void *);
int rv = epoll_shim_fcntl(fd, cmd, arg);
int rv = epoll_shim_vfcntl(fd, cmd, ap);
va_end(ap);

return rv;
Expand Down
2 changes: 1 addition & 1 deletion src/timerfd_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ timerfd_ctx_read(TimerFDCtx *timerfd, int kq, uint64_t *value)
}

bool got_kevent = false;
unsigned long event_ident;
uintptr_t event_ident;
{
struct kevent kevs[3];
int n = kevent(kq, NULL, 0, kevs, 3,
Expand Down
43 changes: 40 additions & 3 deletions src/wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <unistd.h>

#include "compat_ppoll.h"
#include "epoll_shim_config.h"

static struct {
pthread_once_t wrap_init;
Expand All @@ -27,7 +28,11 @@ static struct {
typeof(ppoll) *real_ppoll;
#endif
#endif
#if !HAVE_VFCNTL
typeof(fcntl) *real_fcntl;
#else
typeof(vfcntl) *real_vfcntl;
#endif
} wrap = { .wrap_init = PTHREAD_ONCE_INIT };

static void
Expand Down Expand Up @@ -65,7 +70,11 @@ wrap_initialize_impl(void)
WRAP(ppoll);
#endif
#endif
#if !HAVE_VFCNTL
WRAP(fcntl);
#else
WRAP(vfcntl);
#endif

#undef WRAP
}
Expand Down Expand Up @@ -124,14 +133,42 @@ real_ppoll(struct pollfd fds[], nfds_t nfds,
}

int
real_fcntl(int fd, int cmd, ...)
real_vfcntl(int fd, int cmd, va_list ap)
{
wrap_initialize();

// fcntl() abuses C variadic arguments to implement optional parameters.
// We want to forward this argument to the real fcntl() call, but doing
// so is non-portable. On most architectures, we can just read an
// intptr_t/void* and this will give us a (semi-)valid result even if
// no argument/an int was passed instead since va_arg() will generally
// read the next argument register or arbitrary data from the stack.
//
// On CHERI-enabled architectures, variadic arguments are tightly
// bounded, which means that reading an 8-byte void* if a 4-byte int was
// passed will result in a runtime trap. Newer CheriBSD systems support
// a vfcntl() function that can be used to safely forward arguments to
// fcntl() without having to duplicate the logic to determine how many
// arguments will be read.
#if HAVE_VFCNTL
// vfcntl() is present, can just foward the va_list.
return wrap.real_vfcntl(fd, cmd, ap);
#else
// Otherwise, we assume that we can read a void* from the va_list
// even if the actual value passed was smaller or a different type and
// hope that this will match the calling convention.
void *arg = va_arg(ap, void *);
return wrap.real_fcntl(fd, cmd, arg);
#endif
}

int
real_fcntl(int fd, int cmd, ...)
{
va_list ap;

va_start(ap, cmd);
void *arg = va_arg(ap, void *);
int rv = wrap.real_fcntl(fd, cmd, arg);
int rv = real_vfcntl(fd, cmd, ap);
va_end(ap);

return rv;
Expand Down
2 changes: 2 additions & 0 deletions src/wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <poll.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <time.h>
#include <unistd.h>
Expand All @@ -15,5 +16,6 @@ int real_ppoll(struct pollfd fds[], nfds_t nfds,
struct timespec const *restrict timeout,
sigset_t const *restrict newsigmask);
int real_fcntl(int fd, int cmd, ...);
int real_vfcntl(int fd, int cmd, va_list ap);

#endif
7 changes: 7 additions & 0 deletions test/epoll-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,12 @@ ATF_TC_BODY_FD_LEAKCHECK(epoll__event_size, tc)
struct epoll_event event;
// this check works on 32bit _and_ 64bit, since
// sizeof(epoll_event) == sizeof(uint32_t) + sizeof(uint64_t)
#if __SIZEOF_POINTER__ <= 8
ATF_REQUIRE(sizeof(event) == 12);
#else
/* On systems with 128-bit pointers, it will be padded to 32 bytes */
ATF_REQUIRE(sizeof(event) == 2 * sizeof(void*));
#endif
}

ATF_TC_WITHOUT_HEAD(epoll__recursive_register);
Expand Down Expand Up @@ -1232,7 +1237,9 @@ ATF_TC_BODY_FD_LEAKCHECK(epoll__epollpri, tcptr)
fd_tcp_socket(fds);

ATF_REQUIRE(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
ATF_REQUIRE(fcntl(fds[0], F_GETFL) & O_NONBLOCK);
ATF_REQUIRE(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0);
ATF_REQUIRE(fcntl(fds[1], F_GETFL) & O_NONBLOCK);

int ep = epoll_create1(EPOLL_CLOEXEC);
ATF_REQUIRE(ep >= 0);
Expand Down