// libuuid
#include <uuid.h>
-// Enable legacy logging
-#define PAKFIRE_LEGACY_LOGGING
-
#include <pakfire/arch.h>
#include <pakfire/cgroup.h>
#include <pakfire/jail.h>
}
static void pakfire_jail_free(struct pakfire_jail* jail) {
- DEBUG(jail->pakfire, "Freeing jail at %p\n", jail);
+ CTX_DEBUG(jail->ctx, "Freeing jail at %p\n", jail);
// Free environment
for (unsigned int i = 0; jail->env[i]; i++)
// Generate a random UUID
uuid_generate_random(j->uuid);
- DEBUG(j->pakfire, "Allocated new jail at %p\n", j);
+ CTX_DEBUG(j->ctx, "Allocated new jail at %p\n", j);
// Set default environment
for (const struct environ* e = ENV; e->key; e++) {
// Set any new cgroup
if (cgroup) {
- DEBUG(jail->pakfire, "Setting cgroup %p\n", cgroup);
+ CTX_DEBUG(jail->ctx, "Setting cgroup %p\n", cgroup);
jail->cgroup = pakfire_cgroup_ref(cgroup);
}
// Format and set environment variable
asprintf(&jail->env[i], "%s=%s", key, value);
- DEBUG(jail->pakfire, "Set environment variable: %s\n", jail->env[i]);
+ CTX_DEBUG(jail->ctx, "Set environment variable: %s\n", jail->env[i]);
return 0;
}
jail->timeout.it_value.tv_sec = timeout;
if (timeout > 0)
- DEBUG(jail->pakfire, "Timeout set to %u second(s)\n", timeout);
+ CTX_DEBUG(jail->ctx, "Timeout set to %u second(s)\n", timeout);
else
- DEBUG(jail->pakfire, "Timeout disabled\n");
+ CTX_DEBUG(jail->ctx, "Timeout disabled\n");
return 0;
}
// Create a new timer
const int fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (fd < 0) {
- ERROR(jail->pakfire, "Could not create timer: %m\n");
+ CTX_ERROR(jail->ctx, "Could not create timer: %m\n");
goto ERROR;
}
// Arm timer
r = timerfd_settime(fd, 0, &jail->timeout, NULL);
if (r) {
- ERROR(jail->pakfire, "Could not arm timer: %m\n");
+ CTX_ERROR(jail->ctx, "Could not arm timer: %m\n");
goto ERROR;
}
static int pakfire_jail_setup_pipe(struct pakfire_jail* jail, int (*fds)[2], const int flags) {
int r = pipe2(*fds, flags);
if (r < 0) {
- ERROR(jail->pakfire, "Could not setup pipe: %m\n");
+ CTX_ERROR(jail->ctx, "Could not setup pipe: %m\n");
return 1;
}
// Add the file descriptor to the loop
r = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
if (r < 0) {
- ERROR(jail->pakfire, "Could not add file descriptor %d to epoll(): %s\n",
+ CTX_ERROR(jail->ctx, "Could not add file descriptor %d to epoll(): %s\n",
fd, strerror(errno));
return -errno;
}
// Setup epoll
epollfd = epoll_create1(0);
if (epollfd < 0) {
- ERROR(jail->pakfire, "Could not initialize epoll(): %m\n");
+ CTX_ERROR(jail->ctx, "Could not initialize epoll(): %m\n");
r = 1;
goto ERROR;
}
if (errno == EINTR)
continue;
- ERROR(jail->pakfire, "epoll_wait() failed: %m\n");
+ CTX_ERROR(jail->ctx, "epoll_wait() failed: %m\n");
r = 1;
goto ERROR;
// Call waidid() and store the result
r = waitid(P_PIDFD, ctx->pidfd, &ctx->status, WEXITED);
if (r) {
- ERROR(jail->pakfire, "waitid() failed: %m\n");
+ CTX_ERROR(jail->ctx, "waitid() failed: %m\n");
goto ERROR;
}
// Handle timer events
} else if (timerfd == fd) {
if (e & EPOLLIN) {
- DEBUG(jail->pakfire, "Timer event received\n");
+ CTX_DEBUG(jail->ctx, "Timer event received\n");
// Disarm the timer
r = read(timerfd, garbage, sizeof(garbage));
if (r < 1) {
- ERROR(jail->pakfire, "Could not disarm timer: %m\n");
+ 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) {
- DEBUG(jail->pakfire, "Terminating process...\n");
+ CTX_DEBUG(jail->ctx, "Terminating process...\n");
// Send SIGTERM to the process
r = pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
if (r) {
- ERROR(jail->pakfire, "Could not kill process: %m\n");
+ CTX_ERROR(jail->ctx, "Could not kill process: %m\n");
goto ERROR;
}
}
// Log a message for anything else
} else {
- DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
+ CTX_DEBUG(jail->ctx, "Received invalid file descriptor %d\n", fd);
continue;
}
// Remove the file descriptor
r = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
if (r) {
- ERROR(jail->pakfire, "Could not remove closed file-descriptor %d: %m\n", fd);
+ CTX_ERROR(jail->ctx, "Could not remove closed file-descriptor %d: %m\n", fd);
goto ERROR;
}
}
// Fetch all capabilities
caps = cap_get_proc();
if (!caps) {
- ERROR(jail->pakfire, "Could not fetch capabilities: %m\n");
+ CTX_ERROR(jail->ctx, "Could not fetch capabilities: %m\n");
r = 1;
goto ERROR;
}
- DEBUG(jail->pakfire, "Capabilities of PID %d:\n", pid);
+ CTX_DEBUG(jail->ctx, "Capabilities of PID %d:\n", pid);
// Iterate over all capabilities
for (unsigned int cap = 0; cap_valid(cap); cap++) {
if (r)
goto ERROR;
- DEBUG(jail->pakfire,
+ CTX_DEBUG(jail->ctx,
" %-24s : %c%c%c\n",
name,
(value_e == CAP_SET) ? 'e' : '-',
// Fetch capabilities
caps = cap_get_proc();
if (!caps) {
- ERROR(jail->pakfire, "Could not read capabilities: %m\n");
+ CTX_ERROR(jail->ctx, "Could not read capabilities: %m\n");
r = 1;
goto ERROR;
}
r = cap_set_flag(caps, CAP_EFFECTIVE, 1, _caps, CAP_SET);
if (r) {
- ERROR(jail->pakfire, "Could not set %s: %m\n", name);
+ CTX_ERROR(jail->ctx, "Could not set %s: %m\n", name);
goto ERROR;
}
r = cap_set_flag(caps, CAP_INHERITABLE, 1, _caps, CAP_SET);
if (r) {
- ERROR(jail->pakfire, "Could not set %s: %m\n", name);
+ CTX_ERROR(jail->ctx, "Could not set %s: %m\n", name);
goto ERROR;
}
r = cap_set_flag(caps, CAP_PERMITTED, 1, _caps, CAP_SET);
if (r) {
- ERROR(jail->pakfire, "Could not set %s: %m\n", name);
+ CTX_ERROR(jail->ctx, "Could not set %s: %m\n", name);
goto ERROR;
}
// Restore all capabilities
r = cap_set_proc(caps);
if (r) {
- ERROR(jail->pakfire, "Restoring capabilities failed: %m\n");
+ CTX_ERROR(jail->ctx, "Restoring capabilities failed: %m\n");
goto ERROR;
}
// Raise the capability
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
if (r) {
- ERROR(jail->pakfire, "Could not set ambient capability %s: %m\n", name);
+ CTX_ERROR(jail->ctx, "Could not set ambient capability %s: %m\n", name);
goto ERROR;
}
};
int r = 1;
- DEBUG(jail->pakfire, "Applying syscall filter...\n");
+ CTX_DEBUG(jail->ctx, "Applying syscall filter...\n");
// Setup a syscall filter which allows everything by default
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
if (!ctx) {
- ERROR(jail->pakfire, "Could not setup seccomp filter: %m\n");
+ CTX_ERROR(jail->ctx, "Could not setup seccomp filter: %m\n");
goto ERROR;
}
for (const int* syscall = syscalls; *syscall; syscall++) {
r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), *syscall, 0);
if (r) {
- ERROR(jail->pakfire, "Could not configure syscall %d: %m\n", *syscall);
+ CTX_ERROR(jail->ctx, "Could not configure syscall %d: %m\n", *syscall);
goto ERROR;
}
}
// Load syscall filter into the kernel
r = seccomp_load(ctx);
if (r) {
- ERROR(jail->pakfire, "Could not load syscall filter into the kernel: %m\n");
+ CTX_ERROR(jail->ctx, "Could not load syscall filter into the kernel: %m\n");
goto ERROR;
}
// Copy source
r = pakfire_string_set(mp->source, source);
if (r) {
- ERROR(jail->pakfire, "Could not copy source: %m\n");
+ CTX_ERROR(jail->ctx, "Could not copy source: %m\n");
return r;
}
// Copy target
r = pakfire_string_set(mp->target, target);
if (r) {
- ERROR(jail->pakfire, "Could not copy target: %m\n");
+ CTX_ERROR(jail->ctx, "Could not copy target: %m\n");
return r;
}
struct rtnl_link* change = NULL;
int r;
- DEBUG(jail->pakfire, "Setting up loopback...\n");
+ CTX_DEBUG(jail->ctx, "Setting up loopback...\n");
// Allocate a netlink socket
nl = nl_socket_alloc();
if (!nl) {
- ERROR(jail->pakfire, "Could not allocate a netlink socket: %m\n");
+ CTX_ERROR(jail->ctx, "Could not allocate a netlink socket: %m\n");
r = 1;
goto ERROR;
}
// Connect the socket
r = nl_connect(nl, NETLINK_ROUTE);
if (r) {
- ERROR(jail->pakfire, "Could not connect netlink socket: %s\n", nl_geterror(r));
+ CTX_ERROR(jail->ctx, "Could not connect netlink socket: %s\n", nl_geterror(r));
goto ERROR;
}
// Allocate the netlink cache
r = rtnl_link_alloc_cache(nl, AF_UNSPEC, &cache);
if (r < 0) {
- ERROR(jail->pakfire, "Unable to allocate netlink cache: %s\n", nl_geterror(r));
+ CTX_ERROR(jail->ctx, "Unable to allocate netlink cache: %s\n", nl_geterror(r));
goto ERROR;
}
// Fetch loopback interface
link = rtnl_link_get_by_name(cache, "lo");
if (!link) {
- ERROR(jail->pakfire, "Could not find lo interface. Ignoring.\n");
+ CTX_ERROR(jail->ctx, "Could not find lo interface. Ignoring.\n");
r = 0;
goto ERROR;
}
// Allocate a new link
change = rtnl_link_alloc();
if (!change) {
- ERROR(jail->pakfire, "Could not allocate change link\n");
+ CTX_ERROR(jail->ctx, "Could not allocate change link\n");
r = 1;
goto ERROR;
}
// Apply any changes
r = rtnl_link_change(nl, link, change, 0);
if (r) {
- ERROR(jail->pakfire, "Unable to activate loopback: %s\n", nl_geterror(r));
+ CTX_ERROR(jail->ctx, "Unable to activate loopback: %s\n", nl_geterror(r));
goto ERROR;
}
}
if (r) {
- ERROR(jail->pakfire, "Could not map UIDs: %m\n");
+ CTX_ERROR(jail->ctx, "Could not map UIDs: %m\n");
return r;
}
}
if (r) {
- ERROR(jail->pakfire, "Could not map GIDs: %m\n");
+ CTX_ERROR(jail->ctx, "Could not map GIDs: %m\n");
return r;
}
const uint64_t val = 1;
int r = 0;
- DEBUG(jail->pakfire, "Sending signal...\n");
+ CTX_DEBUG(jail->ctx, "Sending signal...\n");
// Write to the file descriptor
r = eventfd_write(fd, val);
if (r < 0) {
- ERROR(jail->pakfire, "Could not send signal: %s\n", strerror(errno));
+ CTX_ERROR(jail->ctx, "Could not send signal: %s\n", strerror(errno));
r = -errno;
}
uint64_t val = 0;
int r = 0;
- DEBUG(jail->pakfire, "Waiting for signal...\n");
+ CTX_DEBUG(jail->ctx, "Waiting for signal...\n");
r = eventfd_read(fd, &val);
if (r < 0) {
- ERROR(jail->pakfire, "Error waiting for signal: %s\n", strerror(errno));
+ CTX_ERROR(jail->ctx, "Error waiting for signal: %s\n", strerror(errno));
r = -errno;
}
return r;
// Parent has finished initialisation
- DEBUG(jail->pakfire, "Parent has finished initialization\n");
+ CTX_DEBUG(jail->ctx, "Parent has finished initialization\n");
// Send signal to client
r = pakfire_jail_send_signal(jail, ctx->completed_fd);
// Change to the new root
r = chdir(root);
if (r) {
- ERROR(jail->pakfire, "chdir(%s) failed: %m\n", root);
+ CTX_ERROR(jail->ctx, "chdir(%s) failed: %m\n", root);
return r;
}
// Switch Root!
r = pivot_root(".", ".");
if (r) {
- ERROR(jail->pakfire, "Failed changing into the new root directory %s: %m\n", root);
+ CTX_ERROR(jail->ctx, "Failed changing into the new root directory %s: %m\n", root);
return r;
}
// Umount the old root
r = umount2(".", MNT_DETACH);
if (r) {
- ERROR(jail->pakfire, "Could not umount the old root filesystem: %m\n");
+ CTX_ERROR(jail->ctx, "Could not umount the old root filesystem: %m\n");
return r;
}
// Fetch my own PID
pid_t pid = getpid();
- DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", pid);
+ CTX_DEBUG(jail->ctx, "Launched child process in jail with PID %d\n", pid);
// Wait for the parent to finish initialization
r = pakfire_jail_wait_for_signal(jail, ctx->completed_fd);
// Die with parent
r = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
if (r) {
- ERROR(jail->pakfire, "Could not configure to die with parent: %m\n");
+ CTX_ERROR(jail->ctx, "Could not configure to die with parent: %m\n");
return 126;
}
// Make this process dumpable
r = prctl (PR_SET_DUMPABLE, 1, 0, 0, 0);
if (r) {
- ERROR(jail->pakfire, "Could not make the process dumpable: %m\n");
+ CTX_ERROR(jail->ctx, "Could not make the process dumpable: %m\n");
return 126;
}
// Don't drop any capabilities on setuid()
r = prctl(PR_SET_KEEPCAPS, 1);
if (r) {
- ERROR(jail->pakfire, "Could not set PR_SET_KEEPCAPS: %m\n");
+ CTX_ERROR(jail->ctx, "Could not set PR_SET_KEEPCAPS: %m\n");
return 126;
}
uid_t euid = geteuid();
gid_t egid = getegid();
- DEBUG(jail->pakfire, " UID: %u (effective %u)\n", uid, euid);
- DEBUG(jail->pakfire, " GID: %u (effective %u)\n", gid, egid);
+ CTX_DEBUG(jail->ctx, " UID: %u (effective %u)\n", uid, euid);
+ CTX_DEBUG(jail->ctx, " GID: %u (effective %u)\n", gid, egid);
// Log all mountpoints
pakfire_mount_list(jail->pakfire);
// Fail if we are not running as root
if (uid || gid || euid || egid) {
- ERROR(jail->pakfire, "Child process is not running as root\n");
+ CTX_ERROR(jail->ctx, "Child process is not running as root\n");
return 126;
}
if (persona) {
r = personality(persona);
if (r < 0) {
- ERROR(jail->pakfire, "Could not set personality (%x)\n", (unsigned int)persona);
+ CTX_ERROR(jail->ctx, "Could not set personality (%x)\n", (unsigned int)persona);
return 1;
}
}
// Set nice level
if (jail->nice) {
- DEBUG(jail->pakfire, "Setting nice level to %d\n", jail->nice);
+ CTX_DEBUG(jail->ctx, "Setting nice level to %d\n", jail->nice);
r = setpriority(PRIO_PROCESS, pid, jail->nice);
if (r) {
- ERROR(jail->pakfire, "Could not set nice level: %m\n");
+ CTX_ERROR(jail->ctx, "Could not set nice level: %m\n");
return 1;
}
}
if (r)
return r;
- DEBUG(jail->pakfire, "Child process initialization done\n");
- DEBUG(jail->pakfire, "Launching command:\n");
+ CTX_DEBUG(jail->ctx, "Child process initialization done\n");
+ CTX_DEBUG(jail->ctx, "Launching command:\n");
// Log argv
for (unsigned int i = 0; argv[i]; i++)
- DEBUG(jail->pakfire, " argv[%u] = %s\n", i, argv[i]);
+ CTX_DEBUG(jail->ctx, " argv[%u] = %s\n", i, argv[i]);
// exec() command
r = execvpe(argv[0], (char**)argv, jail->env);
r = 1;
}
- ERROR(jail->pakfire, "Could not execve(%s): %m\n", argv[0]);
+ CTX_ERROR(jail->ctx, "Could not execve(%s): %m\n", argv[0]);
}
// We should not get here
},
};
- DEBUG(jail->pakfire, "Executing jail...\n");
+ CTX_DEBUG(jail->ctx, "Executing jail...\n");
// Enable networking in interactive mode
if (ctx.flags & PAKFIRE_JAIL_PTY_FORWARDING)
*/
ctx.completed_fd = eventfd(0, EFD_CLOEXEC);
if (ctx.completed_fd < 0) {
- ERROR(jail->pakfire, "eventfd() failed: %m\n");
+ CTX_ERROR(jail->ctx, "eventfd() failed: %m\n");
return -1;
}
// Create a temporary cgroup
r = pakfire_cgroup_child(&ctx.cgroup, jail->cgroup, uuid, 0);
if (r) {
- ERROR(jail->pakfire, "Could not create cgroup for jail: %m\n");
+ CTX_ERROR(jail->ctx, "Could not create cgroup for jail: %m\n");
goto ERROR;
}
// Fork this process
ctx.pid = clone3(&args, sizeof(args));
if (ctx.pid < 0) {
- ERROR(jail->pakfire, "Could not clone: %m\n");
+ CTX_ERROR(jail->ctx, "Could not clone: %m\n");
return -1;
// Child process
if (r)
goto ERROR;
- DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", ctx.pid);
+ CTX_DEBUG(jail->ctx, "Waiting for PID %d to finish its work\n", ctx.pid);
// Read output of the child process
r = pakfire_jail_wait(jail, &ctx);
// Handle exit status
switch (ctx.status.si_code) {
case CLD_EXITED:
- DEBUG(jail->pakfire, "The child process exited with code %d\n",
+ CTX_DEBUG(jail->ctx, "The child process exited with code %d\n",
ctx.status.si_status);
// Pass exit code
break;
case CLD_KILLED:
- ERROR(jail->pakfire, "The child process was killed\n");
+ CTX_ERROR(jail->ctx, "The child process was killed\n");
exit = 139;
break;
case CLD_DUMPED:
- ERROR(jail->pakfire, "The child process terminated abnormally\n");
+ CTX_ERROR(jail->ctx, "The child process terminated abnormally\n");
break;
// Log anything else
default:
- ERROR(jail->pakfire, "Unknown child exit code: %d\n", ctx.status.si_code);
+ CTX_ERROR(jail->ctx, "Unknown child exit code: %d\n", ctx.status.si_code);
break;
}
// Create a temporary file
f = pakfire_mktemp(path, 0700);
if (!f) {
- ERROR(jail->pakfire, "Could not create temporary file: %m\n");
+ CTX_ERROR(jail->ctx, "Could not create temporary file: %m\n");
goto ERROR;
}
- DEBUG(jail->pakfire, "Writing script to %s:\n%.*s\n", path, (int)size, script);
+ CTX_DEBUG(jail->ctx, "Writing script to %s:\n%.*s\n", path, (int)size, script);
// Write data
r = fprintf(f, "%s", script);
if (r < 0) {
- ERROR(jail->pakfire, "Could not write script to file %s: %m\n", path);
+ CTX_ERROR(jail->ctx, "Could not write script to file %s: %m\n", path);
goto ERROR;
}
// Close file
r = fclose(f);
if (r) {
- ERROR(jail->pakfire, "Could not close script file %s: %m\n", path);
+ CTX_ERROR(jail->ctx, "Could not close script file %s: %m\n", path);
goto ERROR;
}
argv = calloc(argc + 1, sizeof(*argv));
if (!argv) {
- ERROR(jail->pakfire, "Could not allocate argv: %m\n");
+ CTX_ERROR(jail->ctx, "Could not allocate argv: %m\n");
goto ERROR;
}
char path[PATH_MAX];
int r;
+ // Fetch the context
+ struct pakfire_ctx* ctx = pakfire_ctx(pakfire);
+
r = pakfire_path(pakfire, path, "%s", *argv);
if (r)
- return r;
+ goto ERROR;
// Check if the file is executable
r = access(path, X_OK);
if (r) {
- DEBUG(pakfire, "%s is not executable. Skipping...\n", *argv);
- return 0;
+ CTX_DEBUG(ctx, "%s is not executable. Skipping...\n", *argv);
+ goto ERROR;
}
- return pakfire_jail_run(pakfire, argv, 0, NULL);
+ r = pakfire_jail_run(pakfire, argv, 0, NULL);
+
+ERROR:
+ if (ctx)
+ pakfire_ctx_unref(ctx);
+
+ return r;
}
int pakfire_jail_ldconfig(struct pakfire* pakfire) {