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 char* env
[ENVIRON_SIZE
];
79 pakfire_jail_log_callback log_callback
;
83 struct pakfire_log_buffer
{
84 char data
[BUFFER_SIZE
];
88 struct pakfire_jail_exec
{
93 // Process status (from waitid)
96 // FD to notify the client that the parent has finished initialization
100 struct pakfire_jail_pipes
{
111 struct pakfire_jail_buffers
{
112 struct pakfire_log_buffer stdout
;
113 struct pakfire_log_buffer stderr
;
116 struct pakfire_log_buffer log_INFO
;
117 struct pakfire_log_buffer log_ERROR
;
118 struct pakfire_log_buffer log_DEBUG
;
122 struct pakfire_cgroup
* cgroup
;
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) {
273 // Returns the length of the environment
274 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
277 // Count everything in the environment
278 for (char** e
= jail
->env
; *e
; e
++)
284 // Finds an existing environment variable and returns its index or -1 if not found
285 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
291 char buffer
[strlen(key
) + 2];
292 pakfire_string_format(buffer
, "%s=", key
);
294 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
295 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
303 // Returns the value of an environment variable or NULL
304 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
306 int i
= pakfire_jail_find_env(jail
, key
);
310 return jail
->env
[i
] + strlen(key
) + 1;
313 // Sets an environment variable
314 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
315 const char* key
, const char* value
) {
316 // Find the index where to write this value to
317 int i
= pakfire_jail_find_env(jail
, key
);
319 i
= pakfire_jail_env_length(jail
);
321 // Return -ENOSPC when the environment is full
322 if (i
>= ENVIRON_SIZE
) {
327 // Free any previous value
331 // Format and set environment variable
332 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
334 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
339 // Imports an environment
340 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
348 // Copy environment variables
349 for (unsigned int i
= 0; env
[i
]; i
++) {
350 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
355 r
= pakfire_jail_set_env(jail
, key
, val
);
372 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
373 pakfire_jail_log_callback callback
, void* data
) {
374 jail
->log_callback
= callback
;
375 jail
->log_data
= data
;
381 This function replaces any logging in the child process.
383 All log messages will be sent to the parent process through their respective pipes.
385 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
386 int line
, const char* fn
, const char* format
, va_list args
) {
387 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
392 fd
= pipes
->log_INFO
[1];
396 fd
= pipes
->log_ERROR
[1];
401 fd
= pipes
->log_DEBUG
[1];
403 #endif /* ENABLE_DEBUG */
405 // Ignore any messages of an unknown priority
410 // Send the log message
412 vdprintf(fd
, format
, args
);
415 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
416 return (sizeof(buffer
->data
) == buffer
->used
);
420 This function reads as much data as it can from the file descriptor.
421 If it finds a whole line in it, it will send it to the logger and repeat the process.
422 If not newline character is found, it will try to read more data until it finds one.
424 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
425 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
426 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
427 char line
[BUFFER_SIZE
+ 1];
429 // Fill up buffer from fd
430 if (buffer
->used
< sizeof(buffer
->data
)) {
431 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
432 sizeof(buffer
->data
) - buffer
->used
);
435 if (bytes_read
< 0) {
436 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
440 // Update buffer size
441 buffer
->used
+= bytes_read
;
444 // See if we have any lines that we can write
445 while (buffer
->used
) {
446 // Search for the end of the first line
447 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
451 // If the buffer is full, we send the content to the logger and try again
452 // This should not happen in practise
453 if (pakfire_jail_log_buffer_is_full(buffer
)) {
454 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
456 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
458 // Otherwise we might have only read parts of the output
463 // Find the length of the string
464 size_t length
= eol
- buffer
->data
+ 1;
466 // Copy the line into the buffer
467 memcpy(line
, buffer
->data
, length
);
469 // Terminate the string
474 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
476 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
481 // Remove line from buffer
482 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
483 buffer
->used
-= length
;
489 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
490 int r
= pipe2(*fds
, flags
);
492 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
499 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
500 for (unsigned int i
= 0; i
< 2; i
++)
506 This is a convenience function to fetch the reading end of a pipe and
507 closes the write end.
509 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
510 // Give the variables easier names to avoid confusion
511 int* fd_read
= &(*fds
)[0];
512 int* fd_write
= &(*fds
)[1];
514 // Close the write end of the pipe
520 // Return the read end
524 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
526 struct epoll_event ev
;
527 struct epoll_event events
[EPOLL_MAX_EVENTS
];
530 // Fetch file descriptors from context
531 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
532 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
533 const int pidfd
= ctx
->pidfd
;
536 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
537 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
538 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
540 // Make a list of all file descriptors we are interested in
542 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
546 epollfd
= epoll_create1(0);
548 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
555 // Turn file descriptors into non-blocking mode and add them to epoll()
556 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
559 // Skip fds which were not initialized
565 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
566 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
574 // Loop for as long as the process is alive
576 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
578 // Ignore if epoll_wait() has been interrupted
582 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
588 for (int i
= 0; i
< num
; i
++) {
589 int fd
= events
[i
].data
.fd
;
591 struct pakfire_log_buffer
* buffer
= NULL
;
592 pakfire_jail_log_callback callback
= NULL
;
596 // Handle any changes to the PIDFD
598 // Call waidid() and store the result
599 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
601 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
605 // Mark that we have ended so that we will process the remaining
606 // events from epoll() now, but won't restart the outer loop.
610 // Handle logging messages
611 } else if (fd
== log_INFO
) {
612 buffer
= &ctx
->buffers
.log_INFO
;
615 callback
= pakfire_jail_default_log_callback
;
617 } else if (fd
== log_ERROR
) {
618 buffer
= &ctx
->buffers
.log_ERROR
;
621 callback
= pakfire_jail_default_log_callback
;
623 } else if (fd
== log_DEBUG
) {
624 buffer
= &ctx
->buffers
.log_DEBUG
;
625 priority
= LOG_DEBUG
;
627 callback
= pakfire_jail_default_log_callback
;
629 // Handle anything from the log pipes
630 } else if (fd
== stdout
) {
631 buffer
= &ctx
->buffers
.stdout
;
634 callback
= jail
->log_callback
;
635 data
= jail
->log_data
;
637 } else if (fd
== stderr
) {
638 buffer
= &ctx
->buffers
.stderr
;
641 callback
= jail
->log_callback
;
642 data
= jail
->log_data
;
645 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
650 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
663 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
664 const char* line
, size_t length
) {
665 char*** array
= (char***)data
;
667 // Append everything from stdout to an array
668 if (priority
== LOG_INFO
) {
671 // Create a copy of line
672 char* message
= strdup(line
);
676 // Determine the length of the existing array
678 for (char** element
= *array
; *element
; element
++)
683 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
687 // Append message and terminate the array
688 (*array
)[length
] = message
;
689 (*array
)[length
+ 1] = NULL
;
694 // Send everything else to the default logger
695 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
700 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
701 const int capabilities
[] = {
702 // Deny access to the kernel's audit system
707 // Deny suspending block devices
710 // Deny any stuff with BPF
713 // Deny checkpoint restore
714 CAP_CHECKPOINT_RESTORE
,
716 // Deny opening files by inode number (open_by_handle_at)
719 // Deny setting SUID bits
722 // Deny locking more memory
725 // Deny modifying any Apparmor/SELinux/SMACK configuration
729 // Deny creating any special devices
732 // Deny setting any capabilities
735 // Deny reading from syslog
738 // Deny any admin actions (mount, sethostname, ...)
741 // Deny rebooting the system
744 // Deny loading kernel modules
747 // Deny setting nice level
750 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
753 // Deny circumventing any resource limits
756 // Deny setting the system time
759 // Deny playing with suspend
765 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
770 // Drop any capabilities
771 for (const int* cap
= capabilities
; *cap
; cap
++) {
772 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
774 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
781 // Fetch any capabilities
782 cap_t caps
= cap_get_proc();
784 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
789 Set inheritable capabilities
791 This ensures that no processes will be able to gain any of the listed
794 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
796 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
800 // Restore capabilities
801 r
= cap_set_proc(caps
);
803 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
816 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
817 const int syscalls
[] = {
818 // The kernel's keyring isn't namespaced
821 SCMP_SYS(request_key
),
823 // Disable userfaultfd
824 SCMP_SYS(userfaultfd
),
826 // Disable perf which could leak a lot of information about the host
827 SCMP_SYS(perf_event_open
),
833 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
835 // Setup a syscall filter which allows everything by default
836 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
838 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
843 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
844 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
846 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
851 // Load syscall filter into the kernel
852 r
= seccomp_load(ctx
);
854 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
860 seccomp_release(ctx
);
867 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
868 const char* path
, uid_t mapped_id
, size_t length
) {
871 // Open file for writing
872 FILE* f
= fopen(path
, "w");
874 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
878 // Write configuration
879 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
880 if (bytes_written
<= 0) {
881 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
889 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
904 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
908 uid_t mapped_uid
= 0;
909 const size_t length
= 1;
911 // Fetch the UID of the calling process
912 uid_t uid
= getuid();
914 // Have we been called by root?
918 // Have we been called by an unprivileged user?
925 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
929 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
931 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
934 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
938 gid_t mapped_gid
= 0;
939 const size_t length
= 1;
941 // Fetch the GID of the calling process
942 gid_t gid
= getgid();
944 // Have we been called from the root group?
948 // Have we been called by an unprivileged group?
955 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
959 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
961 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
964 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
969 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
973 // Open file for writing
974 FILE* f
= fopen(path
, "w");
976 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
981 int bytes_written
= fprintf(f
, "deny\n");
982 if (bytes_written
<= 0) {
983 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
990 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1001 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1002 const uint64_t val
= 1;
1005 DEBUG(jail
->pakfire
, "Sending signal...\n");
1007 // Write to the file descriptor
1008 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1009 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1010 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1014 // Close the file descriptor
1020 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1024 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1026 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1027 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1028 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1032 // Close the file descriptor
1039 Performs the initialisation that needs to happen in the parent part
1041 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1044 // Setup UID mapping
1045 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1049 // Write "deny" to /proc/PID/setgroups
1050 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1054 // Setup GID mapping
1055 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1059 // Parent has finished initialisation
1060 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1062 // Send signal to client
1063 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1070 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1071 const char* argv
[]) {
1074 // Redirect any logging to our log pipe
1075 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1078 pid_t pid
= getpid();
1080 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1082 // Wait for the parent to finish initialization
1083 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1087 // Perform further initialization
1090 uid_t uid
= getuid();
1091 gid_t gid
= getgid();
1094 uid_t euid
= geteuid();
1095 gid_t egid
= getegid();
1097 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1098 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1100 // Check if we are (effectively running as root)
1101 if (uid
!= 0 || gid
!= 0) {
1102 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1106 const char* root
= pakfire_get_path(jail
->pakfire
);
1107 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1109 // Change root (unless root is /)
1110 if (!pakfire_on_root(jail
->pakfire
)) {
1112 r
= pakfire_mount_all(jail
->pakfire
);
1116 // Log all mountpoints
1117 pakfire_mount_list(jail
->pakfire
);
1122 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1126 // Change directory to /
1129 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1135 unsigned long persona
= pakfire_arch_personality(arch
);
1137 r
= personality(persona
);
1139 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1146 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1148 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1150 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1155 // Close other end of log pipes
1156 close(ctx
->pipes
.log_INFO
[0]);
1157 close(ctx
->pipes
.log_ERROR
[0]);
1159 close(ctx
->pipes
.log_DEBUG
[0]);
1160 #endif /* ENABLE_DEBUG */
1162 // Connect standard output and error
1163 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1164 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1166 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1167 ctx
->pipes
.stdout
[1]);
1172 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1174 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1175 ctx
->pipes
.stderr
[1]);
1180 // Close the pipe (as we have moved the original file descriptors)
1181 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1182 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1185 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1186 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1190 // Drop capabilities
1191 r
= pakfire_jail_drop_capabilities(jail
);
1196 r
= pakfire_jail_limit_syscalls(jail
);
1201 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1203 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1205 // Translate errno into regular exit code
1215 // We should not get here
1219 // Run a command in the jail
1220 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1224 // Check if argv is valid
1225 if (!argv
|| !argv
[0]) {
1230 // Initialize context for this call
1231 struct pakfire_jail_exec ctx
= {
1238 DEBUG(jail
->pakfire
, "Executing jail...\n");
1241 Setup a file descriptor which can be used to notify the client that the parent
1242 has completed configuration.
1244 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1245 if (ctx
.completed_fd
< 0) {
1246 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1250 // Create pipes to communicate with child process if we are not running interactively
1251 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1253 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1258 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1263 // Setup pipes for logging
1265 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1270 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1276 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1279 #endif /* ENABLE_DEBUG */
1282 r
= pakfire_cgroup_open(&ctx
.cgroup
, jail
->pakfire
, "jail/test1",
1283 PAKFIRE_CGROUP_ENABLE_ACCOUNTING
);
1287 // Configure child process
1288 struct clone_args args
= {
1298 .exit_signal
= SIGCHLD
,
1299 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1301 // Clone into the new cgroup
1302 .cgroup
= pakfire_cgroup_fd(ctx
.cgroup
),
1305 // Fork this process
1306 ctx
.pid
= clone3(&args
, sizeof(args
));
1308 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1312 } else if (ctx
.pid
== 0) {
1313 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1318 r
= pakfire_jail_parent(jail
, &ctx
);
1322 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1324 // Read output of the child process
1325 r
= pakfire_jail_wait(jail
, &ctx
);
1329 // Handle exit status
1330 switch (ctx
.status
.si_code
) {
1332 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1333 ctx
.status
.si_status
);
1336 exit
= ctx
.status
.si_status
;
1341 ERROR(jail
->pakfire
, "The child process was killed\n");
1344 // Log anything else
1346 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1351 // Close any file descriptors
1352 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1353 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1356 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1357 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1358 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1362 pakfire_cgroup_destroy(ctx
.cgroup
);
1363 pakfire_cgroup_unref(ctx
.cgroup
);
1366 // Umount everything
1367 if (!pakfire_on_root(jail
->pakfire
))
1368 pakfire_umount_all(jail
->pakfire
);
1373 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1374 const char* argv
[], char*** output
) {
1377 // Store logging callback
1378 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1379 void* log_data
= jail
->log_data
;
1381 // Capture output if requested by user
1383 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1386 r
= __pakfire_jail_exec(jail
, argv
);
1388 // Restore log callback
1389 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1394 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1395 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1396 char path
[PATH_MAX
];
1397 const char** argv
= NULL
;
1400 const char* root
= pakfire_get_path(jail
->pakfire
);
1402 // Write the scriptlet to disk
1403 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1407 // Open a temporary file
1408 int fd
= mkstemp(path
);
1410 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1415 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1418 ssize_t bytes_written
= write(fd
, script
, size
);
1419 if (bytes_written
< (ssize_t
)size
) {
1420 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1425 // Make the script executable
1426 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1428 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1435 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1440 // Count how many arguments were passed
1441 unsigned int argc
= 1;
1443 for (const char** arg
= args
; *arg
; arg
++)
1447 argv
= calloc(argc
+ 1, sizeof(*argv
));
1449 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1454 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1457 for (unsigned int i
= 1; i
< argc
; i
++)
1458 argv
[i
] = args
[i
-1];
1461 r
= pakfire_jail_exec(jail
, argv
, output
);
1467 // Remove script from disk
1475 A convenience function that creates a new jail, runs the given command and destroys
1478 int pakfire_jail_run(struct pakfire
* pakfire
, 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(jail
, argv
, output
);
1492 pakfire_jail_unref(jail
);
1497 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1498 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1499 struct pakfire_jail
* jail
= NULL
;
1502 // Create a new jail
1503 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1507 // Execute the command
1508 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1512 pakfire_jail_unref(jail
);
1518 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1519 const char* argv
[] = {
1520 "/bin/bash", "--login", NULL
,
1523 // Execute /bin/bash
1524 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1527 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1528 char path
[PATH_MAX
];
1530 const char* ldconfig
= "/sbin/ldconfig";
1532 // Check if ldconfig exists before calling it to avoid overhead
1533 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1537 // Check if ldconfig is executable
1538 r
= access(path
, X_OK
);
1540 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1544 const char* argv
[] = {
1549 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
1552 // Utility functions
1554 PAKFIRE_EXPORT
char* pakfire_jail_concat_output(struct pakfire_jail
* jail
,
1555 const char** input
, size_t* length
) {
1556 // Return nothing on no input
1560 // XXX Maybe there is a more efficient way to do this
1562 char* output
= pakfire_string_join((char**)input
, "");
1566 // Store the length of the result
1568 *length
= strlen(output
);