Skip to content

Commit

Permalink
fixup! [LibOS] Add support for timerfd system calls
Browse files Browse the repository at this point in the history
Signed-off-by: Kailun Qin <[email protected]>
  • Loading branch information
kailun-qin committed Aug 13, 2024
1 parent 7d8e249 commit 7223726
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 18 deletions.
19 changes: 10 additions & 9 deletions Documentation/devel/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -2873,12 +2873,13 @@ Gramine implements alarm clocks via `alarm()`.

Gramine implements timers that notify via file descriptors: `timerfd_create()`, `timerfd_settime()`
and `timerfd_gettime()`. The timerfd object is created inside Gramine, and all operations are
resolved entirely inside Gramine. Each timerfd object is associated with a dummy eventfd created on
the host. This is purely for triggering read notifications (e.g., in epoll); timerfd data is
verified inside Gramine and is never exposed to the host. Since the host is used purely for
notifications, a malicious host can only induce Denial of Service (DoS) attacks.
`TFD_TIMER_CANCEL_ON_SET` is silently ignored because there are no "discontinuous changes of time"
in Gramine (via e.g., `settimeofday()`). `TFD_IOC_SET_TICKS` is not supported.
resolved entirely inside Gramine (note that the time source in Gramine SGX is still untrusted). Each
timerfd object is associated with a dummy eventfd created on the host. This is purely for triggering
read notifications (e.g., in epoll); timerfd data is verified inside Gramine and is never exposed to
the host. Since the host is used purely for notifications, a malicious host can only induce Denial
of Service (DoS) attacks. `TFD_TIMER_CANCEL_ON_SET` is silently ignored because there are no
"discontinuous changes of time" in Gramine (via e.g., `settimeofday()`). `TFD_IOC_SET_TICKS` is not
supported.

The emulation is currently implemented at the level of a single process. The emulation *may* work
for multi-process applications, e.g., if the child process inherits the timerfd object but doesn't
Expand All @@ -2902,9 +2903,9 @@ could implement it in the future, if need arises.
-`timer_getoverrun()`: may be implemented in the future
-`timer_delete()`: may be implemented in the future

-`timerfd_create()`: see notes above
-`timerfd_settime()`: see notes above
-`timerfd_gettime()`: see notes above
-`timerfd_create()`: see the notes above
-`timerfd_settime()`: see the notes above
-`timerfd_gettime()`: see the notes above

</details><br />

Expand Down
20 changes: 17 additions & 3 deletions libos/include/linux_abi/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
/* These need to be binary-identical with the ones used by Linux. */

// TODO: remove all of these includes and make this header libc-independent.
#include <linux/times.h>
#include <linux/timex.h>
#include <linux/utime.h>
#include <linux/version.h>

typedef long __kernel_suseconds_t;
typedef long __kernel_time_t;

typedef __kernel_time_t time_t;

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
Expand All @@ -38,6 +38,20 @@ struct __kernel_timezone {
int tz_dsttime; /* type of dst correction */
};

/* The IDs of the various system clocks (for POSIX.1b interval timers). */
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#define CLOCK_PROCESS_CPUTIME_ID 2
#define CLOCK_THREAD_CPUTIME_ID 3
#define CLOCK_MONOTONIC_RAW 4
#define CLOCK_REALTIME_COARSE 5
#define CLOCK_MONOTONIC_COARSE 6
#define CLOCK_BOOTTIME 7
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9

#define MAX_CLOCKS 16

#define TFD_TIMER_ABSTIME (1 << 0)
#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
#define TFD_CLOEXEC O_CLOEXEC
Expand Down
45 changes: 43 additions & 2 deletions libos/src/libos_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "linux_abi/sched.h"
#include "linux_abi/signals.h"
#include "linux_abi/syscalls_nr_arch.h"
#include "linux_abi/time.h"
#include "socket_utils.h"

static void parse_open_flags(struct print_buf*, va_list*);
Expand Down Expand Up @@ -54,6 +55,7 @@ static void parse_getrandom_flags(struct print_buf*, va_list*);
static void parse_epoll_op(struct print_buf*, va_list*);
static void parse_epoll_event(struct print_buf* buf, va_list* ap);
static void parse_close_range_flags(struct print_buf* buf, va_list* ap);
static void parse_clockid(struct print_buf* buf, va_list* ap);
static void parse_timerfd_create_flags(struct print_buf* buf, va_list* ap);
static void parse_timerfd_settime_flags(struct print_buf* buf, va_list* ap);

