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
;
125 static int clone3(struct clone_args
* args
, size_t size
) {
126 return syscall(__NR_clone3
, args
, size
);
129 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
130 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
133 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
136 pakfire_unref(jail
->pakfire
);
141 Passes any log messages on to the default pakfire log callback
143 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
144 int priority
, const char* line
, size_t length
) {
147 INFO(pakfire
, "%s", line
);
151 ERROR(pakfire
, "%s", line
);
156 DEBUG(pakfire
, "%s", line
);
164 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
166 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
171 char* TERM
= secure_getenv("TERM");
173 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
179 char* LANG
= secure_getenv("LANG");
181 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
189 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
190 struct pakfire
* pakfire
, int flags
) {
193 // Allocate a new jail
194 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
199 j
->pakfire
= pakfire_ref(pakfire
);
201 // Initialize reference counter
207 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
209 // Set default log callback
210 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
214 // Set default environment
215 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
216 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
221 // Setup interactive stuff
222 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
223 r
= pakfire_jail_setup_interactive_env(j
);
233 pakfire_jail_free(j
);
238 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
244 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
245 if (--jail
->nrefs
> 0)
248 pakfire_jail_free(jail
);
252 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
253 return jail
->flags
& flag
;
258 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
259 // Check if nice level is in range
260 if (nice
< -19 || nice
> 20) {
271 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
272 // Free any previous cgroup
274 pakfire_cgroup_unref(jail
->cgroup
);
278 // Set any new cgroup
280 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
282 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
291 // Returns the length of the environment
292 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
295 // Count everything in the environment
296 for (char** e
= jail
->env
; *e
; e
++)
302 // Finds an existing environment variable and returns its index or -1 if not found
303 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
309 char buffer
[strlen(key
) + 2];
310 pakfire_string_format(buffer
, "%s=", key
);
312 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
313 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
321 // Returns the value of an environment variable or NULL
322 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
324 int i
= pakfire_jail_find_env(jail
, key
);
328 return jail
->env
[i
] + strlen(key
) + 1;
331 // Sets an environment variable
332 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
333 const char* key
, const char* value
) {
334 // Find the index where to write this value to
335 int i
= pakfire_jail_find_env(jail
, key
);
337 i
= pakfire_jail_env_length(jail
);
339 // Return -ENOSPC when the environment is full
340 if (i
>= ENVIRON_SIZE
) {
345 // Free any previous value
349 // Format and set environment variable
350 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
352 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
357 // Imports an environment
358 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
366 // Copy environment variables
367 for (unsigned int i
= 0; env
[i
]; i
++) {
368 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
373 r
= pakfire_jail_set_env(jail
, key
, val
);
390 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
391 pakfire_jail_log_callback callback
, void* data
) {
392 jail
->log_callback
= callback
;
393 jail
->log_data
= data
;
399 This function replaces any logging in the child process.
401 All log messages will be sent to the parent process through their respective pipes.
403 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
404 int line
, const char* fn
, const char* format
, va_list args
) {
405 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
410 fd
= pipes
->log_INFO
[1];
414 fd
= pipes
->log_ERROR
[1];
419 fd
= pipes
->log_DEBUG
[1];
421 #endif /* ENABLE_DEBUG */
423 // Ignore any messages of an unknown priority
428 // Send the log message
430 vdprintf(fd
, format
, args
);
433 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
434 return (sizeof(buffer
->data
) == buffer
->used
);
438 This function reads as much data as it can from the file descriptor.
439 If it finds a whole line in it, it will send it to the logger and repeat the process.
440 If not newline character is found, it will try to read more data until it finds one.
442 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
443 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
444 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
445 char line
[BUFFER_SIZE
+ 1];
447 // Fill up buffer from fd
448 if (buffer
->used
< sizeof(buffer
->data
)) {
449 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
450 sizeof(buffer
->data
) - buffer
->used
);
453 if (bytes_read
< 0) {
454 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
458 // Update buffer size
459 buffer
->used
+= bytes_read
;
462 // See if we have any lines that we can write
463 while (buffer
->used
) {
464 // Search for the end of the first line
465 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
469 // If the buffer is full, we send the content to the logger and try again
470 // This should not happen in practise
471 if (pakfire_jail_log_buffer_is_full(buffer
)) {
472 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
474 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
476 // Otherwise we might have only read parts of the output
481 // Find the length of the string
482 size_t length
= eol
- buffer
->data
+ 1;
484 // Copy the line into the buffer
485 memcpy(line
, buffer
->data
, length
);
487 // Terminate the string
492 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
494 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
499 // Remove line from buffer
500 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
501 buffer
->used
-= length
;
507 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
508 int r
= pipe2(*fds
, flags
);
510 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
517 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
518 for (unsigned int i
= 0; i
< 2; i
++)
524 This is a convenience function to fetch the reading end of a pipe and
525 closes the write end.
527 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
528 // Give the variables easier names to avoid confusion
529 int* fd_read
= &(*fds
)[0];
530 int* fd_write
= &(*fds
)[1];
532 // Close the write end of the pipe
538 // Return the read end
542 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
544 struct epoll_event ev
;
545 struct epoll_event events
[EPOLL_MAX_EVENTS
];
548 // Fetch file descriptors from context
549 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
550 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
551 const int pidfd
= ctx
->pidfd
;
554 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
555 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
556 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
558 // Make a list of all file descriptors we are interested in
560 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
564 epollfd
= epoll_create1(0);
566 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
573 // Turn file descriptors into non-blocking mode and add them to epoll()
574 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
577 // Skip fds which were not initialized
583 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
584 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
592 // Loop for as long as the process is alive
594 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
596 // Ignore if epoll_wait() has been interrupted
600 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
606 for (int i
= 0; i
< num
; i
++) {
607 int fd
= events
[i
].data
.fd
;
609 struct pakfire_log_buffer
* buffer
= NULL
;
610 pakfire_jail_log_callback callback
= NULL
;
614 // Handle any changes to the PIDFD
616 // Call waidid() and store the result
617 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
619 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
623 // Mark that we have ended so that we will process the remaining
624 // events from epoll() now, but won't restart the outer loop.
628 // Handle logging messages
629 } else if (fd
== log_INFO
) {
630 buffer
= &ctx
->buffers
.log_INFO
;
633 callback
= pakfire_jail_default_log_callback
;
635 } else if (fd
== log_ERROR
) {
636 buffer
= &ctx
->buffers
.log_ERROR
;
639 callback
= pakfire_jail_default_log_callback
;
641 } else if (fd
== log_DEBUG
) {
642 buffer
= &ctx
->buffers
.log_DEBUG
;
643 priority
= LOG_DEBUG
;
645 callback
= pakfire_jail_default_log_callback
;
647 // Handle anything from the log pipes
648 } else if (fd
== stdout
) {
649 buffer
= &ctx
->buffers
.stdout
;
652 callback
= jail
->log_callback
;
653 data
= jail
->log_data
;
655 } else if (fd
== stderr
) {
656 buffer
= &ctx
->buffers
.stderr
;
659 callback
= jail
->log_callback
;
660 data
= jail
->log_data
;
663 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
668 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
681 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
682 const char* line
, size_t length
) {
683 char*** array
= (char***)data
;
685 // Append everything from stdout to an array
686 if (priority
== LOG_INFO
) {
689 // Create a copy of line
690 char* message
= strdup(line
);
694 // Determine the length of the existing array
696 for (char** element
= *array
; *element
; element
++)
701 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
705 // Append message and terminate the array
706 (*array
)[length
] = message
;
707 (*array
)[length
+ 1] = NULL
;
712 // Send everything else to the default logger
713 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
718 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
719 const int capabilities
[] = {
720 // Deny access to the kernel's audit system
725 // Deny suspending block devices
728 // Deny any stuff with BPF
731 // Deny checkpoint restore
732 CAP_CHECKPOINT_RESTORE
,
734 // Deny opening files by inode number (open_by_handle_at)
737 // Deny setting SUID bits
740 // Deny locking more memory
743 // Deny modifying any Apparmor/SELinux/SMACK configuration
747 // Deny creating any special devices
750 // Deny setting any capabilities
753 // Deny reading from syslog
756 // Deny any admin actions (mount, sethostname, ...)
759 // Deny rebooting the system
762 // Deny loading kernel modules
765 // Deny setting nice level
768 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
771 // Deny circumventing any resource limits
774 // Deny setting the system time
777 // Deny playing with suspend
783 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
788 // Drop any capabilities
789 for (const int* cap
= capabilities
; *cap
; cap
++) {
790 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
792 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
799 // Fetch any capabilities
800 cap_t caps
= cap_get_proc();
802 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
807 Set inheritable capabilities
809 This ensures that no processes will be able to gain any of the listed
812 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
814 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
818 // Restore capabilities
819 r
= cap_set_proc(caps
);
821 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
834 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
835 const int syscalls
[] = {
836 // The kernel's keyring isn't namespaced
839 SCMP_SYS(request_key
),
841 // Disable userfaultfd
842 SCMP_SYS(userfaultfd
),
844 // Disable perf which could leak a lot of information about the host
845 SCMP_SYS(perf_event_open
),
851 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
853 // Setup a syscall filter which allows everything by default
854 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
856 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
861 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
862 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
864 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
869 // Load syscall filter into the kernel
870 r
= seccomp_load(ctx
);
872 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
878 seccomp_release(ctx
);
885 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
886 const char* path
, uid_t mapped_id
, size_t length
) {
889 // Open file for writing
890 FILE* f
= fopen(path
, "w");
892 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
896 // Write configuration
897 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
898 if (bytes_written
<= 0) {
899 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
907 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
922 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
926 uid_t mapped_uid
= 0;
927 const size_t length
= 1;
929 // Fetch the UID of the calling process
930 uid_t uid
= getuid();
932 // Have we been called by root?
936 // Have we been called by an unprivileged user?
943 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
947 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
949 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
952 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
956 gid_t mapped_gid
= 0;
957 const size_t length
= 1;
959 // Fetch the GID of the calling process
960 gid_t gid
= getgid();
962 // Have we been called from the root group?
966 // Have we been called by an unprivileged group?
973 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
977 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
979 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
982 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
987 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
991 // Open file for writing
992 FILE* f
= fopen(path
, "w");
994 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
999 int bytes_written
= fprintf(f
, "deny\n");
1000 if (bytes_written
<= 0) {
1001 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1008 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1019 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1020 const uint64_t val
= 1;
1023 DEBUG(jail
->pakfire
, "Sending signal...\n");
1025 // Write to the file descriptor
1026 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1027 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1028 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1032 // Close the file descriptor
1038 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1042 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1044 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1045 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1046 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1050 // Close the file descriptor
1057 Performs the initialisation that needs to happen in the parent part
1059 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1062 // Setup UID mapping
1063 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1067 // Write "deny" to /proc/PID/setgroups
1068 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1072 // Setup GID mapping
1073 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1077 // Parent has finished initialisation
1078 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1080 // Send signal to client
1081 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1088 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1089 const char* argv
[]) {
1092 // Redirect any logging to our log pipe
1093 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1096 pid_t pid
= getpid();
1098 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1100 // Wait for the parent to finish initialization
1101 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1105 // Perform further initialization
1108 uid_t uid
= getuid();
1109 gid_t gid
= getgid();
1112 uid_t euid
= geteuid();
1113 gid_t egid
= getegid();
1115 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1116 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1118 // Check if we are (effectively running as root)
1119 if (uid
!= 0 || gid
!= 0) {
1120 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1124 const char* root
= pakfire_get_path(jail
->pakfire
);
1125 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1127 // Change root (unless root is /)
1128 if (!pakfire_on_root(jail
->pakfire
)) {
1130 r
= pakfire_mount_all(jail
->pakfire
);
1134 // Log all mountpoints
1135 pakfire_mount_list(jail
->pakfire
);
1140 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1144 // Change directory to /
1147 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1153 unsigned long persona
= pakfire_arch_personality(arch
);
1155 r
= personality(persona
);
1157 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1164 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1166 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1168 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1173 // Close other end of log pipes
1174 close(ctx
->pipes
.log_INFO
[0]);
1175 close(ctx
->pipes
.log_ERROR
[0]);
1177 close(ctx
->pipes
.log_DEBUG
[0]);
1178 #endif /* ENABLE_DEBUG */
1180 // Connect standard output and error
1181 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1182 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1184 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1185 ctx
->pipes
.stdout
[1]);
1190 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1192 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1193 ctx
->pipes
.stderr
[1]);
1198 // Close the pipe (as we have moved the original file descriptors)
1199 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1200 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1203 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1204 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1208 // Drop capabilities
1209 r
= pakfire_jail_drop_capabilities(jail
);
1214 r
= pakfire_jail_limit_syscalls(jail
);
1219 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1221 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1223 // Translate errno into regular exit code
1233 // We should not get here
1237 // Run a command in the jail
1238 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1242 // Check if argv is valid
1243 if (!argv
|| !argv
[0]) {
1248 // Initialize context for this call
1249 struct pakfire_jail_exec ctx
= {
1256 DEBUG(jail
->pakfire
, "Executing jail...\n");
1259 Setup a file descriptor which can be used to notify the client that the parent
1260 has completed configuration.
1262 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1263 if (ctx
.completed_fd
< 0) {
1264 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1268 // Create pipes to communicate with child process if we are not running interactively
1269 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1271 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1276 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1281 // Setup pipes for logging
1283 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1288 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1294 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1297 #endif /* ENABLE_DEBUG */
1299 // Configure child process
1300 struct clone_args args
= {
1309 .exit_signal
= SIGCHLD
,
1310 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1313 // Launch the process in a cgroup (if requested)
1315 args
.flags
|= CLONE_INTO_CGROUP
;
1317 // Clone into this cgroup
1318 args
.cgroup
= pakfire_cgroup_fd(jail
->cgroup
);
1321 // Fork this process
1322 ctx
.pid
= clone3(&args
, sizeof(args
));
1324 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1328 } else if (ctx
.pid
== 0) {
1329 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1334 r
= pakfire_jail_parent(jail
, &ctx
);
1338 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1340 // Read output of the child process
1341 r
= pakfire_jail_wait(jail
, &ctx
);
1345 // Handle exit status
1346 switch (ctx
.status
.si_code
) {
1348 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1349 ctx
.status
.si_status
);
1352 exit
= ctx
.status
.si_status
;
1357 ERROR(jail
->pakfire
, "The child process was killed\n");
1360 // Log anything else
1362 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1367 // Close any file descriptors
1368 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1369 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1372 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1373 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1374 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1376 // Umount everything
1377 if (!pakfire_on_root(jail
->pakfire
))
1378 pakfire_umount_all(jail
->pakfire
);
1383 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1384 const char* argv
[], char*** output
) {
1387 // Store logging callback
1388 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1389 void* log_data
= jail
->log_data
;
1391 // Capture output if requested by user
1393 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1396 r
= __pakfire_jail_exec(jail
, argv
);
1398 // Restore log callback
1399 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1404 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1405 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1406 char path
[PATH_MAX
];
1407 const char** argv
= NULL
;
1410 const char* root
= pakfire_get_path(jail
->pakfire
);
1412 // Write the scriptlet to disk
1413 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1417 // Open a temporary file
1418 int fd
= mkstemp(path
);
1420 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1425 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1428 ssize_t bytes_written
= write(fd
, script
, size
);
1429 if (bytes_written
< (ssize_t
)size
) {
1430 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1435 // Make the script executable
1436 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1438 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1445 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1450 // Count how many arguments were passed
1451 unsigned int argc
= 1;
1453 for (const char** arg
= args
; *arg
; arg
++)
1457 argv
= calloc(argc
+ 1, sizeof(*argv
));
1459 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1464 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1467 for (unsigned int i
= 1; i
< argc
; i
++)
1468 argv
[i
] = args
[i
-1];
1471 r
= pakfire_jail_exec(jail
, argv
, output
);
1477 // Remove script from disk
1485 A convenience function that creates a new jail, runs the given command and destroys
1488 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char*** output
) {
1489 struct pakfire_jail
* jail
= NULL
;
1492 // Create a new jail
1493 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1497 // Execute the command
1498 r
= pakfire_jail_exec(jail
, argv
, output
);
1502 pakfire_jail_unref(jail
);
1507 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1508 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1509 struct pakfire_jail
* jail
= NULL
;
1512 // Create a new jail
1513 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1517 // Execute the command
1518 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1522 pakfire_jail_unref(jail
);
1528 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1529 const char* argv
[] = {
1530 "/bin/bash", "--login", NULL
,
1533 // Execute /bin/bash
1534 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1537 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1538 char path
[PATH_MAX
];
1540 const char* ldconfig
= "/sbin/ldconfig";
1542 // Check if ldconfig exists before calling it to avoid overhead
1543 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1547 // Check if ldconfig is executable
1548 r
= access(path
, X_OK
);
1550 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1554 const char* argv
[] = {
1559 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
1562 // Utility functions
1564 PAKFIRE_EXPORT
char* pakfire_jail_concat_output(struct pakfire_jail
* jail
,
1565 const char** input
, size_t* length
) {
1566 // Return nothing on no input
1570 // XXX Maybe there is a more efficient way to do this
1572 char* output
= pakfire_string_join((char**)input
, "");
1576 // Store the length of the result
1578 *length
= strlen(output
);