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** output
= (char**)data
;
689 // Append everything from stdout to a buffer
690 if (priority
== LOG_INFO
) {
691 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
697 // Send everything else to the default logger
698 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
703 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
704 const int capabilities
[] = {
705 // Deny access to the kernel's audit system
710 // Deny suspending block devices
713 // Deny any stuff with BPF
716 // Deny checkpoint restore
717 CAP_CHECKPOINT_RESTORE
,
719 // Deny opening files by inode number (open_by_handle_at)
722 // Deny setting SUID bits
725 // Deny locking more memory
728 // Deny modifying any Apparmor/SELinux/SMACK configuration
732 // Deny creating any special devices
735 // Deny setting any capabilities
738 // Deny reading from syslog
741 // Deny any admin actions (mount, sethostname, ...)
744 // Deny rebooting the system
747 // Deny loading kernel modules
750 // Deny setting nice level
753 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
756 // Deny circumventing any resource limits
759 // Deny setting the system time
762 // Deny playing with suspend
768 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
773 // Drop any capabilities
774 for (const int* cap
= capabilities
; *cap
; cap
++) {
775 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
777 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
784 // Fetch any capabilities
785 cap_t caps
= cap_get_proc();
787 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
792 Set inheritable capabilities
794 This ensures that no processes will be able to gain any of the listed
797 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
799 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
803 // Restore capabilities
804 r
= cap_set_proc(caps
);
806 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
819 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
820 const int syscalls
[] = {
821 // The kernel's keyring isn't namespaced
824 SCMP_SYS(request_key
),
826 // Disable userfaultfd
827 SCMP_SYS(userfaultfd
),
829 // Disable perf which could leak a lot of information about the host
830 SCMP_SYS(perf_event_open
),
836 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
838 // Setup a syscall filter which allows everything by default
839 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
841 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
846 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
847 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
849 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
854 // Load syscall filter into the kernel
855 r
= seccomp_load(ctx
);
857 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
863 seccomp_release(ctx
);
870 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
871 const char* path
, uid_t mapped_id
, size_t length
) {
874 // Open file for writing
875 FILE* f
= fopen(path
, "w");
877 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
881 // Write configuration
882 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
883 if (bytes_written
<= 0) {
884 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
892 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
907 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
911 uid_t mapped_uid
= 0;
912 const size_t length
= 1;
914 // Fetch the UID of the calling process
915 uid_t uid
= getuid();
917 // Have we been called by root?
921 // Have we been called by an unprivileged user?
928 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
932 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
934 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
937 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
941 gid_t mapped_gid
= 0;
942 const size_t length
= 1;
944 // Fetch the GID of the calling process
945 gid_t gid
= getgid();
947 // Have we been called from the root group?
951 // Have we been called by an unprivileged group?
958 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
962 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
964 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
967 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
972 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
976 // Open file for writing
977 FILE* f
= fopen(path
, "w");
979 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
984 int bytes_written
= fprintf(f
, "deny\n");
985 if (bytes_written
<= 0) {
986 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
993 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1004 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1005 const uint64_t val
= 1;
1008 DEBUG(jail
->pakfire
, "Sending signal...\n");
1010 // Write to the file descriptor
1011 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1012 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1013 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1017 // Close the file descriptor
1023 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1027 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1029 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1030 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1031 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1035 // Close the file descriptor
1042 Performs the initialisation that needs to happen in the parent part
1044 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1047 // Setup UID mapping
1048 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1052 // Write "deny" to /proc/PID/setgroups
1053 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1057 // Setup GID mapping
1058 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1062 // Parent has finished initialisation
1063 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1065 // Send signal to client
1066 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1073 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1074 const char* argv
[]) {
1077 // Redirect any logging to our log pipe
1078 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1081 pid_t pid
= getpid();
1083 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1086 for (unsigned int i
= 0; argv
[i
]; i
++)
1087 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1089 // Wait for the parent to finish initialization
1090 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1094 // Perform further initialization
1097 uid_t uid
= getuid();
1098 gid_t gid
= getgid();
1101 uid_t euid
= geteuid();
1102 gid_t egid
= getegid();
1104 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1105 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1107 // Check if we are (effectively running as root)
1108 if (uid
!= 0 || gid
!= 0) {
1109 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1113 const char* root
= pakfire_get_path(jail
->pakfire
);
1114 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1116 // Change root (unless root is /)
1117 if (!pakfire_on_root(jail
->pakfire
)) {
1119 r
= pakfire_mount_all(jail
->pakfire
);
1123 // Log all mountpoints
1124 pakfire_mount_list(jail
->pakfire
);
1129 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1133 // Change directory to /
1136 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1142 unsigned long persona
= pakfire_arch_personality(arch
);
1144 r
= personality(persona
);
1146 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1153 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1155 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1157 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1162 // Close other end of log pipes
1163 close(ctx
->pipes
.log_INFO
[0]);
1164 close(ctx
->pipes
.log_ERROR
[0]);
1166 close(ctx
->pipes
.log_DEBUG
[0]);
1167 #endif /* ENABLE_DEBUG */
1169 // Connect standard output and error
1170 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1171 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1173 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1174 ctx
->pipes
.stdout
[1]);
1179 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1181 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1182 ctx
->pipes
.stderr
[1]);
1187 // Close the pipe (as we have moved the original file descriptors)
1188 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1189 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1192 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1193 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1197 // Drop capabilities
1198 r
= pakfire_jail_drop_capabilities(jail
);
1203 r
= pakfire_jail_limit_syscalls(jail
);
1208 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1210 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1212 // Translate errno into regular exit code
1222 // We should not get here
1226 // Run a command in the jail
1227 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1231 // Check if argv is valid
1232 if (!argv
|| !argv
[0]) {
1237 // Initialize context for this call
1238 struct pakfire_jail_exec ctx
= {
1245 DEBUG(jail
->pakfire
, "Executing jail...\n");
1248 Setup a file descriptor which can be used to notify the client that the parent
1249 has completed configuration.
1251 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1252 if (ctx
.completed_fd
< 0) {
1253 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1257 // Create pipes to communicate with child process if we are not running interactively
1258 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1260 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1265 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1270 // Setup pipes for logging
1272 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1277 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1283 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1286 #endif /* ENABLE_DEBUG */
1288 // Configure child process
1289 struct clone_args args
= {
1298 .exit_signal
= SIGCHLD
,
1299 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1302 // Launch the process in a cgroup (if requested)
1304 args
.flags
|= CLONE_INTO_CGROUP
;
1306 // Clone into this cgroup
1307 args
.cgroup
= pakfire_cgroup_fd(jail
->cgroup
);
1310 // Fork this process
1311 ctx
.pid
= clone3(&args
, sizeof(args
));
1313 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1317 } else if (ctx
.pid
== 0) {
1318 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1323 r
= pakfire_jail_parent(jail
, &ctx
);
1327 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1329 // Read output of the child process
1330 r
= pakfire_jail_wait(jail
, &ctx
);
1334 // Handle exit status
1335 switch (ctx
.status
.si_code
) {
1337 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1338 ctx
.status
.si_status
);
1341 exit
= ctx
.status
.si_status
;
1346 ERROR(jail
->pakfire
, "The child process was killed\n");
1349 // Log anything else
1351 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1356 // Close any file descriptors
1357 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1358 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1361 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1362 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1363 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1365 // Umount everything
1366 if (!pakfire_on_root(jail
->pakfire
))
1367 pakfire_umount_all(jail
->pakfire
);
1372 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1373 const char* argv
[], char** output
) {
1376 // Store logging callback
1377 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1378 void* log_data
= jail
->log_data
;
1380 // Capture output if requested by user
1382 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1385 r
= __pakfire_jail_exec(jail
, argv
);
1387 // Restore log callback
1388 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1393 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1394 const char* script
, const size_t size
, const char* args
[], char** output
) {
1395 char path
[PATH_MAX
];
1396 const char** argv
= NULL
;
1399 const char* root
= pakfire_get_path(jail
->pakfire
);
1401 // Write the scriptlet to disk
1402 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1406 // Open a temporary file
1407 int fd
= mkstemp(path
);
1409 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1414 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1417 ssize_t bytes_written
= write(fd
, script
, size
);
1418 if (bytes_written
< (ssize_t
)size
) {
1419 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1424 // Make the script executable
1425 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1427 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1434 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1439 // Count how many arguments were passed
1440 unsigned int argc
= 1;
1442 for (const char** arg
= args
; *arg
; arg
++)
1446 argv
= calloc(argc
+ 1, sizeof(*argv
));
1448 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1453 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1456 for (unsigned int i
= 1; i
< argc
; i
++)
1457 argv
[i
] = args
[i
-1];
1460 r
= pakfire_jail_exec(jail
, argv
, output
);
1466 // Remove script from disk
1474 A convenience function that creates a new jail, runs the given command and destroys
1477 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
1478 struct pakfire_jail
* jail
= NULL
;
1481 // Create a new jail
1482 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1486 // Execute the command
1487 r
= pakfire_jail_exec(jail
, argv
, output
);
1491 pakfire_jail_unref(jail
);
1496 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1497 const char* script
, const size_t length
, const char* argv
[], int flags
, char** output
) {
1498 struct pakfire_jail
* jail
= NULL
;
1501 // Create a new jail
1502 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1506 // Execute the command
1507 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1511 pakfire_jail_unref(jail
);
1517 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1518 const char* argv
[] = {
1519 "/bin/bash", "--login", NULL
,
1522 // Execute /bin/bash
1523 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1526 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1527 char path
[PATH_MAX
];
1529 const char* ldconfig
= "/sbin/ldconfig";
1531 // Check if ldconfig exists before calling it to avoid overhead
1532 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1536 // Check if ldconfig is executable
1537 r
= access(path
, X_OK
);
1539 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1543 const char* argv
[] = {
1548 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);