Skip to content

Commit

Permalink
[LibOS] Refactor eventfd implementation and corresponding tests
Browse files Browse the repository at this point in the history
This commit refactors eventfd code, in preparation for a second, secure
(not passthrough-to-host) implementation of eventfd. The corresponding
`eventfd` test is split into two tests: a single-process test and a new
multi-process (forking) test. This is because the new secure
implementation of eventfd will only be applicable to single-process
applications.

Signed-off-by: Dmitrii Kuvaiskii <dmitrii.kuvaiskii@intel.com>
  • Loading branch information
dimakuv committed Apr 2, 2024
1 parent 0ee48ee commit ff06284
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 224 deletions.
6 changes: 5 additions & 1 deletion libos/include/libos_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ struct libos_epoll_handle {
size_t last_returned_index;
};

struct libos_eventfd_handle {
bool is_semaphore;
};

struct libos_handle {
enum libos_handle_type type;
bool is_dir;
Expand Down Expand Up @@ -203,7 +207,7 @@ struct libos_handle {
struct libos_sock_handle sock; /* TYPE_SOCK */

struct libos_epoll_handle epoll; /* TYPE_EPOLL */
struct { bool is_semaphore; } eventfd; /* TYPE_EVENTFD */
struct libos_eventfd_handle eventfd; /* TYPE_EVENTFD */
} info;

struct libos_dir_handle dir_info;
Expand Down
3 changes: 3 additions & 0 deletions libos/include/libos_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ long pal_to_unix_errno(long err);

int set_hostname(const char* name, size_t len);

extern bool g_eventfd_passthrough_mode;
int init_eventfd_mode(void);

void warn_unsupported_syscall(unsigned long sysno);
void debug_print_syscall_before(unsigned long sysno, ...);
void debug_print_syscall_after(unsigned long sysno, ...);
Expand Down
34 changes: 17 additions & 17 deletions libos/src/fs/eventfd/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* Copyright (C) 2019 Intel Corporation */

/*
* This file contains code for implementation of 'eventfd' filesystem.
* This file contains code for passthrough-to-host implementation of 'eventfd' filesystem.
*/

#include "libos_fs.h"
Expand All @@ -18,15 +18,15 @@ static ssize_t eventfd_read(struct libos_handle* hdl, void* buf, size_t count, f
if (count < sizeof(uint64_t))
return -EINVAL;

size_t orig_count = count;
int ret = PalStreamRead(hdl->pal_handle, 0, &count, buf);
ret = pal_to_unix_errno(ret);
maybe_epoll_et_trigger(hdl, ret, /*in=*/true, ret == 0 ? count < orig_count : false);
if (ret < 0) {
return ret;
int ret = PalStreamRead(hdl->pal_handle, /*offset=*/0, &count, buf);
if (!ret && count != sizeof(uint64_t)) {
/* successful read must return 8 bytes, otherwise it's an attack or host malfunction */
return -EPERM;
}

return (ssize_t)count;
ret = pal_to_unix_errno(ret);
/* eventfd objects never perform partial reads, see also check above */
maybe_epoll_et_trigger(hdl, ret, /*in=*/true, /*unused was_partial=*/false);
return ret < 0 ? ret : (ssize_t)count;
}

static ssize_t eventfd_write(struct libos_handle* hdl, const void* buf, size_t count,
Expand All @@ -36,15 +36,15 @@ static ssize_t eventfd_write(struct libos_handle* hdl, const void* buf, size_t c
if (count < sizeof(uint64_t))
return -EINVAL;

size_t orig_count = count;
int ret = PalStreamWrite(hdl->pal_handle, 0, &count, (void*)buf);
ret = pal_to_unix_errno(ret);
maybe_epoll_et_trigger(hdl, ret, /*in=*/false, ret == 0 ? count < orig_count : false);
if (ret < 0) {
return ret;
int ret = PalStreamWrite(hdl->pal_handle, /*offset=*/0, &count, (void*)buf);
if (!ret && count != sizeof(uint64_t)) {
/* successful write must return 8 bytes, otherwise it's an attack or host malfunction */
return -EPERM;
}

return (ssize_t)count;
ret = pal_to_unix_errno(ret);
/* eventfd objects never perform partial writes, see also check above */
maybe_epoll_et_trigger(hdl, ret, /*in=*/false, /*unused was_partial=*/false);
return ret < 0 ? ret : (ssize_t)count;
}

struct libos_fs_ops eventfd_fs_ops = {
Expand Down
2 changes: 2 additions & 0 deletions libos/src/libos_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,8 @@ noreturn void libos_init(const char* const* argv, const char* const* envp) {
RUN_INIT(set_hostname, g_pal_public_state->dns_host.hostname,
strlen(g_pal_public_state->dns_host.hostname));

RUN_INIT(init_eventfd_mode);

log_debug("LibOS initialized");

libos_tcb_t* cur_tcb = libos_get_tcb();
Expand Down
56 changes: 26 additions & 30 deletions libos/src/sys/libos_eventfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,38 @@
#include "pal.h"
#include "toml_utils.h"

static int create_eventfd(PAL_HANDLE* efd, uint64_t initial_count, int flags) {
int ret;
bool g_eventfd_passthrough_mode = false;

int init_eventfd_mode(void) {
assert(g_manifest_root);
bool allow_eventfd;
int ret;

ret = toml_bool_in(g_manifest_root, "sys.insecure__allow_eventfd", /*defaultval=*/false,
&allow_eventfd);
&g_eventfd_passthrough_mode);
if (ret < 0) {
log_error("Cannot parse \'sys.insecure__allow_eventfd\' (the value must be `true` or "
log_error("Cannot parse 'sys.insecure__allow_eventfd' (the value must be `true` or "
"`false`)");
return -ENOSYS;
return -EPERM;
}

if (!allow_eventfd) {
/* eventfd is not explicitly allowed in manifest */
return 0;
}

static int create_eventfd_pal_handle(uint64_t initial_count, int flags,
PAL_HANDLE* out_pal_handle) {
int ret;

if (!g_eventfd_passthrough_mode) {
if (FIRST_TIME()) {
log_warning("The app tried to use eventfd, but it's turned off "
"(sys.insecure__allow_eventfd = false)");
}

return -ENOSYS;
}

PAL_HANDLE hdl = NULL;
int pal_flags = 0;

int pal_flags = 0;
pal_flags |= flags & EFD_NONBLOCK ? PAL_OPTION_NONBLOCK : 0;
pal_flags |= flags & EFD_SEMAPHORE ? PAL_OPTION_EFD_SEMAPHORE : 0;

Expand All @@ -65,41 +71,31 @@ static int create_eventfd(PAL_HANDLE* efd, uint64_t initial_count, int flags) {
return -EINTR;
}

*efd = hdl;
*out_pal_handle = hdl;
return 0;
}

long libos_syscall_eventfd2(unsigned int count, int flags) {
int ret = 0;
struct libos_handle* hdl = get_new_handle();
int ret;

if (!hdl) {
ret = -ENOMEM;
goto out;
}
struct libos_handle* hdl = get_new_handle();
if (!hdl)
return -ENOMEM;

hdl->type = TYPE_EVENTFD;
hdl->fs = &eventfd_builtin_fs;
hdl->flags = O_RDWR;
hdl->acc_mode = MAY_READ | MAY_WRITE;

if ((ret = create_eventfd(&hdl->pal_handle, count, flags)) < 0)
goto out;

hdl->info.eventfd.is_semaphore = !!(flags & EFD_SEMAPHORE);

flags = flags & EFD_CLOEXEC ? FD_CLOEXEC : 0;

/* get_new_handle() above increments hdl's refcount. Followed by another increment inside
* set_new_fd_handle. So we need to put_handle() afterwards. */
int vfd = set_new_fd_handle(hdl, flags, NULL);

ret = vfd;
ret = create_eventfd_pal_handle(count, flags, &hdl->pal_handle);
if (ret < 0)
goto out;

ret = set_new_fd_handle(hdl, flags & EFD_CLOEXEC ? FD_CLOEXEC : 0, NULL);
out:
if (hdl)
put_handle(hdl);

put_handle(hdl);
return ret;
}

Expand Down

0 comments on commit ff06284

Please sign in to comment.