Expand Down Expand Up @@ -520,7 +522,7 @@ struct parser_table {
parse_integer_arg, parse_pointer_arg, parse_pointer_arg}},
[__NR_signalfd] = {.slow = false, .name = "signalfd", .parser = {NULL}},
[__NR_timerfd_create] = {.slow = false, .name = "timerfd_create", .parser = {parse_long_arg,
parse_integer_arg, parse_timerfd_create_flags}},
parse_clockid, parse_timerfd_create_flags}},
[__NR_eventfd] = {.slow = false, .name = "eventfd", .parser = {parse_long_arg,
parse_integer_arg}},
[__NR_fallocate] = {.slow = false, .name = "fallocate", .parser = {parse_long_arg,
Expand Down Expand Up @@ -1159,7 +1161,7 @@ static void parse_itimerspec(struct print_buf* buf, va_list* ap) {
return;
}

buf_printf(buf, "intvl:[%ld,%ld] val: [%ld,%ld]",
buf_printf(buf, "intvl:[%ld,%ld] val:[%ld,%ld]",
it->it_interval.tv_sec, it->it_interval.tv_nsec,
it->it_value.tv_sec, it->it_value.tv_nsec);
}
Expand Down Expand Up @@ -1640,6 +1642,45 @@ static void parse_close_range_flags(struct print_buf* buf, va_list* ap) {
buf_printf(buf, "|0x%x", flags);
}

static void parse_clockid(struct print_buf* buf, va_list* ap) {
int clockid = va_arg(*ap, int);
switch (clockid) {
case CLOCK_REALTIME:
buf_puts(buf, "CLOCK_REALTIME");
break;
case CLOCK_MONOTONIC:
buf_puts(buf, "CLOCK_MONOTONIC");
break;
case CLOCK_PROCESS_CPUTIME_ID:
buf_puts(buf, "CLOCK_PROCESS_CPUTIME_ID");
break;
case CLOCK_THREAD_CPUTIME_ID:
buf_puts(buf, "CLOCK_THREAD_CPUTIME_ID");
break;
case CLOCK_MONOTONIC_RAW:
buf_puts(buf, "CLOCK_MONOTONIC_RAW");
break;
case CLOCK_REALTIME_COARSE:
buf_puts(buf, "CLOCK_REALTIME_COARSE");
break;
case CLOCK_MONOTONIC_COARSE:
buf_puts(buf, "CLOCK_MONOTONIC_COARSE");
break;
case CLOCK_BOOTTIME:
buf_puts(buf, "CLOCK_BOOTTIME");
break;
case CLOCK_REALTIME_ALARM:
buf_puts(buf, "CLOCK_REALTIME_ALARM");
break;
case CLOCK_BOOTTIME_ALARM:
buf_puts(buf, "CLOCK_BOOTTIME_ALARM");
break;
default:
buf_printf(buf, "(unknown: %d)", clockid);
break;
}
}

static void parse_timerfd_create_flags(struct print_buf* buf, va_list* ap) {
int flags = va_arg(*ap, int);

Expand Down
1 change: 1 addition & 0 deletions libos/src/sys/libos_sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "libos_thread.h"
#include "libos_utils.h"
#include "linux_abi/errors.h"
#include "linux_abi/time.h"
#include "pal.h"

long libos_syscall_pause(void) {
Expand Down
1 change: 1 addition & 0 deletions libos/src/sys/libos_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "libos_internal.h"
#include "libos_table.h"
#include "linux_abi/errors.h"
#include "linux_abi/time.h"
#include "pal.h"

long libos_syscall_gettimeofday(struct __kernel_timeval* tv, struct __kernel_timezone* tz) {
Expand Down
9 changes: 5 additions & 4 deletions libos/src/sys/libos_timerfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
/* Implementation of "timerfd" system calls.
*
* The timerfd object is created inside the LibOS, and all operations are resolved entirely inside
* the LibOS. Each timerfd object is associated with a dummy eventfd created on the host. This is
* purely for triggering read notifications (e.g., in epoll); timerfd data is verified inside
* the LibOS and is never exposed to the host. Since the host is used purely for notifications, a
* malicious host can only induce Denial of Service (DoS) attacks.
* the LibOS (note that the time source in Gramine SGX is still untrusted). Each timerfd object is
* associated with a dummy eventfd created on the host. This is purely for triggering read
* notifications (e.g., in epoll); timerfd data is verified inside the LibOS and is never exposed to
* the host. Since the host is used purely for notifications, a malicious host can only induce
* Denial of Service (DoS) attacks.
*
* The emulation is currently implemented at the level of a single process. The emulation *may* work
* for multi-process applications, e.g., if the child process inherits the timerfd object but
Expand Down

0 comments on commit 7223726

Please sign in to comment.