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 // Socket to pass FDs
138 // Process status (from waitid)
141 // FD to notify the client that the parent has finished initialization
145 struct pakfire_jail_pipes
{
155 #endif /* ENABLE_DEBUG */
159 struct pakfire_jail_communicate
{
160 pakfire_jail_communicate_in in
;
161 pakfire_jail_communicate_out out
;
166 struct pakfire_jail_buffers
{
167 struct pakfire_log_buffer stdout
;
168 struct pakfire_log_buffer stderr
;
171 struct pakfire_log_buffer log_INFO
;
172 struct pakfire_log_buffer log_ERROR
;
174 struct pakfire_log_buffer log_DEBUG
;
175 #endif /* ENABLE_DEBUG */
178 struct pakfire_cgroup
* cgroup
;
179 struct pakfire_cgroup_stats cgroup_stats
;
182 char console
[PATH_MAX
];
186 static int clone3(struct clone_args
* args
, size_t size
) {
187 return syscall(__NR_clone3
, args
, size
);
190 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
191 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
194 static int pivot_root(const char* new_root
, const char* old_root
) {
195 return syscall(SYS_pivot_root
, new_root
, old_root
);
198 static int pakfire_jail_exec_has_flag(
199 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
200 return ctx
->flags
& flag
;
203 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
204 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
207 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
211 pakfire_cgroup_unref(jail
->cgroup
);
213 pakfire_unref(jail
->pakfire
);
215 pakfire_ctx_unref(jail
->ctx
);
220 Passes any log messages on to the default pakfire log callback
222 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
223 int priority
, const char* line
, size_t length
) {
226 INFO(pakfire
, "%s", line
);
230 ERROR(pakfire
, "%s", line
);
235 DEBUG(pakfire
, "%s", line
);
243 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
245 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
250 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
252 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
257 char* TERM
= secure_getenv("TERM");
259 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
265 char* LANG
= secure_getenv("LANG");
267 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
275 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
278 const char* arch
= pakfire_get_effective_arch(pakfire
);
280 // Allocate a new jail
281 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
286 j
->ctx
= pakfire_ctx(pakfire
);
289 j
->pakfire
= pakfire_ref(pakfire
);
291 // Initialize reference counter
294 // Generate a random UUID
295 uuid_generate_random(j
->uuid
);
297 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
299 // Set the default logging callback
300 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
302 // Set default environment
303 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
304 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
309 // Enable all CPU features that CPU has to offer
310 if (!pakfire_arch_is_supported_by_host(arch
)) {
311 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
316 // Set container UUID
317 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
321 // Disable systemctl to talk to systemd
322 if (!pakfire_on_root(j
->pakfire
)) {
323 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
333 pakfire_jail_free(j
);
338 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
344 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
345 if (--jail
->nrefs
> 0)
348 pakfire_jail_free(jail
);
354 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
355 pakfire_jail_log_callback callback
, void* data
) {
356 jail
->callbacks
.log
= callback
;
357 jail
->callbacks
.log_data
= data
;
362 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
363 // Check if nice level is in range
364 if (nice
< -19 || nice
> 20) {
375 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
376 // Free any previous cgroup
378 pakfire_cgroup_unref(jail
->cgroup
);
382 // Set any new cgroup
384 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
386 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
395 // Returns the length of the environment
396 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
399 // Count everything in the environment
400 for (char** e
= jail
->env
; *e
; e
++)
406 // Finds an existing environment variable and returns its index or -1 if not found
407 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
413 const size_t length
= strlen(key
);
415 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
416 if ((pakfire_string_startswith(jail
->env
[i
], key
)
417 && *(jail
->env
[i
] + length
) == '=')) {
426 // Returns the value of an environment variable or NULL
427 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
429 int i
= pakfire_jail_find_env(jail
, key
);
433 return jail
->env
[i
] + strlen(key
) + 1;
436 // Sets an environment variable
437 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
438 const char* key
, const char* value
) {
439 // Find the index where to write this value to
440 int i
= pakfire_jail_find_env(jail
, key
);
442 i
= pakfire_jail_env_length(jail
);
444 // Return -ENOSPC when the environment is full
445 if (i
>= ENVIRON_SIZE
) {
450 // Free any previous value
454 // Format and set environment variable
455 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
457 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
462 // Imports an environment
463 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
471 // Copy environment variables
472 for (unsigned int i
= 0; env
[i
]; i
++) {
473 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
478 r
= pakfire_jail_set_env(jail
, key
, val
);
495 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
496 struct pakfire_jail
* jail
, unsigned int timeout
) {
498 jail
->timeout
.it_value
.tv_sec
= timeout
;
501 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
503 DEBUG(jail
->pakfire
, "Timeout disabled\n");
508 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
511 // Nothing to do if no timeout has been set
512 if (!jail
->timeout
.it_value
.tv_sec
)
515 // Create a new timer
516 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
518 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
523 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
525 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
539 This function replaces any logging in the child process.
541 All log messages will be sent to the parent process through their respective pipes.
543 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
544 int line
, const char* fn
, const char* format
, va_list args
) {
545 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
550 fd
= pipes
->log_INFO
[1];
554 fd
= pipes
->log_ERROR
[1];
559 fd
= pipes
->log_DEBUG
[1];
561 #endif /* ENABLE_DEBUG */
563 // Ignore any messages of an unknown priority
568 // Send the log message
570 vdprintf(fd
, format
, args
);
573 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
574 return (sizeof(buffer
->data
) == buffer
->used
);
578 This function reads as much data as it can from the file descriptor.
579 If it finds a whole line in it, it will send it to the logger and repeat the process.
580 If not newline character is found, it will try to read more data until it finds one.
582 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
583 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
584 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
585 char line
[BUFFER_SIZE
+ 1];
587 // Fill up buffer from fd
588 if (buffer
->used
< sizeof(buffer
->data
)) {
589 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
590 sizeof(buffer
->data
) - buffer
->used
);
593 if (bytes_read
< 0) {
594 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
598 // Update buffer size
599 buffer
->used
+= bytes_read
;
602 // See if we have any lines that we can write
603 while (buffer
->used
) {
604 // Search for the end of the first line
605 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
609 // If the buffer is full, we send the content to the logger and try again
610 // This should not happen in practise
611 if (pakfire_jail_log_buffer_is_full(buffer
)) {
612 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
614 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
616 // Otherwise we might have only read parts of the output
621 // Find the length of the string
622 size_t length
= eol
- buffer
->data
+ 1;
624 // Copy the line into the buffer
625 memcpy(line
, buffer
->data
, length
);
627 // Terminate the string
632 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
634 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
639 // Remove line from buffer
640 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
641 buffer
->used
-= length
;
647 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
648 struct pakfire_jail_exec
* ctx
, const int fd
) {
651 // Nothing to do if there is no stdin callback set
652 if (!ctx
->communicate
.in
) {
653 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
657 // Skip if the writing pipe has already been closed
658 if (ctx
->pipes
.stdin
[1] < 0)
661 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
663 // Calling the callback
664 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
666 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
668 // The callback signaled that it has written everything
670 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
672 // Close the file-descriptor
675 // Reset the file-descriptor so it won't be closed again later
676 ctx
->pipes
.stdin
[1] = -1;
685 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
686 const size_t payload_length
= sizeof(fd
);
687 char buffer
[CMSG_SPACE(payload_length
)];
690 struct msghdr msg
= {
691 .msg_control
= buffer
,
692 .msg_controllen
= sizeof(buffer
),
695 // Receive the message
696 r
= recvmsg(socket
, &msg
, 0);
698 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
703 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
707 *fd
= *((int*)CMSG_DATA(cmsg
));
709 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
714 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
715 const size_t payload_length
= sizeof(fd
);
716 char buffer
[CMSG_SPACE(payload_length
)];
719 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
722 struct msghdr msg
= {
723 .msg_control
= buffer
,
724 .msg_controllen
= sizeof(buffer
),
728 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
729 cmsg
->cmsg_level
= SOL_SOCKET
;
730 cmsg
->cmsg_type
= SCM_RIGHTS
;
731 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
734 *((int*)CMSG_DATA(cmsg
)) = fd
;
737 r
= sendmsg(socket
, &msg
, 0);
739 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
746 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
747 int r
= pipe2(*fds
, flags
);
749 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
756 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
757 for (unsigned int i
= 0; i
< 2; i
++)
763 This is a convenience function to fetch the reading end of a pipe and
764 closes the write end.
766 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
767 // Give the variables easier names to avoid confusion
768 int* fd_read
= &(*fds
)[0];
769 int* fd_write
= &(*fds
)[1];
771 // Close the write end of the pipe
772 if (*fd_write
>= 0) {
777 // Return the read end
784 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
785 // Give the variables easier names to avoid confusion
786 int* fd_read
= &(*fds
)[0];
787 int* fd_write
= &(*fds
)[1];
789 // Close the read end of the pipe
795 // Return the write end
802 static int pakfire_jail_log(struct pakfire
* pakfire
, void* data
, int priority
,
803 const char* line
, const size_t length
) {
804 // Pass everything to the parent logger
805 pakfire_log_condition(pakfire
, priority
, 0, "%.*s", (int)length
, line
);
810 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
811 struct epoll_event event
= {
812 .events
= events
|EPOLLHUP
,
820 int flags
= fcntl(fd
, F_GETFL
, 0);
822 // Set modified flags
823 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
825 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
826 fd
, strerror(errno
));
830 // Add the file descriptor to the loop
831 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
833 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
834 fd
, strerror(errno
));
841 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
843 struct epoll_event events
[EPOLL_MAX_EVENTS
];
847 // Fetch file descriptors from context
848 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
849 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
850 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
851 const int pidfd
= ctx
->pidfd
;
853 // Fetch the UNIX domain socket
854 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
857 const int timerfd
= pakfire_jail_create_timer(jail
);
860 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
861 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
863 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
864 #endif /* ENABLE_DEBUG */
866 // Make a list of all file descriptors we are interested in
867 const struct pakfire_wait_fds
{
871 // Standard input/output
877 { timerfd
, EPOLLIN
},
880 { ctx
->pidfd
, EPOLLIN
},
883 { log_INFO
, EPOLLIN
},
884 { log_ERROR
, EPOLLIN
},
886 { log_DEBUG
, EPOLLIN
},
887 #endif /* ENABLE_DEBUG */
889 // UNIX Domain Socket
890 { socket_recv
, EPOLLIN
},
897 epollfd
= epoll_create1(0);
899 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
904 // Turn file descriptors into non-blocking mode and add them to epoll()
905 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
906 // Skip fds which were not initialized
910 // Add the FD to the event loop
911 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
918 // Loop for as long as the process is alive
920 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
922 // Ignore if epoll_wait() has been interrupted
926 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
932 for (int i
= 0; i
< num
; i
++) {
933 int e
= events
[i
].events
;
934 int fd
= events
[i
].data
.fd
;
936 struct pakfire_log_buffer
* buffer
= NULL
;
937 pakfire_jail_communicate_out callback
= NULL
;
941 // Check if there is any data to be read
943 // Handle any changes to the PIDFD
945 // Call waidid() and store the result
946 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
948 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
952 // Mark that we have ended so that we will process the remaining
953 // events from epoll() now, but won't restart the outer loop.
957 // Handle timer events
958 } else if (fd
== timerfd
) {
959 DEBUG(jail
->pakfire
, "Timer event received\n");
962 r
= read(timerfd
, garbage
, sizeof(garbage
));
964 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
969 // Terminate the process if it hasn't already ended
971 DEBUG(jail
->pakfire
, "Terminating process...\n");
973 // Send SIGTERM to the process
974 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
976 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
981 // Don't fall through to log processing
984 // Handle logging messages
985 } else if (fd
== log_INFO
) {
986 buffer
= &ctx
->buffers
.log_INFO
;
989 callback
= pakfire_jail_log
;
991 } else if (fd
== log_ERROR
) {
992 buffer
= &ctx
->buffers
.log_ERROR
;
995 callback
= pakfire_jail_log
;
998 } else if (fd
== log_DEBUG
) {
999 buffer
= &ctx
->buffers
.log_DEBUG
;
1000 priority
= LOG_DEBUG
;
1002 callback
= pakfire_jail_log
;
1003 #endif /* ENABLE_DEBUG */
1005 // Handle anything from the log pipes
1006 } else if (fd
== stdout
) {
1007 buffer
= &ctx
->buffers
.stdout
;
1008 priority
= LOG_INFO
;
1010 // Send any output to the default logger if no callback is set
1011 if (ctx
->communicate
.out
) {
1012 callback
= ctx
->communicate
.out
;
1013 data
= ctx
->communicate
.data
;
1015 callback
= jail
->callbacks
.log
;
1016 data
= jail
->callbacks
.log_data
;
1019 } else if (fd
== stderr
) {
1020 buffer
= &ctx
->buffers
.stderr
;
1023 // Send any output to the default logger if no callback is set
1024 if (ctx
->communicate
.out
) {
1025 callback
= ctx
->communicate
.out
;
1026 data
= ctx
->communicate
.data
;
1028 callback
= jail
->callbacks
.log
;
1029 data
= jail
->callbacks
.log_data
;
1032 // Handle socket messages
1033 } else if (fd
== socket_recv
) {
1034 // Receive the passed FD
1035 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1039 // XXX Do something with the file descriptor
1041 // Don't fall through to log processing
1045 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1050 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
1056 // Handle standard input
1058 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
1061 // Ignore if we filled up the buffer
1066 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
1073 // Check if any file descriptors have been closed
1075 // Remove the file descriptor
1076 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1078 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1094 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1095 int priority
, const char* line
, size_t length
) {
1096 char** output
= (char**)data
;
1099 // Append everything from stdout to a buffer
1100 if (output
&& priority
== LOG_INFO
) {
1101 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
1107 // Send everything else to the default logger
1108 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1113 // Logs all capabilities of the current process
1114 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1117 cap_flag_value_t value_e
;
1118 cap_flag_value_t value_i
;
1119 cap_flag_value_t value_p
;
1123 pid_t pid
= getpid();
1125 // Fetch all capabilities
1126 caps
= cap_get_proc();
1128 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1133 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1135 // Iterate over all capabilities
1136 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1137 name
= cap_to_name(cap
);
1139 // Fetch effective value
1140 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1144 // Fetch inheritable value
1145 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1149 // Fetch permitted value
1150 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1154 DEBUG(jail
->pakfire
,
1155 " %-24s : %c%c%c\n",
1157 (value_e
== CAP_SET
) ? 'e' : '-',
1158 (value_i
== CAP_SET
) ? 'i' : '-',
1159 (value_p
== CAP_SET
) ? 'p' : '-'
1179 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1184 // Fetch capabilities
1185 caps
= cap_get_proc();
1187 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1192 // Walk through all capabilities
1193 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1194 cap_value_t _caps
[] = { cap
};
1196 // Fetch the name of the capability
1197 name
= cap_to_name(cap
);
1199 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1201 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1205 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1207 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1211 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1213 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1222 // Restore all capabilities
1223 r
= cap_set_proc(caps
);
1225 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1229 // Add all capabilities to the ambient set
1230 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1231 name
= cap_to_name(cap
);
1233 // Raise the capability
1234 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1236 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1259 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1260 const int syscalls
[] = {
1261 // The kernel's keyring isn't namespaced
1264 SCMP_SYS(request_key
),
1266 // Disable userfaultfd
1267 SCMP_SYS(userfaultfd
),
1269 // Disable perf which could leak a lot of information about the host
1270 SCMP_SYS(perf_event_open
),
1276 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1278 // Setup a syscall filter which allows everything by default
1279 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1281 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1286 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1287 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1289 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1294 // Load syscall filter into the kernel
1295 r
= seccomp_load(ctx
);
1297 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1303 seccomp_release(ctx
);
1310 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1311 const char* source
, const char* target
, int flags
) {
1312 struct pakfire_jail_mountpoint
* mp
= NULL
;
1315 // Check if there is any space left
1316 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1321 // Check for valid inputs
1322 if (!source
|| !target
) {
1327 // Select the next free slot
1328 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1331 r
= pakfire_string_set(mp
->source
, source
);
1333 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1338 r
= pakfire_string_set(mp
->target
, target
);
1340 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1347 // Increment counter
1348 jail
->num_mountpoints
++;
1353 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1356 const char* paths
[] = {
1362 // Bind-mount all paths read-only
1363 for (const char** path
= paths
; *path
; path
++) {
1364 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1367 // Ignore if we don't have permission
1382 Mounts everything that we require in the new namespace
1384 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1385 struct pakfire_jail_mountpoint
* mp
= NULL
;
1389 // Enable loop devices
1390 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1391 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1393 // Mount all default stuff
1394 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1399 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1403 // Mount the interpreter (if needed)
1404 r
= pakfire_mount_interpreter(jail
->pakfire
);
1408 // Mount networking stuff
1409 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1410 r
= pakfire_jail_mount_networking(jail
);
1415 // Mount all custom stuff
1416 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1418 mp
= &jail
->mountpoints
[i
];
1421 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1431 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1432 struct nl_sock
* nl
= NULL
;
1433 struct nl_cache
* cache
= NULL
;
1434 struct rtnl_link
* link
= NULL
;
1435 struct rtnl_link
* change
= NULL
;
1438 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1440 // Allocate a netlink socket
1441 nl
= nl_socket_alloc();
1443 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1448 // Connect the socket
1449 r
= nl_connect(nl
, NETLINK_ROUTE
);
1451 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1455 // Allocate the netlink cache
1456 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1458 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1462 // Fetch loopback interface
1463 link
= rtnl_link_get_by_name(cache
, "lo");
1465 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1470 // Allocate a new link
1471 change
= rtnl_link_alloc();
1473 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1478 // Set the link to UP
1479 rtnl_link_set_flags(change
, IFF_UP
);
1481 // Apply any changes
1482 r
= rtnl_link_change(nl
, link
, change
, 0);
1484 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1500 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1501 char path
[PATH_MAX
];
1504 // Skip mapping anything when running on /
1505 if (pakfire_on_root(jail
->pakfire
))
1509 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1514 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1517 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1521 /* When running as root, we will map the entire range.
1523 When running as a non-privileged user, we will map the root user inside the jail
1524 to the user's UID outside of the jail, and we will map the rest starting from one.
1529 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1530 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1532 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1533 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1537 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1544 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1545 char path
[PATH_MAX
];
1548 // Skip mapping anything when running on /
1549 if (pakfire_on_root(jail
->pakfire
))
1553 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1556 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1561 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1567 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1568 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1570 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1571 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1575 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1582 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1583 char path
[PATH_MAX
];
1587 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1591 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1593 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1600 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1601 const uint64_t val
= 1;
1604 DEBUG(jail
->pakfire
, "Sending signal...\n");
1606 // Write to the file descriptor
1607 r
= eventfd_write(fd
, val
);
1609 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1613 // Close the file descriptor
1619 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1623 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1625 r
= eventfd_read(fd
, &val
);
1627 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1631 // Close the file descriptor
1638 Performs the initialisation that needs to happen in the parent part
1640 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1643 // Setup UID mapping
1644 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1648 // Write "deny" to /proc/PID/setgroups
1649 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1653 // Setup GID mapping
1654 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1658 // Parent has finished initialisation
1659 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1661 // Send signal to client
1662 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1669 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1672 // Change to the new root
1675 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1680 r
= pivot_root(".", ".");
1682 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1686 // Umount the old root
1687 r
= umount2(".", MNT_DETACH
);
1689 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1697 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1700 // Allocate a new PTY
1701 ctx
->consolefd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
1702 if (ctx
->consolefd
< 0)
1706 r
= ptsname_r(ctx
->consolefd
, ctx
->console
, sizeof(ctx
->console
));
1710 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->console
, ctx
->consolefd
);
1713 r
= pakfire_symlink(jail
->ctx
, "/dev/console", ctx
->console
);
1721 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1722 const char* argv
[]) {
1725 // Redirect any logging to our log pipe
1726 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
1729 pid_t pid
= getpid();
1731 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1733 // Wait for the parent to finish initialization
1734 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1739 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1741 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1745 // Make this process dumpable
1746 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
1748 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
1752 // Don't drop any capabilities on setuid()
1753 r
= prctl(PR_SET_KEEPCAPS
, 1);
1755 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1760 uid_t uid
= getuid();
1761 gid_t gid
= getgid();
1764 uid_t euid
= geteuid();
1765 gid_t egid
= getegid();
1767 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
1768 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
1770 // Log all mountpoints
1771 pakfire_mount_list(jail
->ctx
);
1773 // Fail if we are not PID 1
1775 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
1779 // Fail if we are not running as root
1780 if (uid
|| gid
|| euid
|| egid
) {
1781 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1785 // Mount all default stuff
1786 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
1791 // Create a new session
1794 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
1798 // Allocate a new PTY
1799 r
= pakfire_jail_open_pty(jail
, ctx
);
1801 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
1806 const char* root
= pakfire_get_path(jail
->pakfire
);
1807 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
1809 // Change mount propagation to slave to receive anything from the parent namespace
1810 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
1814 // Make root a mountpoint in the new mount namespace
1815 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
1819 // Change mount propagation to private
1820 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
1824 // Change root (unless root is /)
1825 if (!pakfire_on_root(jail
->pakfire
)) {
1827 r
= pakfire_jail_mount(jail
, ctx
);
1832 r
= pakfire_jail_switch_root(jail
, root
);
1838 unsigned long persona
= pakfire_arch_personality(arch
);
1840 r
= personality(persona
);
1842 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1848 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1849 r
= pakfire_jail_setup_loopback(jail
);
1856 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1858 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1860 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1865 // Close other end of log pipes
1866 close(ctx
->pipes
.log_INFO
[0]);
1867 close(ctx
->pipes
.log_ERROR
[0]);
1869 close(ctx
->pipes
.log_DEBUG
[0]);
1870 #endif /* ENABLE_DEBUG */
1872 // Connect standard input
1873 if (ctx
->pipes
.stdin
[0] >= 0) {
1874 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
1876 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
1877 ctx
->pipes
.stdin
[0]);
1883 // Connect standard output and error
1884 if (ctx
->pipes
.stdout
[1] >= 0 && ctx
->pipes
.stderr
[1] >= 0) {
1885 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
1887 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
1888 ctx
->pipes
.stdout
[1]);
1893 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
1895 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
1896 ctx
->pipes
.stderr
[1]);
1901 // Close the pipe (as we have moved the original file descriptors)
1902 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
1903 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
1904 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
1907 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1908 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
1913 r
= pakfire_jail_set_capabilities(jail
);
1917 // Show capabilities
1918 r
= pakfire_jail_show_capabilities(jail
);
1923 r
= pakfire_jail_limit_syscalls(jail
);
1927 DEBUG(jail
->pakfire
, "Child process initialization done\n");
1928 DEBUG(jail
->pakfire
, "Launching command:\n");
1931 for (unsigned int i
= 0; argv
[i
]; i
++)
1932 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
1935 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
1937 // Translate errno into regular exit code
1940 // Ignore if the command doesn't exist
1941 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
1952 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
1955 // We should not get here
1959 // Run a command in the jail
1960 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
1961 const int interactive
,
1962 pakfire_jail_communicate_in communicate_in
,
1963 pakfire_jail_communicate_out communicate_out
,
1964 void* data
, int flags
) {
1968 // Check if argv is valid
1969 if (!argv
|| !argv
[0]) {
1974 // Initialize context for this call
1975 struct pakfire_jail_exec ctx
= {
1978 .socket
= { -1, -1 },
1981 .stdin
= { -1, -1 },
1982 .stdout
= { -1, -1 },
1983 .stderr
= { -1, -1 },
1984 .log_INFO
= { -1, -1 },
1985 .log_ERROR
= { -1, -1 },
1987 .log_DEBUG
= { -1, -1 },
1988 #endif /* ENABLE_DEBUG */
1992 .in
= communicate_in
,
1993 .out
= communicate_out
,
2000 DEBUG(jail
->pakfire
, "Executing jail...\n");
2002 // Enable networking in interactive mode
2004 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2007 Setup a file descriptor which can be used to notify the client that the parent
2008 has completed configuration.
2010 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2011 if (ctx
.completed_fd
< 0) {
2012 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2016 // Create a UNIX domain socket
2017 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2019 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2024 // Create pipes to communicate with child process if we are not running interactively
2026 // stdin (only if callback is set)
2027 if (ctx
.communicate
.in
) {
2028 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
2034 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
2039 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
2044 // Setup pipes for logging
2046 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2051 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2057 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2060 #endif /* ENABLE_DEBUG */
2062 // Configure child process
2063 struct clone_args args
= {
2073 .exit_signal
= SIGCHLD
,
2074 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2077 // Launch the process in a cgroup that is a leaf of the configured cgroup
2079 args
.flags
|= CLONE_INTO_CGROUP
;
2082 const char* uuid
= pakfire_jail_uuid(jail
);
2084 // Create a temporary cgroup
2085 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2087 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2091 // Clone into this cgroup
2092 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2096 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2097 args
.flags
|= CLONE_NEWNET
;
2100 // Fork this process
2101 ctx
.pid
= clone3(&args
, sizeof(args
));
2103 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2107 } else if (ctx
.pid
== 0) {
2108 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2113 r
= pakfire_jail_parent(jail
, &ctx
);
2117 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2119 // Read output of the child process
2120 r
= pakfire_jail_wait(jail
, &ctx
);
2124 // Handle exit status
2125 switch (ctx
.status
.si_code
) {
2127 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2128 ctx
.status
.si_status
);
2131 exit
= ctx
.status
.si_status
;
2135 ERROR(jail
->pakfire
, "The child process was killed\n");
2140 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2143 // Log anything else
2145 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2150 // Destroy the temporary cgroup (if any)
2152 // Read cgroup stats
2153 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2154 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2155 pakfire_cgroup_destroy(ctx
.cgroup
);
2156 pakfire_cgroup_unref(ctx
.cgroup
);
2159 // Close any file descriptors
2160 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
2161 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
2162 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
2165 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2166 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2168 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2169 #endif /* ENABLE_DEBUG */
2170 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2175 PAKFIRE_EXPORT
int pakfire_jail_exec(
2176 struct pakfire_jail
* jail
,
2178 pakfire_jail_communicate_in callback_in
,
2179 pakfire_jail_communicate_out callback_out
,
2180 void* data
, int flags
) {
2181 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
2184 static int pakfire_jail_exec_interactive(
2185 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2188 // Setup interactive stuff
2189 r
= pakfire_jail_setup_interactive_env(jail
);
2193 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
2196 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2200 pakfire_jail_communicate_in callback_in
,
2201 pakfire_jail_communicate_out callback_out
,
2203 char path
[PATH_MAX
];
2204 const char** argv
= NULL
;
2208 const char* root
= pakfire_get_path(jail
->pakfire
);
2210 // Write the scriptlet to disk
2211 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2215 // Create a temporary file
2216 f
= pakfire_mktemp(path
, 0700);
2218 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2222 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2225 r
= fprintf(f
, "%s", script
);
2227 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2234 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2240 // Count how many arguments were passed
2241 unsigned int argc
= 1;
2243 for (const char** arg
= args
; *arg
; arg
++)
2247 argv
= calloc(argc
+ 1, sizeof(*argv
));
2249 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2254 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2257 for (unsigned int i
= 1; i
< argc
; i
++)
2258 argv
[i
] = args
[i
-1];
2261 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2269 // Remove script from disk
2277 A convenience function that creates a new jail, runs the given command and destroys
2280 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2281 struct pakfire_jail
* jail
= NULL
;
2284 // Create a new jail
2285 r
= pakfire_jail_create(&jail
, pakfire
);
2289 // Execute the command
2290 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2294 pakfire_jail_unref(jail
);
2299 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2300 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2301 struct pakfire_jail
* jail
= NULL
;
2304 // Create a new jail
2305 r
= pakfire_jail_create(&jail
, pakfire
);
2309 // Execute the command
2310 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2314 pakfire_jail_unref(jail
);
2319 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2322 const char* argv
[] = {
2323 "/bin/bash", "--login", NULL
,
2326 // Execute /bin/bash
2327 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2333 // Ignore any return codes from the shell
2337 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2338 char path
[PATH_MAX
];
2341 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2345 // Check if the file is executable
2346 r
= access(path
, X_OK
);
2348 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2352 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2355 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2356 const char* argv
[] = {
2361 return pakfire_jail_run_if_possible(pakfire
, argv
);
2364 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2365 const char* argv
[] = {
2366 "/usr/bin/systemd-tmpfiles",
2371 return pakfire_jail_run_if_possible(pakfire
, argv
);