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>
45 #include <pakfire/arch.h>
46 #include <pakfire/cgroup.h>
47 #include <pakfire/jail.h>
48 #include <pakfire/logging.h>
49 #include <pakfire/mount.h>
50 #include <pakfire/pakfire.h>
51 #include <pakfire/private.h>
52 #include <pakfire/pwd.h>
53 #include <pakfire/util.h>
55 #define BUFFER_SIZE 1024 * 64
56 #define ENVIRON_SIZE 128
57 #define EPOLL_MAX_EVENTS 2
58 #define MAX_MOUNTPOINTS 8
60 // The default environment that will be set for every command
61 static const struct environ
{
65 { "LANG", "en_US.utf-8" },
70 struct pakfire_jail_mountpoint
{
71 char source
[PATH_MAX
];
72 char target
[PATH_MAX
];
77 struct pakfire
* pakfire
;
80 // A unique ID for each jail
82 char __uuid
[UUID_STR_LEN
];
91 struct pakfire_cgroup
* cgroup
;
94 char* env
[ENVIRON_SIZE
];
97 pakfire_jail_log_callback log_callback
;
101 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
102 unsigned int num_mountpoints
;
105 struct pakfire_log_buffer
{
106 char data
[BUFFER_SIZE
];
110 struct pakfire_jail_exec
{
111 // PID (of the child)
115 // Process status (from waitid)
118 // FD to notify the client that the parent has finished initialization
122 struct pakfire_jail_pipes
{
133 struct pakfire_jail_buffers
{
134 struct pakfire_log_buffer stdout
;
135 struct pakfire_log_buffer stderr
;
138 struct pakfire_log_buffer log_INFO
;
139 struct pakfire_log_buffer log_ERROR
;
140 struct pakfire_log_buffer log_DEBUG
;
143 struct pakfire_cgroup
* cgroup
;
144 struct pakfire_cgroup_stats cgroup_stats
;
147 static int clone3(struct clone_args
* args
, size_t size
) {
148 return syscall(__NR_clone3
, args
, size
);
151 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
152 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
155 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
159 pakfire_cgroup_unref(jail
->cgroup
);
161 pakfire_unref(jail
->pakfire
);
166 Passes any log messages on to the default pakfire log callback
168 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
169 int priority
, const char* line
, size_t length
) {
172 INFO(pakfire
, "%s", line
);
176 ERROR(pakfire
, "%s", line
);
181 DEBUG(pakfire
, "%s", line
);
189 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
191 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
196 char* TERM
= secure_getenv("TERM");
198 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
204 char* LANG
= secure_getenv("LANG");
206 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
214 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
215 struct pakfire
* pakfire
, int flags
) {
218 // Allocate a new jail
219 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
224 j
->pakfire
= pakfire_ref(pakfire
);
226 // Initialize reference counter
232 // Generate a random UUID
233 uuid_generate_random(j
->uuid
);
235 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
237 // Set default log callback
238 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
242 // Set default environment
243 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
244 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
254 pakfire_jail_free(j
);
259 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
265 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
266 if (--jail
->nrefs
> 0)
269 pakfire_jail_free(jail
);
273 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
274 return jail
->flags
& flag
;
277 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
279 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
286 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
287 // Check if nice level is in range
288 if (nice
< -19 || nice
> 20) {
299 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
300 // Free any previous cgroup
302 pakfire_cgroup_unref(jail
->cgroup
);
306 // Set any new cgroup
308 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
310 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
319 // Returns the length of the environment
320 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
323 // Count everything in the environment
324 for (char** e
= jail
->env
; *e
; e
++)
330 // Finds an existing environment variable and returns its index or -1 if not found
331 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
337 char buffer
[strlen(key
) + 2];
338 pakfire_string_format(buffer
, "%s=", key
);
340 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
341 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
349 // Returns the value of an environment variable or NULL
350 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
352 int i
= pakfire_jail_find_env(jail
, key
);
356 return jail
->env
[i
] + strlen(key
) + 1;
359 // Sets an environment variable
360 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
361 const char* key
, const char* value
) {
362 // Find the index where to write this value to
363 int i
= pakfire_jail_find_env(jail
, key
);
365 i
= pakfire_jail_env_length(jail
);
367 // Return -ENOSPC when the environment is full
368 if (i
>= ENVIRON_SIZE
) {
373 // Free any previous value
377 // Format and set environment variable
378 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
380 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
385 // Imports an environment
386 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
394 // Copy environment variables
395 for (unsigned int i
= 0; env
[i
]; i
++) {
396 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
401 r
= pakfire_jail_set_env(jail
, key
, val
);
418 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
419 pakfire_jail_log_callback callback
, void* data
) {
420 jail
->log_callback
= callback
;
421 jail
->log_data
= data
;
427 This function replaces any logging in the child process.
429 All log messages will be sent to the parent process through their respective pipes.
431 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
432 int line
, const char* fn
, const char* format
, va_list args
) {
433 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
438 fd
= pipes
->log_INFO
[1];
442 fd
= pipes
->log_ERROR
[1];
447 fd
= pipes
->log_DEBUG
[1];
449 #endif /* ENABLE_DEBUG */
451 // Ignore any messages of an unknown priority
456 // Send the log message
458 vdprintf(fd
, format
, args
);
461 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
462 return (sizeof(buffer
->data
) == buffer
->used
);
466 This function reads as much data as it can from the file descriptor.
467 If it finds a whole line in it, it will send it to the logger and repeat the process.
468 If not newline character is found, it will try to read more data until it finds one.
470 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
471 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
472 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
473 char line
[BUFFER_SIZE
+ 1];
475 // Fill up buffer from fd
476 if (buffer
->used
< sizeof(buffer
->data
)) {
477 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
478 sizeof(buffer
->data
) - buffer
->used
);
481 if (bytes_read
< 0) {
482 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
486 // Update buffer size
487 buffer
->used
+= bytes_read
;
490 // See if we have any lines that we can write
491 while (buffer
->used
) {
492 // Search for the end of the first line
493 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
497 // If the buffer is full, we send the content to the logger and try again
498 // This should not happen in practise
499 if (pakfire_jail_log_buffer_is_full(buffer
)) {
500 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
502 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
504 // Otherwise we might have only read parts of the output
509 // Find the length of the string
510 size_t length
= eol
- buffer
->data
+ 1;
512 // Copy the line into the buffer
513 memcpy(line
, buffer
->data
, length
);
515 // Terminate the string
520 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
522 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
527 // Remove line from buffer
528 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
529 buffer
->used
-= length
;
535 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
536 int r
= pipe2(*fds
, flags
);
538 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
545 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
546 for (unsigned int i
= 0; i
< 2; i
++)
552 This is a convenience function to fetch the reading end of a pipe and
553 closes the write end.
555 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
556 // Give the variables easier names to avoid confusion
557 int* fd_read
= &(*fds
)[0];
558 int* fd_write
= &(*fds
)[1];
560 // Close the write end of the pipe
566 // Return the read end
570 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
572 struct epoll_event ev
;
573 struct epoll_event events
[EPOLL_MAX_EVENTS
];
576 // Fetch file descriptors from context
577 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
578 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
579 const int pidfd
= ctx
->pidfd
;
582 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
583 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
584 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
586 // Make a list of all file descriptors we are interested in
588 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
592 epollfd
= epoll_create1(0);
594 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
601 // Turn file descriptors into non-blocking mode and add them to epoll()
602 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
605 // Skip fds which were not initialized
611 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
612 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
620 // Loop for as long as the process is alive
622 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
624 // Ignore if epoll_wait() has been interrupted
628 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
634 for (int i
= 0; i
< num
; i
++) {
635 int fd
= events
[i
].data
.fd
;
637 struct pakfire_log_buffer
* buffer
= NULL
;
638 pakfire_jail_log_callback callback
= NULL
;
642 // Handle any changes to the PIDFD
644 // Call waidid() and store the result
645 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
647 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
651 // Mark that we have ended so that we will process the remaining
652 // events from epoll() now, but won't restart the outer loop.
656 // Handle logging messages
657 } else if (fd
== log_INFO
) {
658 buffer
= &ctx
->buffers
.log_INFO
;
661 callback
= pakfire_jail_default_log_callback
;
663 } else if (fd
== log_ERROR
) {
664 buffer
= &ctx
->buffers
.log_ERROR
;
667 callback
= pakfire_jail_default_log_callback
;
669 } else if (fd
== log_DEBUG
) {
670 buffer
= &ctx
->buffers
.log_DEBUG
;
671 priority
= LOG_DEBUG
;
673 callback
= pakfire_jail_default_log_callback
;
675 // Handle anything from the log pipes
676 } else if (fd
== stdout
) {
677 buffer
= &ctx
->buffers
.stdout
;
680 callback
= jail
->log_callback
;
681 data
= jail
->log_data
;
683 } else if (fd
== stderr
) {
684 buffer
= &ctx
->buffers
.stderr
;
687 callback
= jail
->log_callback
;
688 data
= jail
->log_data
;
691 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
696 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
709 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
710 const char* line
, size_t length
) {
711 char** output
= (char**)data
;
714 // Append everything from stdout to a buffer
715 if (priority
== LOG_INFO
) {
716 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
722 // Send everything else to the default logger
723 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
728 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
729 const int capabilities
[] = {
730 // Deny access to the kernel's audit system
735 // Deny suspending block devices
738 // Deny any stuff with BPF
741 // Deny checkpoint restore
742 CAP_CHECKPOINT_RESTORE
,
744 // Deny opening files by inode number (open_by_handle_at)
747 // Deny setting SUID bits
750 // Deny locking more memory
753 // Deny modifying any Apparmor/SELinux/SMACK configuration
757 // Deny creating any special devices
760 // Deny setting any capabilities
763 // Deny reading from syslog
766 // Deny any admin actions (mount, sethostname, ...)
769 // Deny rebooting the system
772 // Deny loading kernel modules
775 // Deny setting nice level
778 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
781 // Deny circumventing any resource limits
784 // Deny setting the system time
787 // Deny playing with suspend
793 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
798 // Drop any capabilities
799 for (const int* cap
= capabilities
; *cap
; cap
++) {
800 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
802 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
809 // Fetch any capabilities
810 cap_t caps
= cap_get_proc();
812 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
817 Set inheritable capabilities
819 This ensures that no processes will be able to gain any of the listed
822 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
824 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
828 // Restore capabilities
829 r
= cap_set_proc(caps
);
831 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
844 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
845 const int syscalls
[] = {
846 // The kernel's keyring isn't namespaced
849 SCMP_SYS(request_key
),
851 // Disable userfaultfd
852 SCMP_SYS(userfaultfd
),
854 // Disable perf which could leak a lot of information about the host
855 SCMP_SYS(perf_event_open
),
861 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
863 // Setup a syscall filter which allows everything by default
864 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
866 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
871 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
872 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
874 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
879 // Load syscall filter into the kernel
880 r
= seccomp_load(ctx
);
882 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
888 seccomp_release(ctx
);
895 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
896 const char* source
, const char* target
, int flags
) {
897 struct pakfire_jail_mountpoint
* mp
= NULL
;
900 // Check if there is any space left
901 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
906 // Check for valid inputs
907 if (!source
|| !target
) {
912 // Select the next free slot
913 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
916 r
= pakfire_string_set(mp
->source
, source
);
918 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
923 r
= pakfire_string_set(mp
->target
, target
);
925 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
933 jail
->num_mountpoints
++;
939 Mounts everything that we require in the new namespace
941 static int pakfire_jail_mount(struct pakfire_jail
* jail
) {
942 struct pakfire_jail_mountpoint
* mp
= NULL
;
945 // Mount all default stuff
946 r
= pakfire_mount_all(jail
->pakfire
);
950 // Mount all custom stuff
951 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
953 mp
= &jail
->mountpoints
[i
];
956 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
961 // Log all mountpoints
962 pakfire_mount_list(jail
->pakfire
);
969 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
970 const char* path
, const struct pakfire_subid
* subid
) {
973 // Open file for writing
974 FILE* f
= fopen(path
, "w");
976 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
980 // Write configuration
981 int bytes_written
= fprintf(f
, "%d %u %lu\n", 0, subid
->id
, subid
->length
);
982 if (bytes_written
<= 0) {
983 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
991 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
1006 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1007 char path
[PATH_MAX
];
1010 // Skip mapping anything when running on /
1011 if (pakfire_on_root(jail
->pakfire
))
1015 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1020 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1024 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n",
1025 subuid
->id
, subuid
->id
+ subuid
->length
);
1027 return pakfire_jail_write_uidgid_mapping(jail
, path
, subuid
);
1030 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1031 char path
[PATH_MAX
];
1034 // Skip mapping anything when running on /
1035 if (pakfire_on_root(jail
->pakfire
))
1039 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1044 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1048 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n",
1049 subgid
->id
, subgid
->id
+ subgid
->length
);
1051 return pakfire_jail_write_uidgid_mapping(jail
, path
, subgid
);
1054 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1055 char path
[PATH_MAX
];
1059 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1063 // Open file for writing
1064 FILE* f
= fopen(path
, "w");
1066 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
1071 int bytes_written
= fprintf(f
, "deny\n");
1072 if (bytes_written
<= 0) {
1073 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1080 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1091 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1092 const uint64_t val
= 1;
1095 DEBUG(jail
->pakfire
, "Sending signal...\n");
1097 // Write to the file descriptor
1098 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1099 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1100 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1104 // Close the file descriptor
1110 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1114 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1116 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1117 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1118 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1122 // Close the file descriptor
1129 Performs the initialisation that needs to happen in the parent part
1131 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1134 // Write "deny" to /proc/PID/setgroups
1135 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1139 // Setup UID mapping
1140 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1144 // Setup GID mapping
1145 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1149 // Parent has finished initialisation
1150 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1152 // Send signal to client
1153 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1160 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1161 const char* argv
[]) {
1164 // Redirect any logging to our log pipe
1165 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1168 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1170 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1175 pid_t pid
= getpid();
1177 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1180 for (unsigned int i
= 0; argv
[i
]; i
++)
1181 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1183 // Wait for the parent to finish initialization
1184 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1188 // Perform further initialization
1191 uid_t uid
= getuid();
1192 gid_t gid
= getgid();
1195 uid_t euid
= geteuid();
1196 gid_t egid
= getegid();
1198 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1199 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1201 // Check if we are (effectively running as root)
1202 if (uid
|| gid
|| euid
|| egid
) {
1203 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1207 const char* root
= pakfire_get_path(jail
->pakfire
);
1208 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1210 // Change root (unless root is /)
1211 if (!pakfire_on_root(jail
->pakfire
)) {
1213 r
= pakfire_jail_mount(jail
);
1220 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1224 // Change directory to /
1227 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1233 unsigned long persona
= pakfire_arch_personality(arch
);
1235 r
= personality(persona
);
1237 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1244 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1246 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1248 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1253 // Close other end of log pipes
1254 close(ctx
->pipes
.log_INFO
[0]);
1255 close(ctx
->pipes
.log_ERROR
[0]);
1257 close(ctx
->pipes
.log_DEBUG
[0]);
1258 #endif /* ENABLE_DEBUG */
1260 // Connect standard output and error
1261 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1262 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1264 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1265 ctx
->pipes
.stdout
[1]);
1270 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1272 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1273 ctx
->pipes
.stderr
[1]);
1278 // Close the pipe (as we have moved the original file descriptors)
1279 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1280 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1283 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1284 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1288 // Drop capabilities
1289 r
= pakfire_jail_drop_capabilities(jail
);
1294 r
= pakfire_jail_limit_syscalls(jail
);
1299 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1301 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1303 // Translate errno into regular exit code
1313 // We should not get here
1317 // Run a command in the jail
1318 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
1319 const int interactive
) {
1323 // Check if argv is valid
1324 if (!argv
|| !argv
[0]) {
1329 // Initialize context for this call
1330 struct pakfire_jail_exec ctx
= {
1337 DEBUG(jail
->pakfire
, "Executing jail...\n");
1340 Setup a file descriptor which can be used to notify the client that the parent
1341 has completed configuration.
1343 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1344 if (ctx
.completed_fd
< 0) {
1345 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1349 // Create pipes to communicate with child process if we are not running interactively
1352 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1357 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1362 // Setup pipes for logging
1364 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1369 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1375 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1378 #endif /* ENABLE_DEBUG */
1380 // Configure child process
1381 struct clone_args args
= {
1390 .exit_signal
= SIGCHLD
,
1391 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1394 // Launch the process in a cgroup that is a leaf of the configured cgroup
1396 args
.flags
|= CLONE_INTO_CGROUP
;
1399 const char* uuid
= pakfire_jail_uuid(jail
);
1401 // Create a temporary cgroup
1402 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
1404 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1408 // Clone into this cgroup
1409 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
1412 // Fork this process
1413 ctx
.pid
= clone3(&args
, sizeof(args
));
1415 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1419 } else if (ctx
.pid
== 0) {
1420 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1425 r
= pakfire_jail_parent(jail
, &ctx
);
1429 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1431 // Read output of the child process
1432 r
= pakfire_jail_wait(jail
, &ctx
);
1436 // Handle exit status
1437 switch (ctx
.status
.si_code
) {
1439 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1440 ctx
.status
.si_status
);
1443 exit
= ctx
.status
.si_status
;
1448 ERROR(jail
->pakfire
, "The child process was killed\n");
1451 // Log anything else
1453 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1458 // Destroy the temporary cgroup (if any)
1460 // Read cgroup stats
1461 r
= pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
1463 ERROR(jail
->pakfire
, "Could not read cgroup stats: %m\n");
1465 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
1468 pakfire_cgroup_destroy(ctx
.cgroup
);
1469 pakfire_cgroup_unref(ctx
.cgroup
);
1472 // Close any file descriptors
1473 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1474 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1477 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1478 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1479 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1484 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1485 const char* argv
[], char** output
) {
1488 // Store logging callback
1489 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1490 void* log_data
= jail
->log_data
;
1492 // Capture output if requested by user
1494 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1497 r
= __pakfire_jail_exec(jail
, argv
, 0);
1499 // Restore log callback
1500 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1505 static int pakfire_jail_exec_interactive(
1506 struct pakfire_jail
* jail
, const char* argv
[]) {
1509 // Setup interactive stuff
1510 r
= pakfire_jail_setup_interactive_env(jail
);
1514 return __pakfire_jail_exec(jail
, argv
, 1);
1517 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1518 const char* script
, const size_t size
, const char* args
[], char** output
) {
1519 char path
[PATH_MAX
];
1520 const char** argv
= NULL
;
1523 const char* root
= pakfire_get_path(jail
->pakfire
);
1525 // Write the scriptlet to disk
1526 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1530 // Open a temporary file
1531 int fd
= mkstemp(path
);
1533 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1538 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1541 ssize_t bytes_written
= write(fd
, script
, size
);
1542 if (bytes_written
< (ssize_t
)size
) {
1543 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1548 // Make the script executable
1549 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1551 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1558 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1563 // Count how many arguments were passed
1564 unsigned int argc
= 1;
1566 for (const char** arg
= args
; *arg
; arg
++)
1570 argv
= calloc(argc
+ 1, sizeof(*argv
));
1572 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1577 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1580 for (unsigned int i
= 1; i
< argc
; i
++)
1581 argv
[i
] = args
[i
-1];
1584 r
= pakfire_jail_exec(jail
, argv
, output
);
1590 // Remove script from disk
1598 A convenience function that creates a new jail, runs the given command and destroys
1601 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
1602 struct pakfire_jail
* jail
= NULL
;
1605 // Create a new jail
1606 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1610 // Execute the command
1611 r
= pakfire_jail_exec(jail
, argv
, output
);
1615 pakfire_jail_unref(jail
);
1620 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1621 const char* script
, const size_t length
, const char* argv
[], int flags
, char** output
) {
1622 struct pakfire_jail
* jail
= NULL
;
1625 // Create a new jail
1626 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1630 // Execute the command
1631 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1635 pakfire_jail_unref(jail
);
1640 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
1641 const char* argv
[] = {
1642 "/bin/bash", "--login", NULL
,
1645 // Execute /bin/bash
1646 return pakfire_jail_exec_interactive(jail
, argv
);
1649 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1650 char path
[PATH_MAX
];
1652 const char* ldconfig
= "/sbin/ldconfig";
1654 // Check if ldconfig exists before calling it to avoid overhead
1655 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1659 // Check if ldconfig is executable
1660 r
= access(path
, X_OK
);
1662 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1666 const char* argv
[] = {
1671 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);