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
{
155 struct pakfire_jail_communicate
{
156 pakfire_jail_communicate_in in
;
157 pakfire_jail_communicate_out out
;
162 struct pakfire_jail_buffers
{
163 struct pakfire_log_buffer stdout
;
164 struct pakfire_log_buffer stderr
;
167 struct pakfire_log_buffer log_INFO
;
168 struct pakfire_log_buffer log_ERROR
;
169 struct pakfire_log_buffer log_DEBUG
;
172 struct pakfire_cgroup
* cgroup
;
173 struct pakfire_cgroup_stats cgroup_stats
;
176 static int clone3(struct clone_args
* args
, size_t size
) {
177 return syscall(__NR_clone3
, args
, size
);
180 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
181 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
184 static int pivot_root(const char* new_root
, const char* old_root
) {
185 return syscall(SYS_pivot_root
, new_root
, old_root
);
188 static int pakfire_jail_exec_has_flag(
189 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
190 return ctx
->flags
& flag
;
193 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
194 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
197 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
201 pakfire_cgroup_unref(jail
->cgroup
);
203 pakfire_unref(jail
->pakfire
);
205 pakfire_ctx_unref(jail
->ctx
);
210 Passes any log messages on to the default pakfire log callback
212 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
213 int priority
, const char* line
, size_t length
) {
216 INFO(pakfire
, "%s", line
);
220 ERROR(pakfire
, "%s", line
);
225 DEBUG(pakfire
, "%s", line
);
233 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
235 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
240 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
242 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
247 char* TERM
= secure_getenv("TERM");
249 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
255 char* LANG
= secure_getenv("LANG");
257 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
265 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
268 const char* arch
= pakfire_get_effective_arch(pakfire
);
270 // Allocate a new jail
271 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
276 j
->ctx
= pakfire_ctx(pakfire
);
279 j
->pakfire
= pakfire_ref(pakfire
);
281 // Initialize reference counter
284 // Generate a random UUID
285 uuid_generate_random(j
->uuid
);
287 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
289 // Set the default logging callback
290 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
292 // Set default environment
293 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
294 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
299 // Enable all CPU features that CPU has to offer
300 if (!pakfire_arch_is_supported_by_host(arch
)) {
301 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
306 // Set container UUID
307 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
311 // Disable systemctl to talk to systemd
312 if (!pakfire_on_root(j
->pakfire
)) {
313 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
323 pakfire_jail_free(j
);
328 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
334 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
335 if (--jail
->nrefs
> 0)
338 pakfire_jail_free(jail
);
344 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
345 pakfire_jail_log_callback callback
, void* data
) {
346 jail
->callbacks
.log
= callback
;
347 jail
->callbacks
.log_data
= data
;
352 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
353 // Check if nice level is in range
354 if (nice
< -19 || nice
> 20) {
365 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
366 // Free any previous cgroup
368 pakfire_cgroup_unref(jail
->cgroup
);
372 // Set any new cgroup
374 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
376 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
385 // Returns the length of the environment
386 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
389 // Count everything in the environment
390 for (char** e
= jail
->env
; *e
; e
++)
396 // Finds an existing environment variable and returns its index or -1 if not found
397 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
403 const size_t length
= strlen(key
);
405 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
406 if ((pakfire_string_startswith(jail
->env
[i
], key
)
407 && *(jail
->env
[i
] + length
) == '=')) {
416 // Returns the value of an environment variable or NULL
417 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
419 int i
= pakfire_jail_find_env(jail
, key
);
423 return jail
->env
[i
] + strlen(key
) + 1;
426 // Sets an environment variable
427 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
428 const char* key
, const char* value
) {
429 // Find the index where to write this value to
430 int i
= pakfire_jail_find_env(jail
, key
);
432 i
= pakfire_jail_env_length(jail
);
434 // Return -ENOSPC when the environment is full
435 if (i
>= ENVIRON_SIZE
) {
440 // Free any previous value
444 // Format and set environment variable
445 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
447 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
452 // Imports an environment
453 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
461 // Copy environment variables
462 for (unsigned int i
= 0; env
[i
]; i
++) {
463 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
468 r
= pakfire_jail_set_env(jail
, key
, val
);
485 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
486 struct pakfire_jail
* jail
, unsigned int timeout
) {
488 jail
->timeout
.it_value
.tv_sec
= timeout
;
491 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
493 DEBUG(jail
->pakfire
, "Timeout disabled\n");
498 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
501 // Nothing to do if no timeout has been set
502 if (!jail
->timeout
.it_value
.tv_sec
)
505 // Create a new timer
506 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
508 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
513 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
515 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
530 static int pakfire_jail_handle_signals(struct pakfire_jail
* jail
) {
535 sigaddset(&mask
, SIGINT
);
538 r
= sigprocmask(SIG_BLOCK
, &mask
, NULL
);
540 ERROR(jail
->pakfire
, "Failed to block signals: %m\n");
544 // Create a file descriptor
545 r
= signalfd(-1, &mask
, SFD_NONBLOCK
|SFD_CLOEXEC
);
547 ERROR(jail
->pakfire
, "Failed to create signalfd: %m\n");
555 This function replaces any logging in the child process.
557 All log messages will be sent to the parent process through their respective pipes.
559 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
560 int line
, const char* fn
, const char* format
, va_list args
) {
561 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
566 fd
= pipes
->log_INFO
[1];
570 fd
= pipes
->log_ERROR
[1];
575 fd
= pipes
->log_DEBUG
[1];
577 #endif /* ENABLE_DEBUG */
579 // Ignore any messages of an unknown priority
584 // Send the log message
586 vdprintf(fd
, format
, args
);
589 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
590 return (sizeof(buffer
->data
) == buffer
->used
);
594 This function reads as much data as it can from the file descriptor.
595 If it finds a whole line in it, it will send it to the logger and repeat the process.
596 If not newline character is found, it will try to read more data until it finds one.
598 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
599 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
600 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
601 char line
[BUFFER_SIZE
+ 1];
603 // Fill up buffer from fd
604 if (buffer
->used
< sizeof(buffer
->data
)) {
605 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
606 sizeof(buffer
->data
) - buffer
->used
);
609 if (bytes_read
< 0) {
610 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
614 // Update buffer size
615 buffer
->used
+= bytes_read
;
618 // See if we have any lines that we can write
619 while (buffer
->used
) {
620 // Search for the end of the first line
621 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
625 // If the buffer is full, we send the content to the logger and try again
626 // This should not happen in practise
627 if (pakfire_jail_log_buffer_is_full(buffer
)) {
628 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
630 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
632 // Otherwise we might have only read parts of the output
637 // Find the length of the string
638 size_t length
= eol
- buffer
->data
+ 1;
640 // Copy the line into the buffer
641 memcpy(line
, buffer
->data
, length
);
643 // Terminate the string
648 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
650 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
655 // Remove line from buffer
656 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
657 buffer
->used
-= length
;
663 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
664 struct pakfire_jail_exec
* ctx
, const int fd
) {
667 // Nothing to do if there is no stdin callback set
668 if (!ctx
->communicate
.in
) {
669 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
673 // Skip if the writing pipe has already been closed
674 if (!ctx
->pipes
.stdin
[1])
677 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
679 // Calling the callback
680 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
682 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
684 // The callback signaled that it has written everything
686 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
688 // Close the file-descriptor
691 // Reset the file-descriptor so it won't be closed again later
692 ctx
->pipes
.stdin
[1] = -1;
701 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
702 int r
= pipe2(*fds
, flags
);
704 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
711 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
712 for (unsigned int i
= 0; i
< 2; i
++)
718 This is a convenience function to fetch the reading end of a pipe and
719 closes the write end.
721 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
722 // Give the variables easier names to avoid confusion
723 int* fd_read
= &(*fds
)[0];
724 int* fd_write
= &(*fds
)[1];
726 // Close the write end of the pipe
727 if (*fd_write
>= 0) {
732 // Return the read end
739 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
740 // Give the variables easier names to avoid confusion
741 int* fd_read
= &(*fds
)[0];
742 int* fd_write
= &(*fds
)[1];
744 // Close the read end of the pipe
750 // Return the write end
757 static int pakfire_jail_log(struct pakfire
* pakfire
, void* data
, int priority
,
758 const char* line
, const size_t length
) {
759 // Pass everything to the parent logger
760 pakfire_log_condition(pakfire
, priority
, 0, "%.*s", (int)length
, line
);
765 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
767 struct epoll_event ev
;
768 struct epoll_event events
[EPOLL_MAX_EVENTS
];
769 struct signalfd_siginfo siginfo
;
773 // Fetch file descriptors from context
774 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
775 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
776 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
777 const int pidfd
= ctx
->pidfd
;
780 const int timerfd
= pakfire_jail_create_timer(jail
);
783 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
784 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
785 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
788 const int signalfd
= pakfire_jail_handle_signals(jail
);
790 // Make a list of all file descriptors we are interested in
792 stdin
, stdout
, stderr
, pidfd
, timerfd
, signalfd
, log_INFO
, log_ERROR
, log_DEBUG
,
796 epollfd
= epoll_create1(0);
798 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
803 // Turn file descriptors into non-blocking mode and add them to epoll()
804 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
807 // Skip fds which were not initialized
811 ev
.events
= EPOLLHUP
;
814 ev
.events
|= EPOLLOUT
;
816 ev
.events
|= EPOLLIN
;
819 int flags
= fcntl(fd
, F_GETFL
, 0);
821 // Set modified flags
822 if (fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
) < 0) {
824 "Could not set file descriptor %d into non-blocking mode: %m\n", fd
);
831 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
832 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
840 // Loop for as long as the process is alive
842 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
844 // Ignore if epoll_wait() has been interrupted
848 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
854 for (int i
= 0; i
< num
; i
++) {
855 int e
= events
[i
].events
;
856 int fd
= events
[i
].data
.fd
;
858 struct pakfire_log_buffer
* buffer
= NULL
;
859 pakfire_jail_communicate_out callback
= NULL
;
863 // Check if there is any data to be read
865 // Handle any changes to the PIDFD
867 // Call waidid() and store the result
868 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
870 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
874 // Mark that we have ended so that we will process the remaining
875 // events from epoll() now, but won't restart the outer loop.
879 // Handle timer events
880 } else if (fd
== timerfd
) {
881 DEBUG(jail
->pakfire
, "Timer event received\n");
884 r
= read(timerfd
, garbage
, sizeof(garbage
));
886 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
891 // Terminate the process if it hasn't already ended
893 DEBUG(jail
->pakfire
, "Terminating process...\n");
895 // Send SIGTERM to the process
896 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
898 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
903 // There is nothing else to do
907 } else if (fd
== signalfd
) {
909 r
= read(signalfd
, &siginfo
, sizeof(siginfo
));
911 ERROR(jail
->pakfire
, "Could not read signal: %m\n");
915 DEBUG(jail
->pakfire
, "Received signal %u\n", siginfo
.ssi_signo
);
918 switch (siginfo
.ssi_signo
) {
919 // Pass SIGINT down to the child process
921 r
= pidfd_send_signal(pidfd
, siginfo
.ssi_signo
, NULL
, 0);
923 ERROR(jail
->pakfire
, "Could not send signal to process: %m\n");
929 ERROR(jail
->pakfire
, "Received unhandled signal %u\n",
934 // Don't fall through to log processing
937 // Handle logging messages
938 } else if (fd
== log_INFO
) {
939 buffer
= &ctx
->buffers
.log_INFO
;
942 callback
= pakfire_jail_log
;
944 } else if (fd
== log_ERROR
) {
945 buffer
= &ctx
->buffers
.log_ERROR
;
948 callback
= pakfire_jail_log
;
950 } else if (fd
== log_DEBUG
) {
951 buffer
= &ctx
->buffers
.log_DEBUG
;
952 priority
= LOG_DEBUG
;
954 callback
= pakfire_jail_log
;
956 // Handle anything from the log pipes
957 } else if (fd
== stdout
) {
958 buffer
= &ctx
->buffers
.stdout
;
961 // Send any output to the default logger if no callback is set
962 if (ctx
->communicate
.out
) {
963 callback
= ctx
->communicate
.out
;
964 data
= ctx
->communicate
.data
;
966 callback
= jail
->callbacks
.log
;
967 data
= jail
->callbacks
.log_data
;
970 } else if (fd
== stderr
) {
971 buffer
= &ctx
->buffers
.stderr
;
974 // Send any output to the default logger if no callback is set
975 if (ctx
->communicate
.out
) {
976 callback
= ctx
->communicate
.out
;
977 data
= ctx
->communicate
.data
;
979 callback
= jail
->callbacks
.log
;
980 data
= jail
->callbacks
.log_data
;
984 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
989 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
995 // Handle standard input
997 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
1000 // Ignore if we filled up the buffer
1005 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
1012 // Check if any file descriptors have been closed
1014 // Remove the file descriptor
1015 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1017 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1035 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1036 int priority
, const char* line
, size_t length
) {
1037 char** output
= (char**)data
;
1040 // Append everything from stdout to a buffer
1041 if (output
&& priority
== LOG_INFO
) {
1042 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
1048 // Send everything else to the default logger
1049 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1054 // Logs all capabilities of the current process
1055 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1058 cap_flag_value_t value_e
;
1059 cap_flag_value_t value_i
;
1060 cap_flag_value_t value_p
;
1064 pid_t pid
= getpid();
1066 // Fetch all capabilities
1067 caps
= cap_get_proc();
1069 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1074 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1076 // Iterate over all capabilities
1077 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1078 name
= cap_to_name(cap
);
1080 // Fetch effective value
1081 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1085 // Fetch inheritable value
1086 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1090 // Fetch permitted value
1091 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1095 DEBUG(jail
->pakfire
,
1096 " %-24s : %c%c%c\n",
1098 (value_e
== CAP_SET
) ? 'e' : '-',
1099 (value_i
== CAP_SET
) ? 'i' : '-',
1100 (value_p
== CAP_SET
) ? 'p' : '-'
1120 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1125 // Fetch capabilities
1126 caps
= cap_get_proc();
1128 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1133 // Walk through all capabilities
1134 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1135 cap_value_t _caps
[] = { cap
};
1137 // Fetch the name of the capability
1138 name
= cap_to_name(cap
);
1140 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1142 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1146 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1148 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1152 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1154 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1163 // Restore all capabilities
1164 r
= cap_set_proc(caps
);
1166 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1170 // Add all capabilities to the ambient set
1171 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1172 name
= cap_to_name(cap
);
1174 // Raise the capability
1175 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1177 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1200 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1201 const int syscalls
[] = {
1202 // The kernel's keyring isn't namespaced
1205 SCMP_SYS(request_key
),
1207 // Disable userfaultfd
1208 SCMP_SYS(userfaultfd
),
1210 // Disable perf which could leak a lot of information about the host
1211 SCMP_SYS(perf_event_open
),
1217 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1219 // Setup a syscall filter which allows everything by default
1220 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1222 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1227 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1228 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1230 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1235 // Load syscall filter into the kernel
1236 r
= seccomp_load(ctx
);
1238 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1244 seccomp_release(ctx
);
1251 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1252 const char* source
, const char* target
, int flags
) {
1253 struct pakfire_jail_mountpoint
* mp
= NULL
;
1256 // Check if there is any space left
1257 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1262 // Check for valid inputs
1263 if (!source
|| !target
) {
1268 // Select the next free slot
1269 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1272 r
= pakfire_string_set(mp
->source
, source
);
1274 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1279 r
= pakfire_string_set(mp
->target
, target
);
1281 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1288 // Increment counter
1289 jail
->num_mountpoints
++;
1294 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1297 const char* paths
[] = {
1303 // Bind-mount all paths read-only
1304 for (const char** path
= paths
; *path
; path
++) {
1305 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1308 // Ignore if we don't have permission
1323 Mounts everything that we require in the new namespace
1325 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1326 struct pakfire_jail_mountpoint
* mp
= NULL
;
1330 // Enable loop devices
1331 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1332 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1334 // Mount all default stuff
1335 r
= pakfire_mount_all(jail
->pakfire
, flags
);
1339 // Mount networking stuff
1340 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1341 r
= pakfire_jail_mount_networking(jail
);
1346 // Mount all custom stuff
1347 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1349 mp
= &jail
->mountpoints
[i
];
1352 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1357 // Log all mountpoints
1358 pakfire_mount_list(jail
->pakfire
);
1365 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1366 struct nl_sock
* nl
= NULL
;
1367 struct nl_cache
* cache
= NULL
;
1368 struct rtnl_link
* link
= NULL
;
1369 struct rtnl_link
* change
= NULL
;
1372 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1374 // Allocate a netlink socket
1375 nl
= nl_socket_alloc();
1377 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1382 // Connect the socket
1383 r
= nl_connect(nl
, NETLINK_ROUTE
);
1385 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1389 // Allocate the netlink cache
1390 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1392 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1396 // Fetch loopback interface
1397 link
= rtnl_link_get_by_name(cache
, "lo");
1399 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1404 // Allocate a new link
1405 change
= rtnl_link_alloc();
1407 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1412 // Set the link to UP
1413 rtnl_link_set_flags(change
, IFF_UP
);
1415 // Apply any changes
1416 r
= rtnl_link_change(nl
, link
, change
, 0);
1418 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1434 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1435 char path
[PATH_MAX
];
1438 // Skip mapping anything when running on /
1439 if (pakfire_on_root(jail
->pakfire
))
1443 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1448 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1451 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1455 /* When running as root, we will map the entire range.
1457 When running as a non-privileged user, we will map the root user inside the jail
1458 to the user's UID outside of the jail, and we will map the rest starting from one.
1463 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1464 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1466 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1467 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1471 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1478 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1479 char path
[PATH_MAX
];
1482 // Skip mapping anything when running on /
1483 if (pakfire_on_root(jail
->pakfire
))
1487 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1490 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1495 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1501 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1502 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1504 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1505 "0 %lu 1\n%1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1509 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1516 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1517 char path
[PATH_MAX
];
1521 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1525 // Open file for writing
1526 FILE* f
= fopen(path
, "w");
1528 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
1533 int bytes_written
= fprintf(f
, "deny\n");
1534 if (bytes_written
<= 0) {
1535 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1542 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1553 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1554 const uint64_t val
= 1;
1557 DEBUG(jail
->pakfire
, "Sending signal...\n");
1559 // Write to the file descriptor
1560 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1561 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1562 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1566 // Close the file descriptor
1572 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1576 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1578 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1579 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1580 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1584 // Close the file descriptor
1591 Performs the initialisation that needs to happen in the parent part
1593 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1596 // Setup UID mapping
1597 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1601 // Write "deny" to /proc/PID/setgroups
1602 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1606 // Setup GID mapping
1607 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1611 // Parent has finished initialisation
1612 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1614 // Send signal to client
1615 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1622 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1625 // Change to the new root
1628 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1633 r
= pivot_root(".", ".");
1635 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1639 // Umount the old root
1640 r
= umount2(".", MNT_DETACH
);
1642 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1649 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1650 const char* argv
[]) {
1653 // Redirect any logging to our log pipe
1654 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
1657 pid_t pid
= getpid();
1659 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1661 // Wait for the parent to finish initialization
1662 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1667 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1669 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1673 // Make this process dumpable
1674 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
1676 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
1680 // Don't drop any capabilities on setuid()
1681 r
= prctl(PR_SET_KEEPCAPS
, 1);
1683 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1688 uid_t uid
= getuid();
1689 gid_t gid
= getgid();
1692 uid_t euid
= geteuid();
1693 gid_t egid
= getegid();
1695 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
1696 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
1698 // Check if we are (effectively running as root)
1699 if (uid
|| gid
|| euid
|| egid
) {
1700 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1704 const char* root
= pakfire_get_path(jail
->pakfire
);
1705 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
1707 // Change mount propagation to slave to receive anything from the parent namespace
1708 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
1712 // Make root a mountpoint in the new mount namespace
1713 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
1717 // Change mount propagation to private
1718 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
1722 // Change root (unless root is /)
1723 if (!pakfire_on_root(jail
->pakfire
)) {
1725 r
= pakfire_jail_mount(jail
, ctx
);
1730 r
= pakfire_jail_switch_root(jail
, root
);
1736 unsigned long persona
= pakfire_arch_personality(arch
);
1738 r
= personality(persona
);
1740 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1746 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1747 r
= pakfire_jail_setup_loopback(jail
);
1754 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1756 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1758 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1763 // Close other end of log pipes
1764 close(ctx
->pipes
.log_INFO
[0]);
1765 close(ctx
->pipes
.log_ERROR
[0]);
1767 close(ctx
->pipes
.log_DEBUG
[0]);
1768 #endif /* ENABLE_DEBUG */
1770 // Connect standard input
1771 if (ctx
->pipes
.stdin
[0] >= 0) {
1772 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
1774 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
1775 ctx
->pipes
.stdin
[0]);
1781 // Connect standard output and error
1782 if (ctx
->pipes
.stdout
[1] >= 0 && ctx
->pipes
.stderr
[1] >= 0) {
1783 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1785 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1786 ctx
->pipes
.stdout
[1]);
1791 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1793 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1794 ctx
->pipes
.stderr
[1]);
1799 // Close the pipe (as we have moved the original file descriptors)
1800 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
1801 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1802 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1805 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1806 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1811 r
= pakfire_jail_set_capabilities(jail
);
1815 // Show capabilities
1816 r
= pakfire_jail_show_capabilities(jail
);
1821 r
= pakfire_jail_limit_syscalls(jail
);
1825 DEBUG(jail
->pakfire
, "Child process initialization done\n");
1826 DEBUG(jail
->pakfire
, "Launching command:\n");
1829 for (unsigned int i
= 0; argv
[i
]; i
++)
1830 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
1833 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1835 // Translate errno into regular exit code
1838 // Ignore if the command doesn't exist
1839 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
1850 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
1853 // We should not get here
1857 // Run a command in the jail
1858 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
1859 const int interactive
,
1860 pakfire_jail_communicate_in communicate_in
,
1861 pakfire_jail_communicate_out communicate_out
,
1862 void* data
, int flags
) {
1866 // Check if argv is valid
1867 if (!argv
|| !argv
[0]) {
1872 // Initialize context for this call
1873 struct pakfire_jail_exec ctx
= {
1877 .stdin
= { -1, -1 },
1878 .stdout
= { -1, -1 },
1879 .stderr
= { -1, -1 },
1880 .log_INFO
= { -1, -1 },
1881 .log_ERROR
= { -1, -1 },
1882 .log_DEBUG
= { -1, -1 },
1886 .in
= communicate_in
,
1887 .out
= communicate_out
,
1894 DEBUG(jail
->pakfire
, "Executing jail...\n");
1896 // Enable networking in interactive mode
1898 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
1901 Setup a file descriptor which can be used to notify the client that the parent
1902 has completed configuration.
1904 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1905 if (ctx
.completed_fd
< 0) {
1906 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1910 // Create pipes to communicate with child process if we are not running interactively
1912 // stdin (only if callback is set)
1913 if (ctx
.communicate
.in
) {
1914 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
1920 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1925 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1930 // Setup pipes for logging
1932 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1937 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1943 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1946 #endif /* ENABLE_DEBUG */
1948 // Configure child process
1949 struct clone_args args
= {
1959 .exit_signal
= SIGCHLD
,
1960 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1963 // Launch the process in a cgroup that is a leaf of the configured cgroup
1965 args
.flags
|= CLONE_INTO_CGROUP
;
1968 const char* uuid
= pakfire_jail_uuid(jail
);
1970 // Create a temporary cgroup
1971 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
1973 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1977 // Clone into this cgroup
1978 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
1982 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1983 args
.flags
|= CLONE_NEWNET
;
1986 // Fork this process
1987 ctx
.pid
= clone3(&args
, sizeof(args
));
1989 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1993 } else if (ctx
.pid
== 0) {
1994 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1999 r
= pakfire_jail_parent(jail
, &ctx
);
2003 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2005 // Read output of the child process
2006 r
= pakfire_jail_wait(jail
, &ctx
);
2010 // Handle exit status
2011 switch (ctx
.status
.si_code
) {
2013 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2014 ctx
.status
.si_status
);
2017 exit
= ctx
.status
.si_status
;
2021 ERROR(jail
->pakfire
, "The child process was killed\n");
2026 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2029 // Log anything else
2031 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2036 // Destroy the temporary cgroup (if any)
2038 // Read cgroup stats
2039 r
= pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2041 ERROR(jail
->pakfire
, "Could not read cgroup stats: %m\n");
2043 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2046 pakfire_cgroup_destroy(ctx
.cgroup
);
2047 pakfire_cgroup_unref(ctx
.cgroup
);
2050 // Close any file descriptors
2051 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
2052 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
2053 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
2056 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2057 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2058 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2063 PAKFIRE_EXPORT
int pakfire_jail_exec(
2064 struct pakfire_jail
* jail
,
2066 pakfire_jail_communicate_in callback_in
,
2067 pakfire_jail_communicate_out callback_out
,
2068 void* data
, int flags
) {
2069 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
2072 static int pakfire_jail_exec_interactive(
2073 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2076 // Setup interactive stuff
2077 r
= pakfire_jail_setup_interactive_env(jail
);
2081 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
2084 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2088 pakfire_jail_communicate_in callback_in
,
2089 pakfire_jail_communicate_out callback_out
,
2091 char path
[PATH_MAX
];
2092 const char** argv
= NULL
;
2096 const char* root
= pakfire_get_path(jail
->pakfire
);
2098 // Write the scriptlet to disk
2099 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2103 // Create a temporary file
2104 f
= pakfire_mktemp(path
, 0700);
2106 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2110 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2113 r
= fprintf(f
, "%s", script
);
2115 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2122 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2128 // Count how many arguments were passed
2129 unsigned int argc
= 1;
2131 for (const char** arg
= args
; *arg
; arg
++)
2135 argv
= calloc(argc
+ 1, sizeof(*argv
));
2137 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2142 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2145 for (unsigned int i
= 1; i
< argc
; i
++)
2146 argv
[i
] = args
[i
-1];
2149 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2157 // Remove script from disk
2165 A convenience function that creates a new jail, runs the given command and destroys
2168 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2169 struct pakfire_jail
* jail
= NULL
;
2172 // Create a new jail
2173 r
= pakfire_jail_create(&jail
, pakfire
);
2177 // Execute the command
2178 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2182 pakfire_jail_unref(jail
);
2187 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2188 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2189 struct pakfire_jail
* jail
= NULL
;
2192 // Create a new jail
2193 r
= pakfire_jail_create(&jail
, pakfire
);
2197 // Execute the command
2198 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2202 pakfire_jail_unref(jail
);
2207 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2210 const char* argv
[] = {
2211 "/bin/bash", "--login", NULL
,
2214 // Execute /bin/bash
2215 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2221 // Ignore any return codes from the shell
2225 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2226 char path
[PATH_MAX
];
2229 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2233 // Check if the file is executable
2234 r
= access(path
, X_OK
);
2236 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2240 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2243 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2244 const char* argv
[] = {
2249 return pakfire_jail_run_if_possible(pakfire
, argv
);
2252 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2253 const char* argv
[] = {
2254 "/usr/bin/systemd-tmpfiles",
2259 return pakfire_jail_run_if_possible(pakfire
, argv
);