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>
45 #include <netlink/route/link.h>
53 #include <pakfire/arch.h>
54 #include <pakfire/cgroup.h>
55 #include <pakfire/jail.h>
56 #include <pakfire/logging.h>
57 #include <pakfire/mount.h>
58 #include <pakfire/pakfire.h>
59 #include <pakfire/path.h>
60 #include <pakfire/private.h>
61 #include <pakfire/pwd.h>
62 #include <pakfire/string.h>
63 #include <pakfire/util.h>
65 #define BUFFER_SIZE 1024 * 64
66 #define ENVIRON_SIZE 128
67 #define EPOLL_MAX_EVENTS 2
68 #define MAX_MOUNTPOINTS 8
70 // The default environment that will be set for every command
71 static const struct environ
{
76 { "LANG", "C.utf-8" },
77 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
80 // Tell everything that it is running inside a Pakfire container
81 { "container", "pakfire" },
85 struct pakfire_jail_mountpoint
{
86 char source
[PATH_MAX
];
87 char target
[PATH_MAX
];
92 struct pakfire_ctx
* ctx
;
93 struct pakfire
* pakfire
;
96 // A unique ID for each jail
98 char __uuid
[UUID_STR_LEN
];
104 struct itimerspec timeout
;
107 struct pakfire_cgroup
* cgroup
;
110 char* env
[ENVIRON_SIZE
];
113 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
114 unsigned int num_mountpoints
;
117 struct pakfire_jail_callbacks
{
119 pakfire_jail_log_callback log
;
124 struct pakfire_log_buffer
{
125 char data
[BUFFER_SIZE
];
129 struct pakfire_jail_exec
{
132 // PID (of the child)
136 // Socket to pass FDs
139 // Process status (from waitid)
142 // FD to notify the client that the parent has finished initialization
146 struct pakfire_jail_pipes
{
156 #endif /* ENABLE_DEBUG */
160 struct pakfire_jail_communicate
{
161 pakfire_jail_communicate_in in
;
162 pakfire_jail_communicate_out out
;
167 struct pakfire_jail_buffers
{
168 struct pakfire_log_buffer stdout
;
169 struct pakfire_log_buffer stderr
;
172 struct pakfire_log_buffer log_INFO
;
173 struct pakfire_log_buffer log_ERROR
;
175 struct pakfire_log_buffer log_DEBUG
;
176 #endif /* ENABLE_DEBUG */
179 struct pakfire_cgroup
* cgroup
;
180 struct pakfire_cgroup_stats cgroup_stats
;
183 struct pakfire_jail_pty
{
184 // The path to the console
185 char console
[PATH_MAX
];
188 struct pakfire_jail_pty_master
{
191 enum pakfire_jail_pty_flags
{
192 PAKFIRE_JAIL_PTY_READY_TO_READ
= (1 << 0),
193 PAKFIRE_JAIL_PTY_READY_TO_WRITE
= (1 << 1),
198 struct pakfire_jail_pty_stdio
{
200 char buffer
[LINE_MAX
];
201 struct termios attrs
;
202 enum pakfire_jail_pty_flags flags
;
206 struct pakfire_jail_pty_stdio stdout
;
210 static int clone3(struct clone_args
* args
, size_t size
) {
211 return syscall(__NR_clone3
, args
, size
);
214 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
215 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
218 static int pivot_root(const char* new_root
, const char* old_root
) {
219 return syscall(SYS_pivot_root
, new_root
, old_root
);
222 static int pakfire_jail_exec_has_flag(
223 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
224 return ctx
->flags
& flag
;
227 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
228 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
231 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
235 pakfire_cgroup_unref(jail
->cgroup
);
237 pakfire_unref(jail
->pakfire
);
239 pakfire_ctx_unref(jail
->ctx
);
244 Passes any log messages on to the default pakfire log callback
246 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
247 int priority
, const char* line
, size_t length
) {
250 INFO(pakfire
, "%s", line
);
254 ERROR(pakfire
, "%s", line
);
259 DEBUG(pakfire
, "%s", line
);
267 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
269 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
274 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
276 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
281 char* TERM
= secure_getenv("TERM");
283 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
289 char* LANG
= secure_getenv("LANG");
291 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
299 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
302 const char* arch
= pakfire_get_effective_arch(pakfire
);
304 // Allocate a new jail
305 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
310 j
->ctx
= pakfire_ctx(pakfire
);
313 j
->pakfire
= pakfire_ref(pakfire
);
315 // Initialize reference counter
318 // Generate a random UUID
319 uuid_generate_random(j
->uuid
);
321 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
323 // Set the default logging callback
324 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
326 // Set default environment
327 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
328 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
333 // Enable all CPU features that CPU has to offer
334 if (!pakfire_arch_is_supported_by_host(arch
)) {
335 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
340 // Set container UUID
341 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
345 // Disable systemctl to talk to systemd
346 if (!pakfire_on_root(j
->pakfire
)) {
347 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
357 pakfire_jail_free(j
);
362 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
368 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
369 if (--jail
->nrefs
> 0)
372 pakfire_jail_free(jail
);
378 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
379 pakfire_jail_log_callback callback
, void* data
) {
380 jail
->callbacks
.log
= callback
;
381 jail
->callbacks
.log_data
= data
;
386 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
387 // Check if nice level is in range
388 if (nice
< -19 || nice
> 20) {
399 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
400 // Free any previous cgroup
402 pakfire_cgroup_unref(jail
->cgroup
);
406 // Set any new cgroup
408 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
410 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
419 // Returns the length of the environment
420 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
423 // Count everything in the environment
424 for (char** e
= jail
->env
; *e
; e
++)
430 // Finds an existing environment variable and returns its index or -1 if not found
431 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
437 const size_t length
= strlen(key
);
439 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
440 if ((pakfire_string_startswith(jail
->env
[i
], key
)
441 && *(jail
->env
[i
] + length
) == '=')) {
450 // Returns the value of an environment variable or NULL
451 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
453 int i
= pakfire_jail_find_env(jail
, key
);
457 return jail
->env
[i
] + strlen(key
) + 1;
460 // Sets an environment variable
461 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
462 const char* key
, const char* value
) {
463 // Find the index where to write this value to
464 int i
= pakfire_jail_find_env(jail
, key
);
466 i
= pakfire_jail_env_length(jail
);
468 // Return -ENOSPC when the environment is full
469 if (i
>= ENVIRON_SIZE
) {
474 // Free any previous value
478 // Format and set environment variable
479 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
481 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
486 // Imports an environment
487 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
495 // Copy environment variables
496 for (unsigned int i
= 0; env
[i
]; i
++) {
497 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
502 r
= pakfire_jail_set_env(jail
, key
, val
);
519 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
520 struct pakfire_jail
* jail
, unsigned int timeout
) {
522 jail
->timeout
.it_value
.tv_sec
= timeout
;
525 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
527 DEBUG(jail
->pakfire
, "Timeout disabled\n");
532 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
535 // Nothing to do if no timeout has been set
536 if (!jail
->timeout
.it_value
.tv_sec
)
539 // Create a new timer
540 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
542 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
547 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
549 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
563 This function replaces any logging in the child process.
565 All log messages will be sent to the parent process through their respective pipes.
567 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
568 int line
, const char* fn
, const char* format
, va_list args
) {
569 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
574 fd
= pipes
->log_INFO
[1];
578 fd
= pipes
->log_ERROR
[1];
583 fd
= pipes
->log_DEBUG
[1];
585 #endif /* ENABLE_DEBUG */
587 // Ignore any messages of an unknown priority
592 // Send the log message
594 vdprintf(fd
, format
, args
);
597 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
598 return (sizeof(buffer
->data
) == buffer
->used
);
602 This function reads as much data as it can from the file descriptor.
603 If it finds a whole line in it, it will send it to the logger and repeat the process.
604 If not newline character is found, it will try to read more data until it finds one.
606 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
607 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
608 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
609 char line
[BUFFER_SIZE
+ 1];
611 // Fill up buffer from fd
612 if (buffer
->used
< sizeof(buffer
->data
)) {
613 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
614 sizeof(buffer
->data
) - buffer
->used
);
617 if (bytes_read
< 0) {
618 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
622 // Update buffer size
623 buffer
->used
+= bytes_read
;
626 // See if we have any lines that we can write
627 while (buffer
->used
) {
628 // Search for the end of the first line
629 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
633 // If the buffer is full, we send the content to the logger and try again
634 // This should not happen in practise
635 if (pakfire_jail_log_buffer_is_full(buffer
)) {
636 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
638 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
640 // Otherwise we might have only read parts of the output
645 // Find the length of the string
646 size_t length
= eol
- buffer
->data
+ 1;
648 // Copy the line into the buffer
649 memcpy(line
, buffer
->data
, length
);
651 // Terminate the string
656 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
658 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
663 // Remove line from buffer
664 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
665 buffer
->used
-= length
;
671 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
672 struct pakfire_jail_exec
* ctx
, const int fd
) {
675 // Nothing to do if there is no stdin callback set
676 if (!ctx
->communicate
.in
) {
677 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
681 // Skip if the writing pipe has already been closed
682 if (ctx
->pipes
.stdin
[1] < 0)
685 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
687 // Calling the callback
688 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
690 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
692 // The callback signaled that it has written everything
694 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
696 // Close the file-descriptor
699 // Reset the file-descriptor so it won't be closed again later
700 ctx
->pipes
.stdin
[1] = -1;
709 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
710 const size_t payload_length
= sizeof(fd
);
711 char buffer
[CMSG_SPACE(payload_length
)];
714 struct msghdr msg
= {
715 .msg_control
= buffer
,
716 .msg_controllen
= sizeof(buffer
),
719 // Receive the message
720 r
= recvmsg(socket
, &msg
, 0);
722 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
727 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
731 *fd
= *((int*)CMSG_DATA(cmsg
));
733 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
738 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
739 const size_t payload_length
= sizeof(fd
);
740 char buffer
[CMSG_SPACE(payload_length
)];
743 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
746 struct msghdr msg
= {
747 .msg_control
= buffer
,
748 .msg_controllen
= sizeof(buffer
),
752 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
753 cmsg
->cmsg_level
= SOL_SOCKET
;
754 cmsg
->cmsg_type
= SCM_RIGHTS
;
755 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
758 *((int*)CMSG_DATA(cmsg
)) = fd
;
761 r
= sendmsg(socket
, &msg
, 0);
763 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
770 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
771 int r
= pipe2(*fds
, flags
);
773 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
780 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
781 for (unsigned int i
= 0; i
< 2; i
++)
787 This is a convenience function to fetch the reading end of a pipe and
788 closes the write end.
790 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
791 // Give the variables easier names to avoid confusion
792 int* fd_read
= &(*fds
)[0];
793 int* fd_write
= &(*fds
)[1];
795 // Close the write end of the pipe
796 if (*fd_write
>= 0) {
801 // Return the read end
808 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
809 // Give the variables easier names to avoid confusion
810 int* fd_read
= &(*fds
)[0];
811 int* fd_write
= &(*fds
)[1];
813 // Close the read end of the pipe
819 // Return the write end
826 static int pakfire_jail_log(struct pakfire
* pakfire
, void* data
, int priority
,
827 const char* line
, const size_t length
) {
828 // Pass everything to the parent logger
829 pakfire_log_condition(pakfire
, priority
, 0, "%.*s", (int)length
, line
);
834 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
835 struct epoll_event event
= {
836 .events
= events
|EPOLLHUP
,
844 int flags
= fcntl(fd
, F_GETFL
, 0);
846 // Set modified flags
847 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
849 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
850 fd
, strerror(errno
));
854 // Add the file descriptor to the loop
855 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
857 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
858 fd
, strerror(errno
));
867 static int pakfire_jail_enable_raw_mode(struct pakfire_jail
* jail
,
868 struct pakfire_jail_pty_stdio
* stdio
) {
869 struct termios raw_attrs
;
872 // Fetch all attributes
873 r
= tcgetattr(stdio
->fd
, &stdio
->attrs
);
875 CTX_ERROR(jail
->ctx
, "Could not fetch terminal attributes from fd %d: %s\n",
876 stdio
->fd
, strerror(errno
));
880 // Copy all attributes
881 raw_attrs
= stdio
->attrs
;
884 cfmakeraw(&raw_attrs
);
886 // Restore the attributes
887 r
= tcsetattr(stdio
->fd
, TCSANOW
, &raw_attrs
);
889 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for fd %d: %s\n",
890 stdio
->fd
, strerror(errno
));
897 static void pakfire_jail_restore_attrs(struct pakfire_jail
* jail
,
898 const struct pakfire_jail_pty_stdio
* stdio
) {
901 // Restore the attributes
902 r
= tcsetattr(stdio
->fd
, TCSANOW
, &stdio
->attrs
);
904 CTX_DEBUG(jail
->ctx
, "Could not restore terminal attributes for %d, ignoring: %s\n",
905 stdio
->fd
, strerror(errno
));
909 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail
* jail
,
910 struct pakfire_jail_exec
* ctx
, const int epollfd
, const int fd
) {
914 CTX_DEBUG(jail
->ctx
, "Setting up PTY forwarding on fd %d\n", fd
);
916 // Store the file descriptor
917 ctx
->pty
.master
.fd
= fd
;
919 // Configure stdin/stdout
920 ctx
->pty
.stdin
.fd
= STDIN_FILENO
;
921 ctx
->pty
.stdout
.fd
= STDOUT_FILENO
;
924 r
= ioctl(ctx
->pty
.stdout
.fd
, TIOCGWINSZ
, &size
);
926 CTX_ERROR(jail
->ctx
, "Failed to determine terminal dimensions: %s\n", strerror(errno
));
931 r
= ioctl(ctx
->pty
.master
.fd
, TIOCSWINSZ
, &size
);
933 CTX_ERROR(jail
->ctx
, "Failed setting dimensions: %s\n", strerror(errno
));
937 // Enable RAW mode on standard input
938 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdin
);
942 // Enable RAW mode on standard output
943 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdout
);
947 // Add the master to the event loop
948 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.master
.fd
, EPOLLIN
|EPOLLOUT
|EPOLLET
);
952 // Add standard input to the event loop
953 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdin
.fd
, EPOLLIN
|EPOLLET
);
957 // Add standard output to the event loop
958 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdout
.fd
, EPOLLOUT
|EPOLLET
);
965 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
967 struct epoll_event events
[EPOLL_MAX_EVENTS
];
971 // Fetch file descriptors from context
972 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
973 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
974 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
975 const int pidfd
= ctx
->pidfd
;
977 // Fetch the UNIX domain socket
978 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
981 const int timerfd
= pakfire_jail_create_timer(jail
);
984 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
985 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
987 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
988 #endif /* ENABLE_DEBUG */
990 // Make a list of all file descriptors we are interested in
991 const struct pakfire_wait_fds
{
995 // Standard input/output
1001 { timerfd
, EPOLLIN
},
1004 { ctx
->pidfd
, EPOLLIN
},
1007 { log_INFO
, EPOLLIN
},
1008 { log_ERROR
, EPOLLIN
},
1010 { log_DEBUG
, EPOLLIN
},
1011 #endif /* ENABLE_DEBUG */
1013 // UNIX Domain Socket
1014 { socket_recv
, EPOLLIN
},
1021 epollfd
= epoll_create1(0);
1023 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
1028 // Turn file descriptors into non-blocking mode and add them to epoll()
1029 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
1030 // Skip fds which were not initialized
1034 // Add the FD to the event loop
1035 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
1042 // Loop for as long as the process is alive
1044 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
1046 // Ignore if epoll_wait() has been interrupted
1050 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
1056 for (int i
= 0; i
< num
; i
++) {
1057 int e
= events
[i
].events
;
1058 int fd
= events
[i
].data
.fd
;
1060 struct pakfire_log_buffer
* buffer
= NULL
;
1061 pakfire_jail_communicate_out callback
= NULL
;
1065 // Check if there is any data to be read
1067 // Handle any changes to the PIDFD
1069 // Call waidid() and store the result
1070 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
1072 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
1076 // Mark that we have ended so that we will process the remaining
1077 // events from epoll() now, but won't restart the outer loop.
1081 // Handle timer events
1082 } else if (fd
== timerfd
) {
1083 DEBUG(jail
->pakfire
, "Timer event received\n");
1086 r
= read(timerfd
, garbage
, sizeof(garbage
));
1088 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
1093 // Terminate the process if it hasn't already ended
1095 DEBUG(jail
->pakfire
, "Terminating process...\n");
1097 // Send SIGTERM to the process
1098 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
1100 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
1105 // Don't fall through to log processing
1108 // Handle logging messages
1109 } else if (fd
== log_INFO
) {
1110 buffer
= &ctx
->buffers
.log_INFO
;
1111 priority
= LOG_INFO
;
1113 callback
= pakfire_jail_log
;
1115 } else if (fd
== log_ERROR
) {
1116 buffer
= &ctx
->buffers
.log_ERROR
;
1119 callback
= pakfire_jail_log
;
1122 } else if (fd
== log_DEBUG
) {
1123 buffer
= &ctx
->buffers
.log_DEBUG
;
1124 priority
= LOG_DEBUG
;
1126 callback
= pakfire_jail_log
;
1127 #endif /* ENABLE_DEBUG */
1129 // Handle anything from the log pipes
1130 } else if (fd
== stdout
) {
1131 buffer
= &ctx
->buffers
.stdout
;
1132 priority
= LOG_INFO
;
1134 // Send any output to the default logger if no callback is set
1135 if (ctx
->communicate
.out
) {
1136 callback
= ctx
->communicate
.out
;
1137 data
= ctx
->communicate
.data
;
1139 callback
= jail
->callbacks
.log
;
1140 data
= jail
->callbacks
.log_data
;
1143 } else if (fd
== stderr
) {
1144 buffer
= &ctx
->buffers
.stderr
;
1147 // Send any output to the default logger if no callback is set
1148 if (ctx
->communicate
.out
) {
1149 callback
= ctx
->communicate
.out
;
1150 data
= ctx
->communicate
.data
;
1152 callback
= jail
->callbacks
.log
;
1153 data
= jail
->callbacks
.log_data
;
1156 // Handle socket messages
1157 } else if (fd
== socket_recv
) {
1158 // Receive the passed FD
1159 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1163 // Setup PTY forwarding
1164 if (ctx
->pty
.master
.fd
< 0) {
1165 r
= pakfire_jail_setup_pty_forwarding(jail
, ctx
, epollfd
, fd
);
1167 CTX_ERROR(jail
->ctx
, "Failed setting up PTY forwarding: %s\n", strerror(-r
));
1172 // Don't fall through to log processing
1176 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1181 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
1187 // Handle standard input
1189 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
1192 // Ignore if we filled up the buffer
1197 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
1204 // Check if any file descriptors have been closed
1206 // Remove the file descriptor
1207 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1209 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1222 // Restore any changed terminal attributes
1223 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdin
);
1224 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdout
);
1229 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1230 int priority
, const char* line
, size_t length
) {
1231 char** output
= (char**)data
;
1234 // Append everything from stdout to a buffer
1235 if (output
&& priority
== LOG_INFO
) {
1236 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
1242 // Send everything else to the default logger
1243 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1248 // Logs all capabilities of the current process
1249 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1252 cap_flag_value_t value_e
;
1253 cap_flag_value_t value_i
;
1254 cap_flag_value_t value_p
;
1258 pid_t pid
= getpid();
1260 // Fetch all capabilities
1261 caps
= cap_get_proc();
1263 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1268 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1270 // Iterate over all capabilities
1271 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1272 name
= cap_to_name(cap
);
1274 // Fetch effective value
1275 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1279 // Fetch inheritable value
1280 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1284 // Fetch permitted value
1285 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1289 DEBUG(jail
->pakfire
,
1290 " %-24s : %c%c%c\n",
1292 (value_e
== CAP_SET
) ? 'e' : '-',
1293 (value_i
== CAP_SET
) ? 'i' : '-',
1294 (value_p
== CAP_SET
) ? 'p' : '-'
1314 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1319 // Fetch capabilities
1320 caps
= cap_get_proc();
1322 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1327 // Walk through all capabilities
1328 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1329 cap_value_t _caps
[] = { cap
};
1331 // Fetch the name of the capability
1332 name
= cap_to_name(cap
);
1334 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1336 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1340 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1342 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1346 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1348 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1357 // Restore all capabilities
1358 r
= cap_set_proc(caps
);
1360 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1364 // Add all capabilities to the ambient set
1365 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1366 name
= cap_to_name(cap
);
1368 // Raise the capability
1369 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1371 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1394 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1395 const int syscalls
[] = {
1396 // The kernel's keyring isn't namespaced
1399 SCMP_SYS(request_key
),
1401 // Disable userfaultfd
1402 SCMP_SYS(userfaultfd
),
1404 // Disable perf which could leak a lot of information about the host
1405 SCMP_SYS(perf_event_open
),
1411 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1413 // Setup a syscall filter which allows everything by default
1414 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1416 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1421 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1422 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1424 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1429 // Load syscall filter into the kernel
1430 r
= seccomp_load(ctx
);
1432 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1438 seccomp_release(ctx
);
1445 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1446 const char* source
, const char* target
, int flags
) {
1447 struct pakfire_jail_mountpoint
* mp
= NULL
;
1450 // Check if there is any space left
1451 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1456 // Check for valid inputs
1457 if (!source
|| !target
) {
1462 // Select the next free slot
1463 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1466 r
= pakfire_string_set(mp
->source
, source
);
1468 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1473 r
= pakfire_string_set(mp
->target
, target
);
1475 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1482 // Increment counter
1483 jail
->num_mountpoints
++;
1488 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1491 const char* paths
[] = {
1497 // Bind-mount all paths read-only
1498 for (const char** path
= paths
; *path
; path
++) {
1499 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1502 // Ignore if we don't have permission
1517 Mounts everything that we require in the new namespace
1519 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1520 struct pakfire_jail_mountpoint
* mp
= NULL
;
1524 // Enable loop devices
1525 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1526 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1528 // Mount all default stuff
1529 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1534 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1538 // Mount the interpreter (if needed)
1539 r
= pakfire_mount_interpreter(jail
->pakfire
);
1543 // Mount networking stuff
1544 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1545 r
= pakfire_jail_mount_networking(jail
);
1550 // Mount all custom stuff
1551 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1553 mp
= &jail
->mountpoints
[i
];
1556 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1566 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1567 struct nl_sock
* nl
= NULL
;
1568 struct nl_cache
* cache
= NULL
;
1569 struct rtnl_link
* link
= NULL
;
1570 struct rtnl_link
* change
= NULL
;
1573 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1575 // Allocate a netlink socket
1576 nl
= nl_socket_alloc();
1578 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1583 // Connect the socket
1584 r
= nl_connect(nl
, NETLINK_ROUTE
);
1586 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1590 // Allocate the netlink cache
1591 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1593 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1597 // Fetch loopback interface
1598 link
= rtnl_link_get_by_name(cache
, "lo");
1600 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1605 // Allocate a new link
1606 change
= rtnl_link_alloc();
1608 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1613 // Set the link to UP
1614 rtnl_link_set_flags(change
, IFF_UP
);
1616 // Apply any changes
1617 r
= rtnl_link_change(nl
, link
, change
, 0);
1619 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1635 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1636 char path
[PATH_MAX
];
1639 // Skip mapping anything when running on /
1640 if (pakfire_on_root(jail
->pakfire
))
1644 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1649 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1652 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1656 /* When running as root, we will map the entire range.
1658 When running as a non-privileged user, we will map the root user inside the jail
1659 to the user's UID outside of the jail, and we will map the rest starting from one.
1664 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1665 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1667 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1668 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1672 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1679 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1680 char path
[PATH_MAX
];
1683 // Skip mapping anything when running on /
1684 if (pakfire_on_root(jail
->pakfire
))
1688 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1691 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1696 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1702 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1703 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1705 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1706 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1710 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1717 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1718 char path
[PATH_MAX
];
1722 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1726 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1728 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1735 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1736 const uint64_t val
= 1;
1739 DEBUG(jail
->pakfire
, "Sending signal...\n");
1741 // Write to the file descriptor
1742 r
= eventfd_write(fd
, val
);
1744 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1748 // Close the file descriptor
1754 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1758 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1760 r
= eventfd_read(fd
, &val
);
1762 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1766 // Close the file descriptor
1773 Performs the initialisation that needs to happen in the parent part
1775 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1778 // Setup UID mapping
1779 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1783 // Write "deny" to /proc/PID/setgroups
1784 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1788 // Setup GID mapping
1789 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1793 // Parent has finished initialisation
1794 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1796 // Send signal to client
1797 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1804 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1807 // Change to the new root
1810 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1815 r
= pivot_root(".", ".");
1817 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1821 // Umount the old root
1822 r
= umount2(".", MNT_DETACH
);
1824 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1831 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1834 // Allocate a new PTY
1835 ctx
->pty
.master
.fd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
1836 if (ctx
->pty
.master
.fd
< 0)
1840 r
= ptsname_r(ctx
->pty
.master
.fd
, ctx
->pty
.console
, sizeof(ctx
->pty
.console
));
1844 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->pty
.console
, ctx
->pty
.master
.fd
);
1848 r
= pakfire_symlink(jail
->ctx
, "/dev/console", ctx
->pty
.console
);
1856 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1857 const char* argv
[]) {
1860 // Redirect any logging to our log pipe
1861 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
1864 pid_t pid
= getpid();
1866 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1868 // Wait for the parent to finish initialization
1869 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1874 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1876 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1880 // Make this process dumpable
1881 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
1883 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
1887 // Don't drop any capabilities on setuid()
1888 r
= prctl(PR_SET_KEEPCAPS
, 1);
1890 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1895 uid_t uid
= getuid();
1896 gid_t gid
= getgid();
1899 uid_t euid
= geteuid();
1900 gid_t egid
= getegid();
1902 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
1903 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
1905 // Log all mountpoints
1906 pakfire_mount_list(jail
->ctx
);
1908 // Fail if we are not PID 1
1910 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
1914 // Fail if we are not running as root
1915 if (uid
|| gid
|| euid
|| egid
) {
1916 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1920 const int socket_send
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->socket
);
1922 // Mount all default stuff
1923 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
1927 const char* root
= pakfire_get_path(jail
->pakfire
);
1928 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
1930 // Change mount propagation to slave to receive anything from the parent namespace
1931 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
1935 // Make root a mountpoint in the new mount namespace
1936 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
1940 // Change mount propagation to private
1941 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
1945 // Change root (unless root is /)
1946 if (!pakfire_on_root(jail
->pakfire
)) {
1948 r
= pakfire_jail_mount(jail
, ctx
);
1953 r
= pakfire_jail_switch_root(jail
, root
);
1959 unsigned long persona
= pakfire_arch_personality(arch
);
1961 r
= personality(persona
);
1963 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
1969 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1970 r
= pakfire_jail_setup_loopback(jail
);
1977 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
1979 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
1981 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
1987 // Create a new session
1990 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
1995 // Allocate a new PTY
1996 r
= pakfire_jail_open_pty(jail
, ctx
);
1998 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
2002 // Send the PTY master to the parent process
2003 r
= pakfire_jail_send_fd(jail
, socket_send
, ctx
->pty
.master
.fd
);
2005 CTX_ERROR(jail
->ctx
, "Failed sending the PTY master to the parent: %s\n", strerror(-r
));
2009 // Close the master of the PTY
2010 close(ctx
->pty
.master
.fd
);
2011 ctx
->pty
.master
.fd
= -1;
2016 // Close other end of log pipes
2017 close(ctx
->pipes
.log_INFO
[0]);
2018 close(ctx
->pipes
.log_ERROR
[0]);
2020 close(ctx
->pipes
.log_DEBUG
[0]);
2021 #endif /* ENABLE_DEBUG */
2023 // Connect standard input
2024 if (ctx
->pipes
.stdin
[0] >= 0) {
2025 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
2027 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
2028 ctx
->pipes
.stdin
[0]);
2034 // Connect standard output and error
2035 if (ctx
->pipes
.stdout
[1] >= 0 && ctx
->pipes
.stderr
[1] >= 0) {
2036 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
2038 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
2039 ctx
->pipes
.stdout
[1]);
2044 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
2046 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
2047 ctx
->pipes
.stderr
[1]);
2052 // Close the pipe (as we have moved the original file descriptors)
2053 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
2054 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
2055 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
2058 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2059 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
2064 r
= pakfire_jail_set_capabilities(jail
);
2068 // Show capabilities
2069 r
= pakfire_jail_show_capabilities(jail
);
2074 r
= pakfire_jail_limit_syscalls(jail
);
2078 DEBUG(jail
->pakfire
, "Child process initialization done\n");
2079 DEBUG(jail
->pakfire
, "Launching command:\n");
2082 for (unsigned int i
= 0; argv
[i
]; i
++)
2083 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
2086 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
2088 // Translate errno into regular exit code
2091 // Ignore if the command doesn't exist
2092 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
2103 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
2106 // We should not get here
2110 // Run a command in the jail
2111 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
2112 const int interactive
,
2113 pakfire_jail_communicate_in communicate_in
,
2114 pakfire_jail_communicate_out communicate_out
,
2115 void* data
, int flags
) {
2119 // Check if argv is valid
2120 if (!argv
|| !argv
[0]) {
2125 // Initialize context for this call
2126 struct pakfire_jail_exec ctx
= {
2129 .socket
= { -1, -1 },
2132 .stdin
= { -1, -1 },
2133 .stdout
= { -1, -1 },
2134 .stderr
= { -1, -1 },
2135 .log_INFO
= { -1, -1 },
2136 .log_ERROR
= { -1, -1 },
2138 .log_DEBUG
= { -1, -1 },
2139 #endif /* ENABLE_DEBUG */
2143 .in
= communicate_in
,
2144 .out
= communicate_out
,
2164 DEBUG(jail
->pakfire
, "Executing jail...\n");
2166 // Enable networking in interactive mode
2168 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2171 Setup a file descriptor which can be used to notify the client that the parent
2172 has completed configuration.
2174 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2175 if (ctx
.completed_fd
< 0) {
2176 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2180 // Create a UNIX domain socket
2181 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2183 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2188 // Create pipes to communicate with child process if we are not running interactively
2190 // stdin (only if callback is set)
2191 if (ctx
.communicate
.in
) {
2192 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
2198 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
2203 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
2208 // Setup pipes for logging
2210 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2215 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2221 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2224 #endif /* ENABLE_DEBUG */
2226 // Configure child process
2227 struct clone_args args
= {
2237 .exit_signal
= SIGCHLD
,
2238 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2241 // Launch the process in a cgroup that is a leaf of the configured cgroup
2243 args
.flags
|= CLONE_INTO_CGROUP
;
2246 const char* uuid
= pakfire_jail_uuid(jail
);
2248 // Create a temporary cgroup
2249 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2251 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2255 // Clone into this cgroup
2256 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2260 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2261 args
.flags
|= CLONE_NEWNET
;
2264 // Fork this process
2265 ctx
.pid
= clone3(&args
, sizeof(args
));
2267 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2271 } else if (ctx
.pid
== 0) {
2272 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2277 r
= pakfire_jail_parent(jail
, &ctx
);
2281 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2283 // Read output of the child process
2284 r
= pakfire_jail_wait(jail
, &ctx
);
2288 // Handle exit status
2289 switch (ctx
.status
.si_code
) {
2291 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2292 ctx
.status
.si_status
);
2295 exit
= ctx
.status
.si_status
;
2299 ERROR(jail
->pakfire
, "The child process was killed\n");
2304 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2307 // Log anything else
2309 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2314 // Destroy the temporary cgroup (if any)
2316 // Read cgroup stats
2317 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2318 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2319 pakfire_cgroup_destroy(ctx
.cgroup
);
2320 pakfire_cgroup_unref(ctx
.cgroup
);
2323 // Close any file descriptors
2324 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
2325 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
2326 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
2329 if (ctx
.pty
.master
.fd
>= 0)
2330 close(ctx
.pty
.master
.fd
);
2331 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2332 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2334 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2335 #endif /* ENABLE_DEBUG */
2336 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2341 PAKFIRE_EXPORT
int pakfire_jail_exec(
2342 struct pakfire_jail
* jail
,
2344 pakfire_jail_communicate_in callback_in
,
2345 pakfire_jail_communicate_out callback_out
,
2346 void* data
, int flags
) {
2347 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
2350 static int pakfire_jail_exec_interactive(
2351 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2354 // Setup interactive stuff
2355 r
= pakfire_jail_setup_interactive_env(jail
);
2359 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
2362 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2366 pakfire_jail_communicate_in callback_in
,
2367 pakfire_jail_communicate_out callback_out
,
2369 char path
[PATH_MAX
];
2370 const char** argv
= NULL
;
2374 const char* root
= pakfire_get_path(jail
->pakfire
);
2376 // Write the scriptlet to disk
2377 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2381 // Create a temporary file
2382 f
= pakfire_mktemp(path
, 0700);
2384 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2388 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2391 r
= fprintf(f
, "%s", script
);
2393 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2400 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2406 // Count how many arguments were passed
2407 unsigned int argc
= 1;
2409 for (const char** arg
= args
; *arg
; arg
++)
2413 argv
= calloc(argc
+ 1, sizeof(*argv
));
2415 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2420 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2423 for (unsigned int i
= 1; i
< argc
; i
++)
2424 argv
[i
] = args
[i
-1];
2427 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2435 // Remove script from disk
2443 A convenience function that creates a new jail, runs the given command and destroys
2446 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2447 struct pakfire_jail
* jail
= NULL
;
2450 // Create a new jail
2451 r
= pakfire_jail_create(&jail
, pakfire
);
2455 // Execute the command
2456 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2460 pakfire_jail_unref(jail
);
2465 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2466 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2467 struct pakfire_jail
* jail
= NULL
;
2470 // Create a new jail
2471 r
= pakfire_jail_create(&jail
, pakfire
);
2475 // Execute the command
2476 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2480 pakfire_jail_unref(jail
);
2485 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2488 const char* argv
[] = {
2489 "/bin/bash", "--login", NULL
,
2492 // Execute /bin/bash
2493 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2499 // Ignore any return codes from the shell
2503 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2504 char path
[PATH_MAX
];
2507 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2511 // Check if the file is executable
2512 r
= access(path
, X_OK
);
2514 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2518 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2521 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2522 const char* argv
[] = {
2527 return pakfire_jail_run_if_possible(pakfire
, argv
);
2530 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2531 const char* argv
[] = {
2532 "/usr/bin/systemd-tmpfiles",
2537 return pakfire_jail_run_if_possible(pakfire
, argv
);