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
;
203 enum pakfire_jail_pty_flags flags
;
207 struct pakfire_jail_pty_stdio stdout
;
211 static int clone3(struct clone_args
* args
, size_t size
) {
212 return syscall(__NR_clone3
, args
, size
);
215 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
216 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
219 static int pivot_root(const char* new_root
, const char* old_root
) {
220 return syscall(SYS_pivot_root
, new_root
, old_root
);
223 static int pakfire_jail_exec_has_flag(
224 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
225 return ctx
->flags
& flag
;
228 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
229 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
232 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
236 pakfire_cgroup_unref(jail
->cgroup
);
238 pakfire_unref(jail
->pakfire
);
240 pakfire_ctx_unref(jail
->ctx
);
245 Passes any log messages on to the default pakfire log callback
247 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
248 int priority
, const char* line
, size_t length
) {
251 INFO(pakfire
, "%s", line
);
255 ERROR(pakfire
, "%s", line
);
260 DEBUG(pakfire
, "%s", line
);
268 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
270 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
275 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
277 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
282 char* TERM
= secure_getenv("TERM");
284 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
290 char* LANG
= secure_getenv("LANG");
292 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
300 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
303 const char* arch
= pakfire_get_effective_arch(pakfire
);
305 // Allocate a new jail
306 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
311 j
->ctx
= pakfire_ctx(pakfire
);
314 j
->pakfire
= pakfire_ref(pakfire
);
316 // Initialize reference counter
319 // Generate a random UUID
320 uuid_generate_random(j
->uuid
);
322 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
324 // Set the default logging callback
325 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
327 // Set default environment
328 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
329 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
334 // Enable all CPU features that CPU has to offer
335 if (!pakfire_arch_is_supported_by_host(arch
)) {
336 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
341 // Set container UUID
342 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
346 // Disable systemctl to talk to systemd
347 if (!pakfire_on_root(j
->pakfire
)) {
348 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
358 pakfire_jail_free(j
);
363 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
369 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
370 if (--jail
->nrefs
> 0)
373 pakfire_jail_free(jail
);
379 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
380 pakfire_jail_log_callback callback
, void* data
) {
381 jail
->callbacks
.log
= callback
;
382 jail
->callbacks
.log_data
= data
;
387 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
388 // Check if nice level is in range
389 if (nice
< -19 || nice
> 20) {
400 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
401 // Free any previous cgroup
403 pakfire_cgroup_unref(jail
->cgroup
);
407 // Set any new cgroup
409 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
411 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
420 // Returns the length of the environment
421 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
424 // Count everything in the environment
425 for (char** e
= jail
->env
; *e
; e
++)
431 // Finds an existing environment variable and returns its index or -1 if not found
432 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
438 const size_t length
= strlen(key
);
440 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
441 if ((pakfire_string_startswith(jail
->env
[i
], key
)
442 && *(jail
->env
[i
] + length
) == '=')) {
451 // Returns the value of an environment variable or NULL
452 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
454 int i
= pakfire_jail_find_env(jail
, key
);
458 return jail
->env
[i
] + strlen(key
) + 1;
461 // Sets an environment variable
462 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
463 const char* key
, const char* value
) {
464 // Find the index where to write this value to
465 int i
= pakfire_jail_find_env(jail
, key
);
467 i
= pakfire_jail_env_length(jail
);
469 // Return -ENOSPC when the environment is full
470 if (i
>= ENVIRON_SIZE
) {
475 // Free any previous value
479 // Format and set environment variable
480 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
482 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
487 // Imports an environment
488 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
496 // Copy environment variables
497 for (unsigned int i
= 0; env
[i
]; i
++) {
498 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
503 r
= pakfire_jail_set_env(jail
, key
, val
);
520 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
521 struct pakfire_jail
* jail
, unsigned int timeout
) {
523 jail
->timeout
.it_value
.tv_sec
= timeout
;
526 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
528 DEBUG(jail
->pakfire
, "Timeout disabled\n");
533 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
536 // Nothing to do if no timeout has been set
537 if (!jail
->timeout
.it_value
.tv_sec
)
540 // Create a new timer
541 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
543 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
548 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
550 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
564 This function replaces any logging in the child process.
566 All log messages will be sent to the parent process through their respective pipes.
568 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
569 int line
, const char* fn
, const char* format
, va_list args
) {
570 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
575 fd
= pipes
->log_INFO
[1];
579 fd
= pipes
->log_ERROR
[1];
584 fd
= pipes
->log_DEBUG
[1];
586 #endif /* ENABLE_DEBUG */
588 // Ignore any messages of an unknown priority
593 // Send the log message
595 vdprintf(fd
, format
, args
);
598 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
599 return (sizeof(buffer
->data
) == buffer
->used
);
603 This function reads as much data as it can from the file descriptor.
604 If it finds a whole line in it, it will send it to the logger and repeat the process.
605 If not newline character is found, it will try to read more data until it finds one.
607 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
608 struct pakfire_jail_exec
* ctx
, int priority
, int fd
,
609 struct pakfire_log_buffer
* buffer
, pakfire_jail_communicate_out callback
, void* data
) {
610 char line
[BUFFER_SIZE
+ 1];
612 // Fill up buffer from fd
613 if (buffer
->used
< sizeof(buffer
->data
)) {
614 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
615 sizeof(buffer
->data
) - buffer
->used
);
618 if (bytes_read
< 0) {
619 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
623 // Update buffer size
624 buffer
->used
+= bytes_read
;
627 // See if we have any lines that we can write
628 while (buffer
->used
) {
629 // Search for the end of the first line
630 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
634 // If the buffer is full, we send the content to the logger and try again
635 // This should not happen in practise
636 if (pakfire_jail_log_buffer_is_full(buffer
)) {
637 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
639 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
641 // Otherwise we might have only read parts of the output
646 // Find the length of the string
647 size_t length
= eol
- buffer
->data
+ 1;
649 // Copy the line into the buffer
650 memcpy(line
, buffer
->data
, length
);
652 // Terminate the string
657 int r
= callback(jail
->pakfire
, data
, priority
, line
, length
);
659 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
664 // Remove line from buffer
665 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
666 buffer
->used
-= length
;
672 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
673 struct pakfire_jail_exec
* ctx
, const int fd
) {
676 // Nothing to do if there is no stdin callback set
677 if (!ctx
->communicate
.in
) {
678 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
682 // Skip if the writing pipe has already been closed
683 if (ctx
->pipes
.stdin
[1] < 0)
686 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
688 // Calling the callback
689 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
691 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
693 // The callback signaled that it has written everything
695 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
697 // Close the file-descriptor
700 // Reset the file-descriptor so it won't be closed again later
701 ctx
->pipes
.stdin
[1] = -1;
710 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
711 const size_t payload_length
= sizeof(fd
);
712 char buffer
[CMSG_SPACE(payload_length
)];
715 struct msghdr msg
= {
716 .msg_control
= buffer
,
717 .msg_controllen
= sizeof(buffer
),
720 // Receive the message
721 r
= recvmsg(socket
, &msg
, 0);
723 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
728 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
732 *fd
= *((int*)CMSG_DATA(cmsg
));
734 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
739 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
740 const size_t payload_length
= sizeof(fd
);
741 char buffer
[CMSG_SPACE(payload_length
)];
744 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
747 struct msghdr msg
= {
748 .msg_control
= buffer
,
749 .msg_controllen
= sizeof(buffer
),
753 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
754 cmsg
->cmsg_level
= SOL_SOCKET
;
755 cmsg
->cmsg_type
= SCM_RIGHTS
;
756 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
759 *((int*)CMSG_DATA(cmsg
)) = fd
;
762 r
= sendmsg(socket
, &msg
, 0);
764 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
771 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
772 int r
= pipe2(*fds
, flags
);
774 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
781 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
782 for (unsigned int i
= 0; i
< 2; i
++)
788 This is a convenience function to fetch the reading end of a pipe and
789 closes the write end.
791 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
792 // Give the variables easier names to avoid confusion
793 int* fd_read
= &(*fds
)[0];
794 int* fd_write
= &(*fds
)[1];
796 // Close the write end of the pipe
797 if (*fd_write
>= 0) {
802 // Return the read end
809 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
810 // Give the variables easier names to avoid confusion
811 int* fd_read
= &(*fds
)[0];
812 int* fd_write
= &(*fds
)[1];
814 // Close the read end of the pipe
820 // Return the write end
827 static int pakfire_jail_log(struct pakfire
* pakfire
, void* data
, int priority
,
828 const char* line
, const size_t length
) {
829 // Pass everything to the parent logger
830 pakfire_log_condition(pakfire
, priority
, 0, "%.*s", (int)length
, line
);
835 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
836 struct epoll_event event
= {
837 .events
= events
|EPOLLHUP
,
845 int flags
= fcntl(fd
, F_GETFL
, 0);
847 // Set modified flags
848 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
850 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
851 fd
, strerror(errno
));
855 // Add the file descriptor to the loop
856 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
858 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
859 fd
, strerror(errno
));
868 static int pakfire_jail_enable_raw_mode(struct pakfire_jail
* jail
,
869 struct pakfire_jail_pty_stdio
* stdio
) {
870 struct termios raw_attrs
;
874 stdio
->fdflags
= fcntl(stdio
->fd
, F_GETFL
);
875 if (stdio
->fdflags
< 0) {
876 CTX_ERROR(jail
->ctx
, "Could not fetch flags from fd %d: %s\n",
877 stdio
->fd
, strerror(errno
));
881 // Fetch all attributes
882 r
= tcgetattr(stdio
->fd
, &stdio
->attrs
);
884 CTX_ERROR(jail
->ctx
, "Could not fetch terminal attributes from fd %d: %s\n",
885 stdio
->fd
, strerror(errno
));
889 // Copy all attributes
890 raw_attrs
= stdio
->attrs
;
893 cfmakeraw(&raw_attrs
);
897 raw_attrs
.c_oflag
= stdio
->attrs
.c_oflag
;
901 raw_attrs
.c_iflag
= stdio
->attrs
.c_iflag
;
902 raw_attrs
.c_lflag
= stdio
->attrs
.c_lflag
;
906 // Restore the attributes
907 r
= tcsetattr(stdio
->fd
, TCSANOW
, &raw_attrs
);
909 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for fd %d: %s\n",
910 stdio
->fd
, strerror(errno
));
917 static int pakfire_jail_restore_attrs(struct pakfire_jail
* jail
,
918 const struct pakfire_jail_pty_stdio
* stdio
) {
922 r
= fcntl(stdio
->fd
, F_SETFL
, stdio
->fdflags
);
924 CTX_ERROR(jail
->ctx
, "Could not set flags for file descriptor %d: %s\n",
925 stdio
->fd
, strerror(errno
));
929 // Restore the attributes
930 r
= tcsetattr(stdio
->fd
, TCSANOW
, &stdio
->attrs
);
932 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for %d, ignoring: %s\n",
933 stdio
->fd
, strerror(errno
));
940 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail
* jail
,
941 struct pakfire_jail_exec
* ctx
, const int epollfd
, const int fd
) {
945 CTX_DEBUG(jail
->ctx
, "Setting up PTY forwarding on fd %d\n", fd
);
947 // Store the file descriptor
948 ctx
->pty
.master
.fd
= fd
;
950 // Configure stdin/stdout
951 ctx
->pty
.stdin
.fd
= STDIN_FILENO
;
952 ctx
->pty
.stdout
.fd
= STDOUT_FILENO
;
955 r
= ioctl(ctx
->pty
.stdout
.fd
, TIOCGWINSZ
, &size
);
957 CTX_ERROR(jail
->ctx
, "Failed to determine terminal dimensions: %s\n", strerror(errno
));
962 r
= ioctl(ctx
->pty
.master
.fd
, TIOCSWINSZ
, &size
);
964 CTX_ERROR(jail
->ctx
, "Failed setting dimensions: %s\n", strerror(errno
));
968 // Enable RAW mode on standard input
969 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdin
);
973 // Enable RAW mode on standard output
974 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdout
);
978 // Add the master to the event loop
979 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.master
.fd
, EPOLLIN
|EPOLLOUT
|EPOLLET
);
983 // Add standard input to the event loop
984 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdin
.fd
, EPOLLIN
|EPOLLET
);
988 // Add standard output to the event loop
989 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdout
.fd
, EPOLLOUT
|EPOLLET
);
996 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
998 struct epoll_event events
[EPOLL_MAX_EVENTS
];
1002 // Fetch file descriptors from context
1003 const int stdin
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->pipes
.stdin
);
1004 const int stdout
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stdout
);
1005 const int stderr
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.stderr
);
1006 const int pidfd
= ctx
->pidfd
;
1008 // Fetch the UNIX domain socket
1009 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
1012 const int timerfd
= pakfire_jail_create_timer(jail
);
1015 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
1016 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
1018 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
1019 #endif /* ENABLE_DEBUG */
1021 // Make a list of all file descriptors we are interested in
1022 const struct pakfire_wait_fds
{
1026 // Standard input/output
1027 { stdin
, EPOLLOUT
},
1028 { stdout
, EPOLLIN
},
1029 { stderr
, EPOLLIN
},
1032 { timerfd
, EPOLLIN
},
1035 { ctx
->pidfd
, EPOLLIN
},
1038 { log_INFO
, EPOLLIN
},
1039 { log_ERROR
, EPOLLIN
},
1041 { log_DEBUG
, EPOLLIN
},
1042 #endif /* ENABLE_DEBUG */
1044 // UNIX Domain Socket
1045 { socket_recv
, EPOLLIN
},
1052 epollfd
= epoll_create1(0);
1054 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
1059 // Turn file descriptors into non-blocking mode and add them to epoll()
1060 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
1061 // Skip fds which were not initialized
1065 // Add the FD to the event loop
1066 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
1073 // Loop for as long as the process is alive
1075 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
1077 // Ignore if epoll_wait() has been interrupted
1081 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
1087 for (int i
= 0; i
< num
; i
++) {
1088 int e
= events
[i
].events
;
1089 int fd
= events
[i
].data
.fd
;
1091 struct pakfire_log_buffer
* buffer
= NULL
;
1092 pakfire_jail_communicate_out callback
= NULL
;
1096 // Check if there is any data to be read
1098 // Handle any changes to the PIDFD
1100 // Call waidid() and store the result
1101 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
1103 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
1107 // Mark that we have ended so that we will process the remaining
1108 // events from epoll() now, but won't restart the outer loop.
1112 // Handle timer events
1113 } else if (fd
== timerfd
) {
1114 DEBUG(jail
->pakfire
, "Timer event received\n");
1117 r
= read(timerfd
, garbage
, sizeof(garbage
));
1119 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
1124 // Terminate the process if it hasn't already ended
1126 DEBUG(jail
->pakfire
, "Terminating process...\n");
1128 // Send SIGTERM to the process
1129 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
1131 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
1136 // Don't fall through to log processing
1139 // Handle logging messages
1140 } else if (fd
== log_INFO
) {
1141 buffer
= &ctx
->buffers
.log_INFO
;
1142 priority
= LOG_INFO
;
1144 callback
= pakfire_jail_log
;
1146 } else if (fd
== log_ERROR
) {
1147 buffer
= &ctx
->buffers
.log_ERROR
;
1150 callback
= pakfire_jail_log
;
1153 } else if (fd
== log_DEBUG
) {
1154 buffer
= &ctx
->buffers
.log_DEBUG
;
1155 priority
= LOG_DEBUG
;
1157 callback
= pakfire_jail_log
;
1158 #endif /* ENABLE_DEBUG */
1160 // Handle anything from the log pipes
1161 } else if (fd
== stdout
) {
1162 buffer
= &ctx
->buffers
.stdout
;
1163 priority
= LOG_INFO
;
1165 // Send any output to the default logger if no callback is set
1166 if (ctx
->communicate
.out
) {
1167 callback
= ctx
->communicate
.out
;
1168 data
= ctx
->communicate
.data
;
1170 callback
= jail
->callbacks
.log
;
1171 data
= jail
->callbacks
.log_data
;
1174 } else if (fd
== stderr
) {
1175 buffer
= &ctx
->buffers
.stderr
;
1178 // Send any output to the default logger if no callback is set
1179 if (ctx
->communicate
.out
) {
1180 callback
= ctx
->communicate
.out
;
1181 data
= ctx
->communicate
.data
;
1183 callback
= jail
->callbacks
.log
;
1184 data
= jail
->callbacks
.log_data
;
1187 // Handle socket messages
1188 } else if (fd
== socket_recv
) {
1189 // Receive the passed FD
1190 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1194 // Setup PTY forwarding
1195 if (ctx
->pty
.master
.fd
< 0) {
1196 r
= pakfire_jail_setup_pty_forwarding(jail
, ctx
, epollfd
, fd
);
1198 CTX_ERROR(jail
->ctx
, "Failed setting up PTY forwarding: %s\n", strerror(-r
));
1203 // Don't fall through to log processing
1207 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1212 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
, callback
, data
);
1218 // Handle standard input
1220 r
= pakfire_jail_stream_stdin(jail
, ctx
, fd
);
1223 // Ignore if we filled up the buffer
1228 ERROR(jail
->pakfire
, "Could not write to stdin: %m\n");
1235 // Check if any file descriptors have been closed
1237 // Remove the file descriptor
1238 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1240 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1253 // Restore any changed terminal attributes
1254 if (ctx
->pty
.stdin
.fd
>= 0)
1255 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdin
);
1256 if (ctx
->pty
.stdout
.fd
>= 0)
1257 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdout
);
1262 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1263 int priority
, const char* line
, size_t length
) {
1264 char** output
= (char**)data
;
1267 // Append everything from stdout to a buffer
1268 if (output
&& priority
== LOG_INFO
) {
1269 r
= asprintf(output
, "%s%s", (output
&& *output
) ? *output
: "", line
);
1275 // Send everything else to the default logger
1276 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1281 // Logs all capabilities of the current process
1282 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1285 cap_flag_value_t value_e
;
1286 cap_flag_value_t value_i
;
1287 cap_flag_value_t value_p
;
1291 pid_t pid
= getpid();
1293 // Fetch all capabilities
1294 caps
= cap_get_proc();
1296 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1301 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1303 // Iterate over all capabilities
1304 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1305 name
= cap_to_name(cap
);
1307 // Fetch effective value
1308 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1312 // Fetch inheritable value
1313 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1317 // Fetch permitted value
1318 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1322 DEBUG(jail
->pakfire
,
1323 " %-24s : %c%c%c\n",
1325 (value_e
== CAP_SET
) ? 'e' : '-',
1326 (value_i
== CAP_SET
) ? 'i' : '-',
1327 (value_p
== CAP_SET
) ? 'p' : '-'
1347 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1352 // Fetch capabilities
1353 caps
= cap_get_proc();
1355 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1360 // Walk through all capabilities
1361 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1362 cap_value_t _caps
[] = { cap
};
1364 // Fetch the name of the capability
1365 name
= cap_to_name(cap
);
1367 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1369 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1373 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1375 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1379 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1381 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1390 // Restore all capabilities
1391 r
= cap_set_proc(caps
);
1393 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1397 // Add all capabilities to the ambient set
1398 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1399 name
= cap_to_name(cap
);
1401 // Raise the capability
1402 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1404 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1427 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1428 const int syscalls
[] = {
1429 // The kernel's keyring isn't namespaced
1432 SCMP_SYS(request_key
),
1434 // Disable userfaultfd
1435 SCMP_SYS(userfaultfd
),
1437 // Disable perf which could leak a lot of information about the host
1438 SCMP_SYS(perf_event_open
),
1444 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1446 // Setup a syscall filter which allows everything by default
1447 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1449 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1454 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1455 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1457 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1462 // Load syscall filter into the kernel
1463 r
= seccomp_load(ctx
);
1465 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1471 seccomp_release(ctx
);
1478 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1479 const char* source
, const char* target
, int flags
) {
1480 struct pakfire_jail_mountpoint
* mp
= NULL
;
1483 // Check if there is any space left
1484 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1489 // Check for valid inputs
1490 if (!source
|| !target
) {
1495 // Select the next free slot
1496 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1499 r
= pakfire_string_set(mp
->source
, source
);
1501 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1506 r
= pakfire_string_set(mp
->target
, target
);
1508 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1515 // Increment counter
1516 jail
->num_mountpoints
++;
1521 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1524 const char* paths
[] = {
1530 // Bind-mount all paths read-only
1531 for (const char** path
= paths
; *path
; path
++) {
1532 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1535 // Ignore if we don't have permission
1550 Mounts everything that we require in the new namespace
1552 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1553 struct pakfire_jail_mountpoint
* mp
= NULL
;
1557 // Enable loop devices
1558 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1559 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1561 // Mount all default stuff
1562 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1567 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1571 // Mount the interpreter (if needed)
1572 r
= pakfire_mount_interpreter(jail
->pakfire
);
1576 // Mount networking stuff
1577 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1578 r
= pakfire_jail_mount_networking(jail
);
1583 // Mount all custom stuff
1584 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1586 mp
= &jail
->mountpoints
[i
];
1589 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1599 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1600 struct nl_sock
* nl
= NULL
;
1601 struct nl_cache
* cache
= NULL
;
1602 struct rtnl_link
* link
= NULL
;
1603 struct rtnl_link
* change
= NULL
;
1606 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1608 // Allocate a netlink socket
1609 nl
= nl_socket_alloc();
1611 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1616 // Connect the socket
1617 r
= nl_connect(nl
, NETLINK_ROUTE
);
1619 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1623 // Allocate the netlink cache
1624 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1626 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1630 // Fetch loopback interface
1631 link
= rtnl_link_get_by_name(cache
, "lo");
1633 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1638 // Allocate a new link
1639 change
= rtnl_link_alloc();
1641 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1646 // Set the link to UP
1647 rtnl_link_set_flags(change
, IFF_UP
);
1649 // Apply any changes
1650 r
= rtnl_link_change(nl
, link
, change
, 0);
1652 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1668 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1669 char path
[PATH_MAX
];
1672 // Skip mapping anything when running on /
1673 if (pakfire_on_root(jail
->pakfire
))
1677 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1682 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1685 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1689 /* When running as root, we will map the entire range.
1691 When running as a non-privileged user, we will map the root user inside the jail
1692 to the user's UID outside of the jail, and we will map the rest starting from one.
1697 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1698 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1700 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1701 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1705 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1712 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1713 char path
[PATH_MAX
];
1716 // Skip mapping anything when running on /
1717 if (pakfire_on_root(jail
->pakfire
))
1721 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1724 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1729 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1735 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1736 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1738 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1739 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1743 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1750 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1751 char path
[PATH_MAX
];
1755 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1759 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1761 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1768 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1769 const uint64_t val
= 1;
1772 DEBUG(jail
->pakfire
, "Sending signal...\n");
1774 // Write to the file descriptor
1775 r
= eventfd_write(fd
, val
);
1777 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1781 // Close the file descriptor
1787 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1791 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1793 r
= eventfd_read(fd
, &val
);
1795 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1799 // Close the file descriptor
1806 Performs the initialisation that needs to happen in the parent part
1808 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1811 // Setup UID mapping
1812 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1816 // Write "deny" to /proc/PID/setgroups
1817 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1821 // Setup GID mapping
1822 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1826 // Parent has finished initialisation
1827 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1829 // Send signal to client
1830 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1837 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1840 // Change to the new root
1843 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1848 r
= pivot_root(".", ".");
1850 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1854 // Umount the old root
1855 r
= umount2(".", MNT_DETACH
);
1857 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1864 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1867 // Allocate a new PTY
1868 ctx
->pty
.master
.fd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
1869 if (ctx
->pty
.master
.fd
< 0)
1873 r
= ptsname_r(ctx
->pty
.master
.fd
, ctx
->pty
.console
, sizeof(ctx
->pty
.console
));
1877 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->pty
.console
, ctx
->pty
.master
.fd
);
1881 r
= pakfire_symlink(jail
->ctx
, "/dev/console", ctx
->pty
.console
);
1889 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
1890 const char* argv
[]) {
1893 // Redirect any logging to our log pipe
1894 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
1897 pid_t pid
= getpid();
1899 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
1901 // Wait for the parent to finish initialization
1902 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
1907 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
1909 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
1913 // Make this process dumpable
1914 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
1916 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
1920 // Don't drop any capabilities on setuid()
1921 r
= prctl(PR_SET_KEEPCAPS
, 1);
1923 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
1928 uid_t uid
= getuid();
1929 gid_t gid
= getgid();
1932 uid_t euid
= geteuid();
1933 gid_t egid
= getegid();
1935 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
1936 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
1938 // Log all mountpoints
1939 pakfire_mount_list(jail
->ctx
);
1941 // Fail if we are not PID 1
1943 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
1947 // Fail if we are not running as root
1948 if (uid
|| gid
|| euid
|| egid
) {
1949 ERROR(jail
->pakfire
, "Child process is not running as root\n");
1953 const int socket_send
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->socket
);
1955 // Mount all default stuff
1956 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
1960 const char* root
= pakfire_get_path(jail
->pakfire
);
1961 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
1963 // Change mount propagation to slave to receive anything from the parent namespace
1964 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
1968 // Make root a mountpoint in the new mount namespace
1969 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
1973 // Change mount propagation to private
1974 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
1978 // Change root (unless root is /)
1979 if (!pakfire_on_root(jail
->pakfire
)) {
1981 r
= pakfire_jail_mount(jail
, ctx
);
1986 r
= pakfire_jail_switch_root(jail
, root
);
1992 unsigned long persona
= pakfire_arch_personality(arch
);
1994 r
= personality(persona
);
1996 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
2002 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2003 r
= pakfire_jail_setup_loopback(jail
);
2010 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
2012 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
2014 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
2020 // Create a new session
2023 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
2028 // Allocate a new PTY
2029 r
= pakfire_jail_open_pty(jail
, ctx
);
2031 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
2035 // Send the PTY master to the parent process
2036 r
= pakfire_jail_send_fd(jail
, socket_send
, ctx
->pty
.master
.fd
);
2038 CTX_ERROR(jail
->ctx
, "Failed sending the PTY master to the parent: %s\n", strerror(-r
));
2042 // Close the master of the PTY
2043 close(ctx
->pty
.master
.fd
);
2044 ctx
->pty
.master
.fd
= -1;
2049 // Close other end of log pipes
2050 close(ctx
->pipes
.log_INFO
[0]);
2051 close(ctx
->pipes
.log_ERROR
[0]);
2053 close(ctx
->pipes
.log_DEBUG
[0]);
2054 #endif /* ENABLE_DEBUG */
2056 // Connect standard input
2057 if (ctx
->pipes
.stdin
[0] >= 0) {
2058 r
= dup2(ctx
->pipes
.stdin
[0], STDIN_FILENO
);
2060 ERROR(jail
->pakfire
, "Could not connect fd %d to stdin: %m\n",
2061 ctx
->pipes
.stdin
[0]);
2067 // Connect standard output and error
2068 if (ctx
->pipes
.stdout
[1] >= 0 && ctx
->pipes
.stderr
[1] >= 0) {
2069 r
= dup2(ctx
->pipes
.stdout
[1], STDOUT_FILENO
);
2071 ERROR(jail
->pakfire
, "Could not connect fd %d to stdout: %m\n",
2072 ctx
->pipes
.stdout
[1]);
2077 r
= dup2(ctx
->pipes
.stderr
[1], STDERR_FILENO
);
2079 ERROR(jail
->pakfire
, "Could not connect fd %d to stderr: %m\n",
2080 ctx
->pipes
.stderr
[1]);
2085 // Close the pipe (as we have moved the original file descriptors)
2086 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdin
);
2087 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stdout
);
2088 pakfire_jail_close_pipe(jail
, ctx
->pipes
.stderr
);
2091 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2092 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
2097 r
= pakfire_jail_set_capabilities(jail
);
2101 // Show capabilities
2102 r
= pakfire_jail_show_capabilities(jail
);
2107 r
= pakfire_jail_limit_syscalls(jail
);
2111 DEBUG(jail
->pakfire
, "Child process initialization done\n");
2112 DEBUG(jail
->pakfire
, "Launching command:\n");
2115 for (unsigned int i
= 0; argv
[i
]; i
++)
2116 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
2119 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
2121 // Translate errno into regular exit code
2124 // Ignore if the command doesn't exist
2125 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
2136 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
2139 // We should not get here
2143 // Run a command in the jail
2144 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
2145 const int interactive
,
2146 pakfire_jail_communicate_in communicate_in
,
2147 pakfire_jail_communicate_out communicate_out
,
2148 void* data
, int flags
) {
2152 // Check if argv is valid
2153 if (!argv
|| !argv
[0]) {
2158 // Initialize context for this call
2159 struct pakfire_jail_exec ctx
= {
2162 .socket
= { -1, -1 },
2165 .stdin
= { -1, -1 },
2166 .stdout
= { -1, -1 },
2167 .stderr
= { -1, -1 },
2168 .log_INFO
= { -1, -1 },
2169 .log_ERROR
= { -1, -1 },
2171 .log_DEBUG
= { -1, -1 },
2172 #endif /* ENABLE_DEBUG */
2176 .in
= communicate_in
,
2177 .out
= communicate_out
,
2197 DEBUG(jail
->pakfire
, "Executing jail...\n");
2199 // Enable networking in interactive mode
2201 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2204 Setup a file descriptor which can be used to notify the client that the parent
2205 has completed configuration.
2207 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2208 if (ctx
.completed_fd
< 0) {
2209 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2213 // Create a UNIX domain socket
2214 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2216 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2221 // Create pipes to communicate with child process if we are not running interactively
2223 // stdin (only if callback is set)
2224 if (ctx
.communicate
.in
) {
2225 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdin
, 0);
2231 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stdout
, 0);
2236 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.stderr
, 0);
2241 // Setup pipes for logging
2243 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2248 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2254 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2257 #endif /* ENABLE_DEBUG */
2259 // Configure child process
2260 struct clone_args args
= {
2270 .exit_signal
= SIGCHLD
,
2271 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2274 // Launch the process in a cgroup that is a leaf of the configured cgroup
2276 args
.flags
|= CLONE_INTO_CGROUP
;
2279 const char* uuid
= pakfire_jail_uuid(jail
);
2281 // Create a temporary cgroup
2282 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2284 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2288 // Clone into this cgroup
2289 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2293 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2294 args
.flags
|= CLONE_NEWNET
;
2297 // Fork this process
2298 ctx
.pid
= clone3(&args
, sizeof(args
));
2300 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2304 } else if (ctx
.pid
== 0) {
2305 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2310 r
= pakfire_jail_parent(jail
, &ctx
);
2314 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2316 // Read output of the child process
2317 r
= pakfire_jail_wait(jail
, &ctx
);
2321 // Handle exit status
2322 switch (ctx
.status
.si_code
) {
2324 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2325 ctx
.status
.si_status
);
2328 exit
= ctx
.status
.si_status
;
2332 ERROR(jail
->pakfire
, "The child process was killed\n");
2337 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2340 // Log anything else
2342 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2347 // Destroy the temporary cgroup (if any)
2349 // Read cgroup stats
2350 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2351 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2352 pakfire_cgroup_destroy(ctx
.cgroup
);
2353 pakfire_cgroup_unref(ctx
.cgroup
);
2356 // Close any file descriptors
2357 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdin
);
2358 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stdout
);
2359 pakfire_jail_close_pipe(jail
, ctx
.pipes
.stderr
);
2362 if (ctx
.pty
.master
.fd
>= 0)
2363 close(ctx
.pty
.master
.fd
);
2364 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2365 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2367 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2368 #endif /* ENABLE_DEBUG */
2369 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2374 PAKFIRE_EXPORT
int pakfire_jail_exec(
2375 struct pakfire_jail
* jail
,
2377 pakfire_jail_communicate_in callback_in
,
2378 pakfire_jail_communicate_out callback_out
,
2379 void* data
, int flags
) {
2380 return __pakfire_jail_exec(jail
, argv
, 0, callback_in
, callback_out
, data
, flags
);
2383 static int pakfire_jail_exec_interactive(
2384 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2387 // Setup interactive stuff
2388 r
= pakfire_jail_setup_interactive_env(jail
);
2392 return __pakfire_jail_exec(jail
, argv
, 1, NULL
, NULL
, NULL
, flags
);
2395 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2399 pakfire_jail_communicate_in callback_in
,
2400 pakfire_jail_communicate_out callback_out
,
2402 char path
[PATH_MAX
];
2403 const char** argv
= NULL
;
2407 const char* root
= pakfire_get_path(jail
->pakfire
);
2409 // Write the scriptlet to disk
2410 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2414 // Create a temporary file
2415 f
= pakfire_mktemp(path
, 0700);
2417 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2421 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2424 r
= fprintf(f
, "%s", script
);
2426 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2433 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2439 // Count how many arguments were passed
2440 unsigned int argc
= 1;
2442 for (const char** arg
= args
; *arg
; arg
++)
2446 argv
= calloc(argc
+ 1, sizeof(*argv
));
2448 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2453 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2456 for (unsigned int i
= 1; i
< argc
; i
++)
2457 argv
[i
] = args
[i
-1];
2460 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2468 // Remove script from disk
2476 A convenience function that creates a new jail, runs the given command and destroys
2479 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2480 struct pakfire_jail
* jail
= NULL
;
2483 // Create a new jail
2484 r
= pakfire_jail_create(&jail
, pakfire
);
2488 // Execute the command
2489 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2493 pakfire_jail_unref(jail
);
2498 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2499 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2500 struct pakfire_jail
* jail
= NULL
;
2503 // Create a new jail
2504 r
= pakfire_jail_create(&jail
, pakfire
);
2508 // Execute the command
2509 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2513 pakfire_jail_unref(jail
);
2518 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2521 const char* argv
[] = {
2522 "/bin/bash", "--login", NULL
,
2525 // Execute /bin/bash
2526 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2532 // Ignore any return codes from the shell
2536 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2537 char path
[PATH_MAX
];
2540 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2544 // Check if the file is executable
2545 r
= access(path
, X_OK
);
2547 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2551 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2554 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2555 const char* argv
[] = {
2560 return pakfire_jail_run_if_possible(pakfire
, argv
);
2563 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2564 const char* argv
[] = {
2565 "/usr/bin/systemd-tmpfiles",
2570 return pakfire_jail_run_if_possible(pakfire
, argv
);