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 #############################################################################*/
23 #include <linux/capability.h>
24 #include <linux/sched.h>
29 #include <sys/capability.h>
30 #include <sys/epoll.h>
31 #include <sys/eventfd.h>
32 #include <sys/personality.h>
33 #include <sys/prctl.h>
34 #include <sys/types.h>
40 #include <pakfire/arch.h>
41 #include <pakfire/jail.h>
42 #include <pakfire/logging.h>
43 #include <pakfire/mount.h>
44 #include <pakfire/pakfire.h>
45 #include <pakfire/private.h>
46 #include <pakfire/util.h>
48 #define BUFFER_SIZE 1024 * 64
49 #define ENVIRON_SIZE 128
50 #define EPOLL_MAX_EVENTS 2
52 // The default environment that will be set for every command
53 static const struct environ
{
57 { "LANG", "en_US.utf-8" },
63 struct pakfire
* pakfire
;
70 char* env
[ENVIRON_SIZE
];
73 pakfire_jail_log_callback log_callback
;
77 struct pakfire_log_buffer
{
78 char data
[BUFFER_SIZE
];
82 struct pakfire_jail_exec
{
86 // Process status (from waitpid)
89 // FD to notify the client that the parent has finished initialization
100 struct pakfire_log_buffer stdout
;
101 struct pakfire_log_buffer stderr
;
105 static int clone3(struct clone_args
* args
, size_t size
) {
106 return syscall(__NR_clone3
, args
, size
);
109 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
110 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
113 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
116 pakfire_unref(jail
->pakfire
);
120 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
121 int priority
, const char* line
, size_t length
) {
124 INFO(pakfire
, "%s", line
);
128 ERROR(pakfire
, "%s", line
);
135 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
137 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
142 char* TERM
= secure_getenv("TERM");
144 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
150 char* LANG
= secure_getenv("LANG");
152 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
160 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
,
161 struct pakfire
* pakfire
, int flags
) {
164 // Allocate a new jail
165 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
170 j
->pakfire
= pakfire_ref(pakfire
);
172 // Initialize reference counter
178 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
180 // Set default log callback
181 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
185 // Set default environment
186 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
187 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
192 // Setup interactive stuff
193 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
194 r
= pakfire_jail_setup_interactive_env(j
);
204 pakfire_jail_free(j
);
209 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
215 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
216 if (--jail
->nrefs
> 0)
219 pakfire_jail_free(jail
);
223 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
224 return jail
->flags
& flag
;
229 // Returns the length of the environment
230 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
233 // Count everything in the environment
234 for (char** e
= jail
->env
; *e
; e
++)
240 // Finds an existing environment variable and returns its index or -1 if not found
241 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
247 char buffer
[strlen(key
) + 2];
248 pakfire_string_format(buffer
, "%s=", key
);
250 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
251 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
259 // Returns the value of an environment variable or NULL
260 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
262 int i
= pakfire_jail_find_env(jail
, key
);
266 return jail
->env
[i
] + strlen(key
) + 1;
269 // Sets an environment variable
270 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
271 const char* key
, const char* value
) {
272 // Find the index where to write this value to
273 int i
= pakfire_jail_find_env(jail
, key
);
275 i
= pakfire_jail_env_length(jail
);
277 // Return -ENOSPC when the environment is full
278 if (i
>= ENVIRON_SIZE
) {
283 // Free any previous value
287 // Format and set environment variable
288 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
290 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
295 // Imports an environment
296 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
304 // Copy environment variables
305 for (unsigned int i
= 0; env
[i
]; i
++) {
306 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
311 r
= pakfire_jail_set_env(jail
, key
, val
);
328 PAKFIRE_EXPORT
int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
329 pakfire_jail_log_callback callback
, void* data
) {
330 jail
->log_callback
= callback
;
331 jail
->log_data
= data
;
336 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
337 return (sizeof(buffer
->data
) == buffer
->used
);
341 This function reads as much data as it can from the file descriptor.
342 If it finds a whole line in it, it will send it to the logger and repeat the process.
343 If not newline character is found, it will try to read more data until it finds one.
345 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
346 struct pakfire_jail_exec
* ctx
, int priority
, int fd
, struct pakfire_log_buffer
* buffer
) {
347 char line
[BUFFER_SIZE
+ 1];
349 // Fill up buffer from fd
350 if (buffer
->used
< sizeof(buffer
->data
)) {
351 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
352 sizeof(buffer
->data
) - buffer
->used
);
355 if (bytes_read
< 0) {
356 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
360 // Update buffer size
361 buffer
->used
+= bytes_read
;
364 // See if we have any lines that we can write
365 while (buffer
->used
) {
366 // Search for the end of the first line
367 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
371 // If the buffer is full, we send the content to the logger and try again
372 // This should not happen in practise
373 if (pakfire_jail_log_buffer_is_full(buffer
)) {
374 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
376 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
378 // Otherwise we might have only read parts of the output
383 // Find the length of the string
384 size_t length
= eol
- buffer
->data
+ 1;
386 // Copy the line into the buffer
387 memcpy(line
, buffer
->data
, length
);
389 // Terminate the string
393 if (jail
->log_callback
) {
394 int r
= jail
->log_callback(jail
->pakfire
, jail
->log_data
, priority
, line
, length
);
396 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
401 // Remove line from buffer
402 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
403 buffer
->used
-= length
;
409 static int pakfire_jail_logger(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
411 struct epoll_event ev
;
412 struct epoll_event events
[EPOLL_MAX_EVENTS
];
415 // Fetch file descriptors from context
416 const int stdout
= ctx
->pipes
.stdout
[1];
417 const int stderr
= ctx
->pipes
.stderr
[1];
424 epollfd
= epoll_create1(0);
426 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
433 // Turn file descriptors into non-blocking mode and add them to epoll()
434 for (unsigned int i
= 0; i
< 2; i
++) {
439 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
440 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
448 // Loop for as long as the process is alive
450 // If waitpid() returns non-zero, the process has ended, but we want to perform
451 // one last iteration over the loop to read any remaining content from the file
452 // descriptor buffers.
453 r
= waitpid(ctx
->pid
, &ctx
->status
, WNOHANG
);
457 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
459 // Ignore if epoll_wait() has been interrupted
463 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
469 struct pakfire_log_buffer
* buffer
;
472 for (int i
= 0; i
< num
; i
++) {
473 int fd
= events
[i
].data
.fd
;
476 buffer
= &ctx
->buffers
.stdout
;
479 } else if (fd
== stderr
) {
480 buffer
= &ctx
->buffers
.stderr
;
484 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
489 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
);
502 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
503 const char* line
, size_t length
) {
504 char*** array
= (char***)data
;
506 // Append everything from stdout to an array
507 if (priority
== LOG_INFO
) {
510 // Create a copy of line
511 char* message
= strdup(line
);
515 // Remove any trailing newline
516 pakfire_remove_trailing_newline(message
);
518 // Determine the length of the existing array
520 for (char** element
= *array
; *element
; element
++)
525 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
529 // Append message and terminate the array
530 (*array
)[length
] = message
;
531 (*array
)[length
+ 1] = NULL
;
536 // Send everything else to the default logger
537 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
542 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
543 const int capabilities
[] = {
544 // Deny access to the kernel's audit system
549 // Deny suspending block devices
552 // Deny any stuff with BPF
555 // Deny checkpoint restore
556 CAP_CHECKPOINT_RESTORE
,
558 // Deny opening files by inode number (open_by_handle_at)
561 // Deny setting SUID bits
564 // Deny locking more memory
567 // Deny modifying any Apparmor/SELinux/SMACK configuration
571 // Deny creating any special devices
574 // Deny setting any capabilities
577 // Deny reading from syslog
580 // Deny any admin actions (mount, sethostname, ...)
583 // Deny rebooting the system
586 // Deny loading kernel modules
589 // Deny setting nice level
592 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
595 // Deny circumventing any resource limits
598 // Deny setting the system time
601 // Deny playing with suspend
607 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
612 // Drop any capabilities
613 for (const int* cap
= capabilities
; *cap
; cap
++) {
614 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
616 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
623 // Fetch any capabilities
624 cap_t caps
= cap_get_proc();
626 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
631 Set inheritable capabilities
633 This ensures that no processes will be able to gain any of the listed
636 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
638 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
642 // Restore capabilities
643 r
= cap_set_proc(caps
);
645 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
658 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
659 const int syscalls
[] = {
660 // The kernel's keyring isn't namespaced
663 SCMP_SYS(request_key
),
665 // Disable userfaultfd
666 SCMP_SYS(userfaultfd
),
668 // Disable perf which could leak a lot of information about the host
669 SCMP_SYS(perf_event_open
),
675 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
677 // Setup a syscall filter which allows everything by default
678 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
680 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
685 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
686 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
688 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
693 // Load syscall filter into the kernel
694 r
= seccomp_load(ctx
);
696 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
702 seccomp_release(ctx
);
709 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
710 const char* path
, uid_t mapped_id
, size_t length
) {
713 // Open file for writing
714 FILE* f
= fopen(path
, "w");
716 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
720 // Write configuration
721 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
722 if (bytes_written
<= 0) {
723 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
731 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
746 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
750 uid_t mapped_uid
= 0;
751 const size_t length
= 1;
753 // Fetch the UID of the calling process
754 uid_t uid
= getuid();
756 // Have we been called by root?
760 // Have we been called by an unprivileged user?
767 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
771 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
773 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
776 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
780 gid_t mapped_gid
= 0;
781 const size_t length
= 1;
783 // Fetch the GID of the calling process
784 gid_t gid
= getgid();
786 // Have we been called from the root group?
790 // Have we been called by an unprivileged group?
797 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
801 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
803 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
806 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
811 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
815 // Open file for writing
816 FILE* f
= fopen(path
, "w");
818 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
823 int bytes_written
= fprintf(f
, "deny\n");
824 if (bytes_written
<= 0) {
825 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
832 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
843 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
844 const uint64_t val
= 1;
847 DEBUG(jail
->pakfire
, "Sending signal...\n");
849 // Write to the file descriptor
850 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
851 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
852 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
856 // Close the file descriptor
862 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
866 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
868 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
869 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
870 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
874 // Close the file descriptor
881 Performs the initialisation that needs to happen in the parent part
883 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
887 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
891 // Write "deny" to /proc/PID/setgroups
892 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
897 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
901 // Parent has finished initialisation
902 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
904 // Send signal to client
905 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
912 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
913 const char* argv
[]) {
916 // XXX do we have to reconfigure logging here?
918 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", getpid());
920 // Wait for the parent to finish initialization
921 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
925 // Perform further initialization
928 uid_t uid
= getuid();
929 gid_t gid
= getgid();
932 uid_t euid
= geteuid();
933 gid_t egid
= getegid();
935 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
936 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
938 // Check if we are (effectively running as root)
939 if (uid
!= 0 || gid
!= 0) {
940 ERROR(jail
->pakfire
, "Child process is not running as root\n");
944 const char* root
= pakfire_get_path(jail
->pakfire
);
945 const char* arch
= pakfire_get_arch(jail
->pakfire
);
947 // Change root (unless root is /)
948 if (!pakfire_on_root(jail
->pakfire
)) {
950 r
= pakfire_mount_all(jail
->pakfire
);
954 // Log all mountpoints
955 pakfire_mount_list(jail
->pakfire
);
960 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
964 // Change directory to /
967 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
973 unsigned long persona
= pakfire_arch_personality(arch
);
975 r
= personality(persona
);
977 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
982 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
983 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
988 r
= pakfire_jail_drop_capabilities(jail
);
993 r
= pakfire_jail_limit_syscalls(jail
);
998 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1000 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
1002 // Translate errno into regular exit code
1012 // We should not get here
1016 // Run a command in the jail
1017 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1021 // Check if argv is valid
1022 if (!argv
|| !argv
[0]) {
1027 // Initialize context for this call
1028 struct pakfire_jail_exec ctx
= {
1030 .stdout
= { 0, 0, },
1031 .stderr
= { 0, 0, },
1036 DEBUG(jail
->pakfire
, "Executing jail...\n");
1039 Setup a file descriptor which can be used to notify the client that the parent
1040 has completed configuration.
1042 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1043 if (ctx
.completed_fd
< 0) {
1044 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1048 // Create pipes to communicate with child process if we are not running interactively
1049 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1051 r
= pipe2(ctx
.pipes
.stdout
, O_NONBLOCK
);
1053 ERROR(jail
->pakfire
, "Could not create file descriptors for stdout: %m\n");
1058 r
= pipe2(ctx
.pipes
.stderr
, O_NONBLOCK
);
1060 ERROR(jail
->pakfire
, "Could not create file descriptors for stderr: %m\n");
1065 // Configure child process
1066 struct clone_args args
= {
1074 .exit_signal
= SIGCHLD
,
1077 // Fork this process
1078 ctx
.pid
= clone3(&args
, sizeof(args
));
1080 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1084 } else if (ctx
.pid
== 0) {
1085 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1090 r
= pakfire_jail_parent(jail
, &ctx
);
1094 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1096 // Read output of the child process
1097 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1098 r
= pakfire_jail_logger(jail
, &ctx
);
1100 ERROR(jail
->pakfire
, "Log reading aborted: %m\n");
1104 waitpid(ctx
.pid
, &ctx
.status
, 0);
1106 if (WIFEXITED(ctx
.status
)) {
1107 exit
= WEXITSTATUS(ctx
.status
);
1109 DEBUG(jail
->pakfire
, "Child process exited with code: %d\n", exit
);
1111 ERROR(jail
->pakfire
, "Could not determine the exit status of process %d\n", ctx
.pid
);
1118 // Close any file descriptors
1119 if (ctx
.pipes
.stdout
[0])
1120 close(ctx
.pipes
.stdout
[0]);
1121 if (ctx
.pipes
.stdout
[1])
1122 close(ctx
.pipes
.stdout
[1]);
1123 if (ctx
.pipes
.stderr
[0])
1124 close(ctx
.pipes
.stderr
[0]);
1125 if (ctx
.pipes
.stderr
[1])
1126 close(ctx
.pipes
.stderr
[1]);
1128 // Umount everything
1129 if (!pakfire_on_root(jail
->pakfire
))
1130 pakfire_umount_all(jail
->pakfire
);
1135 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
,
1136 const char* argv
[], char*** output
) {
1139 // Store logging callback
1140 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1141 void* log_data
= jail
->log_data
;
1143 // Capture output if requested by user
1145 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1148 r
= __pakfire_jail_exec(jail
, argv
);
1150 // Restore log callback
1151 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1156 PAKFIRE_EXPORT
int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1157 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1158 char path
[PATH_MAX
];
1159 const char** argv
= NULL
;
1162 const char* root
= pakfire_get_path(jail
->pakfire
);
1164 // Write the scriptlet to disk
1165 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1169 // Open a temporary file
1170 int fd
= mkstemp(path
);
1172 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1177 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1180 ssize_t bytes_written
= write(fd
, script
, size
);
1181 if (bytes_written
< (ssize_t
)size
) {
1182 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1187 // Make the script executable
1188 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1190 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1197 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1202 // Count how many arguments were passed
1203 unsigned int argc
= 1;
1205 for (const char** arg
= args
; *arg
; arg
++)
1209 argv
= calloc(argc
+ 1, sizeof(*argv
));
1211 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1216 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1219 for (unsigned int i
= 1; i
< argc
; i
++)
1220 argv
[i
] = args
[i
-1];
1223 r
= pakfire_jail_exec(jail
, argv
, output
);
1229 // Remove script from disk
1237 A convenience function that creates a new jail, runs the given command and destroys
1240 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char*** output
) {
1241 struct pakfire_jail
* jail
= NULL
;
1244 // Create a new jail
1245 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1249 // Execute the command
1250 r
= pakfire_jail_exec(jail
, argv
, output
);
1254 pakfire_jail_unref(jail
);
1259 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1260 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1261 struct pakfire_jail
* jail
= NULL
;
1264 // Create a new jail
1265 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1269 // Execute the command
1270 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1274 pakfire_jail_unref(jail
);
1280 int pakfire_jail_shell(struct pakfire
* pakfire
) {
1281 const char* argv
[] = {
1282 "/bin/bash", "--login", NULL
,
1285 // Execute /bin/bash
1286 return pakfire_jail_run(pakfire
, argv
, PAKFIRE_JAIL_INTERACTIVE
, NULL
);
1289 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
1290 char path
[PATH_MAX
];
1292 const char* ldconfig
= "/sbin/ldconfig";
1294 // Check if ldconfig exists before calling it to avoid overhead
1295 int r
= pakfire_make_path(pakfire
, path
, ldconfig
);
1299 // Check if ldconfig is executable
1300 r
= access(path
, X_OK
);
1302 DEBUG(pakfire
, "%s is not executable. Skipping...\n", ldconfig
);
1306 const char* argv
[] = {
1311 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);