--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2023 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#ifndef PAKFIRE_NAMESPACE_H
+#define PAKFIRE_NAMESPACE_H
+
+#ifdef PAKFIRE_PRIVATE
+
+#include <pakfire/ctx.h>
+
+int pakfire_setup_namespace(struct pakfire_ctx* ctx, int* userfd);
+
+#endif /* PAKFIRE_PRIVATE */
+
+#endif /* PAKFIRE_NAMESPACE_H */
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2023 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/sched.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <pakfire/ctx.h>
+#include <pakfire/logging.h>
+#include <pakfire/namespace.h>
+
+static int clone3(struct clone_args* args, size_t size) {
+ return syscall(__NR_clone3, args, size);
+}
+
+static int pakfire_namespace_parent(struct pakfire_ctx* ctx, int* userfd, int efd, int pidfd) {
+ siginfo_t status;
+ int r;
+
+ // Read from the file descriptor
+ r = eventfd_read(efd, (eventfd_t*)userfd);
+ if (r) {
+ CTX_ERROR(ctx, "Could not read file descriptor: %s\n", strerror(errno));
+ return -errno;
+ }
+
+ CTX_DEBUG(ctx, "Waiting for the child process to set up the namespace...\n");
+
+ // Wait for the child process to finish
+ r = waitid(P_PIDFD, pidfd, &status, WEXITED);
+ if (r) {
+ CTX_ERROR(ctx, "Failed waiting for the child process: %s\n", strerror(errno));
+ return -errno;
+ }
+
+ switch (status.si_code) {
+ case CLD_EXITED:
+ if (status.si_status) {
+ CTX_ERROR(ctx, "Child process exited with status %d\n", status.si_status);
+
+ // Pass exit code
+ return status.si_status;
+ }
+ break;
+
+ case CLD_KILLED:
+ CTX_ERROR(ctx, "The child process was killed\n");
+ return 139;
+
+ case CLD_DUMPED:
+ CTX_ERROR(ctx, "The child process terminated abnormally\n");
+ return 1;
+
+ // Log anything else
+ default:
+ CTX_ERROR(ctx, "Unknown child exit code: %d\n", status.si_code);
+ break;
+ }
+
+ CTX_DEBUG(ctx, "User Namespace successfully set up as fd %d\n", *userfd);
+
+ return 0;
+}
+
+static void pakfire_namespace_child(struct pakfire_ctx* ctx, int efd) {
+ pid_t pid = getpid();
+ int fd = -1;
+ int r;
+
+ CTX_DEBUG(ctx, "Launched a new process in a new namespace as PID %d\n", pid);
+
+ // Open the usernamespace
+ fd = open("/proc/self/ns/user", O_RDONLY);
+ if (fd < 0) {
+ CTX_ERROR(ctx, "Could not open the user namespace: %s\n", strerror(errno));
+ _exit(1);
+ }
+
+ // Send the file descriptor to the parent process
+ r = eventfd_write(efd, (eventfd_t)fd);
+ if (r) {
+ CTX_ERROR(ctx, "Could not write the file descriptor: %s\n", strerror(errno));
+ _exit(1);
+ }
+
+ _exit(0);
+}
+
+int pakfire_setup_namespace(struct pakfire_ctx* ctx, int* userfd) {
+ int pidfd = -1;
+ int efd = -1;
+ int r;
+
+ CTX_DEBUG(ctx, "Creating a new user namespace...\n");
+
+ struct clone_args args = {
+ .flags =
+ CLONE_NEWUSER |
+ CLONE_FILES |
+ CLONE_PIDFD,
+ .exit_signal = SIGCHLD,
+ .pidfd = (long long unsigned int)&pidfd,
+ };
+
+ // Setup an event file descriptor
+ efd = eventfd(0, EFD_CLOEXEC);
+ if (efd < 0) {
+ CTX_ERROR(ctx, "eventfd() failed: %s\n", strerror(errno));
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Fork a new process
+ pid_t pid = clone3(&args, sizeof(args));
+
+ // Fail on error
+ if (pid < 0) {
+ CTX_ERROR(ctx, "Could not create a new namespace: %s\n", strerror(errno));
+ return -errno;
+
+ // Child process
+ } else if (pid == 0) {
+ pakfire_namespace_child(ctx, efd);
+
+ // We should never reach this
+ abort();
+
+ // Parent process
+ } else {
+ r = pakfire_namespace_parent(ctx, userfd, efd, pidfd);
+ }
+
+ERROR:
+ if (pidfd >= 0)
+ close(pidfd);
+ if (efd >= 0)
+ close(efd);
+
+ return r;
+}
#include <pakfire/dist.h>
#include <pakfire/logging.h>
#include <pakfire/mount.h>
+#include <pakfire/namespace.h>
#include <pakfire/os.h>
#include <pakfire/package.h>
#include <pakfire/packagelist.h>
int flags;
+ // User Namespace
+ int userfd;
+
// Lock
FILE* lock;
pakfire_rmtree(pakfire->path, 0);
}
+ // Release the namespace
+ if (pakfire->userfd >= 0)
+ close(pakfire->userfd);
+
pakfire_repo_free_all(pakfire);
if (pakfire->pool)
goto ERROR;
}
+ // Setup a new namespace
+ r = pakfire_setup_namespace(p->ctx, &p->userfd);
+ if (r)
+ goto ERROR;
+
// Create a ramdisk if no path was given
if (!path) {
r = pakfire_make_ramdisk(p, tempdir, NULL);