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
{
152 #endif /* ENABLE_DEBUG */
156 struct pakfire_jail_communicate
{
157 pakfire_jail_communicate_in in
;
158 pakfire_jail_communicate_out out
;
163 struct pakfire_jail_buffers
{
164 struct pakfire_log_buffer stdout
;
165 struct pakfire_log_buffer stderr
;
168 struct pakfire_log_buffer log_INFO
;
169 struct pakfire_log_buffer log_ERROR
;
171 struct pakfire_log_buffer log_DEBUG
;
172 #endif /* ENABLE_DEBUG */
175 struct pakfire_cgroup
* cgroup
;
176 struct pakfire_cgroup_stats cgroup_stats
;
179 struct pakfire_jail_pty
{
180 // The path to the console
181 char console
[PATH_MAX
];
184 struct pakfire_jail_pty_master
{
187 enum pakfire_jail_pty_flags
{
188 PAKFIRE_JAIL_PTY_READY_TO_READ
= (1 << 0),
189 PAKFIRE_JAIL_PTY_READY_TO_WRITE
= (1 << 1),
194 struct pakfire_jail_pty_stdio
{
196 struct pakfire_log_buffer buffer
;
197 struct termios attrs
;
199 enum pakfire_jail_pty_flags flags
;
203 struct pakfire_jail_pty_stdio stdout
;
207 static int clone3(struct clone_args
* args
, size_t size
) {
208 return syscall(__NR_clone3
, args
, size
);
211 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
212 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
215 static int pivot_root(const char* new_root
, const char* old_root
) {
216 return syscall(SYS_pivot_root
, new_root
, old_root
);
219 static int pakfire_jail_exec_has_flag(
220 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
221 return ctx
->flags
& flag
;
224 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
225 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
228 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
232 pakfire_cgroup_unref(jail
->cgroup
);
234 pakfire_unref(jail
->pakfire
);
236 pakfire_ctx_unref(jail
->ctx
);
241 Passes any log messages on to the default pakfire log callback
243 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
244 int priority
, const char* line
, size_t length
) {
247 INFO(pakfire
, "%.*s", (int)length
, line
);
251 ERROR(pakfire
, "%.*s", (int)length
, line
);
256 DEBUG(pakfire
, "%.*s", (int)length
, line
);
264 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
266 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
271 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
273 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
278 char* TERM
= secure_getenv("TERM");
280 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
286 char* LANG
= secure_getenv("LANG");
288 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
296 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
299 const char* arch
= pakfire_get_effective_arch(pakfire
);
301 // Allocate a new jail
302 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
307 j
->ctx
= pakfire_ctx(pakfire
);
310 j
->pakfire
= pakfire_ref(pakfire
);
312 // Initialize reference counter
315 // Generate a random UUID
316 uuid_generate_random(j
->uuid
);
318 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
320 // Set the default logging callback
321 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
323 // Set default environment
324 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
325 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
330 // Enable all CPU features that CPU has to offer
331 if (!pakfire_arch_is_supported_by_host(arch
)) {
332 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
337 // Set container UUID
338 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
342 // Disable systemctl to talk to systemd
343 if (!pakfire_on_root(j
->pakfire
)) {
344 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
354 pakfire_jail_free(j
);
359 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
365 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
366 if (--jail
->nrefs
> 0)
369 pakfire_jail_free(jail
);
375 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
376 pakfire_jail_log_callback callback
, void* data
) {
377 jail
->callbacks
.log
= callback
;
378 jail
->callbacks
.log_data
= data
;
383 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
384 // Check if nice level is in range
385 if (nice
< -19 || nice
> 20) {
396 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
397 // Free any previous cgroup
399 pakfire_cgroup_unref(jail
->cgroup
);
403 // Set any new cgroup
405 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
407 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
416 // Returns the length of the environment
417 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
420 // Count everything in the environment
421 for (char** e
= jail
->env
; *e
; e
++)
427 // Finds an existing environment variable and returns its index or -1 if not found
428 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
434 const size_t length
= strlen(key
);
436 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
437 if ((pakfire_string_startswith(jail
->env
[i
], key
)
438 && *(jail
->env
[i
] + length
) == '=')) {
447 // Returns the value of an environment variable or NULL
448 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
450 int i
= pakfire_jail_find_env(jail
, key
);
454 return jail
->env
[i
] + strlen(key
) + 1;
457 // Sets an environment variable
458 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
459 const char* key
, const char* value
) {
460 // Find the index where to write this value to
461 int i
= pakfire_jail_find_env(jail
, key
);
463 i
= pakfire_jail_env_length(jail
);
465 // Return -ENOSPC when the environment is full
466 if (i
>= ENVIRON_SIZE
) {
471 // Free any previous value
475 // Format and set environment variable
476 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
478 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
483 // Imports an environment
484 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
492 // Copy environment variables
493 for (unsigned int i
= 0; env
[i
]; i
++) {
494 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
499 r
= pakfire_jail_set_env(jail
, key
, val
);
516 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
517 struct pakfire_jail
* jail
, unsigned int timeout
) {
519 jail
->timeout
.it_value
.tv_sec
= timeout
;
522 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
524 DEBUG(jail
->pakfire
, "Timeout disabled\n");
529 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
532 // Nothing to do if no timeout has been set
533 if (!jail
->timeout
.it_value
.tv_sec
)
536 // Create a new timer
537 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
539 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
544 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
546 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
560 This function replaces any logging in the child process.
562 All log messages will be sent to the parent process through their respective pipes.
564 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
565 int line
, const char* fn
, const char* format
, va_list args
) {
566 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
571 fd
= pipes
->log_INFO
[1];
575 fd
= pipes
->log_ERROR
[1];
580 fd
= pipes
->log_DEBUG
[1];
582 #endif /* ENABLE_DEBUG */
584 // Ignore any messages of an unknown priority
589 // Send the log message
591 vdprintf(fd
, format
, args
);
594 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
595 return (sizeof(buffer
->data
) == buffer
->used
);
598 static int pakfire_jail_fill_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
601 // Skip this if there is not space left in the buffer
602 if (buffer
->used
>= sizeof(buffer
->data
))
606 r
= read(fd
, buffer
->data
+ buffer
->used
, sizeof(buffer
->data
) - buffer
->used
);
621 // XXX What to do here?
631 static int pakfire_jail_drain_buffer_with_callback(struct pakfire_jail
* jail
,
632 struct pakfire_log_buffer
* buffer
, int priority
, pakfire_jail_communicate_out callback
, void* data
) {
633 const char* eol
= NULL
;
636 while (buffer
->used
) {
637 // Search for the end of the first line
638 eol
= memchr(buffer
->data
, '\n', buffer
->used
);
642 // If the buffer is full, we send the entire content to make space.
643 if (pakfire_jail_log_buffer_is_full(buffer
)) {
644 CTX_DEBUG(jail
->ctx
, "Buffer is full. Sending all content\n");
646 eol
= buffer
->data
+ buffer
->used
- 1;
648 // Otherwise we might have only read parts of the output...
654 // Find the length of the string
655 const size_t length
= eol
- buffer
->data
+ 1;
658 r
= callback(jail
->pakfire
, data
, priority
, buffer
->data
, length
);
660 CTX_ERROR(jail
->ctx
, "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_drain_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
675 // Nothing to do if the buffer is empty
679 // Do not try to write to an invalid file descriptor
684 r
= write(fd
, buffer
->data
, buffer
->used
);
699 memmove(buffer
->data
, buffer
->data
+ r
, buffer
->used
- r
);
708 This function reads as much data as it can from the file descriptor.
709 If it finds a whole line in it, it will send it to the logger and repeat the process.
710 If not newline character is found, it will try to read more data until it finds one.
712 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
713 int priority
, int fd
, struct pakfire_log_buffer
* buffer
,
714 pakfire_jail_communicate_out callback
, void* data
) {
717 // Fill up buffer from fd
718 r
= pakfire_jail_fill_buffer(jail
, fd
, buffer
);
723 r
= pakfire_jail_drain_buffer_with_callback(jail
, buffer
, priority
, callback
, data
);
731 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
732 struct pakfire_jail_exec
* ctx
, const int fd
) {
735 // Nothing to do if there is no stdin callback set
736 if (!ctx
->communicate
.in
) {
737 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
741 // Skip if the writing pipe has already been closed
742 if (ctx
->pipes
.stdin
[1] < 0)
745 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
747 // Calling the callback
748 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
750 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
752 // The callback signaled that it has written everything
754 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
756 // Close the file-descriptor
759 // Reset the file-descriptor so it won't be closed again later
760 ctx
->pipes
.stdin
[1] = -1;
770 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
771 const size_t payload_length
= sizeof(fd
);
772 char buffer
[CMSG_SPACE(payload_length
)];
775 struct msghdr msg
= {
776 .msg_control
= buffer
,
777 .msg_controllen
= sizeof(buffer
),
780 // Receive the message
781 r
= recvmsg(socket
, &msg
, 0);
783 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
788 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
792 *fd
= *((int*)CMSG_DATA(cmsg
));
794 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
799 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
800 const size_t payload_length
= sizeof(fd
);
801 char buffer
[CMSG_SPACE(payload_length
)];
804 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
807 struct msghdr msg
= {
808 .msg_control
= buffer
,
809 .msg_controllen
= sizeof(buffer
),
813 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
814 cmsg
->cmsg_level
= SOL_SOCKET
;
815 cmsg
->cmsg_type
= SCM_RIGHTS
;
816 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
819 *((int*)CMSG_DATA(cmsg
)) = fd
;
822 r
= sendmsg(socket
, &msg
, 0);
824 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
831 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
832 int r
= pipe2(*fds
, flags
);
834 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
841 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
842 for (unsigned int i
= 0; i
< 2; i
++)
848 This is a convenience function to fetch the reading end of a pipe and
849 closes the write end.
851 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
852 // Give the variables easier names to avoid confusion
853 int* fd_read
= &(*fds
)[0];
854 int* fd_write
= &(*fds
)[1];
856 // Close the write end of the pipe
857 if (*fd_write
>= 0) {
862 // Return the read end
869 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
870 // Give the variables easier names to avoid confusion
871 int* fd_read
= &(*fds
)[0];
872 int* fd_write
= &(*fds
)[1];
874 // Close the read end of the pipe
880 // Return the write end
887 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
888 struct epoll_event event
= {
889 .events
= events
|EPOLLHUP
,
897 int flags
= fcntl(fd
, F_GETFL
, 0);
899 // Set modified flags
900 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
902 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
903 fd
, strerror(errno
));
907 // Add the file descriptor to the loop
908 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
910 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
911 fd
, strerror(errno
));
920 static int pakfire_jail_enable_raw_mode(struct pakfire_jail
* jail
,
921 struct pakfire_jail_pty_stdio
* stdio
) {
922 struct termios raw_attrs
;
925 // Skip if we don't know the file descriptor
929 // Skip everything if fd is not a TTY
930 if (!isatty(stdio
->fd
))
934 stdio
->fdflags
= fcntl(stdio
->fd
, F_GETFL
);
935 if (stdio
->fdflags
< 0) {
936 CTX_ERROR(jail
->ctx
, "Could not fetch flags from fd %d: %s\n",
937 stdio
->fd
, strerror(errno
));
941 // Fetch all attributes
942 r
= tcgetattr(stdio
->fd
, &stdio
->attrs
);
944 CTX_ERROR(jail
->ctx
, "Could not fetch terminal attributes from fd %d: %s\n",
945 stdio
->fd
, strerror(errno
));
949 // Copy all attributes
950 raw_attrs
= stdio
->attrs
;
953 cfmakeraw(&raw_attrs
);
957 raw_attrs
.c_oflag
= stdio
->attrs
.c_oflag
;
961 raw_attrs
.c_iflag
= stdio
->attrs
.c_iflag
;
962 raw_attrs
.c_lflag
= stdio
->attrs
.c_lflag
;
966 // Restore the attributes
967 r
= tcsetattr(stdio
->fd
, TCSANOW
, &raw_attrs
);
969 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for fd %d: %s\n",
970 stdio
->fd
, strerror(errno
));
977 static int pakfire_jail_restore_attrs(struct pakfire_jail
* jail
,
978 const struct pakfire_jail_pty_stdio
* stdio
) {
981 // Skip if we don't know the file descriptor
985 // Skip everything if fd is not a TTY
986 if (!isatty(stdio
->fd
))
990 r
= fcntl(stdio
->fd
, F_SETFL
, stdio
->fdflags
);
992 CTX_ERROR(jail
->ctx
, "Could not set flags for file descriptor %d: %s\n",
993 stdio
->fd
, strerror(errno
));
997 // Restore the attributes
998 r
= tcsetattr(stdio
->fd
, TCSANOW
, &stdio
->attrs
);
1000 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for %d, ignoring: %s\n",
1001 stdio
->fd
, strerror(errno
));
1008 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail
* jail
,
1009 struct pakfire_jail_exec
* ctx
, const int epollfd
, const int fd
) {
1010 struct winsize size
;
1013 CTX_DEBUG(jail
->ctx
, "Setting up PTY forwarding on fd %d\n", fd
);
1015 // Store the file descriptor
1016 ctx
->pty
.master
.fd
= fd
;
1018 // Add the master to the event loop
1019 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.master
.fd
, EPOLLIN
|EPOLLOUT
|EPOLLET
);
1023 if (ctx
->flags
& PAKFIRE_JAIL_PTY_FORWARDING
) {
1024 // Configure stdin/stdout
1025 ctx
->pty
.stdin
.fd
= STDIN_FILENO
;
1026 ctx
->pty
.stdout
.fd
= STDOUT_FILENO
;
1029 if (isatty(ctx
->pty
.stdout
.fd
)) {
1030 r
= ioctl(ctx
->pty
.stdout
.fd
, TIOCGWINSZ
, &size
);
1032 CTX_ERROR(jail
->ctx
, "Failed to determine terminal dimensions: %s\n", strerror(errno
));
1037 r
= ioctl(ctx
->pty
.master
.fd
, TIOCSWINSZ
, &size
);
1039 CTX_ERROR(jail
->ctx
, "Failed setting dimensions: %s\n", strerror(errno
));
1044 // Enable RAW mode on standard input
1045 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdin
);
1049 // Enable RAW mode on standard output
1050 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdout
);
1054 // Add standard input to the event loop
1055 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdin
.fd
, EPOLLIN
|EPOLLET
);
1059 // Add standard output to the event loop
1060 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdout
.fd
, EPOLLOUT
|EPOLLET
);
1068 static int pakfire_jail_forward_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1071 // Read from standard input
1072 if (ctx
->pty
.stdin
.flags
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1073 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.stdin
.fd
, &ctx
->pty
.stdin
.buffer
);
1075 CTX_ERROR(jail
->ctx
, "Failed reading from standard input: %s\n", strerror(-r
));
1079 // We are done reading for now
1080 ctx
->pty
.stdin
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1082 // But we may have data to write
1083 if (ctx
->pty
.stdin
.buffer
.used
)
1084 ctx
->pty
.master
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1087 // Write to the master
1088 if (ctx
->pty
.master
.flags
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1089 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdin
.buffer
);
1091 CTX_ERROR(jail
->ctx
, "Failed writing to the PTY: %s\n", strerror(-r
));
1095 // We are done writing for now
1096 ctx
->pty
.master
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1099 // Read from the master
1100 if (ctx
->pty
.master
.flags
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1101 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdout
.buffer
);
1103 CTX_ERROR(jail
->ctx
, "Failed reading from the PTY: %s\n", strerror(-r
));
1107 // We are done reading for now
1108 ctx
->pty
.master
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1110 // But we may have data to write
1111 if (ctx
->pty
.stdout
.buffer
.used
)
1112 ctx
->pty
.stdout
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1115 // Write to standard output
1116 if (ctx
->pty
.stdout
.flags
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1117 // If we have a callback, we will send any output to the callback
1118 if (ctx
->communicate
.out
) {
1119 r
= pakfire_jail_drain_buffer_with_callback(jail
, &ctx
->pty
.stdout
.buffer
,
1120 LOG_INFO
, ctx
->communicate
.out
, ctx
->communicate
.data
);
1124 // If we have a file descriptor, we will forward any output
1125 } else if (ctx
->pty
.stdout
.fd
>= 0) {
1126 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.stdout
.fd
, &ctx
->pty
.stdout
.buffer
);
1128 CTX_ERROR(jail
->ctx
, "Failed writing to standard output: %s\n", strerror(-r
));
1132 // Otherwise we log a message
1134 CTX_ERROR(jail
->ctx
, "No output configured for the PTY\n");
1137 // We are done writing for now
1138 ctx
->pty
.stdout
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1144 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1146 struct epoll_event events
[EPOLL_MAX_EVENTS
];
1150 // Fetch file descriptors from context
1151 const int pidfd
= ctx
->pidfd
;
1153 // Fetch the UNIX domain socket
1154 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
1157 const int timerfd
= pakfire_jail_create_timer(jail
);
1160 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
1161 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
1163 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
1164 #endif /* ENABLE_DEBUG */
1166 // Make a list of all file descriptors we are interested in
1167 const struct pakfire_wait_fds
{
1172 { timerfd
, EPOLLIN
},
1175 { ctx
->pidfd
, EPOLLIN
},
1178 { log_INFO
, EPOLLIN
},
1179 { log_ERROR
, EPOLLIN
},
1181 { log_DEBUG
, EPOLLIN
},
1182 #endif /* ENABLE_DEBUG */
1184 // UNIX Domain Socket
1185 { socket_recv
, EPOLLIN
},
1192 epollfd
= epoll_create1(0);
1194 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
1199 // Turn file descriptors into non-blocking mode and add them to epoll()
1200 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
1201 // Skip fds which were not initialized
1205 // Add the FD to the event loop
1206 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
1213 // Loop for as long as the process is alive
1215 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
1217 // Ignore if epoll_wait() has been interrupted
1221 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
1227 for (int i
= 0; i
< num
; i
++) {
1228 int e
= events
[i
].events
;
1229 int fd
= events
[i
].data
.fd
;
1231 // Handle PTY forwarding events
1232 if (ctx
->pty
.master
.fd
== fd
) {
1233 if (e
& (EPOLLIN
|EPOLLHUP
))
1234 ctx
->pty
.master
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1236 if (e
& (EPOLLOUT
|EPOLLHUP
))
1237 ctx
->pty
.master
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1240 r
= pakfire_jail_forward_pty(jail
, ctx
);
1242 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1246 // Handle standard input
1247 } else if (ctx
->pty
.stdin
.fd
== fd
) {
1248 if (e
& (EPOLLIN
|EPOLLHUP
))
1249 ctx
->pty
.stdin
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1252 r
= pakfire_jail_forward_pty(jail
, ctx
);
1254 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1258 // Handle standard output
1259 } else if (ctx
->pty
.stdout
.fd
== fd
) {
1260 if (e
& (EPOLLOUT
|EPOLLHUP
))
1261 ctx
->pty
.stdout
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1264 r
= pakfire_jail_forward_pty(jail
, ctx
);
1266 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1270 // Handle any changes to the PIDFD
1271 } else if (pidfd
== fd
) {
1273 // Call waidid() and store the result
1274 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
1276 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
1280 // Mark that we have ended so that we will process the remaining
1281 // events from epoll() now, but won't restart the outer loop.
1285 // Handle timer events
1286 } else if (timerfd
== fd
) {
1288 DEBUG(jail
->pakfire
, "Timer event received\n");
1291 r
= read(timerfd
, garbage
, sizeof(garbage
));
1293 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
1298 // Terminate the process if it hasn't already ended
1300 DEBUG(jail
->pakfire
, "Terminating process...\n");
1302 // Send SIGTERM to the process
1303 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
1305 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
1311 // Handle socket messages
1312 } else if (socket_recv
== fd
) {
1314 // Receive the passed FD
1315 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1319 // Setup PTY forwarding
1320 if (ctx
->pty
.master
.fd
< 0) {
1321 r
= pakfire_jail_setup_pty_forwarding(jail
, ctx
, epollfd
, fd
);
1323 CTX_ERROR(jail
->ctx
, "Failed setting up PTY forwarding: %s\n", strerror(-r
));
1329 // Handle log INFO messages
1330 } else if (log_INFO
== fd
) {
1332 r
= pakfire_jail_handle_log(jail
, ctx
, LOG_INFO
, fd
,
1333 &ctx
->buffers
.log_INFO
, pakfire_jail_default_log_callback
, NULL
);
1338 // Handle log ERROR messages
1339 } else if (log_ERROR
== fd
) {
1341 r
= pakfire_jail_handle_log(jail
, ctx
, LOG_ERR
, fd
,
1342 &ctx
->buffers
.log_ERROR
, pakfire_jail_default_log_callback
, NULL
);
1348 // Handle log DEBUG messages
1349 } else if (log_DEBUG
== fd
) {
1351 r
= pakfire_jail_handle_log(jail
, ctx
, LOG_DEBUG
, fd
,
1352 &ctx
->buffers
.log_DEBUG
, pakfire_jail_default_log_callback
, NULL
);
1356 #endif /* ENABLE_DEBUG */
1358 // Log a message for anything else
1360 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1364 // Check if any file descriptors have been closed
1366 // Remove the file descriptor
1367 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1369 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1382 // Restore any changed terminal attributes
1383 if (ctx
->pty
.stdin
.fd
>= 0)
1384 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdin
);
1385 if (ctx
->pty
.stdout
.fd
>= 0)
1386 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdout
);
1391 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1392 int priority
, const char* line
, size_t length
) {
1393 char** output
= (char**)data
;
1396 // Append everything from stdout to a buffer
1397 if (output
&& priority
== LOG_INFO
) {
1398 r
= asprintf(output
, "%s%.*s", (output
&& *output
) ? *output
: "", (int)length
, line
);
1405 // Send everything else to the default logger
1406 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1411 // Logs all capabilities of the current process
1412 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1415 cap_flag_value_t value_e
;
1416 cap_flag_value_t value_i
;
1417 cap_flag_value_t value_p
;
1421 pid_t pid
= getpid();
1423 // Fetch all capabilities
1424 caps
= cap_get_proc();
1426 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1431 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1433 // Iterate over all capabilities
1434 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1435 name
= cap_to_name(cap
);
1437 // Fetch effective value
1438 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1442 // Fetch inheritable value
1443 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1447 // Fetch permitted value
1448 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1452 DEBUG(jail
->pakfire
,
1453 " %-24s : %c%c%c\n",
1455 (value_e
== CAP_SET
) ? 'e' : '-',
1456 (value_i
== CAP_SET
) ? 'i' : '-',
1457 (value_p
== CAP_SET
) ? 'p' : '-'
1477 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1482 // Fetch capabilities
1483 caps
= cap_get_proc();
1485 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1490 // Walk through all capabilities
1491 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1492 cap_value_t _caps
[] = { cap
};
1494 // Fetch the name of the capability
1495 name
= cap_to_name(cap
);
1497 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1499 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1503 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1505 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1509 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1511 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1520 // Restore all capabilities
1521 r
= cap_set_proc(caps
);
1523 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1527 // Add all capabilities to the ambient set
1528 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1529 name
= cap_to_name(cap
);
1531 // Raise the capability
1532 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1534 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1557 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1558 const int syscalls
[] = {
1559 // The kernel's keyring isn't namespaced
1562 SCMP_SYS(request_key
),
1564 // Disable userfaultfd
1565 SCMP_SYS(userfaultfd
),
1567 // Disable perf which could leak a lot of information about the host
1568 SCMP_SYS(perf_event_open
),
1574 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1576 // Setup a syscall filter which allows everything by default
1577 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1579 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1584 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1585 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1587 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1592 // Load syscall filter into the kernel
1593 r
= seccomp_load(ctx
);
1595 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1601 seccomp_release(ctx
);
1608 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1609 const char* source
, const char* target
, int flags
) {
1610 struct pakfire_jail_mountpoint
* mp
= NULL
;
1613 // Check if there is any space left
1614 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1619 // Check for valid inputs
1620 if (!source
|| !target
) {
1625 // Select the next free slot
1626 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1629 r
= pakfire_string_set(mp
->source
, source
);
1631 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1636 r
= pakfire_string_set(mp
->target
, target
);
1638 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1645 // Increment counter
1646 jail
->num_mountpoints
++;
1651 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1654 const char* paths
[] = {
1660 // Bind-mount all paths read-only
1661 for (const char** path
= paths
; *path
; path
++) {
1662 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1665 // Ignore if we don't have permission
1680 Mounts everything that we require in the new namespace
1682 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1683 struct pakfire_jail_mountpoint
* mp
= NULL
;
1687 // Enable loop devices
1688 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1689 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1691 // Mount all default stuff
1692 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1697 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1701 // Mount the interpreter (if needed)
1702 r
= pakfire_mount_interpreter(jail
->pakfire
);
1706 // Mount networking stuff
1707 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1708 r
= pakfire_jail_mount_networking(jail
);
1713 // Mount all custom stuff
1714 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1716 mp
= &jail
->mountpoints
[i
];
1719 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1729 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1730 struct nl_sock
* nl
= NULL
;
1731 struct nl_cache
* cache
= NULL
;
1732 struct rtnl_link
* link
= NULL
;
1733 struct rtnl_link
* change
= NULL
;
1736 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1738 // Allocate a netlink socket
1739 nl
= nl_socket_alloc();
1741 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1746 // Connect the socket
1747 r
= nl_connect(nl
, NETLINK_ROUTE
);
1749 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1753 // Allocate the netlink cache
1754 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1756 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1760 // Fetch loopback interface
1761 link
= rtnl_link_get_by_name(cache
, "lo");
1763 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1768 // Allocate a new link
1769 change
= rtnl_link_alloc();
1771 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1776 // Set the link to UP
1777 rtnl_link_set_flags(change
, IFF_UP
);
1779 // Apply any changes
1780 r
= rtnl_link_change(nl
, link
, change
, 0);
1782 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1798 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1799 char path
[PATH_MAX
];
1802 // Skip mapping anything when running on /
1803 if (pakfire_on_root(jail
->pakfire
))
1807 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1812 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1815 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1819 /* When running as root, we will map the entire range.
1821 When running as a non-privileged user, we will map the root user inside the jail
1822 to the user's UID outside of the jail, and we will map the rest starting from one.
1827 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1828 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1830 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1831 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1835 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1842 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1843 char path
[PATH_MAX
];
1846 // Skip mapping anything when running on /
1847 if (pakfire_on_root(jail
->pakfire
))
1851 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1854 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1859 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1865 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1866 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1868 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1869 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1873 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1880 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1881 char path
[PATH_MAX
];
1885 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1889 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1891 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1898 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1899 const uint64_t val
= 1;
1902 DEBUG(jail
->pakfire
, "Sending signal...\n");
1904 // Write to the file descriptor
1905 r
= eventfd_write(fd
, val
);
1907 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1911 // Close the file descriptor
1917 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1921 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1923 r
= eventfd_read(fd
, &val
);
1925 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1929 // Close the file descriptor
1936 Performs the initialisation that needs to happen in the parent part
1938 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1941 // Setup UID mapping
1942 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1946 // Write "deny" to /proc/PID/setgroups
1947 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1951 // Setup GID mapping
1952 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1956 // Parent has finished initialisation
1957 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1959 // Send signal to client
1960 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1967 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1970 // Change to the new root
1973 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1978 r
= pivot_root(".", ".");
1980 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1984 // Umount the old root
1985 r
= umount2(".", MNT_DETACH
);
1987 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1994 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1997 // Allocate a new PTY
1998 ctx
->pty
.master
.fd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
1999 if (ctx
->pty
.master
.fd
< 0)
2003 r
= ptsname_r(ctx
->pty
.master
.fd
, ctx
->pty
.console
, sizeof(ctx
->pty
.console
));
2007 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->pty
.console
, ctx
->pty
.master
.fd
);
2009 // Unlock the master device
2010 r
= unlockpt(ctx
->pty
.master
.fd
);
2012 CTX_ERROR(jail
->ctx
, "Could not unlock the PTY: %s\n", strerror(errno
));
2017 r
= pakfire_symlink(jail
->ctx
, ctx
->pty
.console
, "/dev/console");
2024 static int pakfire_jail_setup_terminal(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
2028 // Open a new terminal
2029 fd
= open("/dev/console", O_RDWR
|O_NOCTTY
);
2031 CTX_ERROR(jail
->ctx
, "Failed to open a new terminal: %s\n", strerror(errno
));
2035 CTX_DEBUG(jail
->ctx
, "Opened a new terminal %d\n", fd
);
2037 // Connect the new terminal to standard input
2038 r
= dup2(fd
, STDIN_FILENO
);
2040 CTX_ERROR(jail
->ctx
, "Failed to open standard input: %s\n", strerror(errno
));
2044 // Connect the new terminal to standard output
2045 r
= dup2(fd
, STDOUT_FILENO
);
2047 CTX_ERROR(jail
->ctx
, "Failed to open standard output: %s\n", strerror(errno
));
2051 // Connect the new terminal to standard error
2052 r
= dup2(fd
, STDERR_FILENO
);
2054 CTX_ERROR(jail
->ctx
, "Failed to open standard error: %s\n", strerror(errno
));
2061 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
2062 const char* argv
[]) {
2065 // Redirect any logging to our log pipe
2066 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
2069 pid_t pid
= getpid();
2071 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
2073 // Wait for the parent to finish initialization
2074 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
2079 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
2081 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
2085 // Make this process dumpable
2086 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
2088 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
2092 // Don't drop any capabilities on setuid()
2093 r
= prctl(PR_SET_KEEPCAPS
, 1);
2095 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
2100 uid_t uid
= getuid();
2101 gid_t gid
= getgid();
2104 uid_t euid
= geteuid();
2105 gid_t egid
= getegid();
2107 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
2108 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
2110 // Log all mountpoints
2111 pakfire_mount_list(jail
->ctx
);
2113 // Fail if we are not PID 1
2115 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
2119 // Fail if we are not running as root
2120 if (uid
|| gid
|| euid
|| egid
) {
2121 ERROR(jail
->pakfire
, "Child process is not running as root\n");
2125 const int socket_send
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->socket
);
2127 // Mount all default stuff
2128 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
2132 const char* root
= pakfire_get_path(jail
->pakfire
);
2133 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
2135 // Change mount propagation to slave to receive anything from the parent namespace
2136 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
2140 // Make root a mountpoint in the new mount namespace
2141 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
2145 // Change mount propagation to private
2146 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
2150 // Change root (unless root is /)
2151 if (!pakfire_on_root(jail
->pakfire
)) {
2153 r
= pakfire_jail_mount(jail
, ctx
);
2158 r
= pakfire_jail_switch_root(jail
, root
);
2164 unsigned long persona
= pakfire_arch_personality(arch
);
2166 r
= personality(persona
);
2168 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
2174 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2175 r
= pakfire_jail_setup_loopback(jail
);
2182 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
2184 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
2186 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
2191 // Create a new session
2194 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
2198 // Allocate a new PTY
2199 r
= pakfire_jail_open_pty(jail
, ctx
);
2201 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
2205 // Send the PTY master to the parent process
2206 r
= pakfire_jail_send_fd(jail
, socket_send
, ctx
->pty
.master
.fd
);
2208 CTX_ERROR(jail
->ctx
, "Failed sending the PTY master to the parent: %s\n", strerror(-r
));
2212 // Setup the terminal
2213 r
= pakfire_jail_setup_terminal(jail
, ctx
);
2217 // Close the master of the PTY
2218 close(ctx
->pty
.master
.fd
);
2219 ctx
->pty
.master
.fd
= -1;
2224 // Close other end of log pipes
2225 close(ctx
->pipes
.log_INFO
[0]);
2226 close(ctx
->pipes
.log_ERROR
[0]);
2228 close(ctx
->pipes
.log_DEBUG
[0]);
2229 #endif /* ENABLE_DEBUG */
2231 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2232 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
2237 r
= pakfire_jail_set_capabilities(jail
);
2241 // Show capabilities
2242 r
= pakfire_jail_show_capabilities(jail
);
2247 r
= pakfire_jail_limit_syscalls(jail
);
2251 DEBUG(jail
->pakfire
, "Child process initialization done\n");
2252 DEBUG(jail
->pakfire
, "Launching command:\n");
2255 for (unsigned int i
= 0; argv
[i
]; i
++)
2256 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
2259 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
2261 // Translate errno into regular exit code
2264 // Ignore if the command doesn't exist
2265 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
2276 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
2279 // We should not get here
2283 // Run a command in the jail
2284 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
2285 pakfire_jail_communicate_in communicate_in
,
2286 pakfire_jail_communicate_out communicate_out
,
2287 void* data
, int flags
) {
2291 // Check if argv is valid
2292 if (!argv
|| !argv
[0]) {
2297 // Initialize context for this call
2298 struct pakfire_jail_exec ctx
= {
2301 .socket
= { -1, -1 },
2304 .log_INFO
= { -1, -1 },
2305 .log_ERROR
= { -1, -1 },
2307 .log_DEBUG
= { -1, -1 },
2308 #endif /* ENABLE_DEBUG */
2312 .in
= communicate_in
,
2313 .out
= communicate_out
,
2333 DEBUG(jail
->pakfire
, "Executing jail...\n");
2335 // Enable networking in interactive mode
2336 if (ctx
.flags
& PAKFIRE_JAIL_PTY_FORWARDING
)
2337 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2340 Setup a file descriptor which can be used to notify the client that the parent
2341 has completed configuration.
2343 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2344 if (ctx
.completed_fd
< 0) {
2345 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2349 // Create a UNIX domain socket
2350 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2352 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2357 // Setup pipes for logging
2359 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2364 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2370 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2373 #endif /* ENABLE_DEBUG */
2375 // Configure child process
2376 struct clone_args args
= {
2386 .exit_signal
= SIGCHLD
,
2387 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2390 // Launch the process in a cgroup that is a leaf of the configured cgroup
2392 args
.flags
|= CLONE_INTO_CGROUP
;
2395 const char* uuid
= pakfire_jail_uuid(jail
);
2397 // Create a temporary cgroup
2398 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2400 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2404 // Clone into this cgroup
2405 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2409 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2410 args
.flags
|= CLONE_NEWNET
;
2413 // Fork this process
2414 ctx
.pid
= clone3(&args
, sizeof(args
));
2416 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2420 } else if (ctx
.pid
== 0) {
2421 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2426 r
= pakfire_jail_parent(jail
, &ctx
);
2430 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2432 // Read output of the child process
2433 r
= pakfire_jail_wait(jail
, &ctx
);
2437 // Handle exit status
2438 switch (ctx
.status
.si_code
) {
2440 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2441 ctx
.status
.si_status
);
2444 exit
= ctx
.status
.si_status
;
2448 ERROR(jail
->pakfire
, "The child process was killed\n");
2453 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2456 // Log anything else
2458 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2463 // Destroy the temporary cgroup (if any)
2465 // Read cgroup stats
2466 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2467 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2468 pakfire_cgroup_destroy(ctx
.cgroup
);
2469 pakfire_cgroup_unref(ctx
.cgroup
);
2472 // Close any file descriptors
2475 if (ctx
.pty
.master
.fd
>= 0)
2476 close(ctx
.pty
.master
.fd
);
2477 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2478 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2480 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2481 #endif /* ENABLE_DEBUG */
2482 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2487 PAKFIRE_EXPORT
int pakfire_jail_exec(
2488 struct pakfire_jail
* jail
,
2490 pakfire_jail_communicate_in callback_in
,
2491 pakfire_jail_communicate_out callback_out
,
2492 void* data
, int flags
) {
2493 return __pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, flags
);
2496 static int pakfire_jail_exec_interactive(
2497 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2500 flags
|= PAKFIRE_JAIL_PTY_FORWARDING
;
2502 // Setup interactive stuff
2503 r
= pakfire_jail_setup_interactive_env(jail
);
2507 return __pakfire_jail_exec(jail
, argv
, NULL
, NULL
, NULL
, flags
);
2510 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2514 pakfire_jail_communicate_in callback_in
,
2515 pakfire_jail_communicate_out callback_out
,
2517 char path
[PATH_MAX
];
2518 const char** argv
= NULL
;
2522 const char* root
= pakfire_get_path(jail
->pakfire
);
2524 // Write the scriptlet to disk
2525 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2529 // Create a temporary file
2530 f
= pakfire_mktemp(path
, 0700);
2532 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2536 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2539 r
= fprintf(f
, "%s", script
);
2541 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2548 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2554 // Count how many arguments were passed
2555 unsigned int argc
= 1;
2557 for (const char** arg
= args
; *arg
; arg
++)
2561 argv
= calloc(argc
+ 1, sizeof(*argv
));
2563 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2568 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2571 for (unsigned int i
= 1; i
< argc
; i
++)
2572 argv
[i
] = args
[i
-1];
2575 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2583 // Remove script from disk
2591 A convenience function that creates a new jail, runs the given command and destroys
2594 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2595 struct pakfire_jail
* jail
= NULL
;
2598 // Create a new jail
2599 r
= pakfire_jail_create(&jail
, pakfire
);
2603 // Execute the command
2604 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2608 pakfire_jail_unref(jail
);
2613 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2614 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2615 struct pakfire_jail
* jail
= NULL
;
2618 // Create a new jail
2619 r
= pakfire_jail_create(&jail
, pakfire
);
2623 // Execute the command
2624 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2628 pakfire_jail_unref(jail
);
2633 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2636 const char* argv
[] = {
2637 "/bin/bash", "--login", NULL
,
2640 // Execute /bin/bash
2641 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2647 // Ignore any return codes from the shell
2651 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2652 char path
[PATH_MAX
];
2655 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2659 // Check if the file is executable
2660 r
= access(path
, X_OK
);
2662 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2666 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2669 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2670 const char* argv
[] = {
2675 return pakfire_jail_run_if_possible(pakfire
, argv
);
2678 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2679 const char* argv
[] = {
2680 "/usr/bin/systemd-tmpfiles",
2685 return pakfire_jail_run_if_possible(pakfire
, argv
);