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
);
249 // Setup interactive stuff
250 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
251 r
= pakfire_jail_setup_interactive_env(j
);
261 pakfire_jail_free(j
);
266 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
272 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
273 if (--jail
->nrefs
> 0)
276 pakfire_jail_free(jail
);
280 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
281 return jail
->flags
& flag
;
284 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
286 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
293 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
294 // Check if nice level is in range
295 if (nice
< -19 || nice
> 20) {
306 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
307 // Free any previous cgroup
309 pakfire_cgroup_unref(jail
->cgroup
);
313 // Set any new cgroup
315 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
317 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
326 // Returns the length of the environment
327 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
330 // Count everything in the environment
331 for (char** e
= jail
->env
; *e
; e
++)
337 // Finds an existing environment variable and returns its index or -1 if not found
338 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
344 char buffer
[strlen(key
) + 2];
345 pakfire_string_format(buffer
, "%s=", key
);
347 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
348 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
356 // Returns the value of an environment variable or NULL
357 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
359 int i
= pakfire_jail_find_env(jail
, key
);
363 return jail
->env
[i
] + strlen(key
) + 1;
366 // Sets an environment variable
367 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
368 const char* key
, const char* value
) {
369 // Find the index where to write this value to
370 int i
= pakfire_jail_find_env(jail
, key
);
372 i
= pakfire_jail_env_length(jail
);
374 // Return -ENOSPC when the environment is full
375 if (i
>= ENVIRON_SIZE
) {
380 // Free any previous value
384 // Format and set environment variable
385 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
387 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
392 // Imports an environment
393 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
401 // Copy environment variables
402 for (unsigned int i
= 0; env
[i
]; i
++) {
403 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
408 r
= pakfire_jail_set_env(jail
, key
, val
);
425 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
426 pakfire_jail_log_callback callback
, void* data
) {
427 jail
->log_callback
= callback
;
428 jail
->log_data
= data
;
434 This function replaces any logging in the child process.
436 All log messages will be sent to the parent process through their respective pipes.
438 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
439 int line
, const char* fn
, const char* format
, va_list args
) {
440 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
445 fd
= pipes
->log_INFO
[1];
449 fd
= pipes
->log_ERROR
[1];
454 fd
= pipes
->log_DEBUG
[1];
456 #endif /* ENABLE_DEBUG */
458 // Ignore any messages of an unknown priority
463 // Send the log message
465 vdprintf(fd
, format
, args
);
468 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
469 return (sizeof(buffer
->data
) == buffer
->used
);
473 This function reads as much data as it can from the file descriptor.
474 If it finds a whole line in it, it will send it to the logger and repeat the process.
475 If not newline character is found, it will try to read more data until it finds one.
477 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
478 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
479 struct pakfire_log_buffer
* buffer
, pakfire_jail_log_callback callback
, void* data
) {
480 char line
[BUFFER_SIZE
+ 1];
482 // Fill up buffer from fd
483 if (buffer
->used
< sizeof(buffer
->data
)) {
484 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
485 sizeof(buffer
->data
) - buffer
->used
);
488 if (bytes_read
< 0) {
489 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
493 // Update buffer size
494 buffer
->used
+= bytes_read
;
497 // See if we have any lines that we can write
498 while (buffer
->used
) {
499 // Search for the end of the first line
500 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
504 // If the buffer is full, we send the content to the logger and try again
505 // This should not happen in practise
506 if (pakfire_jail_log_buffer_is_full(buffer
)) {
507 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
509 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
511 // Otherwise we might have only read parts of the output
516 // Find the length of the string
517 size_t length
= eol
- buffer
->data
+ 1;
519 // Copy the line into the buffer
520 memcpy(line
, buffer
->data
, length
);
522 // Terminate the string
527 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
529 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
534 // Remove line from buffer
535 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
536 buffer
->used
-= length
;
542 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
543 int r
= pipe2(*fds
, flags
);
545 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
552 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
553 for (unsigned int i
= 0; i
< 2; i
++)
559 This is a convenience function to fetch the reading end of a pipe and
560 closes the write end.
562 static int pakfire_jail_get_pipe(struct pakfire_jail
* jail
, int (*fds
)[2]) {
563 // Give the variables easier names to avoid confusion
564 int* fd_read
= &(*fds
)[0];
565 int* fd_write
= &(*fds
)[1];
567 // Close the write end of the pipe
573 // Return the read end
577 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
579 struct epoll_event ev
;
580 struct epoll_event events
[EPOLL_MAX_EVENTS
];
583 // Fetch file descriptors from context
584 const int stdout
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stdout
);
585 const int stderr
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.stderr
);
586 const int pidfd
= ctx
->pidfd
;
589 const int log_INFO
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_INFO
);
590 const int log_ERROR
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_ERROR
);
591 const int log_DEBUG
= pakfire_jail_get_pipe(jail
, &ctx
->pipes
.log_DEBUG
);
593 // Make a list of all file descriptors we are interested in
595 stdout
, stderr
, pidfd
, log_INFO
, log_ERROR
, log_DEBUG
,
599 epollfd
= epoll_create1(0);
601 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
608 // Turn file descriptors into non-blocking mode and add them to epoll()
609 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
612 // Skip fds which were not initialized
618 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
619 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
627 // Loop for as long as the process is alive
629 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
631 // Ignore if epoll_wait() has been interrupted
635 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
641 for (int i
= 0; i
< num
; i
++) {
642 int fd
= events
[i
].data
.fd
;
644 struct pakfire_log_buffer
* buffer
= NULL
;
645 pakfire_jail_log_callback callback
= NULL
;
649 // Handle any changes to the PIDFD
651 // Call waidid() and store the result
652 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
654 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
658 // Mark that we have ended so that we will process the remaining
659 // events from epoll() now, but won't restart the outer loop.
663 // Handle logging messages
664 } else if (fd
== log_INFO
) {
665 buffer
= &ctx
->buffers
.log_INFO
;
668 callback
= pakfire_jail_default_log_callback
;
670 } else if (fd
== log_ERROR
) {
671 buffer
= &ctx
->buffers
.log_ERROR
;
674 callback
= pakfire_jail_default_log_callback
;
676 } else if (fd
== log_DEBUG
) {
677 buffer
= &ctx
->buffers
.log_DEBUG
;
678 priority
= LOG_DEBUG
;
680 callback
= pakfire_jail_default_log_callback
;
682 // Handle anything from the log pipes
683 } else if (fd
== stdout
) {
684 buffer
= &ctx
->buffers
.stdout
;
687 callback
= jail
->log_callback
;
688 data
= jail
->log_data
;
690 } else if (fd
== stderr
) {
691 buffer
= &ctx
->buffers
.stderr
;
694 callback
= jail
->log_callback
;
695 data
= jail
->log_data
;
698 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
703 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
716 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
717 const char* line
, size_t length
) {
718 char** output
= (char**)data
;
721 // Append everything from stdout to a buffer
722 if (priority
== LOG_INFO
) {
723 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
729 // Send everything else to the default logger
730 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
735 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
736 const int capabilities
[] = {
737 // Deny access to the kernel's audit system
742 // Deny suspending block devices
745 // Deny any stuff with BPF
748 // Deny checkpoint restore
749 CAP_CHECKPOINT_RESTORE
,
751 // Deny opening files by inode number (open_by_handle_at)
754 // Deny setting SUID bits
757 // Deny locking more memory
760 // Deny modifying any Apparmor/SELinux/SMACK configuration
764 // Deny creating any special devices
767 // Deny setting any capabilities
770 // Deny reading from syslog
773 // Deny any admin actions (mount, sethostname, ...)
776 // Deny rebooting the system
779 // Deny loading kernel modules
782 // Deny setting nice level
785 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
788 // Deny circumventing any resource limits
791 // Deny setting the system time
794 // Deny playing with suspend
800 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
805 // Drop any capabilities
806 for (const int* cap
= capabilities
; *cap
; cap
++) {
807 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
809 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
816 // Fetch any capabilities
817 cap_t caps
= cap_get_proc();
819 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
824 Set inheritable capabilities
826 This ensures that no processes will be able to gain any of the listed
829 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
831 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
835 // Restore capabilities
836 r
= cap_set_proc(caps
);
838 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
851 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
852 const int syscalls
[] = {
853 // The kernel's keyring isn't namespaced
856 SCMP_SYS(request_key
),
858 // Disable userfaultfd
859 SCMP_SYS(userfaultfd
),
861 // Disable perf which could leak a lot of information about the host
862 SCMP_SYS(perf_event_open
),
868 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
870 // Setup a syscall filter which allows everything by default
871 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
873 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
878 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
879 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
881 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
886 // Load syscall filter into the kernel
887 r
= seccomp_load(ctx
);
889 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
895 seccomp_release(ctx
);
902 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
903 const char* source
, const char* target
, int flags
) {
904 struct pakfire_jail_mountpoint
* mp
= NULL
;
907 // Check if there is any space left
908 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
913 // Check for valid inputs
914 if (!source
|| !target
) {
919 // Select the next free slot
920 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
923 r
= pakfire_string_set(mp
->source
, source
);
925 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
930 r
= pakfire_string_set(mp
->target
, target
);
932 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
940 jail
->num_mountpoints
++;
946 Mounts everything that we require in the new namespace
948 static int pakfire_jail_mount(struct pakfire_jail
* jail
) {
949 struct pakfire_jail_mountpoint
* mp
= NULL
;
952 // Mount all default stuff
953 r
= pakfire_mount_all(jail
->pakfire
);
957 // Mount all custom stuff
958 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
960 mp
= &jail
->mountpoints
[i
];
963 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
968 // Log all mountpoints
969 pakfire_mount_list(jail
->pakfire
);
976 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
977 const char* path
, const struct pakfire_subid
* subid
) {
980 // Open file for writing
981 FILE* f
= fopen(path
, "w");
983 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
987 // Write configuration
988 int bytes_written
= fprintf(f
, "%d %u %lu\n", 0, subid
->id
, subid
->length
);
989 if (bytes_written
<= 0) {
990 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
998 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
1013 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1014 char path
[PATH_MAX
];
1017 // Skip mapping anything when running on /
1018 if (pakfire_on_root(jail
->pakfire
))
1022 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1027 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1031 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n",
1032 subuid
->id
, subuid
->id
+ subuid
->length
);
1034 return pakfire_jail_write_uidgid_mapping(jail
, path
, subuid
);
1037 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1038 char path
[PATH_MAX
];
1041 // Skip mapping anything when running on /
1042 if (pakfire_on_root(jail
->pakfire
))
1046 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1051 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1055 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n",
1056 subgid
->id
, subgid
->id
+ subgid
->length
);
1058 return pakfire_jail_write_uidgid_mapping(jail
, path
, subgid
);
1061 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1062 char path
[PATH_MAX
];
1066 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1070 // Open file for writing
1071 FILE* f
= fopen(path
, "w");
1073 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
1078 int bytes_written
= fprintf(f
, "deny\n");
1079 if (bytes_written
<= 0) {
1080 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1087 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1098 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1099 const uint64_t val
= 1;
1102 DEBUG(jail
->pakfire
, "Sending signal...\n");
1104 // Write to the file descriptor
1105 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1106 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1107 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1111 // Close the file descriptor
1117 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1121 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1123 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1124 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1125 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1129 // Close the file descriptor
1136 Performs the initialisation that needs to happen in the parent part
1138 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1141 // Write "deny" to /proc/PID/setgroups
1142 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1146 // Setup UID mapping
1147 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1151 // Setup GID mapping
1152 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1156 // Parent has finished initialisation
1157 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1159 // Send signal to client
1160 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1167 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1168 const char* argv
[]) {
1171 // Redirect any logging to our log pipe
1172 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1175 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1177 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1182 pid_t pid
= getpid();
1184 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1187 for (unsigned int i
= 0; argv
[i
]; i
++)
1188 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1190 // Wait for the parent to finish initialization
1191 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1195 // Perform further initialization
1198 uid_t uid
= getuid();
1199 gid_t gid
= getgid();
1202 uid_t euid
= geteuid();
1203 gid_t egid
= getegid();
1205 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1206 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1208 // Check if we are (effectively running as root)
1209 if (uid
|| gid
|| euid
|| egid
) {
1210 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1214 const char* root
= pakfire_get_path(jail
->pakfire
);
1215 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1217 // Change root (unless root is /)
1218 if (!pakfire_on_root(jail
->pakfire
)) {
1220 r
= pakfire_jail_mount(jail
);
1227 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1231 // Change directory to /
1234 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1240 unsigned long persona
= pakfire_arch_personality(arch
);
1242 r
= personality(persona
);
1244 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1251 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1253 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1255 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1260 // Close other end of log pipes
1261 close(ctx
->pipes
.log_INFO
[0]);
1262 close(ctx
->pipes
.log_ERROR
[0]);
1264 close(ctx
->pipes
.log_DEBUG
[0]);
1265 #endif /* ENABLE_DEBUG */
1267 // Connect standard output and error
1268 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1269 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1271 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1272 ctx
->pipes
.stdout
[1]);
1277 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1279 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1280 ctx
->pipes
.stderr
[1]);
1285 // Close the pipe (as we have moved the original file descriptors)
1286 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1287 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1290 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1291 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1295 // Drop capabilities
1296 r
= pakfire_jail_drop_capabilities(jail
);
1301 r
= pakfire_jail_limit_syscalls(jail
);
1306 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1308 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1310 // Translate errno into regular exit code
1320 // We should not get here
1324 // Run a command in the jail
1325 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1329 // Check if argv is valid
1330 if (!argv
|| !argv
[0]) {
1335 // Initialize context for this call
1336 struct pakfire_jail_exec ctx
= {
1343 DEBUG(jail
->pakfire
, "Executing jail...\n");
1346 Setup a file descriptor which can be used to notify the client that the parent
1347 has completed configuration.
1349 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1350 if (ctx
.completed_fd
< 0) {
1351 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1355 // Create pipes to communicate with child process if we are not running interactively
1356 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1358 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1363 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1368 // Setup pipes for logging
1370 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1375 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1381 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1384 #endif /* ENABLE_DEBUG */
1386 // Configure child process
1387 struct clone_args args
= {
1396 .exit_signal
= SIGCHLD
,
1397 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1400 // Launch the process in a cgroup that is a leaf of the configured cgroup
1402 args
.flags
|= CLONE_INTO_CGROUP
;
1405 const char* uuid
= pakfire_jail_uuid(jail
);
1407 // Create a temporary cgroup
1408 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
1410 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1414 // Clone into this cgroup
1415 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
1418 // Fork this process
1419 ctx
.pid
= clone3(&args
, sizeof(args
));
1421 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1425 } else if (ctx
.pid
== 0) {
1426 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1431 r
= pakfire_jail_parent(jail
, &ctx
);
1435 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1437 // Read output of the child process
1438 r
= pakfire_jail_wait(jail
, &ctx
);
1442 // Handle exit status
1443 switch (ctx
.status
.si_code
) {
1445 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1446 ctx
.status
.si_status
);
1449 exit
= ctx
.status
.si_status
;
1454 ERROR(jail
->pakfire
, "The child process was killed\n");
1457 // Log anything else
1459 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1464 // Destroy the temporary cgroup (if any)
1466 // Read cgroup stats
1467 r
= pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
1469 ERROR(jail
->pakfire
, "Could not read cgroup stats: %m\n");
1471 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
1474 pakfire_cgroup_destroy(ctx
.cgroup
);
1475 pakfire_cgroup_unref(ctx
.cgroup
);
1478 // Close any file descriptors
1479 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1480 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1483 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1484 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1485 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1490 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1491 const char* argv
[], char** output
) {
1494 // Store logging callback
1495 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1496 void* log_data
= jail
->log_data
;
1498 // Capture output if requested by user
1500 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1503 r
= __pakfire_jail_exec(jail
, argv
);
1505 // Restore log callback
1506 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1511 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1512 const char* script
, const size_t size
, const char* args
[], char** output
) {
1513 char path
[PATH_MAX
];
1514 const char** argv
= NULL
;
1517 const char* root
= pakfire_get_path(jail
->pakfire
);
1519 // Write the scriptlet to disk
1520 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1524 // Open a temporary file
1525 int fd
= mkstemp(path
);
1527 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1532 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1535 ssize_t bytes_written
= write(fd
, script
, size
);
1536 if (bytes_written
< (ssize_t
)size
) {
1537 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1542 // Make the script executable
1543 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1545 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1552 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1557 // Count how many arguments were passed
1558 unsigned int argc
= 1;
1560 for (const char** arg
= args
; *arg
; arg
++)
1564 argv
= calloc(argc
+ 1, sizeof(*argv
));
1566 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1571 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1574 for (unsigned int i
= 1; i
< argc
; i
++)
1575 argv
[i
] = args
[i
-1];
1578 r
= pakfire_jail_exec(jail
, argv
, output
);
1584 // Remove script from disk
1592 A convenience function that creates a new jail, runs the given command and destroys
1595 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
1596 struct pakfire_jail
* jail
= NULL
;
1599 // Create a new jail
1600 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1604 // Execute the command
1605 r
= pakfire_jail_exec(jail
, argv
, output
);
1609 pakfire_jail_unref(jail
);
1614 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1615 const char* script
, const size_t length
, const char* argv
[], int flags
, char** output
) {
1616 struct pakfire_jail
* jail
= NULL
;
1619 // Create a new jail
1620 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1624 // Execute the command
1625 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1629 pakfire_jail_unref(jail
);
1635 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1636 const char* argv
[] = {
1637 "/bin/bash", "--login", NULL
,
1640 // Execute /bin/bash
1641 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1644 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1645 char path
[PATH_MAX
];
1647 const char* ldconfig
= "/sbin/ldconfig";
1649 // Check if ldconfig exists before calling it to avoid overhead
1650 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1654 // Check if ldconfig is executable
1655 r
= access(path
, X_OK
);
1657 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1661 const char* argv
[] = {
1666 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);