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
++)
137 pakfire_cgroup_unref(jail
->cgroup
);
139 pakfire_unref(jail
->pakfire
);
144 Passes any log messages on to the default pakfire log callback
146 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
147 int priority
, const char* line
, size_t length
) {
150 INFO(pakfire
, "%s", line
);
154 ERROR(pakfire
, "%s", line
);
159 DEBUG(pakfire
, "%s", line
);
167 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
169 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
174 char* TERM
= secure_getenv("TERM");
176 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
182 char* LANG
= secure_getenv("LANG");
184 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
192 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
193 struct pakfire
* pakfire
, int flags
) {
196 // Allocate a new jail
197 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
202 j
->pakfire
= pakfire_ref(pakfire
);
204 // Initialize reference counter
210 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
212 // Set default log callback
213 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
217 // Set default environment
218 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
219 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
224 // Setup interactive stuff
225 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
226 r
= pakfire_jail_setup_interactive_env(j
);
236 pakfire_jail_free(j
);
241 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
247 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
248 if (--jail
->nrefs
> 0)
251 pakfire_jail_free(jail
);
255 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
256 return jail
->flags
& flag
;
261 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
262 // Check if nice level is in range
263 if (nice
< -19 || nice
> 20) {
274 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
275 // Free any previous cgroup
277 pakfire_cgroup_unref(jail
->cgroup
);
281 // Set any new cgroup
283 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
285 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
294 // Returns the length of the environment
295 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
298 // Count everything in the environment
299 for (char** e
= jail
->env
; *e
; e
++)
305 // Finds an existing environment variable and returns its index or -1 if not found
306 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
312 char buffer
[strlen(key
) + 2];
313 pakfire_string_format(buffer
, "%s=", key
);
315 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
316 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
324 // Returns the value of an environment variable or NULL
325 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
327 int i
= pakfire_jail_find_env(jail
, key
);
331 return jail
->env
[i
] + strlen(key
) + 1;
334 // Sets an environment variable
335 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
336 const char* key
, const char* value
) {
337 // Find the index where to write this value to
338 int i
= pakfire_jail_find_env(jail
, key
);
340 i
= pakfire_jail_env_length(jail
);
342 // Return -ENOSPC when the environment is full
343 if (i
>= ENVIRON_SIZE
) {
348 // Free any previous value
352 // Format and set environment variable
353 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
355 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
360 // Imports an environment
361 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
369 // Copy environment variables
370 for (unsigned int i
= 0; env
[i
]; i
++) {
371 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
376 r
= pakfire_jail_set_env(jail
, key
, val
);
393 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
394 pakfire_jail_log_callback callback
, void* data
) {
395 jail
->log_callback
= callback
;
396 jail
->log_data
= data
;
402 This function replaces any logging in the child process.
404 All log messages will be sent to the parent process through their respective pipes.
406 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
407 int line
, const char* fn
, const char* format
, va_list args
) {
408 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
413 fd
= pipes
->log_INFO
[1];
417 fd
= pipes
->log_ERROR
[1];
422 fd
= pipes
->log_DEBUG
[1];
424 #endif /* ENABLE_DEBUG */
426 // Ignore any messages of an unknown priority
431 // Send the log message
433 vdprintf(fd
, format
, args
);
436 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
437 return (sizeof(buffer
->data
) == buffer
->used
);
441 This function reads as much data as it can from the file descriptor.
442 If it finds a whole line in it, it will send it to the logger and repeat the process.
443 If not newline character is found, it will try to read more data until it finds one.
445 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
446 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
447 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
448 char line
[BUFFER_SIZE
+ 1];
450 // Fill up buffer from fd
451 if (buffer
->used
< sizeof(buffer
->data
)) {
452 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
453 sizeof(buffer
->data
) - buffer
->used
);
456 if (bytes_read
< 0) {
457 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
461 // Update buffer size
462 buffer
->used
+= bytes_read
;
465 // See if we have any lines that we can write
466 while (buffer
->used
) {
467 // Search for the end of the first line
468 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
472 // If the buffer is full, we send the content to the logger and try again
473 // This should not happen in practise
474 if (pakfire_jail_log_buffer_is_full(buffer
)) {
475 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
477 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
479 // Otherwise we might have only read parts of the output
484 // Find the length of the string
485 size_t length
= eol
- buffer
->data
+ 1;
487 // Copy the line into the buffer
488 memcpy(line
, buffer
->data
, length
);
490 // Terminate the string
495 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
497 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
502 // Remove line from buffer
503 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
504 buffer
->used
-= length
;
510 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
511 int r
= pipe2(*fds
, flags
);
513 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
520 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
521 for (unsigned int i
= 0; i
< 2; i
++)
527 This is a convenience function to fetch the reading end of a pipe and
528 closes the write end.
530 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
531 // Give the variables easier names to avoid confusion
532 int* fd_read
= &(*fds
)[0];
533 int* fd_write
= &(*fds
)[1];
535 // Close the write end of the pipe
541 // Return the read end
545 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
547 struct epoll_event ev
;
548 struct epoll_event events
[EPOLL_MAX_EVENTS
];
551 // Fetch file descriptors from context
552 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
553 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
554 const int pidfd
= ctx
->pidfd
;
557 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
558 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
559 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
561 // Make a list of all file descriptors we are interested in
563 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
567 epollfd
= epoll_create1(0);
569 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
576 // Turn file descriptors into non-blocking mode and add them to epoll()
577 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
580 // Skip fds which were not initialized
586 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
587 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
595 // Loop for as long as the process is alive
597 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
599 // Ignore if epoll_wait() has been interrupted
603 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
609 for (int i
= 0; i
< num
; i
++) {
610 int fd
= events
[i
].data
.fd
;
612 struct pakfire_log_buffer
* buffer
= NULL
;
613 pakfire_jail_log_callback callback
= NULL
;
617 // Handle any changes to the PIDFD
619 // Call waidid() and store the result
620 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
622 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
626 // Mark that we have ended so that we will process the remaining
627 // events from epoll() now, but won't restart the outer loop.
631 // Handle logging messages
632 } else if (fd
== log_INFO
) {
633 buffer
= &ctx
->buffers
.log_INFO
;
636 callback
= pakfire_jail_default_log_callback
;
638 } else if (fd
== log_ERROR
) {
639 buffer
= &ctx
->buffers
.log_ERROR
;
642 callback
= pakfire_jail_default_log_callback
;
644 } else if (fd
== log_DEBUG
) {
645 buffer
= &ctx
->buffers
.log_DEBUG
;
646 priority
= LOG_DEBUG
;
648 callback
= pakfire_jail_default_log_callback
;
650 // Handle anything from the log pipes
651 } else if (fd
== stdout
) {
652 buffer
= &ctx
->buffers
.stdout
;
655 callback
= jail
->log_callback
;
656 data
= jail
->log_data
;
658 } else if (fd
== stderr
) {
659 buffer
= &ctx
->buffers
.stderr
;
662 callback
= jail
->log_callback
;
663 data
= jail
->log_data
;
666 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
671 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
684 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
685 const char* line
, size_t length
) {
686 char*** array
= (char***)data
;
688 // Append everything from stdout to an array
689 if (priority
== LOG_INFO
) {
692 // Create a copy of line
693 char* message
= strdup(line
);
697 // Determine the length of the existing array
699 for (char** element
= *array
; *element
; element
++)
704 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
708 // Append message and terminate the array
709 (*array
)[length
] = message
;
710 (*array
)[length
+ 1] = NULL
;
715 // Send everything else to the default logger
716 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
721 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
722 const int capabilities
[] = {
723 // Deny access to the kernel's audit system
728 // Deny suspending block devices
731 // Deny any stuff with BPF
734 // Deny checkpoint restore
735 CAP_CHECKPOINT_RESTORE
,
737 // Deny opening files by inode number (open_by_handle_at)
740 // Deny setting SUID bits
743 // Deny locking more memory
746 // Deny modifying any Apparmor/SELinux/SMACK configuration
750 // Deny creating any special devices
753 // Deny setting any capabilities
756 // Deny reading from syslog
759 // Deny any admin actions (mount, sethostname, ...)
762 // Deny rebooting the system
765 // Deny loading kernel modules
768 // Deny setting nice level
771 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
774 // Deny circumventing any resource limits
777 // Deny setting the system time
780 // Deny playing with suspend
786 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
791 // Drop any capabilities
792 for (const int* cap
= capabilities
; *cap
; cap
++) {
793 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
795 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
802 // Fetch any capabilities
803 cap_t caps
= cap_get_proc();
805 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
810 Set inheritable capabilities
812 This ensures that no processes will be able to gain any of the listed
815 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
817 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
821 // Restore capabilities
822 r
= cap_set_proc(caps
);
824 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
837 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
838 const int syscalls
[] = {
839 // The kernel's keyring isn't namespaced
842 SCMP_SYS(request_key
),
844 // Disable userfaultfd
845 SCMP_SYS(userfaultfd
),
847 // Disable perf which could leak a lot of information about the host
848 SCMP_SYS(perf_event_open
),
854 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
856 // Setup a syscall filter which allows everything by default
857 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
859 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
864 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
865 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
867 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
872 // Load syscall filter into the kernel
873 r
= seccomp_load(ctx
);
875 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
881 seccomp_release(ctx
);
888 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
889 const char* path
, uid_t mapped_id
, size_t length
) {
892 // Open file for writing
893 FILE* f
= fopen(path
, "w");
895 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
899 // Write configuration
900 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
901 if (bytes_written
<= 0) {
902 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
910 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
925 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
929 uid_t mapped_uid
= 0;
930 const size_t length
= 1;
932 // Fetch the UID of the calling process
933 uid_t uid
= getuid();
935 // Have we been called by root?
939 // Have we been called by an unprivileged user?
946 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
950 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
952 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
955 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
959 gid_t mapped_gid
= 0;
960 const size_t length
= 1;
962 // Fetch the GID of the calling process
963 gid_t gid
= getgid();
965 // Have we been called from the root group?
969 // Have we been called by an unprivileged group?
976 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
980 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
982 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
985 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
990 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
994 // Open file for writing
995 FILE* f
= fopen(path
, "w");
997 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
1002 int bytes_written
= fprintf(f
, "deny\n");
1003 if (bytes_written
<= 0) {
1004 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1011 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1022 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1023 const uint64_t val
= 1;
1026 DEBUG(jail
->pakfire
, "Sending signal...\n");
1028 // Write to the file descriptor
1029 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1030 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1031 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1035 // Close the file descriptor
1041 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1045 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1047 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1048 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1049 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1053 // Close the file descriptor
1060 Performs the initialisation that needs to happen in the parent part
1062 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1065 // Setup UID mapping
1066 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1070 // Write "deny" to /proc/PID/setgroups
1071 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1075 // Setup GID mapping
1076 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1080 // Parent has finished initialisation
1081 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1083 // Send signal to client
1084 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1091 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1092 const char* argv
[]) {
1095 // Redirect any logging to our log pipe
1096 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1099 pid_t pid
= getpid();
1101 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1104 for (unsigned int i
= 0; argv
[i
]; i
++)
1105 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1107 // Wait for the parent to finish initialization
1108 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1112 // Perform further initialization
1115 uid_t uid
= getuid();
1116 gid_t gid
= getgid();
1119 uid_t euid
= geteuid();
1120 gid_t egid
= getegid();
1122 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1123 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1125 // Check if we are (effectively running as root)
1126 if (uid
!= 0 || gid
!= 0) {
1127 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1131 const char* root
= pakfire_get_path(jail
->pakfire
);
1132 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1134 // Change root (unless root is /)
1135 if (!pakfire_on_root(jail
->pakfire
)) {
1137 r
= pakfire_mount_all(jail
->pakfire
);
1141 // Log all mountpoints
1142 pakfire_mount_list(jail
->pakfire
);
1147 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1151 // Change directory to /
1154 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1160 unsigned long persona
= pakfire_arch_personality(arch
);
1162 r
= personality(persona
);
1164 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1171 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1173 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1175 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1180 // Close other end of log pipes
1181 close(ctx
->pipes
.log_INFO
[0]);
1182 close(ctx
->pipes
.log_ERROR
[0]);
1184 close(ctx
->pipes
.log_DEBUG
[0]);
1185 #endif /* ENABLE_DEBUG */
1187 // Connect standard output and error
1188 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1189 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1191 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1192 ctx
->pipes
.stdout
[1]);
1197 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1199 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1200 ctx
->pipes
.stderr
[1]);
1205 // Close the pipe (as we have moved the original file descriptors)
1206 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1207 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1210 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1211 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1215 // Drop capabilities
1216 r
= pakfire_jail_drop_capabilities(jail
);
1221 r
= pakfire_jail_limit_syscalls(jail
);
1226 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1228 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1230 // Translate errno into regular exit code
1240 // We should not get here
1244 // Run a command in the jail
1245 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1249 // Check if argv is valid
1250 if (!argv
|| !argv
[0]) {
1255 // Initialize context for this call
1256 struct pakfire_jail_exec ctx
= {
1263 DEBUG(jail
->pakfire
, "Executing jail...\n");
1266 Setup a file descriptor which can be used to notify the client that the parent
1267 has completed configuration.
1269 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1270 if (ctx
.completed_fd
< 0) {
1271 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1275 // Create pipes to communicate with child process if we are not running interactively
1276 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1278 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1283 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1288 // Setup pipes for logging
1290 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1295 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1301 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1304 #endif /* ENABLE_DEBUG */
1306 // Configure child process
1307 struct clone_args args
= {
1316 .exit_signal
= SIGCHLD
,
1317 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1320 // Launch the process in a cgroup (if requested)
1322 args
.flags
|= CLONE_INTO_CGROUP
;
1324 // Clone into this cgroup
1325 args
.cgroup
= pakfire_cgroup_fd(jail
->cgroup
);
1328 // Fork this process
1329 ctx
.pid
= clone3(&args
, sizeof(args
));
1331 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1335 } else if (ctx
.pid
== 0) {
1336 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1341 r
= pakfire_jail_parent(jail
, &ctx
);
1345 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1347 // Read output of the child process
1348 r
= pakfire_jail_wait(jail
, &ctx
);
1352 // Handle exit status
1353 switch (ctx
.status
.si_code
) {
1355 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1356 ctx
.status
.si_status
);
1359 exit
= ctx
.status
.si_status
;
1364 ERROR(jail
->pakfire
, "The child process was killed\n");
1367 // Log anything else
1369 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1374 // Close any file descriptors
1375 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1376 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1379 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1380 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1381 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1383 // Umount everything
1384 if (!pakfire_on_root(jail
->pakfire
))
1385 pakfire_umount_all(jail
->pakfire
);
1390 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1391 const char* argv
[], char*** output
) {
1394 // Store logging callback
1395 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1396 void* log_data
= jail
->log_data
;
1398 // Capture output if requested by user
1400 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1403 r
= __pakfire_jail_exec(jail
, argv
);
1405 // Restore log callback
1406 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1411 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1412 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1413 char path
[PATH_MAX
];
1414 const char** argv
= NULL
;
1417 const char* root
= pakfire_get_path(jail
->pakfire
);
1419 // Write the scriptlet to disk
1420 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1424 // Open a temporary file
1425 int fd
= mkstemp(path
);
1427 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1432 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1435 ssize_t bytes_written
= write(fd
, script
, size
);
1436 if (bytes_written
< (ssize_t
)size
) {
1437 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1442 // Make the script executable
1443 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1445 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1452 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1457 // Count how many arguments were passed
1458 unsigned int argc
= 1;
1460 for (const char** arg
= args
; *arg
; arg
++)
1464 argv
= calloc(argc
+ 1, sizeof(*argv
));
1466 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1471 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1474 for (unsigned int i
= 1; i
< argc
; i
++)
1475 argv
[i
] = args
[i
-1];
1478 r
= pakfire_jail_exec(jail
, argv
, output
);
1484 // Remove script from disk
1492 A convenience function that creates a new jail, runs the given command and destroys
1495 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char*** output
) {
1496 struct pakfire_jail
* jail
= NULL
;
1499 // Create a new jail
1500 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1504 // Execute the command
1505 r
= pakfire_jail_exec(jail
, argv
, output
);
1509 pakfire_jail_unref(jail
);
1514 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1515 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1516 struct pakfire_jail
* jail
= NULL
;
1519 // Create a new jail
1520 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1524 // Execute the command
1525 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1529 pakfire_jail_unref(jail
);
1535 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1536 const char* argv
[] = {
1537 "/bin/bash", "--login", NULL
,
1540 // Execute /bin/bash
1541 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1544 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1545 char path
[PATH_MAX
];
1547 const char* ldconfig
= "/sbin/ldconfig";
1549 // Check if ldconfig exists before calling it to avoid overhead
1550 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1554 // Check if ldconfig is executable
1555 r
= access(path
, X_OK
);
1557 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1561 const char* argv
[] = {
1566 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
1569 // Utility functions
1571 PAKFIRE_EXPORT
char* pakfire_jail_concat_output(struct pakfire_jail
* jail
,
1572 const char** input
, size_t* length
) {
1573 // Return nothing on no input
1577 // XXX Maybe there is a more efficient way to do this
1579 char* output
= pakfire_string_join((char**)input
, "");
1583 // Store the length of the result
1585 *length
= strlen(output
);