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
99 struct pakfire_jail_pipes
{
110 struct pakfire_jail_buffers
{
111 struct pakfire_log_buffer stdout
;
112 struct pakfire_log_buffer stderr
;
115 struct pakfire_log_buffer log_INFO
;
116 struct pakfire_log_buffer log_ERROR
;
117 struct pakfire_log_buffer log_DEBUG
;
121 static int clone3(struct clone_args
* args
, size_t size
) {
122 return syscall(__NR_clone3
, args
, size
);
125 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
126 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
129 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
132 pakfire_unref(jail
->pakfire
);
137 Passes any log messages on to the default pakfire log callback
139 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
140 int priority
, const char* line
, size_t length
) {
143 INFO(pakfire
, "%s", line
);
147 ERROR(pakfire
, "%s", line
);
152 DEBUG(pakfire
, "%s", line
);
160 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
162 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
167 char* TERM
= secure_getenv("TERM");
169 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
175 char* LANG
= secure_getenv("LANG");
177 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
185 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
186 struct pakfire
* pakfire
, int flags
) {
189 // Allocate a new jail
190 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
195 j
->pakfire
= pakfire_ref(pakfire
);
197 // Initialize reference counter
203 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
205 // Set default log callback
206 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
210 // Set default environment
211 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
212 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
217 // Setup interactive stuff
218 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
219 r
= pakfire_jail_setup_interactive_env(j
);
229 pakfire_jail_free(j
);
234 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
240 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
241 if (--jail
->nrefs
> 0)
244 pakfire_jail_free(jail
);
248 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
249 return jail
->flags
& flag
;
254 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
255 // Check if nice level is in range
256 if (nice
< -19 || nice
> 20) {
269 // Returns the length of the environment
270 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
273 // Count everything in the environment
274 for (char** e
= jail
->env
; *e
; e
++)
280 // Finds an existing environment variable and returns its index or -1 if not found
281 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
287 char buffer
[strlen(key
) + 2];
288 pakfire_string_format(buffer
, "%s=", key
);
290 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
291 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
299 // Returns the value of an environment variable or NULL
300 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
302 int i
= pakfire_jail_find_env(jail
, key
);
306 return jail
->env
[i
] + strlen(key
) + 1;
309 // Sets an environment variable
310 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
311 const char* key
, const char* value
) {
312 // Find the index where to write this value to
313 int i
= pakfire_jail_find_env(jail
, key
);
315 i
= pakfire_jail_env_length(jail
);
317 // Return -ENOSPC when the environment is full
318 if (i
>= ENVIRON_SIZE
) {
323 // Free any previous value
327 // Format and set environment variable
328 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
330 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
335 // Imports an environment
336 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
344 // Copy environment variables
345 for (unsigned int i
= 0; env
[i
]; i
++) {
346 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
351 r
= pakfire_jail_set_env(jail
, key
, val
);
368 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
369 pakfire_jail_log_callback callback
, void* data
) {
370 jail
->log_callback
= callback
;
371 jail
->log_data
= data
;
377 This function replaces any logging in the child process.
379 All log messages will be sent to the parent process through their respective pipes.
381 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
382 int line
, const char* fn
, const char* format
, va_list args
) {
383 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
388 fd
= pipes
->log_INFO
[1];
392 fd
= pipes
->log_ERROR
[1];
397 fd
= pipes
->log_DEBUG
[1];
399 #endif /* ENABLE_DEBUG */
401 // Ignore any messages of an unknown priority
406 // Send the log message
408 vdprintf(fd
, format
, args
);
411 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
412 return (sizeof(buffer
->data
) == buffer
->used
);
416 This function reads as much data as it can from the file descriptor.
417 If it finds a whole line in it, it will send it to the logger and repeat the process.
418 If not newline character is found, it will try to read more data until it finds one.
420 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
421 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
422 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
423 char line
[BUFFER_SIZE
+ 1];
425 // Fill up buffer from fd
426 if (buffer
->used
< sizeof(buffer
->data
)) {
427 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
428 sizeof(buffer
->data
) - buffer
->used
);
431 if (bytes_read
< 0) {
432 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
436 // Update buffer size
437 buffer
->used
+= bytes_read
;
440 // See if we have any lines that we can write
441 while (buffer
->used
) {
442 // Search for the end of the first line
443 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
447 // If the buffer is full, we send the content to the logger and try again
448 // This should not happen in practise
449 if (pakfire_jail_log_buffer_is_full(buffer
)) {
450 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
452 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
454 // Otherwise we might have only read parts of the output
459 // Find the length of the string
460 size_t length
= eol
- buffer
->data
+ 1;
462 // Copy the line into the buffer
463 memcpy(line
, buffer
->data
, length
);
465 // Terminate the string
470 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
472 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
477 // Remove line from buffer
478 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
479 buffer
->used
-= length
;
486 This is a convenience function to fetch the reading end of a pipe and
487 closes the write end.
489 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
490 // Give the variables easier names to avoid confusion
491 int* fd_read
= &(*fds
)[0];
492 int* fd_write
= &(*fds
)[1];
494 // Close the write end of the pipe
500 // Return the read end
504 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
506 struct epoll_event ev
;
507 struct epoll_event events
[EPOLL_MAX_EVENTS
];
510 // Fetch file descriptors from context
511 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
512 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
513 const int pidfd
= ctx
->pidfd
;
516 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
517 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
518 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
520 // Make a list of all file descriptors we are interested in
522 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
526 epollfd
= epoll_create1(0);
528 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
535 // Turn file descriptors into non-blocking mode and add them to epoll()
536 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
539 // Skip fds which were not initialized
545 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
546 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
554 // Loop for as long as the process is alive
556 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
558 // Ignore if epoll_wait() has been interrupted
562 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
568 for (int i
= 0; i
< num
; i
++) {
569 int fd
= events
[i
].data
.fd
;
571 struct pakfire_log_buffer
* buffer
= NULL
;
572 pakfire_jail_log_callback callback
= NULL
;
576 // Handle any changes to the PIDFD
578 // Call waidid() and store the result
579 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
581 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
585 // Mark that we have ended so that we will process the remaining
586 // events from epoll() now, but won't restart the outer loop.
590 // Handle logging messages
591 } else if (fd
== log_INFO
) {
592 buffer
= &ctx
->buffers
.log_INFO
;
595 callback
= pakfire_jail_default_log_callback
;
597 } else if (fd
== log_ERROR
) {
598 buffer
= &ctx
->buffers
.log_ERROR
;
601 callback
= pakfire_jail_default_log_callback
;
603 } else if (fd
== log_DEBUG
) {
604 buffer
= &ctx
->buffers
.log_DEBUG
;
605 priority
= LOG_DEBUG
;
607 callback
= pakfire_jail_default_log_callback
;
609 // Handle anything from the log pipes
610 } else if (fd
== stdout
) {
611 buffer
= &ctx
->buffers
.stdout
;
614 callback
= jail
->log_callback
;
615 data
= jail
->log_data
;
617 } else if (fd
== stderr
) {
618 buffer
= &ctx
->buffers
.stderr
;
621 callback
= jail
->log_callback
;
622 data
= jail
->log_data
;
625 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
630 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
643 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
644 const char* line
, size_t length
) {
645 char*** array
= (char***)data
;
647 // Append everything from stdout to an array
648 if (priority
== LOG_INFO
) {
651 // Create a copy of line
652 char* message
= strdup(line
);
656 // Determine the length of the existing array
658 for (char** element
= *array
; *element
; element
++)
663 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
667 // Append message and terminate the array
668 (*array
)[length
] = message
;
669 (*array
)[length
+ 1] = NULL
;
674 // Send everything else to the default logger
675 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
680 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
681 const int capabilities
[] = {
682 // Deny access to the kernel's audit system
687 // Deny suspending block devices
690 // Deny any stuff with BPF
693 // Deny checkpoint restore
694 CAP_CHECKPOINT_RESTORE
,
696 // Deny opening files by inode number (open_by_handle_at)
699 // Deny setting SUID bits
702 // Deny locking more memory
705 // Deny modifying any Apparmor/SELinux/SMACK configuration
709 // Deny creating any special devices
712 // Deny setting any capabilities
715 // Deny reading from syslog
718 // Deny any admin actions (mount, sethostname, ...)
721 // Deny rebooting the system
724 // Deny loading kernel modules
727 // Deny setting nice level
730 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
733 // Deny circumventing any resource limits
736 // Deny setting the system time
739 // Deny playing with suspend
745 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
750 // Drop any capabilities
751 for (const int* cap
= capabilities
; *cap
; cap
++) {
752 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
754 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
761 // Fetch any capabilities
762 cap_t caps
= cap_get_proc();
764 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
769 Set inheritable capabilities
771 This ensures that no processes will be able to gain any of the listed
774 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
776 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
780 // Restore capabilities
781 r
= cap_set_proc(caps
);
783 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
796 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
797 const int syscalls
[] = {
798 // The kernel's keyring isn't namespaced
801 SCMP_SYS(request_key
),
803 // Disable userfaultfd
804 SCMP_SYS(userfaultfd
),
806 // Disable perf which could leak a lot of information about the host
807 SCMP_SYS(perf_event_open
),
813 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
815 // Setup a syscall filter which allows everything by default
816 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
818 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
823 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
824 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
826 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
831 // Load syscall filter into the kernel
832 r
= seccomp_load(ctx
);
834 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
840 seccomp_release(ctx
);
847 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
848 const char* path
, uid_t mapped_id
, size_t length
) {
851 // Open file for writing
852 FILE* f
= fopen(path
, "w");
854 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
858 // Write configuration
859 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
860 if (bytes_written
<= 0) {
861 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
869 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
884 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
888 uid_t mapped_uid
= 0;
889 const size_t length
= 1;
891 // Fetch the UID of the calling process
892 uid_t uid
= getuid();
894 // Have we been called by root?
898 // Have we been called by an unprivileged user?
905 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
909 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
911 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
914 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
918 gid_t mapped_gid
= 0;
919 const size_t length
= 1;
921 // Fetch the GID of the calling process
922 gid_t gid
= getgid();
924 // Have we been called from the root group?
928 // Have we been called by an unprivileged group?
935 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
939 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
941 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
944 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
949 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
953 // Open file for writing
954 FILE* f
= fopen(path
, "w");
956 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
961 int bytes_written
= fprintf(f
, "deny\n");
962 if (bytes_written
<= 0) {
963 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
970 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
981 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
982 const uint64_t val
= 1;
985 DEBUG(jail
->pakfire
, "Sending signal...\n");
987 // Write to the file descriptor
988 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
989 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
990 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
994 // Close the file descriptor
1000 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1004 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1006 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1007 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1008 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1012 // Close the file descriptor
1019 Performs the initialisation that needs to happen in the parent part
1021 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1024 // Setup UID mapping
1025 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1029 // Write "deny" to /proc/PID/setgroups
1030 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1034 // Setup GID mapping
1035 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1039 // Parent has finished initialisation
1040 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1042 // Send signal to client
1043 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1050 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1051 const char* argv
[]) {
1054 // Redirect any logging to our log pipe
1055 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1058 pid_t pid
= getpid();
1060 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1062 // Wait for the parent to finish initialization
1063 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1067 // Perform further initialization
1070 uid_t uid
= getuid();
1071 gid_t gid
= getgid();
1074 uid_t euid
= geteuid();
1075 gid_t egid
= getegid();
1077 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1078 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1080 // Check if we are (effectively running as root)
1081 if (uid
!= 0 || gid
!= 0) {
1082 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1086 const char* root
= pakfire_get_path(jail
->pakfire
);
1087 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1089 // Change root (unless root is /)
1090 if (!pakfire_on_root(jail
->pakfire
)) {
1092 r
= pakfire_mount_all(jail
->pakfire
);
1096 // Log all mountpoints
1097 pakfire_mount_list(jail
->pakfire
);
1102 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1106 // Change directory to /
1109 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1115 unsigned long persona
= pakfire_arch_personality(arch
);
1117 r
= personality(persona
);
1119 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1126 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1128 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1130 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1135 // Close other end of log pipes
1136 close(ctx
->pipes
.log_INFO
[0]);
1137 close(ctx
->pipes
.log_ERROR
[0]);
1139 close(ctx
->pipes
.log_DEBUG
[0]);
1140 #endif /* ENABLE_DEBUG */
1142 // Connect standard output and error
1143 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1144 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1146 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1147 ctx
->pipes
.stdout
[1]);
1152 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1154 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1155 ctx
->pipes
.stderr
[1]);
1160 // Close the reading sides of the pipe
1161 close(ctx
->pipes
.stdout
[0]);
1162 close(ctx
->pipes
.stderr
[0]);
1165 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1166 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1170 // Drop capabilities
1171 r
= pakfire_jail_drop_capabilities(jail
);
1176 r
= pakfire_jail_limit_syscalls(jail
);
1181 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1183 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1185 // Translate errno into regular exit code
1195 // We should not get here
1199 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
1200 int r
= pipe2(*fds
, flags
);
1202 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
1209 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
1210 for (unsigned int i
= 0; i
< 2; i
++)
1215 // Run a command in the jail
1216 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1220 // Check if argv is valid
1221 if (!argv
|| !argv
[0]) {
1226 // Initialize context for this call
1227 struct pakfire_jail_exec ctx
= {
1234 DEBUG(jail
->pakfire
, "Executing jail...\n");
1237 Setup a file descriptor which can be used to notify the client that the parent
1238 has completed configuration.
1240 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1241 if (ctx
.completed_fd
< 0) {
1242 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1246 // Create pipes to communicate with child process if we are not running interactively
1247 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1249 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1254 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1259 // Setup pipes for logging
1261 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1266 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1272 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1275 #endif /* ENABLE_DEBUG */
1277 // Configure child process
1278 struct clone_args args
= {
1287 .exit_signal
= SIGCHLD
,
1288 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1291 // Fork this process
1292 ctx
.pid
= clone3(&args
, sizeof(args
));
1294 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1298 } else if (ctx
.pid
== 0) {
1299 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1304 r
= pakfire_jail_parent(jail
, &ctx
);
1308 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1310 // Read output of the child process
1311 r
= pakfire_jail_wait(jail
, &ctx
);
1315 // Handle exit status
1316 switch (ctx
.status
.si_code
) {
1318 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1319 ctx
.status
.si_status
);
1322 exit
= ctx
.status
.si_status
;
1327 ERROR(jail
->pakfire
, "The child process was killed\n");
1330 // Log anything else
1332 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1337 // Close any file descriptors
1338 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1339 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1342 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1343 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1344 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1346 // Umount everything
1347 if (!pakfire_on_root(jail
->pakfire
))
1348 pakfire_umount_all(jail
->pakfire
);
1353 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1354 const char* argv
[], char*** output
) {
1357 // Store logging callback
1358 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1359 void* log_data
= jail
->log_data
;
1361 // Capture output if requested by user
1363 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1366 r
= __pakfire_jail_exec(jail
, argv
);
1368 // Restore log callback
1369 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1374 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1375 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1376 char path
[PATH_MAX
];
1377 const char** argv
= NULL
;
1380 const char* root
= pakfire_get_path(jail
->pakfire
);
1382 // Write the scriptlet to disk
1383 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1387 // Open a temporary file
1388 int fd
= mkstemp(path
);
1390 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1395 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1398 ssize_t bytes_written
= write(fd
, script
, size
);
1399 if (bytes_written
< (ssize_t
)size
) {
1400 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1405 // Make the script executable
1406 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1408 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1415 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1420 // Count how many arguments were passed
1421 unsigned int argc
= 1;
1423 for (const char** arg
= args
; *arg
; arg
++)
1427 argv
= calloc(argc
+ 1, sizeof(*argv
));
1429 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1434 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1437 for (unsigned int i
= 1; i
< argc
; i
++)
1438 argv
[i
] = args
[i
-1];
1441 r
= pakfire_jail_exec(jail
, argv
, output
);
1447 // Remove script from disk
1455 A convenience function that creates a new jail, runs the given command and destroys
1458 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char*** output
) {
1459 struct pakfire_jail
* jail
= NULL
;
1462 // Create a new jail
1463 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1467 // Execute the command
1468 r
= pakfire_jail_exec(jail
, argv
, output
);
1472 pakfire_jail_unref(jail
);
1477 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1478 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1479 struct pakfire_jail
* jail
= NULL
;
1482 // Create a new jail
1483 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1487 // Execute the command
1488 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1492 pakfire_jail_unref(jail
);
1498 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1499 const char* argv
[] = {
1500 "/bin/bash", "--login", NULL
,
1503 // Execute /bin/bash
1504 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1507 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1508 char path
[PATH_MAX
];
1510 const char* ldconfig
= "/sbin/ldconfig";
1512 // Check if ldconfig exists before calling it to avoid overhead
1513 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1517 // Check if ldconfig is executable
1518 r
= access(path
, X_OK
);
1520 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1524 const char* argv
[] = {
1529 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
1532 // Utility functions
1534 PAKFIRE_EXPORT
char* pakfire_jail_concat_output(struct pakfire_jail
* jail
,
1535 const char** input
, size_t* length
) {
1536 // Return nothing on no input
1540 // XXX Maybe there is a more efficient way to do this
1542 char* output
= pakfire_string_join((char**)input
, "");
1546 // Store the length of the result
1548 *length
= strlen(output
);