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/timerfd.h>
39 #include <sys/types.h>
44 #include <netlink/route/link.h>
52 #include <pakfire/arch.h>
53 #include <pakfire/cgroup.h>
54 #include <pakfire/jail.h>
55 #include <pakfire/logging.h>
56 #include <pakfire/mount.h>
57 #include <pakfire/pakfire.h>
58 #include <pakfire/private.h>
59 #include <pakfire/pwd.h>
60 #include <pakfire/string.h>
61 #include <pakfire/util.h>
63 #define BUFFER_SIZE 1024 * 64
64 #define ENVIRON_SIZE 128
65 #define EPOLL_MAX_EVENTS 2
66 #define MAX_MOUNTPOINTS 8
68 // The default environment that will be set for every command
69 static const struct environ
{
74 { "LANG", "C.utf-8" },
75 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
78 // Tell everything that it is running inside a Pakfire container
79 { "container", "pakfire" },
83 struct pakfire_jail_mountpoint
{
84 char source
[PATH_MAX
];
85 char target
[PATH_MAX
];
90 struct pakfire
* pakfire
;
93 // A unique ID for each jail
95 char __uuid
[UUID_STR_LEN
];
101 struct itimerspec timeout
;
104 struct pakfire_cgroup
* cgroup
;
107 char* env
[ENVIRON_SIZE
];
110 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
111 unsigned int num_mountpoints
;
114 struct pakfire_log_buffer
{
115 char data
[BUFFER_SIZE
];
119 struct pakfire_jail_exec
{
122 // PID (of the child)
126 // Process status (from waitid)
129 // FD to notify the client that the parent has finished initialization
133 struct pakfire_jail_pipes
{
145 struct pakfire_jail_communicate
{
146 pakfire_jail_communicate_in in
;
147 pakfire_jail_communicate_out out
;
152 struct pakfire_jail_buffers
{
153 struct pakfire_log_buffer stdout
;
154 struct pakfire_log_buffer stderr
;
157 struct pakfire_log_buffer log_INFO
;
158 struct pakfire_log_buffer log_ERROR
;
159 struct pakfire_log_buffer log_DEBUG
;
162 struct pakfire_cgroup
* cgroup
;
163 struct pakfire_cgroup_stats cgroup_stats
;
166 static int clone3(struct clone_args
* args
, size_t size
) {
167 return syscall(__NR_clone3
, args
, size
);
170 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
171 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
174 static int pakfire_jail_exec_has_flag(
175 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
176 return ctx
->flags
& flag
;
179 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
180 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
183 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
187 pakfire_cgroup_unref(jail
->cgroup
);
189 pakfire_unref(jail
->pakfire
);
194 Passes any log messages on to the default pakfire log callback
196 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
197 int priority
, const char* line
, size_t length
) {
200 INFO(pakfire
, "%s", line
);
204 ERROR(pakfire
, "%s", line
);
209 DEBUG(pakfire
, "%s", line
);
217 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
219 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
224 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
226 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
231 char* TERM
= secure_getenv("TERM");
233 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
239 char* LANG
= secure_getenv("LANG");
241 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
249 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
252 const char* arch
= pakfire_get_arch(pakfire
);
254 // Allocate a new jail
255 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
260 j
->pakfire
= pakfire_ref(pakfire
);
262 // Initialize reference counter
265 // Generate a random UUID
266 uuid_generate_random(j
->uuid
);
268 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
270 // Set default environment
271 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
272 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
277 // Enable all CPU features that CPU has to offer
278 if (!pakfire_arch_supported_by_host(arch
)) {
279 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
284 // Set container UUID
285 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
289 // Disable systemctl to talk to systemd
290 if (!pakfire_on_root(j
->pakfire
)) {
291 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
301 pakfire_jail_free(j
);
306 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
312 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
313 if (--jail
->nrefs
> 0)
316 pakfire_jail_free(jail
);
322 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
323 // Check if nice level is in range
324 if (nice
< -19 || nice
> 20) {
335 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
336 // Free any previous cgroup
338 pakfire_cgroup_unref(jail
->cgroup
);
342 // Set any new cgroup
344 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
346 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
355 // Returns the length of the environment
356 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
359 // Count everything in the environment
360 for (char** e
= jail
->env
; *e
; e
++)
366 // Finds an existing environment variable and returns its index or -1 if not found
367 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
373 const size_t length
= strlen(key
);
375 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
376 if ((pakfire_string_startswith(jail
->env
[i
], key
)
377 && *(jail
->env
[i
] + length
) == '=')) {
386 // Returns the value of an environment variable or NULL
387 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
389 int i
= pakfire_jail_find_env(jail
, key
);
393 return jail
->env
[i
] + strlen(key
) + 1;
396 // Sets an environment variable
397 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
398 const char* key
, const char* value
) {
399 // Find the index where to write this value to
400 int i
= pakfire_jail_find_env(jail
, key
);
402 i
= pakfire_jail_env_length(jail
);
404 // Return -ENOSPC when the environment is full
405 if (i
>= ENVIRON_SIZE
) {
410 // Free any previous value
414 // Format and set environment variable
415 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
417 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
422 // Imports an environment
423 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
431 // Copy environment variables
432 for (unsigned int i
= 0; env
[i
]; i
++) {
433 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
438 r
= pakfire_jail_set_env(jail
, key
, val
);
455 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
456 struct pakfire_jail
* jail
, unsigned int timeout
) {
458 jail
->timeout
.it_value
.tv_sec
= timeout
;
461 DEBUG(jail
->pakfire
, "Timeout set to %d second(s)\n", timeout
);
463 DEBUG(jail
->pakfire
, "Timeout disabled\n");
468 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
471 // Nothing to do if no timeout has been set
472 if (!jail
->timeout
.it_value
.tv_sec
)
475 // Create a new timer
476 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
478 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
483 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
485 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
499 This function replaces any logging in the child process.
501 All log messages will be sent to the parent process through their respective pipes.
503 static void pakfire_jail_log(void* data
, int priority
, const char* file
,
504 int line
, const char* fn
, const char* format
, va_list args
) {
505 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
510 fd
= pipes
->log_INFO
[1];
514 fd
= pipes
->log_ERROR
[1];
519 fd
= pipes
->log_DEBUG
[1];
521 #endif /* ENABLE_DEBUG */
523 // Ignore any messages of an unknown priority
528 // Send the log message
530 vdprintf(fd
, format
, args
);
533 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
534 return (sizeof(buffer
->data
) == buffer
->used
);
538 This function reads as much data as it can from the file descriptor.
539 If it finds a whole line in it, it will send it to the logger and repeat the process.
540 If not newline character is found, it will try to read more data until it finds one.
542 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
543 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
544 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
545 char line
[BUFFER_SIZE
+ 1];
547 // Fill up buffer from fd
548 if (buffer
->used
< sizeof(buffer
->data
)) {
549 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
550 sizeof(buffer
->data
) - buffer
->used
);
553 if (bytes_read
< 0) {
554 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
558 // Update buffer size
559 buffer
->used
+= bytes_read
;
562 // See if we have any lines that we can write
563 while (buffer
->used
) {
564 // Search for the end of the first line
565 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
569 // If the buffer is full, we send the content to the logger and try again
570 // This should not happen in practise
571 if (pakfire_jail_log_buffer_is_full(buffer
)) {
572 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
574 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
576 // Otherwise we might have only read parts of the output
581 // Find the length of the string
582 size_t length
= eol
- buffer
->data
+ 1;
584 // Copy the line into the buffer
585 memcpy(line
, buffer
->data
, length
);
587 // Terminate the string
592 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
594 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
599 // Remove line from buffer
600 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
601 buffer
->used
-= length
;
607 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
608 struct pakfire_jail_exec
* ctx
, const int fd
) {
611 // Nothing to do if there is no stdin callback set
612 if (!ctx
->communicate
.in
) {
613 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
617 // Skip if the writing pipe has already been closed
618 if (!ctx
->pipes
.stdin
[1])
621 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
623 // Calling the callback
624 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
626 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
628 // The callback signaled that it has written everything
630 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
632 // Close the file-descriptor
635 // Reset the file-descriptor so it won't be closed again later
636 ctx
->pipes
.stdin
[1] = 0;
645 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
646 int r
= pipe2(*fds
, flags
);
648 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
655 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
656 for (unsigned int i
= 0; i
< 2; i
++)
662 This is a convenience function to fetch the reading end of a pipe and
663 closes the write end.
665 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
666 // Give the variables easier names to avoid confusion
667 int* fd_read
= &(*fds
)[0];
668 int* fd_write
= &(*fds
)[1];
670 // Close the write end of the pipe
676 // Return the read end
680 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
681 // Give the variables easier names to avoid confusion
682 int* fd_read
= &(*fds
)[0];
683 int* fd_write
= &(*fds
)[1];
685 // Close the read end of the pipe
691 // Return the write end
695 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
697 struct epoll_event ev
;
698 struct epoll_event events
[EPOLL_MAX_EVENTS
];
702 // Fetch file descriptors from context
703 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
704 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
705 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
706 const int pidfd
= ctx
->pidfd
;
709 const int timerfd
= pakfire_jail_create_timer(jail
);
712 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
713 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
714 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
716 // Make a list of all file descriptors we are interested in
718 stdin
, stdout
, stderr
, pidfd
, timerfd
, log_INFO
, log_ERROR
, log_DEBUG
,
722 epollfd
= epoll_create1(0);
724 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
729 // Turn file descriptors into non-blocking mode and add them to epoll()
730 for (unsigned int i
= 0; i
< sizeof(fds
) / sizeof(*fds
); i
++) {
733 // Skip fds which were not initialized
737 ev
.events
= EPOLLHUP
;
740 ev
.events
|= EPOLLOUT
;
742 ev
.events
|= EPOLLIN
;
745 int flags
= fcntl(fd
, F_GETFL
, 0);
747 // Set modified flags
748 if (fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
) < 0) {
750 "Could not set file descriptor %d into non-blocking mode: %m\n", fd
);
757 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
758 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
766 // Loop for as long as the process is alive
768 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
770 // Ignore if epoll_wait() has been interrupted
774 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
780 for (int i
= 0; i
< num
; i
++) {
781 int e
= events
[i
].events
;
782 int fd
= events
[i
].data
.fd
;
784 struct pakfire_log_buffer
* buffer
= NULL
;
785 pakfire_jail_communicate_out callback
= NULL
;
789 // Check if there is any data to be read
791 // Handle any changes to the PIDFD
793 // Call waidid() and store the result
794 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
796 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
800 // Mark that we have ended so that we will process the remaining
801 // events from epoll() now, but won't restart the outer loop.
805 // Handle timer events
806 } else if (fd
== timerfd
) {
807 DEBUG(jail
->pakfire
, "Timer event received\n");
810 r
= read(timerfd
, garbage
, sizeof(garbage
));
812 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
817 // Terminate the process if it hasn't already ended
819 DEBUG(jail
->pakfire
, "Terminating process...\n");
821 // Send SIGTERM to the process
822 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
824 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
829 // There is nothing else to do
832 // Handle logging messages
833 } else if (fd
== log_INFO
) {
834 buffer
= &ctx
->buffers
.log_INFO
;
837 callback
= pakfire_jail_default_log_callback
;
839 } else if (fd
== log_ERROR
) {
840 buffer
= &ctx
->buffers
.log_ERROR
;
843 callback
= pakfire_jail_default_log_callback
;
845 } else if (fd
== log_DEBUG
) {
846 buffer
= &ctx
->buffers
.log_DEBUG
;
847 priority
= LOG_DEBUG
;
849 callback
= pakfire_jail_default_log_callback
;
851 // Handle anything from the log pipes
852 } else if (fd
== stdout
) {
853 buffer
= &ctx
->buffers
.stdout
;
856 callback
= ctx
->communicate
.out
;
857 data
= ctx
->communicate
.data
;
859 } else if (fd
== stderr
) {
860 buffer
= &ctx
->buffers
.stderr
;
863 callback
= ctx
->communicate
.out
;
864 data
= ctx
->communicate
.data
;
867 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
872 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
878 // Handle standard input
880 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
883 // Ignore if we filled up the buffer
888 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
895 // Check if any file descriptors have been closed
897 // Remove the file descriptor
898 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
900 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
916 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
917 int priority
, const char* line
, size_t length
) {
918 char** output
= (char**)data
;
921 // Append everything from stdout to a buffer
922 if (output
&& priority
== LOG_INFO
) {
923 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
929 // Send everything else to the default logger
930 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
935 // Logs all capabilities of the current process
936 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
939 cap_flag_value_t value_e
;
940 cap_flag_value_t value_i
;
941 cap_flag_value_t value_p
;
945 pid_t pid
= getpid();
947 // Fetch all capabilities
948 caps
= cap_get_proc();
950 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
955 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
957 // Iterate over all capabilities
958 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
959 name
= cap_to_name(cap
);
961 // Fetch effective value
962 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
966 // Fetch inheritable value
967 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
971 // Fetch permitted value
972 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
979 (value_e
== CAP_SET
) ? 'e' : '-',
980 (value_i
== CAP_SET
) ? 'i' : '-',
981 (value_p
== CAP_SET
) ? 'p' : '-'
1001 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1006 // Fetch capabilities
1007 caps
= cap_get_proc();
1009 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1014 // Walk through all capabilities
1015 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1016 cap_value_t _caps
[] = { cap
};
1018 // Fetch the name of the capability
1019 name
= cap_to_name(cap
);
1021 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1023 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1027 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1029 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1033 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1035 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1044 // Restore all capabilities
1045 r
= cap_set_proc(caps
);
1047 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1051 // Add all capabilities to the ambient set
1052 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1053 name
= cap_to_name(cap
);
1055 // Raise the capability
1056 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1058 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1081 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1082 const int syscalls
[] = {
1083 // The kernel's keyring isn't namespaced
1086 SCMP_SYS(request_key
),
1088 // Disable userfaultfd
1089 SCMP_SYS(userfaultfd
),
1091 // Disable perf which could leak a lot of information about the host
1092 SCMP_SYS(perf_event_open
),
1098 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1100 // Setup a syscall filter which allows everything by default
1101 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1103 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1108 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1109 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1111 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1116 // Load syscall filter into the kernel
1117 r
= seccomp_load(ctx
);
1119 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1125 seccomp_release(ctx
);
1132 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1133 const char* source
, const char* target
, int flags
) {
1134 struct pakfire_jail_mountpoint
* mp
= NULL
;
1137 // Check if there is any space left
1138 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1143 // Check for valid inputs
1144 if (!source
|| !target
) {
1149 // Select the next free slot
1150 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1153 r
= pakfire_string_set(mp
->source
, source
);
1155 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1160 r
= pakfire_string_set(mp
->target
, target
);
1162 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1169 // Increment counter
1170 jail
->num_mountpoints
++;
1175 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1178 const char* paths
[] = {
1184 // Bind-mount all paths read-only
1185 for (const char** path
= paths
; *path
; path
++) {
1186 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1195 Mounts everything that we require in the new namespace
1197 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1198 struct pakfire_jail_mountpoint
* mp
= NULL
;
1202 // Enable loop devices
1203 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1204 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1206 // Mount all default stuff
1207 r
= pakfire_mount_all(jail
->pakfire
, flags
);
1211 // Mount networking stuff
1212 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1213 r
= pakfire_jail_mount_networking(jail
);
1218 // Mount all custom stuff
1219 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1221 mp
= &jail
->mountpoints
[i
];
1224 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1229 // Log all mountpoints
1230 pakfire_mount_list(jail
->pakfire
);
1237 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1238 struct nl_sock
* nl
= NULL
;
1239 struct nl_cache
* cache
= NULL
;
1240 struct rtnl_link
* link
= NULL
;
1241 struct rtnl_link
* change
= NULL
;
1244 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1246 // Allocate a netlink socket
1247 nl
= nl_socket_alloc();
1249 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1254 // Connect the socket
1255 r
= nl_connect(nl
, NETLINK_ROUTE
);
1257 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1261 // Allocate the netlink cache
1262 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1264 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1268 // Fetch loopback interface
1269 link
= rtnl_link_get_by_name(cache
, "lo");
1271 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1276 // Allocate a new link
1277 change
= rtnl_link_alloc();
1279 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1284 // Set the link to UP
1285 rtnl_link_set_flags(change
, IFF_UP
);
1287 // Apply any changes
1288 r
= rtnl_link_change(nl
, link
, change
, 0);
1290 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1306 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1307 char path
[PATH_MAX
];
1310 // Skip mapping anything when running on /
1311 if (pakfire_on_root(jail
->pakfire
))
1315 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1320 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1323 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1327 /* When running as root, we will map the entire range.
1329 When running as a non-privileged user, we will map the root user inside the jail
1330 to the user's UID outside of the jail, and we will map the rest starting from one.
1335 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1336 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1338 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1339 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1343 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1350 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1351 char path
[PATH_MAX
];
1354 // Skip mapping anything when running on /
1355 if (pakfire_on_root(jail
->pakfire
))
1359 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1362 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1367 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1373 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1374 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1376 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1377 "0 %lu 1\n%1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1381 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1388 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1389 char path
[PATH_MAX
];
1393 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1397 // Open file for writing
1398 FILE* f
= fopen(path
, "w");
1400 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
1405 int bytes_written
= fprintf(f
, "deny\n");
1406 if (bytes_written
<= 0) {
1407 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
1414 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
1425 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1426 const uint64_t val
= 1;
1429 DEBUG(jail
->pakfire
, "Sending signal...\n");
1431 // Write to the file descriptor
1432 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
1433 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
1434 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
1438 // Close the file descriptor
1444 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1448 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1450 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
1451 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
1452 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
1456 // Close the file descriptor
1463 Performs the initialisation that needs to happen in the parent part
1465 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1468 // Setup UID mapping
1469 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1473 // Write "deny" to /proc/PID/setgroups
1474 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1478 // Setup GID mapping
1479 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1483 // Parent has finished initialisation
1484 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1486 // Send signal to client
1487 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1494 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1495 const char* argv
[]) {
1498 // Redirect any logging to our log pipe
1499 pakfire_set_log_callback(jail
->pakfire
, pakfire_jail_log
, &ctx
->pipes
);
1502 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1504 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1509 pid_t pid
= getpid();
1511 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1513 // Wait for the parent to finish initialization
1514 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1518 // Perform further initialization
1521 uid_t uid
= getuid();
1522 gid_t gid
= getgid();
1525 uid_t euid
= geteuid();
1526 gid_t egid
= getegid();
1528 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
1529 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
1531 // Check if we are (effectively running as root)
1532 if (uid
|| gid
|| euid
|| egid
) {
1533 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1537 const char* root
= pakfire_get_path(jail
->pakfire
);
1538 const char* arch
= pakfire_get_arch(jail
->pakfire
);
1540 // Change root (unless root is /)
1541 if (!pakfire_on_root(jail
->pakfire
)) {
1543 r
= pakfire_jail_mount(jail
, ctx
);
1550 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
1554 // Change directory to /
1557 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
1563 unsigned long persona
= pakfire_arch_personality(arch
);
1565 r
= personality(persona
);
1567 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1573 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1574 r
= pakfire_jail_setup_loopback(jail
);
1581 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1583 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1585 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1590 // Close other end of log pipes
1591 close(ctx
->pipes
.log_INFO
[0]);
1592 close(ctx
->pipes
.log_ERROR
[0]);
1594 close(ctx
->pipes
.log_DEBUG
[0]);
1595 #endif /* ENABLE_DEBUG */
1597 // Connect standard input
1598 if (ctx
->pipes
.stdin
[0]) {
1599 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
1601 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
1602 ctx
->pipes
.stdin
[0]);
1608 // Connect standard output and error
1609 if (ctx
->pipes
.stdout
[1] && ctx
->pipes
.stderr
[1]) {
1610 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1612 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1613 ctx
->pipes
.stdout
[1]);
1618 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1620 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1621 ctx
->pipes
.stderr
[1]);
1626 // Close the pipe (as we have moved the original file descriptors)
1627 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
1628 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1629 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1632 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1633 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1637 // Don't drop any capabilities on execve()
1638 r
= prctl(PR_SET_KEEPCAPS
, 1);
1640 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1645 r
= pakfire_jail_set_capabilities(jail
);
1649 // Show capabilities
1650 r
= pakfire_jail_show_capabilities(jail
);
1655 r
= pakfire_jail_limit_syscalls(jail
);
1659 DEBUG(jail
->pakfire
, "Child process initialization done\n");
1660 DEBUG(jail
->pakfire
, "Launching command:\n");
1663 for (unsigned int i
= 0; argv
[i
]; i
++)
1664 DEBUG(jail
->pakfire
, " argv[%d] = %s\n", i
, argv
[i
]);
1667 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1669 // Translate errno into regular exit code
1672 // Ignore if the command doesn't exist
1673 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
1684 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
1687 // We should not get here
1691 // Run a command in the jail
1692 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
1693 const int interactive
,
1694 pakfire_jail_communicate_in communicate_in
,
1695 pakfire_jail_communicate_out communicate_out
,
1696 void* data
, int flags
) {
1700 // Check if argv is valid
1701 if (!argv
|| !argv
[0]) {
1706 // Send any output to the default logger if no callback is set
1707 if (!communicate_out
)
1708 communicate_out
= pakfire_jail_default_log_callback
;
1710 // Initialize context for this call
1711 struct pakfire_jail_exec ctx
= {
1715 .stdin
= { -1, -1 },
1716 .stdout
= { -1, -1 },
1717 .stderr
= { -1, -1 },
1721 .in
= communicate_in
,
1722 .out
= communicate_out
,
1729 DEBUG(jail
->pakfire
, "Executing jail...\n");
1731 // Enable networking in interactive mode
1733 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
1736 Setup a file descriptor which can be used to notify the client that the parent
1737 has completed configuration.
1739 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1740 if (ctx
.completed_fd
< 0) {
1741 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1745 // Create pipes to communicate with child process if we are not running interactively
1747 // stdin (only if callback is set)
1748 if (ctx
.communicate
.in
) {
1749 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
1755 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1760 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1765 // Setup pipes for logging
1767 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1772 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1778 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1781 #endif /* ENABLE_DEBUG */
1783 // Configure child process
1784 struct clone_args args
= {
1793 .exit_signal
= SIGCHLD
,
1794 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1797 // Launch the process in a cgroup that is a leaf of the configured cgroup
1799 args
.flags
|= CLONE_INTO_CGROUP
;
1802 const char* uuid
= pakfire_jail_uuid(jail
);
1804 // Create a temporary cgroup
1805 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
1807 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1811 // Clone into this cgroup
1812 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
1816 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1817 args
.flags
|= CLONE_NEWNET
;
1820 // Fork this process
1821 ctx
.pid
= clone3(&args
, sizeof(args
));
1823 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1827 } else if (ctx
.pid
== 0) {
1828 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1833 r
= pakfire_jail_parent(jail
, &ctx
);
1837 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1839 // Read output of the child process
1840 r
= pakfire_jail_wait(jail
, &ctx
);
1844 // Handle exit status
1845 switch (ctx
.status
.si_code
) {
1847 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
1848 ctx
.status
.si_status
);
1851 exit
= ctx
.status
.si_status
;
1855 ERROR(jail
->pakfire
, "The child process was killed\n");
1860 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
1863 // Log anything else
1865 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
1870 // Destroy the temporary cgroup (if any)
1872 // Read cgroup stats
1873 r
= pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
1875 ERROR(jail
->pakfire
, "Could not read cgroup stats: %m\n");
1877 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
1880 pakfire_cgroup_destroy(ctx
.cgroup
);
1881 pakfire_cgroup_unref(ctx
.cgroup
);
1884 // Close any file descriptors
1885 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
1886 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
1887 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
1890 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
1891 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
1892 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
1897 PAKFIRE_EXPORT
int pakfire_jail_exec(
1898 struct pakfire_jail
* jail
,
1900 pakfire_jail_communicate_in callback_in
,
1901 pakfire_jail_communicate_out callback_out
,
1902 void* data
, int flags
) {
1903 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
1906 static int pakfire_jail_exec_interactive(
1907 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
1910 // Setup interactive stuff
1911 r
= pakfire_jail_setup_interactive_env(jail
);
1915 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
1918 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1922 pakfire_jail_communicate_in callback_in
,
1923 pakfire_jail_communicate_out callback_out
,
1925 char path
[PATH_MAX
];
1926 const char** argv
= NULL
;
1930 const char* root
= pakfire_get_path(jail
->pakfire
);
1932 // Write the scriptlet to disk
1933 r
= pakfire_path_join(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
1937 // Create a temporary file
1938 f
= pakfire_mktemp(path
, 0700);
1940 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
1944 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1947 r
= fprintf(f
, "%s", script
);
1949 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1956 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1962 // Count how many arguments were passed
1963 unsigned int argc
= 1;
1965 for (const char** arg
= args
; *arg
; arg
++)
1969 argv
= calloc(argc
+ 1, sizeof(*argv
));
1971 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1976 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1979 for (unsigned int i
= 1; i
< argc
; i
++)
1980 argv
[i
] = args
[i
-1];
1983 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
1991 // Remove script from disk
1999 A convenience function that creates a new jail, runs the given command and destroys
2002 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2003 struct pakfire_jail
* jail
= NULL
;
2006 // Create a new jail
2007 r
= pakfire_jail_create(&jail
, pakfire
);
2011 // Execute the command
2012 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2016 pakfire_jail_unref(jail
);
2021 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2022 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2023 struct pakfire_jail
* jail
= NULL
;
2026 // Create a new jail
2027 r
= pakfire_jail_create(&jail
, pakfire
);
2031 // Execute the command
2032 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2036 pakfire_jail_unref(jail
);
2041 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2042 const char* argv
[] = {
2043 "/bin/bash", "--login", NULL
,
2046 // Execute /bin/bash
2047 return pakfire_jail_exec_interactive(jail
, argv
, 0);
2050 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2051 char path
[PATH_MAX
];
2054 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2058 // Check if the file is executable
2059 r
= access(path
, X_OK
);
2061 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2065 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2068 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2069 const char* argv
[] = {
2074 return pakfire_jail_run_if_possible(pakfire
, argv
);
2077 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2078 const char* argv
[] = {
2079 "/usr/bin/systemd-tmpfiles",
2084 return pakfire_jail_run_if_possible(pakfire
, argv
);