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
;
124 struct pakfire_cgroup
* cgroup
;
127 static int clone3(struct clone_args
* args
, size_t size
) {
128 return syscall(__NR_clone3
, args
, size
);
131 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
132 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
135 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
139 pakfire_cgroup_unref(jail
->cgroup
);
141 pakfire_unref(jail
->pakfire
);
146 Passes any log messages on to the default pakfire log callback
148 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
149 int priority
, const char* line
, size_t length
) {
152 INFO(pakfire
, "%s", line
);
156 ERROR(pakfire
, "%s", line
);
161 DEBUG(pakfire
, "%s", line
);
169 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
171 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
176 char* TERM
= secure_getenv("TERM");
178 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
184 char* LANG
= secure_getenv("LANG");
186 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
194 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
195 struct pakfire
* pakfire
, int flags
) {
198 // Allocate a new jail
199 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
204 j
->pakfire
= pakfire_ref(pakfire
);
206 // Initialize reference counter
212 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
214 // Set default log callback
215 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
219 // Set default environment
220 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
221 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
226 // Setup interactive stuff
227 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
228 r
= pakfire_jail_setup_interactive_env(j
);
238 pakfire_jail_free(j
);
243 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
249 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
250 if (--jail
->nrefs
> 0)
253 pakfire_jail_free(jail
);
257 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
258 return jail
->flags
& flag
;
263 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
264 // Check if nice level is in range
265 if (nice
< -19 || nice
> 20) {
276 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
277 // Free any previous cgroup
279 pakfire_cgroup_unref(jail
->cgroup
);
283 // Set any new cgroup
285 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
287 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
296 // Returns the length of the environment
297 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
300 // Count everything in the environment
301 for (char** e
= jail
->env
; *e
; e
++)
307 // Finds an existing environment variable and returns its index or -1 if not found
308 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
314 char buffer
[strlen(key
) + 2];
315 pakfire_string_format(buffer
, "%s=", key
);
317 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
318 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
326 // Returns the value of an environment variable or NULL
327 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
329 int i
= pakfire_jail_find_env(jail
, key
);
333 return jail
->env
[i
] + strlen(key
) + 1;
336 // Sets an environment variable
337 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
338 const char* key
, const char* value
) {
339 // Find the index where to write this value to
340 int i
= pakfire_jail_find_env(jail
, key
);
342 i
= pakfire_jail_env_length(jail
);
344 // Return -ENOSPC when the environment is full
345 if (i
>= ENVIRON_SIZE
) {
350 // Free any previous value
354 // Format and set environment variable
355 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
357 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
362 // Imports an environment
363 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
371 // Copy environment variables
372 for (unsigned int i
= 0; env
[i
]; i
++) {
373 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
378 r
= pakfire_jail_set_env(jail
, key
, val
);
395 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
396 pakfire_jail_log_callback callback
, void* data
) {
397 jail
->log_callback
= callback
;
398 jail
->log_data
= data
;
404 This function replaces any logging in the child process.
406 All log messages will be sent to the parent process through their respective pipes.
408 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
409 int line
, const char* fn
, const char* format
, va_list args
) {
410 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
415 fd
= pipes
->log_INFO
[1];
419 fd
= pipes
->log_ERROR
[1];
424 fd
= pipes
->log_DEBUG
[1];
426 #endif /* ENABLE_DEBUG */
428 // Ignore any messages of an unknown priority
433 // Send the log message
435 vdprintf(fd
, format
, args
);
438 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
439 return (sizeof(buffer
->data
) == buffer
->used
);
443 This function reads as much data as it can from the file descriptor.
444 If it finds a whole line in it, it will send it to the logger and repeat the process.
445 If not newline character is found, it will try to read more data until it finds one.
447 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
448 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
449 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
450 char line
[BUFFER_SIZE
+ 1];
452 // Fill up buffer from fd
453 if (buffer
->used
< sizeof(buffer
->data
)) {
454 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
455 sizeof(buffer
->data
) - buffer
->used
);
458 if (bytes_read
< 0) {
459 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
463 // Update buffer size
464 buffer
->used
+= bytes_read
;
467 // See if we have any lines that we can write
468 while (buffer
->used
) {
469 // Search for the end of the first line
470 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
474 // If the buffer is full, we send the content to the logger and try again
475 // This should not happen in practise
476 if (pakfire_jail_log_buffer_is_full(buffer
)) {
477 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
479 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
481 // Otherwise we might have only read parts of the output
486 // Find the length of the string
487 size_t length
= eol
- buffer
->data
+ 1;
489 // Copy the line into the buffer
490 memcpy(line
, buffer
->data
, length
);
492 // Terminate the string
497 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
499 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
504 // Remove line from buffer
505 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
506 buffer
->used
-= length
;
512 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
513 int r
= pipe2(*fds
, flags
);
515 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
522 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
523 for (unsigned int i
= 0; i
< 2; i
++)
529 This is a convenience function to fetch the reading end of a pipe and
530 closes the write end.
532 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
533 // Give the variables easier names to avoid confusion
534 int* fd_read
= &(*fds
)[0];
535 int* fd_write
= &(*fds
)[1];
537 // Close the write end of the pipe
543 // Return the read end
547 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
549 struct epoll_event ev
;
550 struct epoll_event events
[EPOLL_MAX_EVENTS
];
553 // Fetch file descriptors from context
554 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
555 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
556 const int pidfd
= ctx
->pidfd
;
559 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
560 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
561 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
563 // Make a list of all file descriptors we are interested in
565 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
569 epollfd
= epoll_create1(0);
571 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
578 // Turn file descriptors into non-blocking mode and add them to epoll()
579 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
582 // Skip fds which were not initialized
588 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
589 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
597 // Loop for as long as the process is alive
599 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
601 // Ignore if epoll_wait() has been interrupted
605 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
611 for (int i
= 0; i
< num
; i
++) {
612 int fd
= events
[i
].data
.fd
;
614 struct pakfire_log_buffer
* buffer
= NULL
;
615 pakfire_jail_log_callback callback
= NULL
;
619 // Handle any changes to the PIDFD
621 // Call waidid() and store the result
622 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
624 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
628 // Mark that we have ended so that we will process the remaining
629 // events from epoll() now, but won't restart the outer loop.
633 // Handle logging messages
634 } else if (fd
== log_INFO
) {
635 buffer
= &ctx
->buffers
.log_INFO
;
638 callback
= pakfire_jail_default_log_callback
;
640 } else if (fd
== log_ERROR
) {
641 buffer
= &ctx
->buffers
.log_ERROR
;
644 callback
= pakfire_jail_default_log_callback
;
646 } else if (fd
== log_DEBUG
) {
647 buffer
= &ctx
->buffers
.log_DEBUG
;
648 priority
= LOG_DEBUG
;
650 callback
= pakfire_jail_default_log_callback
;
652 // Handle anything from the log pipes
653 } else if (fd
== stdout
) {
654 buffer
= &ctx
->buffers
.stdout
;
657 callback
= jail
->log_callback
;
658 data
= jail
->log_data
;
660 } else if (fd
== stderr
) {
661 buffer
= &ctx
->buffers
.stderr
;
664 callback
= jail
->log_callback
;
665 data
= jail
->log_data
;
668 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
673 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
686 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
687 const char* line
, size_t length
) {
688 char** output
= (char**)data
;
691 // Append everything from stdout to a buffer
692 if (priority
== LOG_INFO
) {
693 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
699 // Send everything else to the default logger
700 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
705 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
706 const int capabilities
[] = {
707 // Deny access to the kernel's audit system
712 // Deny suspending block devices
715 // Deny any stuff with BPF
718 // Deny checkpoint restore
719 CAP_CHECKPOINT_RESTORE
,
721 // Deny opening files by inode number (open_by_handle_at)
724 // Deny setting SUID bits
727 // Deny locking more memory
730 // Deny modifying any Apparmor/SELinux/SMACK configuration
734 // Deny creating any special devices
737 // Deny setting any capabilities
740 // Deny reading from syslog
743 // Deny any admin actions (mount, sethostname, ...)
746 // Deny rebooting the system
749 // Deny loading kernel modules
752 // Deny setting nice level
755 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
758 // Deny circumventing any resource limits
761 // Deny setting the system time
764 // Deny playing with suspend
770 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
775 // Drop any capabilities
776 for (const int* cap
= capabilities
; *cap
; cap
++) {
777 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
779 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
786 // Fetch any capabilities
787 cap_t caps
= cap_get_proc();
789 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
794 Set inheritable capabilities
796 This ensures that no processes will be able to gain any of the listed
799 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
801 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
805 // Restore capabilities
806 r
= cap_set_proc(caps
);
808 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
821 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
822 const int syscalls
[] = {
823 // The kernel's keyring isn't namespaced
826 SCMP_SYS(request_key
),
828 // Disable userfaultfd
829 SCMP_SYS(userfaultfd
),
831 // Disable perf which could leak a lot of information about the host
832 SCMP_SYS(perf_event_open
),
838 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
840 // Setup a syscall filter which allows everything by default
841 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
843 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
848 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
849 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
851 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
856 // Load syscall filter into the kernel
857 r
= seccomp_load(ctx
);
859 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
865 seccomp_release(ctx
);
872 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
873 const char* path
, uid_t mapped_id
, size_t length
) {
876 // Open file for writing
877 FILE* f
= fopen(path
, "w");
879 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
883 // Write configuration
884 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
885 if (bytes_written
<= 0) {
886 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
894 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
909 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
913 uid_t mapped_uid
= 0;
914 const size_t length
= 1;
916 // Fetch the UID of the calling process
917 uid_t uid
= getuid();
919 // Have we been called by root?
923 // Have we been called by an unprivileged user?
930 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
934 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
936 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
939 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
943 gid_t mapped_gid
= 0;
944 const size_t length
= 1;
946 // Fetch the GID of the calling process
947 gid_t gid
= getgid();
949 // Have we been called from the root group?
953 // Have we been called by an unprivileged group?
960 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
964 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
966 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
969 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
974 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
978 // Open file for writing
979 FILE* f
= fopen(path
, "w");
981 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
986 int bytes_written
= fprintf(f
, "deny\n");
987 if (bytes_written
<= 0) {
988 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
995 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1006 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1007 const uint64_t val
= 1;
1010 DEBUG(jail
->pakfire
, "Sending signal...\n");
1012 // Write to the file descriptor
1013 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1014 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1015 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1019 // Close the file descriptor
1025 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1029 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1031 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1032 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1033 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1037 // Close the file descriptor
1044 Performs the initialisation that needs to happen in the parent part
1046 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1049 // Setup UID mapping
1050 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1054 // Write "deny" to /proc/PID/setgroups
1055 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1059 // Setup GID mapping
1060 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1064 // Parent has finished initialisation
1065 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1067 // Send signal to client
1068 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1075 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1076 const char* argv
[]) {
1079 // Redirect any logging to our log pipe
1080 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1083 pid_t pid
= getpid();
1085 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1088 for (unsigned int i
= 0; argv
[i
]; i
++)
1089 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1091 // Wait for the parent to finish initialization
1092 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1096 // Perform further initialization
1099 uid_t uid
= getuid();
1100 gid_t gid
= getgid();
1103 uid_t euid
= geteuid();
1104 gid_t egid
= getegid();
1106 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1107 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1109 // Check if we are (effectively running as root)
1110 if (uid
!= 0 || gid
!= 0) {
1111 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1115 const char* root
= pakfire_get_path(jail
->pakfire
);
1116 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1118 // Change root (unless root is /)
1119 if (!pakfire_on_root(jail
->pakfire
)) {
1121 r
= pakfire_mount_all(jail
->pakfire
);
1125 // Log all mountpoints
1126 pakfire_mount_list(jail
->pakfire
);
1131 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1135 // Change directory to /
1138 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1144 unsigned long persona
= pakfire_arch_personality(arch
);
1146 r
= personality(persona
);
1148 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1155 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1157 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1159 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1164 // Close other end of log pipes
1165 close(ctx
->pipes
.log_INFO
[0]);
1166 close(ctx
->pipes
.log_ERROR
[0]);
1168 close(ctx
->pipes
.log_DEBUG
[0]);
1169 #endif /* ENABLE_DEBUG */
1171 // Connect standard output and error
1172 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1173 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1175 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1176 ctx
->pipes
.stdout
[1]);
1181 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1183 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1184 ctx
->pipes
.stderr
[1]);
1189 // Close the pipe (as we have moved the original file descriptors)
1190 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1191 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1194 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1195 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1199 // Drop capabilities
1200 r
= pakfire_jail_drop_capabilities(jail
);
1205 r
= pakfire_jail_limit_syscalls(jail
);
1210 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1212 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1214 // Translate errno into regular exit code
1224 // We should not get here
1228 // Run a command in the jail
1229 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1233 // Check if argv is valid
1234 if (!argv
|| !argv
[0]) {
1239 // Initialize context for this call
1240 struct pakfire_jail_exec ctx
= {
1247 DEBUG(jail
->pakfire
, "Executing jail...\n");
1250 Setup a file descriptor which can be used to notify the client that the parent
1251 has completed configuration.
1253 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1254 if (ctx
.completed_fd
< 0) {
1255 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1259 // Create pipes to communicate with child process if we are not running interactively
1260 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1262 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1267 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1272 // Setup pipes for logging
1274 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1279 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1285 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1288 #endif /* ENABLE_DEBUG */
1290 // Configure child process
1291 struct clone_args args
= {
1300 .exit_signal
= SIGCHLD
,
1301 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1304 // Launch the process in a cgroup that is a leaf of the configured cgroup
1306 args
.flags
|= CLONE_INTO_CGROUP
;
1308 #warning TODO randomize the name
1310 // Create a temporary cgroup
1311 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, "jail", 0);
1313 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1317 // Clone into this cgroup
1318 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
1321 // Fork this process
1322 ctx
.pid
= clone3(&args
, sizeof(args
));
1324 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1328 } else if (ctx
.pid
== 0) {
1329 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1334 r
= pakfire_jail_parent(jail
, &ctx
);
1338 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1340 // Read output of the child process
1341 r
= pakfire_jail_wait(jail
, &ctx
);
1345 // Handle exit status
1346 switch (ctx
.status
.si_code
) {
1348 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1349 ctx
.status
.si_status
);
1352 exit
= ctx
.status
.si_status
;
1357 ERROR(jail
->pakfire
, "The child process was killed\n");
1360 // Log anything else
1362 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1367 // Destroy the temporary cgroup (if any)
1369 pakfire_cgroup_destroy(ctx
.cgroup
);
1370 pakfire_cgroup_unref(ctx
.cgroup
);
1373 // Close any file descriptors
1374 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1375 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1378 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1379 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1380 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1382 // Umount everything
1383 if (!pakfire_on_root(jail
->pakfire
))
1384 pakfire_umount_all(jail
->pakfire
);
1389 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1390 const char* argv
[], char** output
) {
1393 // Store logging callback
1394 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1395 void* log_data
= jail
->log_data
;
1397 // Capture output if requested by user
1399 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1402 r
= __pakfire_jail_exec(jail
, argv
);
1404 // Restore log callback
1405 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1410 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1411 const char* script
, const size_t size
, const char* args
[], char** output
) {
1412 char path
[PATH_MAX
];
1413 const char** argv
= NULL
;
1416 const char* root
= pakfire_get_path(jail
->pakfire
);
1418 // Write the scriptlet to disk
1419 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1423 // Open a temporary file
1424 int fd
= mkstemp(path
);
1426 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1431 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1434 ssize_t bytes_written
= write(fd
, script
, size
);
1435 if (bytes_written
< (ssize_t
)size
) {
1436 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1441 // Make the script executable
1442 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1444 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1451 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1456 // Count how many arguments were passed
1457 unsigned int argc
= 1;
1459 for (const char** arg
= args
; *arg
; arg
++)
1463 argv
= calloc(argc
+ 1, sizeof(*argv
));
1465 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1470 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1473 for (unsigned int i
= 1; i
< argc
; i
++)
1474 argv
[i
] = args
[i
-1];
1477 r
= pakfire_jail_exec(jail
, argv
, output
);
1483 // Remove script from disk
1491 A convenience function that creates a new jail, runs the given command and destroys
1494 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
1495 struct pakfire_jail
* jail
= NULL
;
1498 // Create a new jail
1499 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1503 // Execute the command
1504 r
= pakfire_jail_exec(jail
, argv
, output
);
1508 pakfire_jail_unref(jail
);
1513 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1514 const char* script
, const size_t length
, const char* argv
[], int flags
, char** output
) {
1515 struct pakfire_jail
* jail
= NULL
;
1518 // Create a new jail
1519 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1523 // Execute the command
1524 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1528 pakfire_jail_unref(jail
);
1534 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1535 const char* argv
[] = {
1536 "/bin/bash", "--login", NULL
,
1539 // Execute /bin/bash
1540 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1543 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1544 char path
[PATH_MAX
];
1546 const char* ldconfig
= "/sbin/ldconfig";
1548 // Check if ldconfig exists before calling it to avoid overhead
1549 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1553 // Check if ldconfig is executable
1554 r
= access(path
, X_OK
);
1556 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1560 const char* argv
[] = {
1565 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);