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>
26 #include <linux/wait.h>
31 #include <sys/capability.h>
32 #include <sys/epoll.h>
33 #include <sys/eventfd.h>
34 #include <sys/mount.h>
35 #include <sys/personality.h>
36 #include <sys/prctl.h>
37 #include <sys/resource.h>
38 #include <sys/signalfd.h>
39 #include <sys/timerfd.h>
40 #include <sys/types.h>
45 #include <netlink/route/link.h>
53 #include <pakfire/arch.h>
54 #include <pakfire/cgroup.h>
55 #include <pakfire/jail.h>
56 #include <pakfire/logging.h>
57 #include <pakfire/mount.h>
58 #include <pakfire/pakfire.h>
59 #include <pakfire/path.h>
60 #include <pakfire/private.h>
61 #include <pakfire/pwd.h>
62 #include <pakfire/string.h>
63 #include <pakfire/util.h>
65 #define BUFFER_SIZE 1024 * 64
66 #define ENVIRON_SIZE 128
67 #define EPOLL_MAX_EVENTS 2
68 #define MAX_MOUNTPOINTS 8
70 // The default environment that will be set for every command
71 static const struct environ
{
76 { "LANG", "C.utf-8" },
77 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
80 // Tell everything that it is running inside a Pakfire container
81 { "container", "pakfire" },
85 struct pakfire_jail_mountpoint
{
86 char source
[PATH_MAX
];
87 char target
[PATH_MAX
];
92 struct pakfire_ctx
* ctx
;
93 struct pakfire
* pakfire
;
96 // A unique ID for each jail
98 char __uuid
[UUID_STR_LEN
];
104 struct itimerspec timeout
;
107 struct pakfire_cgroup
* cgroup
;
110 char* env
[ENVIRON_SIZE
];
113 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
114 unsigned int num_mountpoints
;
117 struct pakfire_jail_callbacks
{
119 pakfire_jail_log_callback log
;
124 struct pakfire_log_buffer
{
125 char data
[BUFFER_SIZE
];
129 struct pakfire_jail_exec
{
132 // PID (of the child)
136 // Process status (from waitid)
139 // FD to notify the client that the parent has finished initialization
143 struct pakfire_jail_pipes
{
153 #endif /* ENABLE_DEBUG */
157 struct pakfire_jail_communicate
{
158 pakfire_jail_communicate_in in
;
159 pakfire_jail_communicate_out out
;
164 struct pakfire_jail_buffers
{
165 struct pakfire_log_buffer stdout
;
166 struct pakfire_log_buffer stderr
;
169 struct pakfire_log_buffer log_INFO
;
170 struct pakfire_log_buffer log_ERROR
;
172 struct pakfire_log_buffer log_DEBUG
;
173 #endif /* ENABLE_DEBUG */
176 struct pakfire_cgroup
* cgroup
;
177 struct pakfire_cgroup_stats cgroup_stats
;
180 static int clone3(struct clone_args
* args
, size_t size
) {
181 return syscall(__NR_clone3
, args
, size
);
184 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
185 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
188 static int pivot_root(const char* new_root
, const char* old_root
) {
189 return syscall(SYS_pivot_root
, new_root
, old_root
);
192 static int pakfire_jail_exec_has_flag(
193 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
194 return ctx
->flags
& flag
;
197 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
198 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
201 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
205 pakfire_cgroup_unref(jail
->cgroup
);
207 pakfire_unref(jail
->pakfire
);
209 pakfire_ctx_unref(jail
->ctx
);
214 Passes any log messages on to the default pakfire log callback
216 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
217 int priority
, const char* line
, size_t length
) {
220 INFO(pakfire
, "%s", line
);
224 ERROR(pakfire
, "%s", line
);
229 DEBUG(pakfire
, "%s", line
);
237 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
239 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
244 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
246 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
251 char* TERM
= secure_getenv("TERM");
253 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
259 char* LANG
= secure_getenv("LANG");
261 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
269 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
272 const char* arch
= pakfire_get_effective_arch(pakfire
);
274 // Allocate a new jail
275 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
280 j
->ctx
= pakfire_ctx(pakfire
);
283 j
->pakfire
= pakfire_ref(pakfire
);
285 // Initialize reference counter
288 // Generate a random UUID
289 uuid_generate_random(j
->uuid
);
291 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
293 // Set the default logging callback
294 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
296 // Set default environment
297 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
298 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
303 // Enable all CPU features that CPU has to offer
304 if (!pakfire_arch_is_supported_by_host(arch
)) {
305 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
310 // Set container UUID
311 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
315 // Disable systemctl to talk to systemd
316 if (!pakfire_on_root(j
->pakfire
)) {
317 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
327 pakfire_jail_free(j
);
332 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
338 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
339 if (--jail
->nrefs
> 0)
342 pakfire_jail_free(jail
);
348 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
349 pakfire_jail_log_callback callback
, void* data
) {
350 jail
->callbacks
.log
= callback
;
351 jail
->callbacks
.log_data
= data
;
356 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
357 // Check if nice level is in range
358 if (nice
< -19 || nice
> 20) {
369 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
370 // Free any previous cgroup
372 pakfire_cgroup_unref(jail
->cgroup
);
376 // Set any new cgroup
378 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
380 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
389 // Returns the length of the environment
390 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
393 // Count everything in the environment
394 for (char** e
= jail
->env
; *e
; e
++)
400 // Finds an existing environment variable and returns its index or -1 if not found
401 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
407 const size_t length
= strlen(key
);
409 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
410 if ((pakfire_string_startswith(jail
->env
[i
], key
)
411 && *(jail
->env
[i
] + length
) == '=')) {
420 // Returns the value of an environment variable or NULL
421 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
423 int i
= pakfire_jail_find_env(jail
, key
);
427 return jail
->env
[i
] + strlen(key
) + 1;
430 // Sets an environment variable
431 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
432 const char* key
, const char* value
) {
433 // Find the index where to write this value to
434 int i
= pakfire_jail_find_env(jail
, key
);
436 i
= pakfire_jail_env_length(jail
);
438 // Return -ENOSPC when the environment is full
439 if (i
>= ENVIRON_SIZE
) {
444 // Free any previous value
448 // Format and set environment variable
449 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
451 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
456 // Imports an environment
457 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
465 // Copy environment variables
466 for (unsigned int i
= 0; env
[i
]; i
++) {
467 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
472 r
= pakfire_jail_set_env(jail
, key
, val
);
489 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
490 struct pakfire_jail
* jail
, unsigned int timeout
) {
492 jail
->timeout
.it_value
.tv_sec
= timeout
;
495 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
497 DEBUG(jail
->pakfire
, "Timeout disabled\n");
502 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
505 // Nothing to do if no timeout has been set
506 if (!jail
->timeout
.it_value
.tv_sec
)
509 // Create a new timer
510 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
512 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
517 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
519 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
534 static int pakfire_jail_handle_signals(struct pakfire_jail
* jail
) {
539 sigaddset(&mask
, SIGINT
);
542 r
= sigprocmask(SIG_BLOCK
, &mask
, NULL
);
544 ERROR(jail
->pakfire
, "Failed to block signals: %m\n");
548 // Create a file descriptor
549 r
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
551 ERROR(jail
->pakfire
, "Failed to create signalfd: %m\n");
559 This function replaces any logging in the child process.
561 All log messages will be sent to the parent process through their respective pipes.
563 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
564 int line
, const char* fn
, const char* format
, va_list args
) {
565 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
570 fd
= pipes
->log_INFO
[1];
574 fd
= pipes
->log_ERROR
[1];
579 fd
= pipes
->log_DEBUG
[1];
581 #endif /* ENABLE_DEBUG */
583 // Ignore any messages of an unknown priority
588 // Send the log message
590 vdprintf(fd
, format
, args
);
593 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
594 return (sizeof(buffer
->data
) == buffer
->used
);
598 This function reads as much data as it can from the file descriptor.
599 If it finds a whole line in it, it will send it to the logger and repeat the process.
600 If not newline character is found, it will try to read more data until it finds one.
602 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
603 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
604 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
605 char line
[BUFFER_SIZE
+ 1];
607 // Fill up buffer from fd
608 if (buffer
->used
< sizeof(buffer
->data
)) {
609 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
610 sizeof(buffer
->data
) - buffer
->used
);
613 if (bytes_read
< 0) {
614 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
618 // Update buffer size
619 buffer
->used
+= bytes_read
;
622 // See if we have any lines that we can write
623 while (buffer
->used
) {
624 // Search for the end of the first line
625 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
629 // If the buffer is full, we send the content to the logger and try again
630 // This should not happen in practise
631 if (pakfire_jail_log_buffer_is_full(buffer
)) {
632 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
634 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
636 // Otherwise we might have only read parts of the output
641 // Find the length of the string
642 size_t length
= eol
- buffer
->data
+ 1;
644 // Copy the line into the buffer
645 memcpy(line
, buffer
->data
, length
);
647 // Terminate the string
652 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
654 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
659 // Remove line from buffer
660 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
661 buffer
->used
-= length
;
667 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
668 struct pakfire_jail_exec
* ctx
, const int fd
) {
671 // Nothing to do if there is no stdin callback set
672 if (!ctx
->communicate
.in
) {
673 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
677 // Skip if the writing pipe has already been closed
678 if (!ctx
->pipes
.stdin
[1])
681 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
683 // Calling the callback
684 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
686 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
688 // The callback signaled that it has written everything
690 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
692 // Close the file-descriptor
695 // Reset the file-descriptor so it won't be closed again later
696 ctx
->pipes
.stdin
[1] = -1;
705 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
706 int r
= pipe2(*fds
, flags
);
708 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
715 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
716 for (unsigned int i
= 0; i
< 2; i
++)
722 This is a convenience function to fetch the reading end of a pipe and
723 closes the write end.
725 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
726 // Give the variables easier names to avoid confusion
727 int* fd_read
= &(*fds
)[0];
728 int* fd_write
= &(*fds
)[1];
730 // Close the write end of the pipe
731 if (*fd_write
>= 0) {
736 // Return the read end
743 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
744 // Give the variables easier names to avoid confusion
745 int* fd_read
= &(*fds
)[0];
746 int* fd_write
= &(*fds
)[1];
748 // Close the read end of the pipe
754 // Return the write end
761 static int pakfire_jail_log(struct pakfire
* pakfire
, void* data
, int priority
,
762 const char* line
, const size_t length
) {
763 // Pass everything to the parent logger
764 pakfire_log_condition(pakfire
, priority
, 0, "%.*s", (int)length
, line
);
769 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
771 struct epoll_event ev
;
772 struct epoll_event events
[EPOLL_MAX_EVENTS
];
773 struct signalfd_siginfo siginfo
;
777 // Fetch file descriptors from context
778 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
779 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
780 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
781 const int pidfd
= ctx
->pidfd
;
784 const int timerfd
= pakfire_jail_create_timer(jail
);
787 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
788 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
790 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
791 #endif /* ENABLE_DEBUG */
794 const int signalfd
= pakfire_jail_handle_signals(jail
);
796 // Make a list of all file descriptors we are interested in
808 #endif /* ENABLE_DEBUG */
812 epollfd
= epoll_create1(0);
814 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
819 // Turn file descriptors into non-blocking mode and add them to epoll()
820 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
823 // Skip fds which were not initialized
827 ev
.events
= EPOLLHUP
;
830 ev
.events
|= EPOLLOUT
;
832 ev
.events
|= EPOLLIN
;
835 int flags
= fcntl(fd
, F_GETFL
, 0);
837 // Set modified flags
838 if (fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
) < 0) {
840 "Could not set file descriptor %d into non-blocking mode: %m\n", fd
);
847 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
848 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
856 // Loop for as long as the process is alive
858 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
860 // Ignore if epoll_wait() has been interrupted
864 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
870 for (int i
= 0; i
< num
; i
++) {
871 int e
= events
[i
].events
;
872 int fd
= events
[i
].data
.fd
;
874 struct pakfire_log_buffer
* buffer
= NULL
;
875 pakfire_jail_communicate_out callback
= NULL
;
879 // Check if there is any data to be read
881 // Handle any changes to the PIDFD
883 // Call waidid() and store the result
884 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
886 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
890 // Mark that we have ended so that we will process the remaining
891 // events from epoll() now, but won't restart the outer loop.
895 // Handle timer events
896 } else if (fd
== timerfd
) {
897 DEBUG(jail
->pakfire
, "Timer event received\n");
900 r
= read(timerfd
, garbage
, sizeof(garbage
));
902 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
907 // Terminate the process if it hasn't already ended
909 DEBUG(jail
->pakfire
, "Terminating process...\n");
911 // Send SIGTERM to the process
912 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
914 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
919 // There is nothing else to do
923 } else if (fd
== signalfd
) {
925 r
= read(signalfd
, &siginfo
, sizeof(siginfo
));
927 ERROR(jail
->pakfire
, "Could not read signal: %m\n");
931 DEBUG(jail
->pakfire
, "Received signal %u\n", siginfo
.ssi_signo
);
934 switch (siginfo
.ssi_signo
) {
935 // Pass SIGINT down to the child process
937 r
= pidfd_send_signal(pidfd
, siginfo
.ssi_signo
, NULL
, 0);
939 ERROR(jail
->pakfire
, "Could not send signal to process: %m\n");
945 ERROR(jail
->pakfire
, "Received unhandled signal %u\n",
950 // Don't fall through to log processing
953 // Handle logging messages
954 } else if (fd
== log_INFO
) {
955 buffer
= &ctx
->buffers
.log_INFO
;
958 callback
= pakfire_jail_log
;
960 } else if (fd
== log_ERROR
) {
961 buffer
= &ctx
->buffers
.log_ERROR
;
964 callback
= pakfire_jail_log
;
967 } else if (fd
== log_DEBUG
) {
968 buffer
= &ctx
->buffers
.log_DEBUG
;
969 priority
= LOG_DEBUG
;
971 callback
= pakfire_jail_log
;
972 #endif /* ENABLE_DEBUG */
974 // Handle anything from the log pipes
975 } else if (fd
== stdout
) {
976 buffer
= &ctx
->buffers
.stdout
;
979 // Send any output to the default logger if no callback is set
980 if (ctx
->communicate
.out
) {
981 callback
= ctx
->communicate
.out
;
982 data
= ctx
->communicate
.data
;
984 callback
= jail
->callbacks
.log
;
985 data
= jail
->callbacks
.log_data
;
988 } else if (fd
== stderr
) {
989 buffer
= &ctx
->buffers
.stderr
;
992 // Send any output to the default logger if no callback is set
993 if (ctx
->communicate
.out
) {
994 callback
= ctx
->communicate
.out
;
995 data
= ctx
->communicate
.data
;
997 callback
= jail
->callbacks
.log
;
998 data
= jail
->callbacks
.log_data
;
1002 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1007 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
1013 // Handle standard input
1015 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
1018 // Ignore if we filled up the buffer
1023 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
1030 // Check if any file descriptors have been closed
1032 // Remove the file descriptor
1033 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1035 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1053 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1054 int priority
, const char* line
, size_t length
) {
1055 char** output
= (char**)data
;
1058 // Append everything from stdout to a buffer
1059 if (output
&& priority
== LOG_INFO
) {
1060 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
1066 // Send everything else to the default logger
1067 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1072 // Logs all capabilities of the current process
1073 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1076 cap_flag_value_t value_e
;
1077 cap_flag_value_t value_i
;
1078 cap_flag_value_t value_p
;
1082 pid_t pid
= getpid();
1084 // Fetch all capabilities
1085 caps
= cap_get_proc();
1087 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1092 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1094 // Iterate over all capabilities
1095 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1096 name
= cap_to_name(cap
);
1098 // Fetch effective value
1099 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1103 // Fetch inheritable value
1104 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1108 // Fetch permitted value
1109 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1113 DEBUG(jail
->pakfire
,
1114 " %-24s : %c%c%c\n",
1116 (value_e
== CAP_SET
) ? 'e' : '-',
1117 (value_i
== CAP_SET
) ? 'i' : '-',
1118 (value_p
== CAP_SET
) ? 'p' : '-'
1138 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1143 // Fetch capabilities
1144 caps
= cap_get_proc();
1146 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1151 // Walk through all capabilities
1152 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1153 cap_value_t _caps
[] = { cap
};
1155 // Fetch the name of the capability
1156 name
= cap_to_name(cap
);
1158 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1160 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1164 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1166 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1170 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1172 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1181 // Restore all capabilities
1182 r
= cap_set_proc(caps
);
1184 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1188 // Add all capabilities to the ambient set
1189 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1190 name
= cap_to_name(cap
);
1192 // Raise the capability
1193 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1195 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1218 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1219 const int syscalls
[] = {
1220 // The kernel's keyring isn't namespaced
1223 SCMP_SYS(request_key
),
1225 // Disable userfaultfd
1226 SCMP_SYS(userfaultfd
),
1228 // Disable perf which could leak a lot of information about the host
1229 SCMP_SYS(perf_event_open
),
1235 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1237 // Setup a syscall filter which allows everything by default
1238 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1240 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1245 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1246 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1248 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1253 // Load syscall filter into the kernel
1254 r
= seccomp_load(ctx
);
1256 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1262 seccomp_release(ctx
);
1269 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1270 const char* source
, const char* target
, int flags
) {
1271 struct pakfire_jail_mountpoint
* mp
= NULL
;
1274 // Check if there is any space left
1275 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1280 // Check for valid inputs
1281 if (!source
|| !target
) {
1286 // Select the next free slot
1287 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1290 r
= pakfire_string_set(mp
->source
, source
);
1292 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1297 r
= pakfire_string_set(mp
->target
, target
);
1299 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1306 // Increment counter
1307 jail
->num_mountpoints
++;
1312 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1315 const char* paths
[] = {
1321 // Bind-mount all paths read-only
1322 for (const char** path
= paths
; *path
; path
++) {
1323 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1326 // Ignore if we don't have permission
1341 Mounts everything that we require in the new namespace
1343 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1344 struct pakfire_jail_mountpoint
* mp
= NULL
;
1348 // Enable loop devices
1349 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1350 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1352 // Mount all default stuff
1353 r
= pakfire_mount_all(jail
->pakfire
, flags
);
1357 // Mount networking stuff
1358 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1359 r
= pakfire_jail_mount_networking(jail
);
1364 // Mount all custom stuff
1365 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1367 mp
= &jail
->mountpoints
[i
];
1370 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1375 // Log all mountpoints
1376 pakfire_mount_list(jail
->pakfire
);
1383 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1384 struct nl_sock
* nl
= NULL
;
1385 struct nl_cache
* cache
= NULL
;
1386 struct rtnl_link
* link
= NULL
;
1387 struct rtnl_link
* change
= NULL
;
1390 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1392 // Allocate a netlink socket
1393 nl
= nl_socket_alloc();
1395 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1400 // Connect the socket
1401 r
= nl_connect(nl
, NETLINK_ROUTE
);
1403 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1407 // Allocate the netlink cache
1408 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1410 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1414 // Fetch loopback interface
1415 link
= rtnl_link_get_by_name(cache
, "lo");
1417 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1422 // Allocate a new link
1423 change
= rtnl_link_alloc();
1425 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1430 // Set the link to UP
1431 rtnl_link_set_flags(change
, IFF_UP
);
1433 // Apply any changes
1434 r
= rtnl_link_change(nl
, link
, change
, 0);
1436 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1452 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1453 char path
[PATH_MAX
];
1456 // Skip mapping anything when running on /
1457 if (pakfire_on_root(jail
->pakfire
))
1461 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1466 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1469 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1473 /* When running as root, we will map the entire range.
1475 When running as a non-privileged user, we will map the root user inside the jail
1476 to the user's UID outside of the jail, and we will map the rest starting from one.
1481 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1482 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1484 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1485 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1489 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1496 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1497 char path
[PATH_MAX
];
1500 // Skip mapping anything when running on /
1501 if (pakfire_on_root(jail
->pakfire
))
1505 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1508 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1513 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1519 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1520 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1522 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1523 "0 %lu 1\n%1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1527 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1534 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1535 char path
[PATH_MAX
];
1539 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1543 // Open file for writing
1544 FILE* f
= fopen(path
, "w");
1546 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
1551 int bytes_written
= fprintf(f
, "deny\n");
1552 if (bytes_written
<= 0) {
1553 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1560 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1571 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1572 const uint64_t val
= 1;
1575 DEBUG(jail
->pakfire
, "Sending signal...\n");
1577 // Write to the file descriptor
1578 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1579 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1580 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1584 // Close the file descriptor
1590 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1594 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1596 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1597 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1598 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1602 // Close the file descriptor
1609 Performs the initialisation that needs to happen in the parent part
1611 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1614 // Setup UID mapping
1615 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1619 // Write "deny" to /proc/PID/setgroups
1620 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1624 // Setup GID mapping
1625 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1629 // Parent has finished initialisation
1630 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1632 // Send signal to client
1633 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1640 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1643 // Change to the new root
1646 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1651 r
= pivot_root(".", ".");
1653 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1657 // Umount the old root
1658 r
= umount2(".", MNT_DETACH
);
1660 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1667 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1668 const char* argv
[]) {
1671 // Redirect any logging to our log pipe
1672 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
1675 pid_t pid
= getpid();
1677 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1679 // Wait for the parent to finish initialization
1680 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1685 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1687 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1691 // Make this process dumpable
1692 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
1694 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
1698 // Don't drop any capabilities on setuid()
1699 r
= prctl(PR_SET_KEEPCAPS
, 1);
1701 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1706 uid_t uid
= getuid();
1707 gid_t gid
= getgid();
1710 uid_t euid
= geteuid();
1711 gid_t egid
= getegid();
1713 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
1714 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
1716 // Check if we are (effectively running as root)
1717 if (uid
|| gid
|| euid
|| egid
) {
1718 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1722 const char* root
= pakfire_get_path(jail
->pakfire
);
1723 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
1725 // Change mount propagation to slave to receive anything from the parent namespace
1726 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
1730 // Make root a mountpoint in the new mount namespace
1731 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
1735 // Change mount propagation to private
1736 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
1740 // Change root (unless root is /)
1741 if (!pakfire_on_root(jail
->pakfire
)) {
1743 r
= pakfire_jail_mount(jail
, ctx
);
1748 r
= pakfire_jail_switch_root(jail
, root
);
1754 unsigned long persona
= pakfire_arch_personality(arch
);
1756 r
= personality(persona
);
1758 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1764 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1765 r
= pakfire_jail_setup_loopback(jail
);
1772 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1774 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1776 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1781 // Close other end of log pipes
1782 close(ctx
->pipes
.log_INFO
[0]);
1783 close(ctx
->pipes
.log_ERROR
[0]);
1785 close(ctx
->pipes
.log_DEBUG
[0]);
1786 #endif /* ENABLE_DEBUG */
1788 // Connect standard input
1789 if (ctx
->pipes
.stdin
[0] >= 0) {
1790 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
1792 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
1793 ctx
->pipes
.stdin
[0]);
1799 // Connect standard output and error
1800 if (ctx
->pipes
.stdout
[1] >= 0 && ctx
->pipes
.stderr
[1] >= 0) {
1801 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1803 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1804 ctx
->pipes
.stdout
[1]);
1809 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1811 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1812 ctx
->pipes
.stderr
[1]);
1817 // Close the pipe (as we have moved the original file descriptors)
1818 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
1819 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1820 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1823 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1824 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1829 r
= pakfire_jail_set_capabilities(jail
);
1833 // Show capabilities
1834 r
= pakfire_jail_show_capabilities(jail
);
1839 r
= pakfire_jail_limit_syscalls(jail
);
1843 DEBUG(jail
->pakfire
, "Child process initialization done\n");
1844 DEBUG(jail
->pakfire
, "Launching command:\n");
1847 for (unsigned int i
= 0; argv
[i
]; i
++)
1848 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
1851 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1853 // Translate errno into regular exit code
1856 // Ignore if the command doesn't exist
1857 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
1868 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
1871 // We should not get here
1875 // Run a command in the jail
1876 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
1877 const int interactive
,
1878 pakfire_jail_communicate_in communicate_in
,
1879 pakfire_jail_communicate_out communicate_out
,
1880 void* data
, int flags
) {
1884 // Check if argv is valid
1885 if (!argv
|| !argv
[0]) {
1890 // Initialize context for this call
1891 struct pakfire_jail_exec ctx
= {
1895 .stdin
= { -1, -1 },
1896 .stdout
= { -1, -1 },
1897 .stderr
= { -1, -1 },
1898 .log_INFO
= { -1, -1 },
1899 .log_ERROR
= { -1, -1 },
1901 .log_DEBUG
= { -1, -1 },
1902 #endif /* ENABLE_DEBUG */
1906 .in
= communicate_in
,
1907 .out
= communicate_out
,
1914 DEBUG(jail
->pakfire
, "Executing jail...\n");
1916 // Enable networking in interactive mode
1918 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
1921 Setup a file descriptor which can be used to notify the client that the parent
1922 has completed configuration.
1924 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1925 if (ctx
.completed_fd
< 0) {
1926 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1930 // Create pipes to communicate with child process if we are not running interactively
1932 // stdin (only if callback is set)
1933 if (ctx
.communicate
.in
) {
1934 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
1940 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1945 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1950 // Setup pipes for logging
1952 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1957 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1963 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1966 #endif /* ENABLE_DEBUG */
1968 // Configure child process
1969 struct clone_args args
= {
1979 .exit_signal
= SIGCHLD
,
1980 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1983 // Launch the process in a cgroup that is a leaf of the configured cgroup
1985 args
.flags
|= CLONE_INTO_CGROUP
;
1988 const char* uuid
= pakfire_jail_uuid(jail
);
1990 // Create a temporary cgroup
1991 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
1993 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1997 // Clone into this cgroup
1998 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2002 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2003 args
.flags
|= CLONE_NEWNET
;
2006 // Fork this process
2007 ctx
.pid
= clone3(&args
, sizeof(args
));
2009 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2013 } else if (ctx
.pid
== 0) {
2014 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2019 r
= pakfire_jail_parent(jail
, &ctx
);
2023 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2025 // Read output of the child process
2026 r
= pakfire_jail_wait(jail
, &ctx
);
2030 // Handle exit status
2031 switch (ctx
.status
.si_code
) {
2033 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2034 ctx
.status
.si_status
);
2037 exit
= ctx
.status
.si_status
;
2041 ERROR(jail
->pakfire
, "The child process was killed\n");
2046 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2049 // Log anything else
2051 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2056 // Destroy the temporary cgroup (if any)
2058 // Read cgroup stats
2059 r
= pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2061 ERROR(jail
->pakfire
, "Could not read cgroup stats: %m\n");
2063 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2066 pakfire_cgroup_destroy(ctx
.cgroup
);
2067 pakfire_cgroup_unref(ctx
.cgroup
);
2070 // Close any file descriptors
2071 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
2072 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
2073 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
2076 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2077 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2079 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2080 #endif /* ENABLE_DEBUG */
2085 PAKFIRE_EXPORT
int pakfire_jail_exec(
2086 struct pakfire_jail
* jail
,
2088 pakfire_jail_communicate_in callback_in
,
2089 pakfire_jail_communicate_out callback_out
,
2090 void* data
, int flags
) {
2091 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
2094 static int pakfire_jail_exec_interactive(
2095 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2098 // Setup interactive stuff
2099 r
= pakfire_jail_setup_interactive_env(jail
);
2103 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
2106 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2110 pakfire_jail_communicate_in callback_in
,
2111 pakfire_jail_communicate_out callback_out
,
2113 char path
[PATH_MAX
];
2114 const char** argv
= NULL
;
2118 const char* root
= pakfire_get_path(jail
->pakfire
);
2120 // Write the scriptlet to disk
2121 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2125 // Create a temporary file
2126 f
= pakfire_mktemp(path
, 0700);
2128 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2132 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2135 r
= fprintf(f
, "%s", script
);
2137 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2144 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2150 // Count how many arguments were passed
2151 unsigned int argc
= 1;
2153 for (const char** arg
= args
; *arg
; arg
++)
2157 argv
= calloc(argc
+ 1, sizeof(*argv
));
2159 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2164 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2167 for (unsigned int i
= 1; i
< argc
; i
++)
2168 argv
[i
] = args
[i
-1];
2171 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2179 // Remove script from disk
2187 A convenience function that creates a new jail, runs the given command and destroys
2190 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2191 struct pakfire_jail
* jail
= NULL
;
2194 // Create a new jail
2195 r
= pakfire_jail_create(&jail
, pakfire
);
2199 // Execute the command
2200 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2204 pakfire_jail_unref(jail
);
2209 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2210 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2211 struct pakfire_jail
* jail
= NULL
;
2214 // Create a new jail
2215 r
= pakfire_jail_create(&jail
, pakfire
);
2219 // Execute the command
2220 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2224 pakfire_jail_unref(jail
);
2229 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2232 const char* argv
[] = {
2233 "/bin/bash", "--login", NULL
,
2236 // Execute /bin/bash
2237 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2243 // Ignore any return codes from the shell
2247 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2248 char path
[PATH_MAX
];
2251 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2255 // Check if the file is executable
2256 r
= access(path
, X_OK
);
2258 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2262 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2265 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2266 const char* argv
[] = {
2271 return pakfire_jail_run_if_possible(pakfire
, argv
);
2274 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2275 const char* argv
[] = {
2276 "/usr/bin/systemd-tmpfiles",
2281 return pakfire_jail_run_if_possible(pakfire
, argv
);