#include <sys/personality.h>
#include <sys/prctl.h>
#include <sys/resource.h>
-#include <sys/timerfd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
int nice;
// Timeout
- struct itimerspec timeout;
+ uint64_t timeout;
// CGroup
struct pakfire_cgroup* cgroup;
#endif /* ENABLE_DEBUG */
} log;
+ // Timeout
+ sd_event_source* timeout;
+
struct pakfire_cgroup* cgroup;
struct pakfire_cgroup_stats cgroup_stats;
PAKFIRE_EXPORT int pakfire_jail_set_timeout(
struct pakfire_jail* jail, unsigned int timeout) {
// Store value
- jail->timeout.it_value.tv_sec = timeout;
+ jail->timeout = timeout;
if (timeout > 0)
CTX_DEBUG(jail->ctx, "Timeout set to %u second(s)\n", timeout);
return 0;
}
-static int pakfire_jail_create_timer(struct pakfire_jail* jail) {
- int r;
-
- // Nothing to do if no timeout has been set
- if (!jail->timeout.it_value.tv_sec)
- return -1;
-
- // Create a new timer
- const int fd = timerfd_create(CLOCK_MONOTONIC, 0);
- if (fd < 0) {
- CTX_ERROR(jail->ctx, "Could not create timer: %m\n");
- goto ERROR;
- }
-
- // Arm timer
- r = timerfd_settime(fd, 0, &jail->timeout, NULL);
- if (r) {
- CTX_ERROR(jail->ctx, "Could not arm timer: %m\n");
- goto ERROR;
- }
-
- return fd;
-
-ERROR:
- if (fd >= 0)
- close(fd);
-
- return -1;
-}
-
/*
Standard Input
*/
static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
int epollfd = -1;
struct epoll_event events[EPOLL_MAX_EVENTS];
- char garbage[8];
int r = 0;
// Fetch the UNIX domain socket
const int socket_recv = pakfire_jail_get_pipe_to_read(jail, &ctx->socket);
- // Timer
- const int timerfd = pakfire_jail_create_timer(jail);
-
// Make a list of all file descriptors we are interested in
const struct pakfire_wait_fds {
const int fd;
const int events;
} fds[] = {
- // Timer
- { timerfd, EPOLLIN },
-
// UNIX Domain Socket
{ socket_recv, EPOLLIN },
goto ERROR;
}
- // Handle timer events
- } else if (timerfd == fd) {
- if (e & EPOLLIN) {
- CTX_DEBUG(jail->ctx, "Timer event received\n");
-
- // Disarm the timer
- r = read(timerfd, garbage, sizeof(garbage));
- if (r < 1) {
- CTX_ERROR(jail->ctx, "Could not disarm timer: %m\n");
- r = 1;
- goto ERROR;
- }
-
- // Terminate the process if it hasn't already ended
- if (!ended) {
- CTX_DEBUG(jail->ctx, "Terminating process...\n");
-
- // Send SIGTERM to the process
- r = pidfd_send_signal(ctx->pidfd, SIGKILL, NULL, 0);
- if (r) {
- CTX_ERROR(jail->ctx, "Could not kill process: %m\n");
- goto ERROR;
- }
- }
- }
-
// Handle socket messages
} else if (socket_recv == fd) {
if (e & EPOLLIN) {
ERROR:
if (epollfd >= 0)
close(epollfd);
- if (timerfd >= 0)
- close(timerfd);
// Restore any changed terminal attributes
if (ctx->pty.stdin.fd >= 0)
return r;
}
+/*
+ Called when the timer has expired.
+*/
+static int pakfire_jail_timer(sd_event_source* s, uint64_t usec, void* data) {
+ struct pakfire_jail_exec* ctx = data;
+ struct pakfire_jail* jail = ctx->jail;
+ int r;
+
+ CTX_DEBUG(jail->ctx, "Timer has fired...\n");
+
+ // Send SIGTERM to the process
+ r = pidfd_send_signal(ctx->pidfd, SIGTERM, NULL, 0);
+ if (r)
+ CTX_ERROR(jail->ctx, "Could not send SIGTERM to the process: %m\n");
+
+ return r;
+}
+
+/*
+ Called when the child process has exited.
+*/
static int pakfire_jail_exited(sd_event_source* source, const siginfo_t* si, void* data) {
struct pakfire_jail_exec* ctx = data;
struct pakfire_jail* jail = ctx->jail;
goto ERROR;
#endif /* ENABLE_DEBUG */
+ // Setup the timer
+ if (jail->timeout) {
+ r = sd_event_add_time_relative(ctx.loop, &ctx.timeout, CLOCK_MONOTONIC,
+ jail->timeout * 1000000, 0, pakfire_jail_timer, &ctx);
+ if (r < 0) {
+ CTX_ERROR(jail->ctx, "Could not setup timer: %s\n", strerror(-r));
+ goto ERROR;
+ }
+ }
+
// Configure child process
struct clone_args args = {
.flags =