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/path.h>
59 #include <pakfire/private.h>
60 #include <pakfire/pwd.h>
61 #include <pakfire/string.h>
62 #include <pakfire/util.h>
64 #define BUFFER_SIZE 1024 * 64
65 #define ENVIRON_SIZE 128
66 #define EPOLL_MAX_EVENTS 2
67 #define MAX_MOUNTPOINTS 8
69 // The default environment that will be set for every command
70 static const struct environ
{
75 { "LANG", "C.utf-8" },
76 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
79 // Tell everything that it is running inside a Pakfire container
80 { "container", "pakfire" },
84 struct pakfire_jail_mountpoint
{
85 char source
[PATH_MAX
];
86 char target
[PATH_MAX
];
91 struct pakfire_ctx
* ctx
;
92 struct pakfire
* pakfire
;
95 // A unique ID for each jail
97 char __uuid
[UUID_STR_LEN
];
103 struct itimerspec timeout
;
106 struct pakfire_cgroup
* cgroup
;
109 char* env
[ENVIRON_SIZE
];
112 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
113 unsigned int num_mountpoints
;
116 struct pakfire_jail_callbacks
{
118 pakfire_jail_log_callback log
;
123 struct pakfire_log_buffer
{
124 char data
[BUFFER_SIZE
];
128 struct pakfire_jail_exec
{
131 // PID (of the child)
135 // Process status (from waitid)
138 // FD to notify the client that the parent has finished initialization
142 struct pakfire_jail_pipes
{
152 #endif /* ENABLE_DEBUG */
156 struct pakfire_jail_communicate
{
157 pakfire_jail_communicate_in in
;
158 pakfire_jail_communicate_out out
;
163 struct pakfire_jail_buffers
{
164 struct pakfire_log_buffer stdout
;
165 struct pakfire_log_buffer stderr
;
168 struct pakfire_log_buffer log_INFO
;
169 struct pakfire_log_buffer log_ERROR
;
171 struct pakfire_log_buffer log_DEBUG
;
172 #endif /* ENABLE_DEBUG */
175 struct pakfire_cgroup
* cgroup
;
176 struct pakfire_cgroup_stats cgroup_stats
;
179 char console
[PATH_MAX
];
183 static int clone3(struct clone_args
* args
, size_t size
) {
184 return syscall(__NR_clone3
, args
, size
);
187 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
188 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
191 static int pivot_root(const char* new_root
, const char* old_root
) {
192 return syscall(SYS_pivot_root
, new_root
, old_root
);
195 static int pakfire_jail_exec_has_flag(
196 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
197 return ctx
->flags
& flag
;
200 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
201 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
204 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
208 pakfire_cgroup_unref(jail
->cgroup
);
210 pakfire_unref(jail
->pakfire
);
212 pakfire_ctx_unref(jail
->ctx
);
217 Passes any log messages on to the default pakfire log callback
219 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
220 int priority
, const char* line
, size_t length
) {
223 INFO(pakfire
, "%s", line
);
227 ERROR(pakfire
, "%s", line
);
232 DEBUG(pakfire
, "%s", line
);
240 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
242 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
247 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
249 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
254 char* TERM
= secure_getenv("TERM");
256 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
262 char* LANG
= secure_getenv("LANG");
264 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
272 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
275 const char* arch
= pakfire_get_effective_arch(pakfire
);
277 // Allocate a new jail
278 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
283 j
->ctx
= pakfire_ctx(pakfire
);
286 j
->pakfire
= pakfire_ref(pakfire
);
288 // Initialize reference counter
291 // Generate a random UUID
292 uuid_generate_random(j
->uuid
);
294 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
296 // Set the default logging callback
297 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
299 // Set default environment
300 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
301 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
306 // Enable all CPU features that CPU has to offer
307 if (!pakfire_arch_is_supported_by_host(arch
)) {
308 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
313 // Set container UUID
314 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
318 // Disable systemctl to talk to systemd
319 if (!pakfire_on_root(j
->pakfire
)) {
320 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
330 pakfire_jail_free(j
);
335 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
341 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
342 if (--jail
->nrefs
> 0)
345 pakfire_jail_free(jail
);
351 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
352 pakfire_jail_log_callback callback
, void* data
) {
353 jail
->callbacks
.log
= callback
;
354 jail
->callbacks
.log_data
= data
;
359 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
360 // Check if nice level is in range
361 if (nice
< -19 || nice
> 20) {
372 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
373 // Free any previous cgroup
375 pakfire_cgroup_unref(jail
->cgroup
);
379 // Set any new cgroup
381 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
383 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
392 // Returns the length of the environment
393 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
396 // Count everything in the environment
397 for (char** e
= jail
->env
; *e
; e
++)
403 // Finds an existing environment variable and returns its index or -1 if not found
404 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
410 const size_t length
= strlen(key
);
412 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
413 if ((pakfire_string_startswith(jail
->env
[i
], key
)
414 && *(jail
->env
[i
] + length
) == '=')) {
423 // Returns the value of an environment variable or NULL
424 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
426 int i
= pakfire_jail_find_env(jail
, key
);
430 return jail
->env
[i
] + strlen(key
) + 1;
433 // Sets an environment variable
434 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
435 const char* key
, const char* value
) {
436 // Find the index where to write this value to
437 int i
= pakfire_jail_find_env(jail
, key
);
439 i
= pakfire_jail_env_length(jail
);
441 // Return -ENOSPC when the environment is full
442 if (i
>= ENVIRON_SIZE
) {
447 // Free any previous value
451 // Format and set environment variable
452 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
454 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
459 // Imports an environment
460 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
468 // Copy environment variables
469 for (unsigned int i
= 0; env
[i
]; i
++) {
470 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
475 r
= pakfire_jail_set_env(jail
, key
, val
);
492 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
493 struct pakfire_jail
* jail
, unsigned int timeout
) {
495 jail
->timeout
.it_value
.tv_sec
= timeout
;
498 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
500 DEBUG(jail
->pakfire
, "Timeout disabled\n");
505 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
508 // Nothing to do if no timeout has been set
509 if (!jail
->timeout
.it_value
.tv_sec
)
512 // Create a new timer
513 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
515 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
520 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
522 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
536 This function replaces any logging in the child process.
538 All log messages will be sent to the parent process through their respective pipes.
540 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
541 int line
, const char* fn
, const char* format
, va_list args
) {
542 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
547 fd
= pipes
->log_INFO
[1];
551 fd
= pipes
->log_ERROR
[1];
556 fd
= pipes
->log_DEBUG
[1];
558 #endif /* ENABLE_DEBUG */
560 // Ignore any messages of an unknown priority
565 // Send the log message
567 vdprintf(fd
, format
, args
);
570 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
571 return (sizeof(buffer
->data
) == buffer
->used
);
575 This function reads as much data as it can from the file descriptor.
576 If it finds a whole line in it, it will send it to the logger and repeat the process.
577 If not newline character is found, it will try to read more data until it finds one.
579 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
580 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
581 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
582 char line
[BUFFER_SIZE
+ 1];
584 // Fill up buffer from fd
585 if (buffer
->used
< sizeof(buffer
->data
)) {
586 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
587 sizeof(buffer
->data
) - buffer
->used
);
590 if (bytes_read
< 0) {
591 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
595 // Update buffer size
596 buffer
->used
+= bytes_read
;
599 // See if we have any lines that we can write
600 while (buffer
->used
) {
601 // Search for the end of the first line
602 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
606 // If the buffer is full, we send the content to the logger and try again
607 // This should not happen in practise
608 if (pakfire_jail_log_buffer_is_full(buffer
)) {
609 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
611 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
613 // Otherwise we might have only read parts of the output
618 // Find the length of the string
619 size_t length
= eol
- buffer
->data
+ 1;
621 // Copy the line into the buffer
622 memcpy(line
, buffer
->data
, length
);
624 // Terminate the string
629 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
631 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
636 // Remove line from buffer
637 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
638 buffer
->used
-= length
;
644 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
645 struct pakfire_jail_exec
* ctx
, const int fd
) {
648 // Nothing to do if there is no stdin callback set
649 if (!ctx
->communicate
.in
) {
650 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
654 // Skip if the writing pipe has already been closed
655 if (!ctx
->pipes
.stdin
[1])
658 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
660 // Calling the callback
661 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
663 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
665 // The callback signaled that it has written everything
667 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
669 // Close the file-descriptor
672 // Reset the file-descriptor so it won't be closed again later
673 ctx
->pipes
.stdin
[1] = -1;
682 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
683 int r
= pipe2(*fds
, flags
);
685 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
692 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
693 for (unsigned int i
= 0; i
< 2; i
++)
699 This is a convenience function to fetch the reading end of a pipe and
700 closes the write end.
702 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
703 // Give the variables easier names to avoid confusion
704 int* fd_read
= &(*fds
)[0];
705 int* fd_write
= &(*fds
)[1];
707 // Close the write end of the pipe
708 if (*fd_write
>= 0) {
713 // Return the read end
720 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
721 // Give the variables easier names to avoid confusion
722 int* fd_read
= &(*fds
)[0];
723 int* fd_write
= &(*fds
)[1];
725 // Close the read end of the pipe
731 // Return the write end
738 static int pakfire_jail_log(struct pakfire
* pakfire
, void* data
, int priority
,
739 const char* line
, const size_t length
) {
740 // Pass everything to the parent logger
741 pakfire_log_condition(pakfire
, priority
, 0, "%.*s", (int)length
, line
);
746 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
747 struct epoll_event event
= {
748 .events
= events
|EPOLLHUP
,
756 int flags
= fcntl(fd
, F_GETFL
, 0);
758 // Set modified flags
759 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
761 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
762 fd
, strerror(errno
));
766 // Add the file descriptor to the loop
767 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
769 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
770 fd
, strerror(errno
));
777 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
779 struct epoll_event events
[EPOLL_MAX_EVENTS
];
783 // Fetch file descriptors from context
784 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
785 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
786 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
787 const int pidfd
= ctx
->pidfd
;
790 const int timerfd
= pakfire_jail_create_timer(jail
);
793 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
794 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
796 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
797 #endif /* ENABLE_DEBUG */
799 // Make a list of all file descriptors we are interested in
800 const struct pakfire_wait_fds
{
804 // Standard input/output
810 { timerfd
, EPOLLIN
},
813 { ctx
->pidfd
, EPOLLIN
},
816 { log_INFO
, EPOLLIN
},
817 { log_ERROR
, EPOLLIN
},
819 { log_DEBUG
, EPOLLIN
},
820 #endif /* ENABLE_DEBUG */
827 epollfd
= epoll_create1(0);
829 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
834 // Turn file descriptors into non-blocking mode and add them to epoll()
835 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
836 // Skip fds which were not initialized
840 // Add the FD to the event loop
841 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
848 // Loop for as long as the process is alive
850 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
852 // Ignore if epoll_wait() has been interrupted
856 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
862 for (int i
= 0; i
< num
; i
++) {
863 int e
= events
[i
].events
;
864 int fd
= events
[i
].data
.fd
;
866 struct pakfire_log_buffer
* buffer
= NULL
;
867 pakfire_jail_communicate_out callback
= NULL
;
871 // Check if there is any data to be read
873 // Handle any changes to the PIDFD
875 // Call waidid() and store the result
876 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
878 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
882 // Mark that we have ended so that we will process the remaining
883 // events from epoll() now, but won't restart the outer loop.
887 // Handle timer events
888 } else if (fd
== timerfd
) {
889 DEBUG(jail
->pakfire
, "Timer event received\n");
892 r
= read(timerfd
, garbage
, sizeof(garbage
));
894 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
899 // Terminate the process if it hasn't already ended
901 DEBUG(jail
->pakfire
, "Terminating process...\n");
903 // Send SIGTERM to the process
904 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
906 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
911 // Don't fall through to log processing
914 // Handle logging messages
915 } else if (fd
== log_INFO
) {
916 buffer
= &ctx
->buffers
.log_INFO
;
919 callback
= pakfire_jail_log
;
921 } else if (fd
== log_ERROR
) {
922 buffer
= &ctx
->buffers
.log_ERROR
;
925 callback
= pakfire_jail_log
;
928 } else if (fd
== log_DEBUG
) {
929 buffer
= &ctx
->buffers
.log_DEBUG
;
930 priority
= LOG_DEBUG
;
932 callback
= pakfire_jail_log
;
933 #endif /* ENABLE_DEBUG */
935 // Handle anything from the log pipes
936 } else if (fd
== stdout
) {
937 buffer
= &ctx
->buffers
.stdout
;
940 // Send any output to the default logger if no callback is set
941 if (ctx
->communicate
.out
) {
942 callback
= ctx
->communicate
.out
;
943 data
= ctx
->communicate
.data
;
945 callback
= jail
->callbacks
.log
;
946 data
= jail
->callbacks
.log_data
;
949 } else if (fd
== stderr
) {
950 buffer
= &ctx
->buffers
.stderr
;
953 // Send any output to the default logger if no callback is set
954 if (ctx
->communicate
.out
) {
955 callback
= ctx
->communicate
.out
;
956 data
= ctx
->communicate
.data
;
958 callback
= jail
->callbacks
.log
;
959 data
= jail
->callbacks
.log_data
;
963 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
968 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
974 // Handle standard input
976 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
979 // Ignore if we filled up the buffer
984 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
991 // Check if any file descriptors have been closed
993 // Remove the file descriptor
994 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
996 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1012 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1013 int priority
, const char* line
, size_t length
) {
1014 char** output
= (char**)data
;
1017 // Append everything from stdout to a buffer
1018 if (output
&& priority
== LOG_INFO
) {
1019 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
1025 // Send everything else to the default logger
1026 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1031 // Logs all capabilities of the current process
1032 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1035 cap_flag_value_t value_e
;
1036 cap_flag_value_t value_i
;
1037 cap_flag_value_t value_p
;
1041 pid_t pid
= getpid();
1043 // Fetch all capabilities
1044 caps
= cap_get_proc();
1046 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1051 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1053 // Iterate over all capabilities
1054 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1055 name
= cap_to_name(cap
);
1057 // Fetch effective value
1058 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1062 // Fetch inheritable value
1063 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1067 // Fetch permitted value
1068 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1072 DEBUG(jail
->pakfire
,
1073 " %-24s : %c%c%c\n",
1075 (value_e
== CAP_SET
) ? 'e' : '-',
1076 (value_i
== CAP_SET
) ? 'i' : '-',
1077 (value_p
== CAP_SET
) ? 'p' : '-'
1097 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1102 // Fetch capabilities
1103 caps
= cap_get_proc();
1105 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1110 // Walk through all capabilities
1111 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1112 cap_value_t _caps
[] = { cap
};
1114 // Fetch the name of the capability
1115 name
= cap_to_name(cap
);
1117 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1119 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1123 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1125 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1129 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1131 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1140 // Restore all capabilities
1141 r
= cap_set_proc(caps
);
1143 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1147 // Add all capabilities to the ambient set
1148 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1149 name
= cap_to_name(cap
);
1151 // Raise the capability
1152 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1154 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1177 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1178 const int syscalls
[] = {
1179 // The kernel's keyring isn't namespaced
1182 SCMP_SYS(request_key
),
1184 // Disable userfaultfd
1185 SCMP_SYS(userfaultfd
),
1187 // Disable perf which could leak a lot of information about the host
1188 SCMP_SYS(perf_event_open
),
1194 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1196 // Setup a syscall filter which allows everything by default
1197 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1199 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1204 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1205 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1207 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1212 // Load syscall filter into the kernel
1213 r
= seccomp_load(ctx
);
1215 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1221 seccomp_release(ctx
);
1228 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1229 const char* source
, const char* target
, int flags
) {
1230 struct pakfire_jail_mountpoint
* mp
= NULL
;
1233 // Check if there is any space left
1234 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1239 // Check for valid inputs
1240 if (!source
|| !target
) {
1245 // Select the next free slot
1246 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1249 r
= pakfire_string_set(mp
->source
, source
);
1251 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1256 r
= pakfire_string_set(mp
->target
, target
);
1258 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1265 // Increment counter
1266 jail
->num_mountpoints
++;
1271 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1274 const char* paths
[] = {
1280 // Bind-mount all paths read-only
1281 for (const char** path
= paths
; *path
; path
++) {
1282 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1285 // Ignore if we don't have permission
1300 Mounts everything that we require in the new namespace
1302 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1303 struct pakfire_jail_mountpoint
* mp
= NULL
;
1307 // Enable loop devices
1308 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1309 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1311 // Mount all default stuff
1312 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1317 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1321 // Mount the interpreter (if needed)
1322 r
= pakfire_mount_interpreter(jail
->pakfire
);
1326 // Mount networking stuff
1327 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1328 r
= pakfire_jail_mount_networking(jail
);
1333 // Mount all custom stuff
1334 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1336 mp
= &jail
->mountpoints
[i
];
1339 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1349 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1350 struct nl_sock
* nl
= NULL
;
1351 struct nl_cache
* cache
= NULL
;
1352 struct rtnl_link
* link
= NULL
;
1353 struct rtnl_link
* change
= NULL
;
1356 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1358 // Allocate a netlink socket
1359 nl
= nl_socket_alloc();
1361 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1366 // Connect the socket
1367 r
= nl_connect(nl
, NETLINK_ROUTE
);
1369 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1373 // Allocate the netlink cache
1374 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1376 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1380 // Fetch loopback interface
1381 link
= rtnl_link_get_by_name(cache
, "lo");
1383 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1388 // Allocate a new link
1389 change
= rtnl_link_alloc();
1391 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1396 // Set the link to UP
1397 rtnl_link_set_flags(change
, IFF_UP
);
1399 // Apply any changes
1400 r
= rtnl_link_change(nl
, link
, change
, 0);
1402 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1418 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1419 char path
[PATH_MAX
];
1422 // Skip mapping anything when running on /
1423 if (pakfire_on_root(jail
->pakfire
))
1427 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1432 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1435 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1439 /* When running as root, we will map the entire range.
1441 When running as a non-privileged user, we will map the root user inside the jail
1442 to the user's UID outside of the jail, and we will map the rest starting from one.
1447 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1448 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1450 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1451 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1455 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1462 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1463 char path
[PATH_MAX
];
1466 // Skip mapping anything when running on /
1467 if (pakfire_on_root(jail
->pakfire
))
1471 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1474 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1479 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1485 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1486 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1488 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1489 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1493 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1500 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1501 char path
[PATH_MAX
];
1505 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1509 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1511 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1518 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1519 const uint64_t val
= 1;
1522 DEBUG(jail
->pakfire
, "Sending signal...\n");
1524 // Write to the file descriptor
1525 r
= eventfd_write(fd
, val
);
1527 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1531 // Close the file descriptor
1537 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1541 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1543 r
= eventfd_read(fd
, &val
);
1545 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1549 // Close the file descriptor
1556 Performs the initialisation that needs to happen in the parent part
1558 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1561 // Setup UID mapping
1562 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1566 // Write "deny" to /proc/PID/setgroups
1567 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1571 // Setup GID mapping
1572 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1576 // Parent has finished initialisation
1577 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1579 // Send signal to client
1580 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1587 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1590 // Change to the new root
1593 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1598 r
= pivot_root(".", ".");
1600 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1604 // Umount the old root
1605 r
= umount2(".", MNT_DETACH
);
1607 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1615 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1618 // Allocate a new PTY
1619 ctx
->consolefd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
1620 if (ctx
->consolefd
< 0)
1624 r
= ptsname_r(ctx
->consolefd
, ctx
->console
, sizeof(ctx
->console
));
1628 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->console
, ctx
->consolefd
);
1631 r
= pakfire_symlink(jail
->ctx
, "/dev/console", ctx
->console
);
1639 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1640 const char* argv
[]) {
1643 // Redirect any logging to our log pipe
1644 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
1647 pid_t pid
= getpid();
1649 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1651 // Wait for the parent to finish initialization
1652 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1657 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1659 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1663 // Make this process dumpable
1664 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
1666 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
1670 // Don't drop any capabilities on setuid()
1671 r
= prctl(PR_SET_KEEPCAPS
, 1);
1673 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1678 uid_t uid
= getuid();
1679 gid_t gid
= getgid();
1682 uid_t euid
= geteuid();
1683 gid_t egid
= getegid();
1685 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
1686 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
1688 // Log all mountpoints
1689 pakfire_mount_list(jail
->ctx
);
1691 // Fail if we are not PID 1
1693 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
1697 // Fail if we are not running as root
1698 if (uid
|| gid
|| euid
|| egid
) {
1699 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1703 // Mount all default stuff
1704 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
1709 // Create a new session
1712 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
1716 // Allocate a new PTY
1717 r
= pakfire_jail_open_pty(jail
, ctx
);
1719 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
1724 const char* root
= pakfire_get_path(jail
->pakfire
);
1725 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
1727 // Change mount propagation to slave to receive anything from the parent namespace
1728 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
1732 // Make root a mountpoint in the new mount namespace
1733 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
1737 // Change mount propagation to private
1738 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
1742 // Change root (unless root is /)
1743 if (!pakfire_on_root(jail
->pakfire
)) {
1745 r
= pakfire_jail_mount(jail
, ctx
);
1750 r
= pakfire_jail_switch_root(jail
, root
);
1756 unsigned long persona
= pakfire_arch_personality(arch
);
1758 r
= personality(persona
);
1760 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1766 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1767 r
= pakfire_jail_setup_loopback(jail
);
1774 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1776 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1778 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1783 // Close other end of log pipes
1784 close(ctx
->pipes
.log_INFO
[0]);
1785 close(ctx
->pipes
.log_ERROR
[0]);
1787 close(ctx
->pipes
.log_DEBUG
[0]);
1788 #endif /* ENABLE_DEBUG */
1790 // Connect standard input
1791 if (ctx
->pipes
.stdin
[0] >= 0) {
1792 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
1794 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
1795 ctx
->pipes
.stdin
[0]);
1801 // Connect standard output and error
1802 if (ctx
->pipes
.stdout
[1] >= 0 && ctx
->pipes
.stderr
[1] >= 0) {
1803 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1805 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1806 ctx
->pipes
.stdout
[1]);
1811 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1813 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1814 ctx
->pipes
.stderr
[1]);
1819 // Close the pipe (as we have moved the original file descriptors)
1820 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
1821 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1822 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1825 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1826 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1831 r
= pakfire_jail_set_capabilities(jail
);
1835 // Show capabilities
1836 r
= pakfire_jail_show_capabilities(jail
);
1841 r
= pakfire_jail_limit_syscalls(jail
);
1845 DEBUG(jail
->pakfire
, "Child process initialization done\n");
1846 DEBUG(jail
->pakfire
, "Launching command:\n");
1849 for (unsigned int i
= 0; argv
[i
]; i
++)
1850 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
1853 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1855 // Translate errno into regular exit code
1858 // Ignore if the command doesn't exist
1859 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
1870 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
1873 // We should not get here
1877 // Run a command in the jail
1878 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
1879 const int interactive
,
1880 pakfire_jail_communicate_in communicate_in
,
1881 pakfire_jail_communicate_out communicate_out
,
1882 void* data
, int flags
) {
1886 // Check if argv is valid
1887 if (!argv
|| !argv
[0]) {
1892 // Initialize context for this call
1893 struct pakfire_jail_exec ctx
= {
1897 .stdin
= { -1, -1 },
1898 .stdout
= { -1, -1 },
1899 .stderr
= { -1, -1 },
1900 .log_INFO
= { -1, -1 },
1901 .log_ERROR
= { -1, -1 },
1903 .log_DEBUG
= { -1, -1 },
1904 #endif /* ENABLE_DEBUG */
1908 .in
= communicate_in
,
1909 .out
= communicate_out
,
1916 DEBUG(jail
->pakfire
, "Executing jail...\n");
1918 // Enable networking in interactive mode
1920 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
1923 Setup a file descriptor which can be used to notify the client that the parent
1924 has completed configuration.
1926 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1927 if (ctx
.completed_fd
< 0) {
1928 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1932 // Create pipes to communicate with child process if we are not running interactively
1934 // stdin (only if callback is set)
1935 if (ctx
.communicate
.in
) {
1936 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
1942 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
1947 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
1952 // Setup pipes for logging
1954 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
1959 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
1965 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
1968 #endif /* ENABLE_DEBUG */
1970 // Configure child process
1971 struct clone_args args
= {
1981 .exit_signal
= SIGCHLD
,
1982 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
1985 // Launch the process in a cgroup that is a leaf of the configured cgroup
1987 args
.flags
|= CLONE_INTO_CGROUP
;
1990 const char* uuid
= pakfire_jail_uuid(jail
);
1992 // Create a temporary cgroup
1993 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
1995 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
1999 // Clone into this cgroup
2000 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2004 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2005 args
.flags
|= CLONE_NEWNET
;
2008 // Fork this process
2009 ctx
.pid
= clone3(&args
, sizeof(args
));
2011 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2015 } else if (ctx
.pid
== 0) {
2016 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2021 r
= pakfire_jail_parent(jail
, &ctx
);
2025 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2027 // Read output of the child process
2028 r
= pakfire_jail_wait(jail
, &ctx
);
2032 // Handle exit status
2033 switch (ctx
.status
.si_code
) {
2035 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2036 ctx
.status
.si_status
);
2039 exit
= ctx
.status
.si_status
;
2043 ERROR(jail
->pakfire
, "The child process was killed\n");
2048 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2051 // Log anything else
2053 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2058 // Destroy the temporary cgroup (if any)
2060 // Read cgroup stats
2061 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2062 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2063 pakfire_cgroup_destroy(ctx
.cgroup
);
2064 pakfire_cgroup_unref(ctx
.cgroup
);
2067 // Close any file descriptors
2068 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
2069 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
2070 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
2073 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2074 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2076 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2077 #endif /* ENABLE_DEBUG */
2082 PAKFIRE_EXPORT
int pakfire_jail_exec(
2083 struct pakfire_jail
* jail
,
2085 pakfire_jail_communicate_in callback_in
,
2086 pakfire_jail_communicate_out callback_out
,
2087 void* data
, int flags
) {
2088 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
2091 static int pakfire_jail_exec_interactive(
2092 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2095 // Setup interactive stuff
2096 r
= pakfire_jail_setup_interactive_env(jail
);
2100 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
2103 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2107 pakfire_jail_communicate_in callback_in
,
2108 pakfire_jail_communicate_out callback_out
,
2110 char path
[PATH_MAX
];
2111 const char** argv
= NULL
;
2115 const char* root
= pakfire_get_path(jail
->pakfire
);
2117 // Write the scriptlet to disk
2118 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2122 // Create a temporary file
2123 f
= pakfire_mktemp(path
, 0700);
2125 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2129 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2132 r
= fprintf(f
, "%s", script
);
2134 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2141 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2147 // Count how many arguments were passed
2148 unsigned int argc
= 1;
2150 for (const char** arg
= args
; *arg
; arg
++)
2154 argv
= calloc(argc
+ 1, sizeof(*argv
));
2156 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2161 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2164 for (unsigned int i
= 1; i
< argc
; i
++)
2165 argv
[i
] = args
[i
-1];
2168 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2176 // Remove script from disk
2184 A convenience function that creates a new jail, runs the given command and destroys
2187 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2188 struct pakfire_jail
* jail
= NULL
;
2191 // Create a new jail
2192 r
= pakfire_jail_create(&jail
, pakfire
);
2196 // Execute the command
2197 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2201 pakfire_jail_unref(jail
);
2206 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2207 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2208 struct pakfire_jail
* jail
= NULL
;
2211 // Create a new jail
2212 r
= pakfire_jail_create(&jail
, pakfire
);
2216 // Execute the command
2217 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2221 pakfire_jail_unref(jail
);
2226 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2229 const char* argv
[] = {
2230 "/bin/bash", "--login", NULL
,
2233 // Execute /bin/bash
2234 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2240 // Ignore any return codes from the shell
2244 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2245 char path
[PATH_MAX
];
2248 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2252 // Check if the file is executable
2253 r
= access(path
, X_OK
);
2255 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2259 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2262 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2263 const char* argv
[] = {
2268 return pakfire_jail_run_if_possible(pakfire
, argv
);
2271 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2272 const char* argv
[] = {
2273 "/usr/bin/systemd-tmpfiles",
2278 return pakfire_jail_run_if_possible(pakfire
, argv
);