1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2022 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
22 #include <linux/capability.h>
23 #include <linux/fcntl.h>
24 #include <linux/sched.h>
25 #include <linux/wait.h>
30 #include <sys/capability.h>
31 #include <sys/epoll.h>
32 #include <sys/eventfd.h>
33 #include <sys/personality.h>
34 #include <sys/prctl.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
42 #include <pakfire/arch.h>
43 #include <pakfire/cgroup.h>
44 #include <pakfire/jail.h>
45 #include <pakfire/logging.h>
46 #include <pakfire/mount.h>
47 #include <pakfire/pakfire.h>
48 #include <pakfire/private.h>
49 #include <pakfire/util.h>
51 #define BUFFER_SIZE 1024 * 64
52 #define ENVIRON_SIZE 128
53 #define EPOLL_MAX_EVENTS 2
55 // The default environment that will be set for every command
56 static const struct environ
{
60 { "LANG", "en_US.utf-8" },
66 struct pakfire
* pakfire
;
76 struct pakfire_cgroup
* cgroup
;
79 char* env
[ENVIRON_SIZE
];
82 pakfire_jail_log_callback log_callback
;
86 struct pakfire_log_buffer
{
87 char data
[BUFFER_SIZE
];
91 struct pakfire_jail_exec
{
96 // Process status (from waitid)
99 // FD to notify the client that the parent has finished initialization
103 struct pakfire_jail_pipes
{
114 struct pakfire_jail_buffers
{
115 struct pakfire_log_buffer stdout
;
116 struct pakfire_log_buffer stderr
;
119 struct pakfire_log_buffer log_INFO
;
120 struct pakfire_log_buffer log_ERROR
;
121 struct pakfire_log_buffer log_DEBUG
;
124 struct pakfire_cgroup
* cgroup
;
125 struct pakfire_cgroup_stats cgroup_stats
;
128 static int clone3(struct clone_args
* args
, size_t size
) {
129 return syscall(__NR_clone3
, args
, size
);
132 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
133 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
136 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
140 pakfire_cgroup_unref(jail
->cgroup
);
142 pakfire_unref(jail
->pakfire
);
147 Passes any log messages on to the default pakfire log callback
149 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
150 int priority
, const char* line
, size_t length
) {
153 INFO(pakfire
, "%s", line
);
157 ERROR(pakfire
, "%s", line
);
162 DEBUG(pakfire
, "%s", line
);
170 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
172 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
177 char* TERM
= secure_getenv("TERM");
179 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
185 char* LANG
= secure_getenv("LANG");
187 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
195 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
196 struct pakfire
* pakfire
, int flags
) {
199 // Allocate a new jail
200 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
205 j
->pakfire
= pakfire_ref(pakfire
);
207 // Initialize reference counter
213 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
215 // Set default log callback
216 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
220 // Set default environment
221 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
222 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
227 // Setup interactive stuff
228 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
229 r
= pakfire_jail_setup_interactive_env(j
);
239 pakfire_jail_free(j
);
244 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
250 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
251 if (--jail
->nrefs
> 0)
254 pakfire_jail_free(jail
);
258 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
259 return jail
->flags
& flag
;
264 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
265 // Check if nice level is in range
266 if (nice
< -19 || nice
> 20) {
277 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
278 // Free any previous cgroup
280 pakfire_cgroup_unref(jail
->cgroup
);
284 // Set any new cgroup
286 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
288 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
297 // Returns the length of the environment
298 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
301 // Count everything in the environment
302 for (char** e
= jail
->env
; *e
; e
++)
308 // Finds an existing environment variable and returns its index or -1 if not found
309 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
315 char buffer
[strlen(key
) + 2];
316 pakfire_string_format(buffer
, "%s=", key
);
318 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
319 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
327 // Returns the value of an environment variable or NULL
328 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
330 int i
= pakfire_jail_find_env(jail
, key
);
334 return jail
->env
[i
] + strlen(key
) + 1;
337 // Sets an environment variable
338 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
339 const char* key
, const char* value
) {
340 // Find the index where to write this value to
341 int i
= pakfire_jail_find_env(jail
, key
);
343 i
= pakfire_jail_env_length(jail
);
345 // Return -ENOSPC when the environment is full
346 if (i
>= ENVIRON_SIZE
) {
351 // Free any previous value
355 // Format and set environment variable
356 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
358 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
363 // Imports an environment
364 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
372 // Copy environment variables
373 for (unsigned int i
= 0; env
[i
]; i
++) {
374 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
379 r
= pakfire_jail_set_env(jail
, key
, val
);
396 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
397 pakfire_jail_log_callback callback
, void* data
) {
398 jail
->log_callback
= callback
;
399 jail
->log_data
= data
;
405 This function replaces any logging in the child process.
407 All log messages will be sent to the parent process through their respective pipes.
409 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
410 int line
, const char* fn
, const char* format
, va_list args
) {
411 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
416 fd
= pipes
->log_INFO
[1];
420 fd
= pipes
->log_ERROR
[1];
425 fd
= pipes
->log_DEBUG
[1];
427 #endif /* ENABLE_DEBUG */
429 // Ignore any messages of an unknown priority
434 // Send the log message
436 vdprintf(fd
, format
, args
);
439 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
440 return (sizeof(buffer
->data
) == buffer
->used
);
444 This function reads as much data as it can from the file descriptor.
445 If it finds a whole line in it, it will send it to the logger and repeat the process.
446 If not newline character is found, it will try to read more data until it finds one.
448 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
449 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
450 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
451 char line
[BUFFER_SIZE
+ 1];
453 // Fill up buffer from fd
454 if (buffer
->used
< sizeof(buffer
->data
)) {
455 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
456 sizeof(buffer
->data
) - buffer
->used
);
459 if (bytes_read
< 0) {
460 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
464 // Update buffer size
465 buffer
->used
+= bytes_read
;
468 // See if we have any lines that we can write
469 while (buffer
->used
) {
470 // Search for the end of the first line
471 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
475 // If the buffer is full, we send the content to the logger and try again
476 // This should not happen in practise
477 if (pakfire_jail_log_buffer_is_full(buffer
)) {
478 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
480 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
482 // Otherwise we might have only read parts of the output
487 // Find the length of the string
488 size_t length
= eol
- buffer
->data
+ 1;
490 // Copy the line into the buffer
491 memcpy(line
, buffer
->data
, length
);
493 // Terminate the string
498 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
500 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
505 // Remove line from buffer
506 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
507 buffer
->used
-= length
;
513 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
514 int r
= pipe2(*fds
, flags
);
516 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
523 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
524 for (unsigned int i
= 0; i
< 2; i
++)
530 This is a convenience function to fetch the reading end of a pipe and
531 closes the write end.
533 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
534 // Give the variables easier names to avoid confusion
535 int* fd_read
= &(*fds
)[0];
536 int* fd_write
= &(*fds
)[1];
538 // Close the write end of the pipe
544 // Return the read end
548 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
550 struct epoll_event ev
;
551 struct epoll_event events
[EPOLL_MAX_EVENTS
];
554 // Fetch file descriptors from context
555 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
556 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
557 const int pidfd
= ctx
->pidfd
;
560 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
561 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
562 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
564 // Make a list of all file descriptors we are interested in
566 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
570 epollfd
= epoll_create1(0);
572 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
579 // Turn file descriptors into non-blocking mode and add them to epoll()
580 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
583 // Skip fds which were not initialized
589 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
590 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
598 // Loop for as long as the process is alive
600 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
602 // Ignore if epoll_wait() has been interrupted
606 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
612 for (int i
= 0; i
< num
; i
++) {
613 int fd
= events
[i
].data
.fd
;
615 struct pakfire_log_buffer
* buffer
= NULL
;
616 pakfire_jail_log_callback callback
= NULL
;
620 // Handle any changes to the PIDFD
622 // Call waidid() and store the result
623 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
625 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
629 // Mark that we have ended so that we will process the remaining
630 // events from epoll() now, but won't restart the outer loop.
634 // Handle logging messages
635 } else if (fd
== log_INFO
) {
636 buffer
= &ctx
->buffers
.log_INFO
;
639 callback
= pakfire_jail_default_log_callback
;
641 } else if (fd
== log_ERROR
) {
642 buffer
= &ctx
->buffers
.log_ERROR
;
645 callback
= pakfire_jail_default_log_callback
;
647 } else if (fd
== log_DEBUG
) {
648 buffer
= &ctx
->buffers
.log_DEBUG
;
649 priority
= LOG_DEBUG
;
651 callback
= pakfire_jail_default_log_callback
;
653 // Handle anything from the log pipes
654 } else if (fd
== stdout
) {
655 buffer
= &ctx
->buffers
.stdout
;
658 callback
= jail
->log_callback
;
659 data
= jail
->log_data
;
661 } else if (fd
== stderr
) {
662 buffer
= &ctx
->buffers
.stderr
;
665 callback
= jail
->log_callback
;
666 data
= jail
->log_data
;
669 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
674 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
687 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
688 const char* line
, size_t length
) {
689 char** output
= (char**)data
;
692 // Append everything from stdout to a buffer
693 if (priority
== LOG_INFO
) {
694 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
700 // Send everything else to the default logger
701 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
706 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
707 const int capabilities
[] = {
708 // Deny access to the kernel's audit system
713 // Deny suspending block devices
716 // Deny any stuff with BPF
719 // Deny checkpoint restore
720 CAP_CHECKPOINT_RESTORE
,
722 // Deny opening files by inode number (open_by_handle_at)
725 // Deny setting SUID bits
728 // Deny locking more memory
731 // Deny modifying any Apparmor/SELinux/SMACK configuration
735 // Deny creating any special devices
738 // Deny setting any capabilities
741 // Deny reading from syslog
744 // Deny any admin actions (mount, sethostname, ...)
747 // Deny rebooting the system
750 // Deny loading kernel modules
753 // Deny setting nice level
756 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
759 // Deny circumventing any resource limits
762 // Deny setting the system time
765 // Deny playing with suspend
771 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
776 // Drop any capabilities
777 for (const int* cap
= capabilities
; *cap
; cap
++) {
778 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
780 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
787 // Fetch any capabilities
788 cap_t caps
= cap_get_proc();
790 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
795 Set inheritable capabilities
797 This ensures that no processes will be able to gain any of the listed
800 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
802 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
806 // Restore capabilities
807 r
= cap_set_proc(caps
);
809 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
822 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
823 const int syscalls
[] = {
824 // The kernel's keyring isn't namespaced
827 SCMP_SYS(request_key
),
829 // Disable userfaultfd
830 SCMP_SYS(userfaultfd
),
832 // Disable perf which could leak a lot of information about the host
833 SCMP_SYS(perf_event_open
),
839 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
841 // Setup a syscall filter which allows everything by default
842 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
844 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
849 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
850 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
852 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
857 // Load syscall filter into the kernel
858 r
= seccomp_load(ctx
);
860 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
866 seccomp_release(ctx
);
873 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
874 const char* path
, uid_t mapped_id
, size_t length
) {
877 // Open file for writing
878 FILE* f
= fopen(path
, "w");
880 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
884 // Write configuration
885 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
886 if (bytes_written
<= 0) {
887 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
895 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
910 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
914 uid_t mapped_uid
= 0;
915 const size_t length
= 1;
917 // Fetch the UID of the calling process
918 uid_t uid
= getuid();
920 // Have we been called by root?
924 // Have we been called by an unprivileged user?
931 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
935 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
937 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
940 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
944 gid_t mapped_gid
= 0;
945 const size_t length
= 1;
947 // Fetch the GID of the calling process
948 gid_t gid
= getgid();
950 // Have we been called from the root group?
954 // Have we been called by an unprivileged group?
961 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
965 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
967 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
970 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
975 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
979 // Open file for writing
980 FILE* f
= fopen(path
, "w");
982 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
987 int bytes_written
= fprintf(f
, "deny\n");
988 if (bytes_written
<= 0) {
989 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
996 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1007 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1008 const uint64_t val
= 1;
1011 DEBUG(jail
->pakfire
, "Sending signal...\n");
1013 // Write to the file descriptor
1014 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1015 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1016 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1020 // Close the file descriptor
1026 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1030 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1032 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1033 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1034 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1038 // Close the file descriptor
1045 Performs the initialisation that needs to happen in the parent part
1047 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1050 // Setup UID mapping
1051 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1055 // Write "deny" to /proc/PID/setgroups
1056 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1060 // Setup GID mapping
1061 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1065 // Parent has finished initialisation
1066 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1068 // Send signal to client
1069 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1076 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1077 const char* argv
[]) {
1080 // Redirect any logging to our log pipe
1081 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1084 pid_t pid
= getpid();
1086 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1089 for (unsigned int i
= 0; argv
[i
]; i
++)
1090 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1092 // Wait for the parent to finish initialization
1093 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1097 // Perform further initialization
1100 uid_t uid
= getuid();
1101 gid_t gid
= getgid();
1104 uid_t euid
= geteuid();
1105 gid_t egid
= getegid();
1107 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1108 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1110 // Check if we are (effectively running as root)
1111 if (uid
|| gid
|| euid
|| egid
) {
1112 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1116 const char* root
= pakfire_get_path(jail
->pakfire
);
1117 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1119 // Change root (unless root is /)
1120 if (!pakfire_on_root(jail
->pakfire
)) {
1122 r
= pakfire_mount_all(jail
->pakfire
);
1126 // Log all mountpoints
1127 pakfire_mount_list(jail
->pakfire
);
1132 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1136 // Change directory to /
1139 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1145 unsigned long persona
= pakfire_arch_personality(arch
);
1147 r
= personality(persona
);
1149 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1156 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1158 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1160 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1165 // Close other end of log pipes
1166 close(ctx
->pipes
.log_INFO
[0]);
1167 close(ctx
->pipes
.log_ERROR
[0]);
1169 close(ctx
->pipes
.log_DEBUG
[0]);
1170 #endif /* ENABLE_DEBUG */
1172 // Connect standard output and error
1173 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1174 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1176 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1177 ctx
->pipes
.stdout
[1]);
1182 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1184 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1185 ctx
->pipes
.stderr
[1]);
1190 // Close the pipe (as we have moved the original file descriptors)
1191 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1192 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1195 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1196 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1200 // Drop capabilities
1201 r
= pakfire_jail_drop_capabilities(jail
);
1206 r
= pakfire_jail_limit_syscalls(jail
);
1211 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1213 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1215 // Translate errno into regular exit code
1225 // We should not get here
1229 // Run a command in the jail
1230 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1234 // Check if argv is valid
1235 if (!argv
|| !argv
[0]) {
1240 // Initialize context for this call
1241 struct pakfire_jail_exec ctx
= {
1248 DEBUG(jail
->pakfire
, "Executing jail...\n");
1251 Setup a file descriptor which can be used to notify the client that the parent
1252 has completed configuration.
1254 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1255 if (ctx
.completed_fd
< 0) {
1256 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1260 // Create pipes to communicate with child process if we are not running interactively
1261 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1263 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1268 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1273 // Setup pipes for logging
1275 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1280 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1286 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1289 #endif /* ENABLE_DEBUG */
1291 // Configure child process
1292 struct clone_args args
= {
1301 .exit_signal
= SIGCHLD
,
1302 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1305 // Launch the process in a cgroup that is a leaf of the configured cgroup
1307 args
.flags
|= CLONE_INTO_CGROUP
;
1309 #warning TODO randomize the name
1311 // Create a temporary cgroup
1312 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, "jail", 0);
1314 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1318 // Clone into this cgroup
1319 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
1322 // Fork this process
1323 ctx
.pid
= clone3(&args
, sizeof(args
));
1325 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1329 } else if (ctx
.pid
== 0) {
1330 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1335 r
= pakfire_jail_parent(jail
, &ctx
);
1339 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1341 // Read output of the child process
1342 r
= pakfire_jail_wait(jail
, &ctx
);
1346 // Handle exit status
1347 switch (ctx
.status
.si_code
) {
1349 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1350 ctx
.status
.si_status
);
1353 exit
= ctx
.status
.si_status
;
1358 ERROR(jail
->pakfire
, "The child process was killed\n");
1361 // Log anything else
1363 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1368 // Destroy the temporary cgroup (if any)
1370 // Read cgroup stats
1371 r
= pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
1373 ERROR(jail
->pakfire
, "Could not read cgroup stats: %m\n");
1375 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
1378 pakfire_cgroup_destroy(ctx
.cgroup
);
1379 pakfire_cgroup_unref(ctx
.cgroup
);
1382 // Close any file descriptors
1383 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1384 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1387 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1388 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1389 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1392 // Umount everything
1393 if (!pakfire_on_root(jail
->pakfire
))
1394 pakfire_umount_all(jail
->pakfire
);
1400 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1401 const char* argv
[], char** output
) {
1404 // Store logging callback
1405 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1406 void* log_data
= jail
->log_data
;
1408 // Capture output if requested by user
1410 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1413 r
= __pakfire_jail_exec(jail
, argv
);
1415 // Restore log callback
1416 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1421 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1422 const char* script
, const size_t size
, const char* args
[], char** output
) {
1423 char path
[PATH_MAX
];
1424 const char** argv
= NULL
;
1427 const char* root
= pakfire_get_path(jail
->pakfire
);
1429 // Write the scriptlet to disk
1430 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1434 // Open a temporary file
1435 int fd
= mkstemp(path
);
1437 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1442 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1445 ssize_t bytes_written
= write(fd
, script
, size
);
1446 if (bytes_written
< (ssize_t
)size
) {
1447 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1452 // Make the script executable
1453 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1455 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1462 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1467 // Count how many arguments were passed
1468 unsigned int argc
= 1;
1470 for (const char** arg
= args
; *arg
; arg
++)
1474 argv
= calloc(argc
+ 1, sizeof(*argv
));
1476 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1481 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1484 for (unsigned int i
= 1; i
< argc
; i
++)
1485 argv
[i
] = args
[i
-1];
1488 r
= pakfire_jail_exec(jail
, argv
, output
);
1494 // Remove script from disk
1502 A convenience function that creates a new jail, runs the given command and destroys
1505 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
1506 struct pakfire_jail
* jail
= NULL
;
1509 // Create a new jail
1510 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1514 // Execute the command
1515 r
= pakfire_jail_exec(jail
, argv
, output
);
1519 pakfire_jail_unref(jail
);
1524 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1525 const char* script
, const size_t length
, const char* argv
[], int flags
, char** output
) {
1526 struct pakfire_jail
* jail
= NULL
;
1529 // Create a new jail
1530 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1534 // Execute the command
1535 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1539 pakfire_jail_unref(jail
);
1545 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1546 const char* argv
[] = {
1547 "/bin/bash", "--login", NULL
,
1550 // Execute /bin/bash
1551 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1554 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1555 char path
[PATH_MAX
];
1557 const char* ldconfig
= "/sbin/ldconfig";
1559 // Check if ldconfig exists before calling it to avoid overhead
1560 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1564 // Check if ldconfig is executable
1565 r
= access(path
, X_OK
);
1567 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1571 const char* argv
[] = {
1576 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);