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/jail.h>
44 #include <pakfire/logging.h>
45 #include <pakfire/mount.h>
46 #include <pakfire/pakfire.h>
47 #include <pakfire/private.h>
48 #include <pakfire/util.h>
50 #define BUFFER_SIZE 1024 * 64
51 #define ENVIRON_SIZE 128
52 #define EPOLL_MAX_EVENTS 2
54 // The default environment that will be set for every command
55 static const struct environ
{
59 { "LANG", "en_US.utf-8" },
65 struct pakfire
* pakfire
;
75 char* env
[ENVIRON_SIZE
];
78 pakfire_jail_log_callback log_callback
;
82 struct pakfire_log_buffer
{
83 char data
[BUFFER_SIZE
];
87 struct pakfire_jail_exec
{
92 // Process status (from waitid)
95 // FD to notify the client that the parent has finished initialization
106 struct pakfire_log_buffer stdout
;
107 struct pakfire_log_buffer stderr
;
111 static int clone3(struct clone_args
* args
, size_t size
) {
112 return syscall(__NR_clone3
, args
, size
);
115 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
116 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
119 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
122 pakfire_unref(jail
->pakfire
);
126 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
127 int priority
, const char* line
, size_t length
) {
130 INFO(pakfire
, "%s", line
);
134 ERROR(pakfire
, "%s", line
);
141 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
143 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
148 char* TERM
= secure_getenv("TERM");
150 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
156 char* LANG
= secure_getenv("LANG");
158 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
166 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
167 struct pakfire
* pakfire
, int flags
) {
170 // Allocate a new jail
171 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
176 j
->pakfire
= pakfire_ref(pakfire
);
178 // Initialize reference counter
184 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
186 // Set default log callback
187 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
191 // Set default environment
192 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
193 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
198 // Setup interactive stuff
199 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
200 r
= pakfire_jail_setup_interactive_env(j
);
210 pakfire_jail_free(j
);
215 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
221 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
222 if (--jail
->nrefs
> 0)
225 pakfire_jail_free(jail
);
229 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
230 return jail
->flags
& flag
;
235 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
236 // Check if nice level is in range
237 if (nice
< -19 || nice
> 20) {
250 // Returns the length of the environment
251 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
254 // Count everything in the environment
255 for (char** e
= jail
->env
; *e
; e
++)
261 // Finds an existing environment variable and returns its index or -1 if not found
262 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
268 char buffer
[strlen(key
) + 2];
269 pakfire_string_format(buffer
, "%s=", key
);
271 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
272 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
280 // Returns the value of an environment variable or NULL
281 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
283 int i
= pakfire_jail_find_env(jail
, key
);
287 return jail
->env
[i
] + strlen(key
) + 1;
290 // Sets an environment variable
291 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
292 const char* key
, const char* value
) {
293 // Find the index where to write this value to
294 int i
= pakfire_jail_find_env(jail
, key
);
296 i
= pakfire_jail_env_length(jail
);
298 // Return -ENOSPC when the environment is full
299 if (i
>= ENVIRON_SIZE
) {
304 // Free any previous value
308 // Format and set environment variable
309 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
311 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
316 // Imports an environment
317 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
325 // Copy environment variables
326 for (unsigned int i
= 0; env
[i
]; i
++) {
327 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
332 r
= pakfire_jail_set_env(jail
, key
, val
);
349 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
350 pakfire_jail_log_callback callback
, void* data
) {
351 jail
->log_callback
= callback
;
352 jail
->log_data
= data
;
357 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
358 return (sizeof(buffer
->data
) == buffer
->used
);
362 This function reads as much data as it can from the file descriptor.
363 If it finds a whole line in it, it will send it to the logger and repeat the process.
364 If not newline character is found, it will try to read more data until it finds one.
366 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
367 struct pakfire_jail_exec
* ctx
, int priority
, int fd
, struct pakfire_log_buffer
* buffer
) {
368 char line
[BUFFER_SIZE
+ 1];
370 // Fill up buffer from fd
371 if (buffer
->used
< sizeof(buffer
->data
)) {
372 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
373 sizeof(buffer
->data
) - buffer
->used
);
376 if (bytes_read
< 0) {
377 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
381 // Update buffer size
382 buffer
->used
+= bytes_read
;
385 // See if we have any lines that we can write
386 while (buffer
->used
) {
387 // Search for the end of the first line
388 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
392 // If the buffer is full, we send the content to the logger and try again
393 // This should not happen in practise
394 if (pakfire_jail_log_buffer_is_full(buffer
)) {
395 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
397 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
399 // Otherwise we might have only read parts of the output
404 // Find the length of the string
405 size_t length
= eol
- buffer
->data
+ 1;
407 // Copy the line into the buffer
408 memcpy(line
, buffer
->data
, length
);
410 // Terminate the string
414 if (jail
->log_callback
) {
415 int r
= jail
->log_callback(jail
->pakfire
, jail
->log_data
, priority
, line
, length
);
417 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
422 // Remove line from buffer
423 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
424 buffer
->used
-= length
;
430 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
432 struct epoll_event ev
;
433 struct epoll_event events
[EPOLL_MAX_EVENTS
];
436 // Fetch file descriptors from context
437 const int stdout
= ctx
->pipes
.stdout
[0];
438 const int stderr
= ctx
->pipes
.stderr
[0];
439 const int pidfd
= ctx
->pidfd
;
441 // Close any unused file descriptors
442 if (ctx
->pipes
.stdout
[1]) {
443 close(ctx
->pipes
.stdout
[1]);
444 ctx
->pipes
.stdout
[1] = 0;
446 if (ctx
->pipes
.stderr
[1]) {
447 close(ctx
->pipes
.stderr
[1]);
448 ctx
->pipes
.stderr
[1] = 0;
451 // Make a list of all file descriptors we are interested in
453 stdout
, stderr
, pidfd
,
457 epollfd
= epoll_create1(0);
459 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
466 // Turn file descriptors into non-blocking mode and add them to epoll()
467 for (unsigned int i
= 0; i
< 3; i
++) {
470 // Skip fds which were not initialized
476 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
477 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
485 // Loop for as long as the process is alive
487 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
489 // Ignore if epoll_wait() has been interrupted
493 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
499 struct pakfire_log_buffer
* buffer
;
502 for (int i
= 0; i
< num
; i
++) {
503 int fd
= events
[i
].data
.fd
;
505 // Handle any changes to the PIDFD
507 // Call waidid() and store the result
508 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
510 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
514 // Mark that we have ended so that we will process the remaining
515 // events from epoll() now, but won't restart the outer loop.
519 // Handle anything from the log pipes
520 } else if (fd
== stdout
) {
521 buffer
= &ctx
->buffers
.stdout
;
524 } else if (fd
== stderr
) {
525 buffer
= &ctx
->buffers
.stderr
;
529 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
534 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
);
547 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
548 const char* line
, size_t length
) {
549 char*** array
= (char***)data
;
551 // Append everything from stdout to an array
552 if (priority
== LOG_INFO
) {
555 // Create a copy of line
556 char* message
= strdup(line
);
560 // Remove any trailing newline
561 pakfire_remove_trailing_newline(message
);
563 // Determine the length of the existing array
565 for (char** element
= *array
; *element
; element
++)
570 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
574 // Append message and terminate the array
575 (*array
)[length
] = message
;
576 (*array
)[length
+ 1] = NULL
;
581 // Send everything else to the default logger
582 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
587 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
588 const int capabilities
[] = {
589 // Deny access to the kernel's audit system
594 // Deny suspending block devices
597 // Deny any stuff with BPF
600 // Deny checkpoint restore
601 CAP_CHECKPOINT_RESTORE
,
603 // Deny opening files by inode number (open_by_handle_at)
606 // Deny setting SUID bits
609 // Deny locking more memory
612 // Deny modifying any Apparmor/SELinux/SMACK configuration
616 // Deny creating any special devices
619 // Deny setting any capabilities
622 // Deny reading from syslog
625 // Deny any admin actions (mount, sethostname, ...)
628 // Deny rebooting the system
631 // Deny loading kernel modules
634 // Deny setting nice level
637 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
640 // Deny circumventing any resource limits
643 // Deny setting the system time
646 // Deny playing with suspend
652 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
657 // Drop any capabilities
658 for (const int* cap
= capabilities
; *cap
; cap
++) {
659 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
661 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
668 // Fetch any capabilities
669 cap_t caps
= cap_get_proc();
671 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
676 Set inheritable capabilities
678 This ensures that no processes will be able to gain any of the listed
681 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
683 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
687 // Restore capabilities
688 r
= cap_set_proc(caps
);
690 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
703 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
704 const int syscalls
[] = {
705 // The kernel's keyring isn't namespaced
708 SCMP_SYS(request_key
),
710 // Disable userfaultfd
711 SCMP_SYS(userfaultfd
),
713 // Disable perf which could leak a lot of information about the host
714 SCMP_SYS(perf_event_open
),
720 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
722 // Setup a syscall filter which allows everything by default
723 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
725 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
730 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
731 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
733 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
738 // Load syscall filter into the kernel
739 r
= seccomp_load(ctx
);
741 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
747 seccomp_release(ctx
);
754 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
755 const char* path
, uid_t mapped_id
, size_t length
) {
758 // Open file for writing
759 FILE* f
= fopen(path
, "w");
761 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
765 // Write configuration
766 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
767 if (bytes_written
<= 0) {
768 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
776 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
791 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
795 uid_t mapped_uid
= 0;
796 const size_t length
= 1;
798 // Fetch the UID of the calling process
799 uid_t uid
= getuid();
801 // Have we been called by root?
805 // Have we been called by an unprivileged user?
812 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
816 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
818 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
821 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
825 gid_t mapped_gid
= 0;
826 const size_t length
= 1;
828 // Fetch the GID of the calling process
829 gid_t gid
= getgid();
831 // Have we been called from the root group?
835 // Have we been called by an unprivileged group?
842 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
846 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
848 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
851 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
856 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
860 // Open file for writing
861 FILE* f
= fopen(path
, "w");
863 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
868 int bytes_written
= fprintf(f
, "deny\n");
869 if (bytes_written
<= 0) {
870 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
877 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
888 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
889 const uint64_t val
= 1;
892 DEBUG(jail
->pakfire
, "Sending signal...\n");
894 // Write to the file descriptor
895 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
896 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
897 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
901 // Close the file descriptor
907 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
911 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
913 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
914 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
915 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
919 // Close the file descriptor
926 Performs the initialisation that needs to happen in the parent part
928 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
932 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
936 // Write "deny" to /proc/PID/setgroups
937 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
942 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
946 // Parent has finished initialisation
947 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
949 // Send signal to client
950 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
957 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
958 const char* argv
[]) {
961 // XXX do we have to reconfigure logging here?
964 pid_t pid
= getpid();
966 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
968 // Wait for the parent to finish initialization
969 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
973 // Perform further initialization
976 uid_t uid
= getuid();
977 gid_t gid
= getgid();
980 uid_t euid
= geteuid();
981 gid_t egid
= getegid();
983 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
984 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
986 // Check if we are (effectively running as root)
987 if (uid
!= 0 || gid
!= 0) {
988 ERROR(jail
->pakfire
, "Child process is not running as root\n");
992 const char* root
= pakfire_get_path(jail
->pakfire
);
993 const char* arch
= pakfire_get_arch(jail
->pakfire
);
995 // Change root (unless root is /)
996 if (!pakfire_on_root(jail
->pakfire
)) {
998 r
= pakfire_mount_all(jail
->pakfire
);
1002 // Log all mountpoints
1003 pakfire_mount_list(jail
->pakfire
);
1008 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1012 // Change directory to /
1015 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1021 unsigned long persona
= pakfire_arch_personality(arch
);
1023 r
= personality(persona
);
1025 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1032 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1034 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1036 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1041 // Connect standard output and error
1042 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1043 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1045 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1046 ctx
->pipes
.stdout
[1]);
1051 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1053 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1054 ctx
->pipes
.stderr
[1]);
1059 // Close the reading sides of the pipe
1060 close(ctx
->pipes
.stdout
[0]);
1061 close(ctx
->pipes
.stderr
[0]);
1064 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1065 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1069 // Drop capabilities
1070 r
= pakfire_jail_drop_capabilities(jail
);
1075 r
= pakfire_jail_limit_syscalls(jail
);
1080 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1082 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1084 // Translate errno into regular exit code
1094 // We should not get here
1098 // Run a command in the jail
1099 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1103 // Check if argv is valid
1104 if (!argv
|| !argv
[0]) {
1109 // Initialize context for this call
1110 struct pakfire_jail_exec ctx
= {
1112 .stdout
= { 0, 0, },
1113 .stderr
= { 0, 0, },
1117 DEBUG(jail
->pakfire
, "Executing jail...\n");
1120 Setup a file descriptor which can be used to notify the client that the parent
1121 has completed configuration.
1123 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1124 if (ctx
.completed_fd
< 0) {
1125 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1129 // Create pipes to communicate with child process if we are not running interactively
1130 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1132 r
= pipe2(ctx
.pipes
.stdout
, O_NONBLOCK
);
1134 ERROR(jail
->pakfire
, "Could not create file descriptors for stdout: %m\n");
1139 r
= pipe2(ctx
.pipes
.stderr
, O_NONBLOCK
);
1141 ERROR(jail
->pakfire
, "Could not create file descriptors for stderr: %m\n");
1146 // Configure child process
1147 struct clone_args args
= {
1156 .exit_signal
= SIGCHLD
,
1157 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1160 // Fork this process
1161 ctx
.pid
= clone3(&args
, sizeof(args
));
1163 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1167 } else if (ctx
.pid
== 0) {
1168 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1173 r
= pakfire_jail_parent(jail
, &ctx
);
1177 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1179 // Read output of the child process
1180 r
= pakfire_jail_wait(jail
, &ctx
);
1184 // Handle exit status
1185 switch (ctx
.status
.si_code
) {
1187 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1188 ctx
.status
.si_status
);
1191 exit
= ctx
.status
.si_status
;
1196 ERROR(jail
->pakfire
, "The child process was killed\n");
1199 // Log anything else
1201 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1206 // Close any file descriptors
1207 if (ctx
.pipes
.stdout
[0])
1208 close(ctx
.pipes
.stdout
[0]);
1209 if (ctx
.pipes
.stdout
[1])
1210 close(ctx
.pipes
.stdout
[1]);
1211 if (ctx
.pipes
.stderr
[0])
1212 close(ctx
.pipes
.stderr
[0]);
1213 if (ctx
.pipes
.stderr
[1])
1214 close(ctx
.pipes
.stderr
[1]);
1218 // Umount everything
1219 if (!pakfire_on_root(jail
->pakfire
))
1220 pakfire_umount_all(jail
->pakfire
);
1225 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1226 const char* argv
[], char*** output
) {
1229 // Store logging callback
1230 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1231 void* log_data
= jail
->log_data
;
1233 // Capture output if requested by user
1235 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1238 r
= __pakfire_jail_exec(jail
, argv
);
1240 // Restore log callback
1241 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1246 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1247 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1248 char path
[PATH_MAX
];
1249 const char** argv
= NULL
;
1252 const char* root
= pakfire_get_path(jail
->pakfire
);
1254 // Write the scriptlet to disk
1255 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1259 // Open a temporary file
1260 int fd
= mkstemp(path
);
1262 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1267 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1270 ssize_t bytes_written
= write(fd
, script
, size
);
1271 if (bytes_written
< (ssize_t
)size
) {
1272 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1277 // Make the script executable
1278 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1280 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1287 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1292 // Count how many arguments were passed
1293 unsigned int argc
= 1;
1295 for (const char** arg
= args
; *arg
; arg
++)
1299 argv
= calloc(argc
+ 1, sizeof(*argv
));
1301 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1306 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1309 for (unsigned int i
= 1; i
< argc
; i
++)
1310 argv
[i
] = args
[i
-1];
1313 r
= pakfire_jail_exec(jail
, argv
, output
);
1319 // Remove script from disk
1327 A convenience function that creates a new jail, runs the given command and destroys
1330 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char*** output
) {
1331 struct pakfire_jail
* jail
= NULL
;
1334 // Create a new jail
1335 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1339 // Execute the command
1340 r
= pakfire_jail_exec(jail
, argv
, output
);
1344 pakfire_jail_unref(jail
);
1349 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1350 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1351 struct pakfire_jail
* jail
= NULL
;
1354 // Create a new jail
1355 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1359 // Execute the command
1360 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1364 pakfire_jail_unref(jail
);
1370 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1371 const char* argv
[] = {
1372 "/bin/bash", "--login", NULL
,
1375 // Execute /bin/bash
1376 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1379 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1380 char path
[PATH_MAX
];
1382 const char* ldconfig
= "/sbin/ldconfig";
1384 // Check if ldconfig exists before calling it to avoid overhead
1385 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1389 // Check if ldconfig is executable
1390 r
= access(path
, X_OK
);
1392 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1396 const char* argv
[] = {
1401 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
1404 // Utility functions
1406 PAKFIRE_EXPORT
char* pakfire_jail_concat_output(struct pakfire_jail
* jail
,
1407 const char** input
, size_t* length
) {
1408 // Return nothing on no input
1412 // XXX Maybe there is a more efficient way to do this
1414 char* output
= pakfire_string_join((char**)input
, "");
1418 // Store the length of the result
1420 *length
= strlen(output
);