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 // Enable legacy logging
54 #define PAKFIRE_LEGACY_LOGGING
56 #include <pakfire/arch.h>
57 #include <pakfire/cgroup.h>
58 #include <pakfire/jail.h>
59 #include <pakfire/logging.h>
60 #include <pakfire/mount.h>
61 #include <pakfire/pakfire.h>
62 #include <pakfire/path.h>
63 #include <pakfire/private.h>
64 #include <pakfire/pwd.h>
65 #include <pakfire/string.h>
66 #include <pakfire/util.h>
68 #define BUFFER_SIZE 1024 * 64
69 #define ENVIRON_SIZE 128
70 #define EPOLL_MAX_EVENTS 2
71 #define MAX_MOUNTPOINTS 8
73 // The default environment that will be set for every command
74 static const struct environ
{
79 { "LANG", "C.utf-8" },
80 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
83 // Tell everything that it is running inside a Pakfire container
84 { "container", "pakfire" },
88 struct pakfire_log_buffer
{
89 char data
[BUFFER_SIZE
];
94 enum pakfire_jail_pty_io
{
95 PAKFIRE_JAIL_PTY_READY_TO_READ
= (1 << 0),
96 PAKFIRE_JAIL_PTY_READY_TO_WRITE
= (1 << 1),
99 struct pakfire_jail_pty_stdio
{
104 struct pakfire_log_buffer buffer
;
106 // Terminal Attributes
107 struct termios attrs
;
109 // File Descriptor Flags
113 enum pakfire_jail_pty_io io
;
116 struct pakfire_jail_mountpoint
{
117 char source
[PATH_MAX
];
118 char target
[PATH_MAX
];
122 struct pakfire_jail
{
123 struct pakfire_ctx
* ctx
;
124 struct pakfire
* pakfire
;
127 // A unique ID for each jail
129 char __uuid
[UUID_STR_LEN
];
135 struct itimerspec timeout
;
138 struct pakfire_cgroup
* cgroup
;
141 char* env
[ENVIRON_SIZE
];
143 struct pakfire_jail_callbacks
{
145 struct pakfire_jail_callbacks_stdin
{
146 pakfire_jail_stdin_callback callback
;
151 struct pakfire_jail_callbacks_stdout
{
152 pakfire_jail_stdout_callback callback
;
158 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
159 unsigned int num_mountpoints
;
162 struct pakfire_jail_exec
{
165 // PID (of the child)
169 // Socket to pass FDs
172 // Process status (from waitid)
175 // FD to notify the client that the parent has finished initialization
179 struct pakfire_jail_pipes
{
185 #endif /* ENABLE_DEBUG */
189 struct pakfire_jail_buffers
{
191 struct pakfire_log_buffer log_INFO
;
192 struct pakfire_log_buffer log_ERROR
;
194 struct pakfire_log_buffer log_DEBUG
;
195 #endif /* ENABLE_DEBUG */
198 struct pakfire_cgroup
* cgroup
;
199 struct pakfire_cgroup_stats cgroup_stats
;
202 struct pakfire_jail_pty
{
203 // The path to the console
204 char console
[PATH_MAX
];
207 struct pakfire_jail_pty_master
{
209 enum pakfire_jail_pty_io io
;
212 // Standard Input/Output
213 struct pakfire_jail_pty_stdio stdin
;
214 struct pakfire_jail_pty_stdio stdout
;
218 static int clone3(struct clone_args
* args
, size_t size
) {
219 return syscall(__NR_clone3
, args
, size
);
222 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
223 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
226 static int pivot_root(const char* new_root
, const char* old_root
) {
227 return syscall(SYS_pivot_root
, new_root
, old_root
);
230 static int pakfire_jail_exec_has_flag(
231 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
232 return ctx
->flags
& flag
;
235 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
236 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
239 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
243 pakfire_cgroup_unref(jail
->cgroup
);
245 pakfire_unref(jail
->pakfire
);
247 pakfire_ctx_unref(jail
->ctx
);
251 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
253 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
258 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
260 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
265 char* TERM
= secure_getenv("TERM");
267 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
273 char* LANG
= secure_getenv("LANG");
275 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
283 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
286 const char* arch
= pakfire_get_effective_arch(pakfire
);
288 // Allocate a new jail
289 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
294 j
->ctx
= pakfire_ctx(pakfire
);
297 j
->pakfire
= pakfire_ref(pakfire
);
299 // Initialize reference counter
302 // Generate a random UUID
303 uuid_generate_random(j
->uuid
);
305 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
307 // Set default environment
308 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
309 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
314 // Enable all CPU features that CPU has to offer
315 if (!pakfire_arch_is_supported_by_host(arch
)) {
316 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
321 // Set container UUID
322 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
326 // Disable systemctl to talk to systemd
327 if (!pakfire_on_root(j
->pakfire
)) {
328 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
338 pakfire_jail_free(j
);
343 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
349 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
350 if (--jail
->nrefs
> 0)
353 pakfire_jail_free(jail
);
359 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
360 // Check if nice level is in range
361 if (nice
< -19 || nice
> 20) {
372 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
373 // Free any previous cgroup
375 pakfire_cgroup_unref(jail
->cgroup
);
379 // Set any new cgroup
381 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
383 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
392 // Returns the length of the environment
393 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
396 // Count everything in the environment
397 for (char** e
= jail
->env
; *e
; e
++)
403 // Finds an existing environment variable and returns its index or -1 if not found
404 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
410 const size_t length
= strlen(key
);
412 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
413 if ((pakfire_string_startswith(jail
->env
[i
], key
)
414 && *(jail
->env
[i
] + length
) == '=')) {
423 // Returns the value of an environment variable or NULL
424 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
426 int i
= pakfire_jail_find_env(jail
, key
);
430 return jail
->env
[i
] + strlen(key
) + 1;
433 // Sets an environment variable
434 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
435 const char* key
, const char* value
) {
436 // Find the index where to write this value to
437 int i
= pakfire_jail_find_env(jail
, key
);
439 i
= pakfire_jail_env_length(jail
);
441 // Return -ENOSPC when the environment is full
442 if (i
>= ENVIRON_SIZE
) {
447 // Free any previous value
451 // Format and set environment variable
452 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
454 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
459 // Imports an environment
460 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
468 // Copy environment variables
469 for (unsigned int i
= 0; env
[i
]; i
++) {
470 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
475 r
= pakfire_jail_set_env(jail
, key
, val
);
492 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
493 struct pakfire_jail
* jail
, unsigned int timeout
) {
495 jail
->timeout
.it_value
.tv_sec
= timeout
;
498 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
500 DEBUG(jail
->pakfire
, "Timeout disabled\n");
505 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
508 // Nothing to do if no timeout has been set
509 if (!jail
->timeout
.it_value
.tv_sec
)
512 // Create a new timer
513 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
515 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
520 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
522 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
538 PAKFIRE_EXPORT
void pakfire_jail_set_stdin_callback(struct pakfire_jail
* jail
,
539 pakfire_jail_stdin_callback callback
, void* data
) {
540 jail
->callbacks
.stdin
.callback
= callback
;
541 jail
->callbacks
.stdin
.data
= data
;
547 PAKFIRE_EXPORT
void pakfire_jail_set_stdout_callback(struct pakfire_jail
* jail
,
548 pakfire_jail_stdout_callback callback
, void* data
) {
549 jail
->callbacks
.stdout
.callback
= callback
;
550 jail
->callbacks
.stdout
.data
= data
;
554 This function replaces any logging in the child process.
556 All log messages will be sent to the parent process through their respective pipes.
558 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
559 int line
, const char* fn
, const char* format
, va_list args
) {
560 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
565 fd
= pipes
->log_INFO
[1];
569 fd
= pipes
->log_ERROR
[1];
574 fd
= pipes
->log_DEBUG
[1];
576 #endif /* ENABLE_DEBUG */
578 // Ignore any messages of an unknown priority
583 // End if we do not have a file descriptor to write to
587 // Optionally log the function name
589 dprintf(fd
, "%s: ", fn
);
591 // Send the log message
592 vdprintf(fd
, format
, args
);
595 static int pakfire_jail_fill_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
598 // Skip this if there is not space left in the buffer
599 if (buffer
->used
>= sizeof(buffer
->data
))
603 r
= read(fd
, buffer
->data
+ buffer
->used
, sizeof(buffer
->data
) - buffer
->used
);
618 // XXX What to do here?
628 static int pakfire_jail_drain_buffer_with_callback(struct pakfire_jail
* jail
,
629 struct pakfire_log_buffer
* buffer
, pakfire_jail_stdout_callback callback
, void* data
) {
630 const char* eol
= NULL
;
633 while (buffer
->used
) {
634 // Search for the end of the first line
635 eol
= memchr(buffer
->data
, '\n', buffer
->used
);
639 // If the buffer is full, we send the entire content to make space.
640 if (buffer
->used
>= sizeof(buffer
->data
)) {
641 CTX_DEBUG(jail
->ctx
, "Buffer is full. Sending all content\n");
643 eol
= buffer
->data
+ buffer
->used
- 1;
645 // Otherwise we might have only read parts of the output...
651 // Find the length of the string
652 const size_t length
= eol
- buffer
->data
+ 1;
655 r
= callback(jail
->ctx
, jail
, data
, buffer
->data
, length
);
657 CTX_ERROR(jail
->ctx
, "The standard output callback returned an error: %d\n", r
);
661 // Remove line from buffer
662 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
663 buffer
->used
-= length
;
669 static int pakfire_jail_drain_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
672 // Nothing to do if the buffer is empty
676 // Do not try to write to an invalid file descriptor
681 r
= write(fd
, buffer
->data
, buffer
->used
);
696 memmove(buffer
->data
, buffer
->data
+ r
, buffer
->used
- r
);
705 Passes any log messages on to the default pakfire log callback
707 static int pakfire_jail_log(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
708 void* data
, const char* line
, size_t length
) {
709 int* priority
= data
;
711 if (pakfire_ctx_get_log_level(jail
->ctx
) >= *priority
)
712 pakfire_ctx_log(jail
->ctx
, *priority
, NULL
, 0, NULL
, "%.*s", (int)length
, line
);
718 This function reads as much data as it can from the file descriptor.
719 If it finds a whole line in it, it will send it to the logger and repeat the process.
720 If not newline character is found, it will try to read more data until it finds one.
722 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
723 int fd
, struct pakfire_log_buffer
* buffer
, pakfire_jail_stdout_callback callback
, void* data
) {
726 // Fill up buffer from fd
727 r
= pakfire_jail_fill_buffer(jail
, fd
, buffer
);
732 r
= pakfire_jail_drain_buffer_with_callback(jail
, buffer
, callback
, data
);
739 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
740 struct pakfire_jail_exec
* ctx
, const int fd
) {
741 const char eof
= 0x04;
744 // Skip if the writing pipe has already been closed
748 CTX_DEBUG(jail
->ctx
, "Streaming standard input...\n");
750 // Calling the callback
751 r
= jail
->callbacks
.stdin
.callback(jail
->ctx
, jail
, jail
->callbacks
.stdin
.data
, fd
);
755 // The callback signaled that it has written everything
756 CTX_DEBUG(jail
->ctx
, "Closing standard input pipe\n");
759 r
= write(fd
, &eof
, sizeof(eof
));
761 CTX_ERROR(jail
->ctx
, "Could not write EOF: %s\n", strerror(errno
));
768 CTX_DEBUG(jail
->ctx
, "Standard input callback finished\n");
772 CTX_ERROR(jail
->ctx
, "Standard input callback failed: %s\n", strerror(-r
));
777 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
778 const size_t payload_length
= sizeof(fd
);
779 char buffer
[CMSG_SPACE(payload_length
)];
782 struct msghdr msg
= {
783 .msg_control
= buffer
,
784 .msg_controllen
= sizeof(buffer
),
787 // Receive the message
788 r
= recvmsg(socket
, &msg
, 0);
790 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
795 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
799 *fd
= *((int*)CMSG_DATA(cmsg
));
801 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
806 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
807 const size_t payload_length
= sizeof(fd
);
808 char buffer
[CMSG_SPACE(payload_length
)];
811 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
814 struct msghdr msg
= {
815 .msg_control
= buffer
,
816 .msg_controllen
= sizeof(buffer
),
820 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
821 cmsg
->cmsg_level
= SOL_SOCKET
;
822 cmsg
->cmsg_type
= SCM_RIGHTS
;
823 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
826 *((int*)CMSG_DATA(cmsg
)) = fd
;
829 r
= sendmsg(socket
, &msg
, 0);
831 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
838 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
839 int r
= pipe2(*fds
, flags
);
841 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
848 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
849 for (unsigned int i
= 0; i
< 2; i
++)
855 This is a convenience function to fetch the reading end of a pipe and
856 closes the write end.
858 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
859 // Give the variables easier names to avoid confusion
860 int* fd_read
= &(*fds
)[0];
861 int* fd_write
= &(*fds
)[1];
863 // Close the write end of the pipe
864 if (*fd_write
>= 0) {
869 // Return the read end
876 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
877 // Give the variables easier names to avoid confusion
878 int* fd_read
= &(*fds
)[0];
879 int* fd_write
= &(*fds
)[1];
881 // Close the read end of the pipe
887 // Return the write end
894 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
895 struct epoll_event event
= {
896 .events
= events
|EPOLLHUP
,
904 int flags
= fcntl(fd
, F_GETFL
, 0);
906 // Set modified flags
907 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
909 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
910 fd
, strerror(errno
));
914 // Add the file descriptor to the loop
915 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
917 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
918 fd
, strerror(errno
));
927 static int pakfire_jail_enable_raw_mode(struct pakfire_jail
* jail
,
928 struct pakfire_jail_pty_stdio
* stdio
) {
929 struct termios raw_attrs
;
932 // Skip if we don't know the file descriptor
936 // Skip everything if fd is not a TTY
937 if (!isatty(stdio
->fd
))
941 stdio
->flags
= fcntl(stdio
->fd
, F_GETFL
);
942 if (stdio
->flags
< 0) {
943 CTX_ERROR(jail
->ctx
, "Could not fetch flags from fd %d: %s\n",
944 stdio
->fd
, strerror(errno
));
948 // Fetch all attributes
949 r
= tcgetattr(stdio
->fd
, &stdio
->attrs
);
951 CTX_ERROR(jail
->ctx
, "Could not fetch terminal attributes from fd %d: %s\n",
952 stdio
->fd
, strerror(errno
));
956 // Copy all attributes
957 raw_attrs
= stdio
->attrs
;
960 cfmakeraw(&raw_attrs
);
964 raw_attrs
.c_oflag
= stdio
->attrs
.c_oflag
;
968 raw_attrs
.c_iflag
= stdio
->attrs
.c_iflag
;
969 raw_attrs
.c_lflag
= stdio
->attrs
.c_lflag
;
973 // Restore the attributes
974 r
= tcsetattr(stdio
->fd
, TCSANOW
, &raw_attrs
);
976 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for fd %d: %s\n",
977 stdio
->fd
, strerror(errno
));
984 static int pakfire_jail_restore_attrs(struct pakfire_jail
* jail
,
985 const struct pakfire_jail_pty_stdio
* stdio
) {
988 // Skip if we don't know the file descriptor
992 // Skip everything if fd is not a TTY
993 if (!isatty(stdio
->fd
))
997 r
= fcntl(stdio
->fd
, F_SETFL
, stdio
->flags
);
999 CTX_ERROR(jail
->ctx
, "Could not set flags for file descriptor %d: %s\n",
1000 stdio
->fd
, strerror(errno
));
1004 // Restore the attributes
1005 r
= tcsetattr(stdio
->fd
, TCSANOW
, &stdio
->attrs
);
1007 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for %d, ignoring: %s\n",
1008 stdio
->fd
, strerror(errno
));
1015 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail
* jail
,
1016 struct pakfire_jail_exec
* ctx
, const int epollfd
, const int fd
) {
1017 struct winsize size
;
1020 CTX_DEBUG(jail
->ctx
, "Setting up PTY forwarding on fd %d\n", fd
);
1022 // Store the file descriptor
1023 ctx
->pty
.master
.fd
= fd
;
1025 // Add the master to the event loop
1026 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.master
.fd
, EPOLLIN
|EPOLLOUT
|EPOLLET
);
1030 if (ctx
->flags
& PAKFIRE_JAIL_PTY_FORWARDING
) {
1031 // Configure stdin/stdout
1032 ctx
->pty
.stdin
.fd
= STDIN_FILENO
;
1033 ctx
->pty
.stdout
.fd
= STDOUT_FILENO
;
1036 if (isatty(ctx
->pty
.stdout
.fd
)) {
1037 r
= ioctl(ctx
->pty
.stdout
.fd
, TIOCGWINSZ
, &size
);
1039 CTX_ERROR(jail
->ctx
, "Failed to determine terminal dimensions: %s\n", strerror(errno
));
1044 r
= ioctl(ctx
->pty
.master
.fd
, TIOCSWINSZ
, &size
);
1046 CTX_ERROR(jail
->ctx
, "Failed setting dimensions: %s\n", strerror(errno
));
1051 // Enable RAW mode on standard input
1052 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdin
);
1056 // Enable RAW mode on standard output
1057 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdout
);
1061 // Add standard input to the event loop
1062 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdin
.fd
, EPOLLIN
|EPOLLET
);
1066 // Add standard output to the event loop
1067 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdout
.fd
, EPOLLOUT
|EPOLLET
);
1075 static int pakfire_jail_command_output(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
1076 void* data
, const char* line
, const size_t length
) {
1077 CTX_INFO(ctx
, "Command Output: %.*s", (int)length
, line
);
1082 static int pakfire_jail_forward_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1085 while (ctx
->pty
.master
.io
|| ctx
->pty
.stdin
.io
|| ctx
->pty
.stdout
.io
) {
1086 // Read from standard input
1087 if (ctx
->pty
.stdin
.io
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1088 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.stdin
.fd
, &ctx
->pty
.stdin
.buffer
);
1090 CTX_ERROR(jail
->ctx
, "Failed reading from standard input: %s\n", strerror(-r
));
1094 // We are done reading for now
1095 ctx
->pty
.stdin
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1097 // But we may have data to write
1098 if (ctx
->pty
.stdin
.buffer
.used
)
1099 ctx
->pty
.master
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1102 // Write to the master
1103 if (ctx
->pty
.master
.io
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1104 if (jail
->callbacks
.stdin
.callback
) {
1105 r
= pakfire_jail_stream_stdin(jail
, ctx
, ctx
->pty
.master
.fd
);
1110 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdin
.buffer
);
1112 CTX_ERROR(jail
->ctx
, "Failed writing to the PTY: %s\n", strerror(-r
));
1117 // We are done writing for now
1118 ctx
->pty
.master
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1121 // Read from the master
1122 if (ctx
->pty
.master
.io
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1123 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdout
.buffer
);
1125 CTX_ERROR(jail
->ctx
, "Failed reading from the PTY: %s\n", strerror(-r
));
1129 // We are done reading for now
1130 ctx
->pty
.master
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1132 // But we may have data to write
1133 if (ctx
->pty
.stdout
.buffer
.used
)
1134 ctx
->pty
.stdout
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1137 // Write to standard output
1138 if (ctx
->pty
.stdout
.io
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1139 // If we have a callback, we will send any output to the callback
1140 if (jail
->callbacks
.stdout
.callback
) {
1141 r
= pakfire_jail_drain_buffer_with_callback(jail
, &ctx
->pty
.stdout
.buffer
,
1142 jail
->callbacks
.stdout
.callback
, jail
->callbacks
.stdout
.data
);
1146 // If we have a file descriptor, we will forward any output
1147 } else if (ctx
->pty
.stdout
.fd
>= 0) {
1148 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.stdout
.fd
, &ctx
->pty
.stdout
.buffer
);
1150 CTX_ERROR(jail
->ctx
, "Failed writing to standard output: %s\n", strerror(-r
));
1154 // Otherwise send the output to the default logger
1156 r
= pakfire_jail_drain_buffer_with_callback(jail
, &ctx
->pty
.stdout
.buffer
,
1157 pakfire_jail_command_output
, NULL
);
1162 // We are done writing for now
1163 ctx
->pty
.stdout
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1170 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1172 struct epoll_event events
[EPOLL_MAX_EVENTS
];
1176 // Fetch file descriptors from context
1177 const int pidfd
= ctx
->pidfd
;
1179 // Fetch the UNIX domain socket
1180 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
1183 const int timerfd
= pakfire_jail_create_timer(jail
);
1186 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
1187 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
1189 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
1190 #endif /* ENABLE_DEBUG */
1192 // Make a list of all file descriptors we are interested in
1193 const struct pakfire_wait_fds
{
1198 { timerfd
, EPOLLIN
},
1201 { ctx
->pidfd
, EPOLLIN
},
1204 { log_INFO
, EPOLLIN
},
1205 { log_ERROR
, EPOLLIN
},
1207 { log_DEBUG
, EPOLLIN
},
1208 #endif /* ENABLE_DEBUG */
1210 // UNIX Domain Socket
1211 { socket_recv
, EPOLLIN
},
1218 epollfd
= epoll_create1(0);
1220 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
1225 // Turn file descriptors into non-blocking mode and add them to epoll()
1226 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
1227 // Skip fds which were not initialized
1231 // Add the FD to the event loop
1232 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
1239 // Loop for as long as the process is alive
1241 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
1243 // Ignore if epoll_wait() has been interrupted
1247 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
1253 for (int i
= 0; i
< num
; i
++) {
1254 int e
= events
[i
].events
;
1255 int fd
= events
[i
].data
.fd
;
1257 // Handle PTY forwarding events
1258 if (ctx
->pty
.master
.fd
== fd
) {
1259 if (e
& (EPOLLIN
|EPOLLHUP
))
1260 ctx
->pty
.master
.io
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1262 if (e
& (EPOLLOUT
|EPOLLHUP
))
1263 ctx
->pty
.master
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1266 r
= pakfire_jail_forward_pty(jail
, ctx
);
1268 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1272 // Handle standard input
1273 } else if (ctx
->pty
.stdin
.fd
== fd
) {
1274 if (e
& (EPOLLIN
|EPOLLHUP
))
1275 ctx
->pty
.stdin
.io
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1278 r
= pakfire_jail_forward_pty(jail
, ctx
);
1280 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1284 // Handle standard output
1285 } else if (ctx
->pty
.stdout
.fd
== fd
) {
1286 if (e
& (EPOLLOUT
|EPOLLHUP
))
1287 ctx
->pty
.stdout
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1290 r
= pakfire_jail_forward_pty(jail
, ctx
);
1292 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1296 // Handle any changes to the PIDFD
1297 } else if (pidfd
== fd
) {
1299 // Call waidid() and store the result
1300 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
1302 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
1306 // Mark that we have ended so that we will process the remaining
1307 // events from epoll() now, but won't restart the outer loop.
1311 // Handle timer events
1312 } else if (timerfd
== fd
) {
1314 DEBUG(jail
->pakfire
, "Timer event received\n");
1317 r
= read(timerfd
, garbage
, sizeof(garbage
));
1319 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
1324 // Terminate the process if it hasn't already ended
1326 DEBUG(jail
->pakfire
, "Terminating process...\n");
1328 // Send SIGTERM to the process
1329 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
1331 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
1337 // Handle socket messages
1338 } else if (socket_recv
== fd
) {
1340 // Receive the passed FD
1341 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1345 // Setup PTY forwarding
1346 if (ctx
->pty
.master
.fd
< 0) {
1347 r
= pakfire_jail_setup_pty_forwarding(jail
, ctx
, epollfd
, fd
);
1349 CTX_ERROR(jail
->ctx
, "Failed setting up PTY forwarding: %s\n", strerror(-r
));
1355 // Handle log INFO messages
1356 } else if (log_INFO
== fd
) {
1358 r
= pakfire_jail_handle_log(jail
, ctx
, fd
, &ctx
->buffers
.log_INFO
,
1359 pakfire_jail_log
, &ctx
->buffers
.log_INFO
.priority
);
1364 // Handle log ERROR messages
1365 } else if (log_ERROR
== fd
) {
1367 r
= pakfire_jail_handle_log(jail
, ctx
, fd
, &ctx
->buffers
.log_ERROR
,
1368 pakfire_jail_log
, &ctx
->buffers
.log_ERROR
.priority
);
1374 // Handle log DEBUG messages
1375 } else if (log_DEBUG
== fd
) {
1377 r
= pakfire_jail_handle_log(jail
, ctx
, fd
, &ctx
->buffers
.log_DEBUG
,
1378 pakfire_jail_log
, &ctx
->buffers
.log_DEBUG
.priority
);
1382 #endif /* ENABLE_DEBUG */
1384 // Log a message for anything else
1386 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1390 // Check if any file descriptors have been closed
1392 // Remove the file descriptor
1393 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1395 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1408 // Restore any changed terminal attributes
1409 if (ctx
->pty
.stdin
.fd
>= 0)
1410 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdin
);
1411 if (ctx
->pty
.stdout
.fd
>= 0)
1412 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdout
);
1417 int pakfire_jail_capture_stdout(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
1418 void* data
, const char* line
, size_t length
) {
1419 char** output
= (char**)data
;
1422 // Append everything from stdout to a buffer
1423 r
= asprintf(output
, "%s%.*s", (output
&& *output
) ? *output
: "", (int)length
, line
);
1432 // Logs all capabilities of the current process
1433 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1436 cap_flag_value_t value_e
;
1437 cap_flag_value_t value_i
;
1438 cap_flag_value_t value_p
;
1442 pid_t pid
= getpid();
1444 // Fetch all capabilities
1445 caps
= cap_get_proc();
1447 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1452 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1454 // Iterate over all capabilities
1455 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1456 name
= cap_to_name(cap
);
1458 // Fetch effective value
1459 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1463 // Fetch inheritable value
1464 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1468 // Fetch permitted value
1469 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1473 DEBUG(jail
->pakfire
,
1474 " %-24s : %c%c%c\n",
1476 (value_e
== CAP_SET
) ? 'e' : '-',
1477 (value_i
== CAP_SET
) ? 'i' : '-',
1478 (value_p
== CAP_SET
) ? 'p' : '-'
1498 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1503 // Fetch capabilities
1504 caps
= cap_get_proc();
1506 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1511 // Walk through all capabilities
1512 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1513 cap_value_t _caps
[] = { cap
};
1515 // Fetch the name of the capability
1516 name
= cap_to_name(cap
);
1518 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1520 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1524 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1526 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1530 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1532 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1541 // Restore all capabilities
1542 r
= cap_set_proc(caps
);
1544 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1548 // Add all capabilities to the ambient set
1549 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1550 name
= cap_to_name(cap
);
1552 // Raise the capability
1553 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1555 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1578 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1579 const int syscalls
[] = {
1580 // The kernel's keyring isn't namespaced
1583 SCMP_SYS(request_key
),
1585 // Disable userfaultfd
1586 SCMP_SYS(userfaultfd
),
1588 // Disable perf which could leak a lot of information about the host
1589 SCMP_SYS(perf_event_open
),
1595 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1597 // Setup a syscall filter which allows everything by default
1598 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1600 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1605 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1606 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1608 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1613 // Load syscall filter into the kernel
1614 r
= seccomp_load(ctx
);
1616 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1622 seccomp_release(ctx
);
1629 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1630 const char* source
, const char* target
, int flags
) {
1631 struct pakfire_jail_mountpoint
* mp
= NULL
;
1634 // Check if there is any space left
1635 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1640 // Check for valid inputs
1641 if (!source
|| !target
) {
1646 // Select the next free slot
1647 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1650 r
= pakfire_string_set(mp
->source
, source
);
1652 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1657 r
= pakfire_string_set(mp
->target
, target
);
1659 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1666 // Increment counter
1667 jail
->num_mountpoints
++;
1672 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1675 const char* paths
[] = {
1681 // Bind-mount all paths read-only
1682 for (const char** path
= paths
; *path
; path
++) {
1683 r
= pakfire_bind(jail
->ctx
, jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1686 // Ignore if we don't have permission
1701 Mounts everything that we require in the new namespace
1703 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1704 struct pakfire_jail_mountpoint
* mp
= NULL
;
1708 // Enable loop devices
1709 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1710 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1712 // Mount all default stuff
1713 r
= pakfire_mount_all(jail
->ctx
, jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1718 r
= pakfire_populate_dev(jail
->ctx
, jail
->pakfire
, flags
);
1722 // Mount the interpreter (if needed)
1723 r
= pakfire_mount_interpreter(jail
->ctx
, jail
->pakfire
);
1727 // Mount networking stuff
1728 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1729 r
= pakfire_jail_mount_networking(jail
);
1734 // Mount all custom stuff
1735 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1737 mp
= &jail
->mountpoints
[i
];
1740 r
= pakfire_bind(jail
->ctx
, jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1750 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1751 struct nl_sock
* nl
= NULL
;
1752 struct nl_cache
* cache
= NULL
;
1753 struct rtnl_link
* link
= NULL
;
1754 struct rtnl_link
* change
= NULL
;
1757 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1759 // Allocate a netlink socket
1760 nl
= nl_socket_alloc();
1762 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1767 // Connect the socket
1768 r
= nl_connect(nl
, NETLINK_ROUTE
);
1770 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1774 // Allocate the netlink cache
1775 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1777 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1781 // Fetch loopback interface
1782 link
= rtnl_link_get_by_name(cache
, "lo");
1784 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1789 // Allocate a new link
1790 change
= rtnl_link_alloc();
1792 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1797 // Set the link to UP
1798 rtnl_link_set_flags(change
, IFF_UP
);
1800 // Apply any changes
1801 r
= rtnl_link_change(nl
, link
, change
, 0);
1803 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1819 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1820 char path
[PATH_MAX
];
1823 // Skip mapping anything when running on /
1824 if (pakfire_on_root(jail
->pakfire
))
1828 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1833 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1836 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1840 /* When running as root, we will map the entire range.
1842 When running as a non-privileged user, we will map the root user inside the jail
1843 to the user's UID outside of the jail, and we will map the rest starting from one.
1848 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1849 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1851 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1852 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1856 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1863 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1864 char path
[PATH_MAX
];
1867 // Skip mapping anything when running on /
1868 if (pakfire_on_root(jail
->pakfire
))
1872 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1875 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1880 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1886 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1887 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1889 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1890 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1894 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1901 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1902 char path
[PATH_MAX
];
1906 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1910 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1912 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1919 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1920 const uint64_t val
= 1;
1923 DEBUG(jail
->pakfire
, "Sending signal...\n");
1925 // Write to the file descriptor
1926 r
= eventfd_write(fd
, val
);
1928 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1932 // Close the file descriptor
1938 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1942 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1944 r
= eventfd_read(fd
, &val
);
1946 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1950 // Close the file descriptor
1957 Performs the initialisation that needs to happen in the parent part
1959 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1962 // Setup UID mapping
1963 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1967 // Write "deny" to /proc/PID/setgroups
1968 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1972 // Setup GID mapping
1973 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1977 // Parent has finished initialisation
1978 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1980 // Send signal to client
1981 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1988 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1991 // Change to the new root
1994 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1999 r
= pivot_root(".", ".");
2001 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
2005 // Umount the old root
2006 r
= umount2(".", MNT_DETACH
);
2008 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
2015 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
2018 // Allocate a new PTY
2019 ctx
->pty
.master
.fd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
2020 if (ctx
->pty
.master
.fd
< 0)
2024 r
= ptsname_r(ctx
->pty
.master
.fd
, ctx
->pty
.console
, sizeof(ctx
->pty
.console
));
2028 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->pty
.console
, ctx
->pty
.master
.fd
);
2030 // Unlock the master device
2031 r
= unlockpt(ctx
->pty
.master
.fd
);
2033 CTX_ERROR(jail
->ctx
, "Could not unlock the PTY: %s\n", strerror(errno
));
2038 r
= pakfire_symlink(jail
->ctx
, ctx
->pty
.console
, "/dev/console");
2045 static int pakfire_jail_setup_terminal(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
2049 // Open a new terminal
2050 fd
= open("/dev/console", O_RDWR
|O_NOCTTY
);
2052 CTX_ERROR(jail
->ctx
, "Failed to open a new terminal: %s\n", strerror(errno
));
2056 CTX_DEBUG(jail
->ctx
, "Opened a new terminal %d\n", fd
);
2058 // Connect the new terminal to standard input
2059 r
= dup2(fd
, STDIN_FILENO
);
2061 CTX_ERROR(jail
->ctx
, "Failed to open standard input: %s\n", strerror(errno
));
2065 // Connect the new terminal to standard output
2066 r
= dup2(fd
, STDOUT_FILENO
);
2068 CTX_ERROR(jail
->ctx
, "Failed to open standard output: %s\n", strerror(errno
));
2072 // Connect the new terminal to standard error
2073 r
= dup2(fd
, STDERR_FILENO
);
2075 CTX_ERROR(jail
->ctx
, "Failed to open standard error: %s\n", strerror(errno
));
2082 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
2083 const char* argv
[]) {
2086 // Redirect any logging to our log pipe
2087 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
2090 pid_t pid
= getpid();
2092 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
2094 // Wait for the parent to finish initialization
2095 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
2100 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
2102 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
2106 // Make this process dumpable
2107 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
2109 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
2113 // Don't drop any capabilities on setuid()
2114 r
= prctl(PR_SET_KEEPCAPS
, 1);
2116 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
2121 uid_t uid
= getuid();
2122 gid_t gid
= getgid();
2125 uid_t euid
= geteuid();
2126 gid_t egid
= getegid();
2128 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
2129 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
2131 // Log all mountpoints
2132 pakfire_mount_list(jail
->ctx
);
2134 // Fail if we are not PID 1
2136 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
2140 // Fail if we are not running as root
2141 if (uid
|| gid
|| euid
|| egid
) {
2142 ERROR(jail
->pakfire
, "Child process is not running as root\n");
2146 const int socket_send
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->socket
);
2148 // Mount all default stuff
2149 r
= pakfire_mount_all(jail
->ctx
, jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
2153 const char* root
= pakfire_get_path(jail
->pakfire
);
2154 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
2156 // Change mount propagation to slave to receive anything from the parent namespace
2157 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
2161 // Make root a mountpoint in the new mount namespace
2162 r
= pakfire_mount_make_mounpoint(jail
->ctx
, jail
->pakfire
, root
);
2166 // Change mount propagation to private
2167 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
2171 // Change root (unless root is /)
2172 if (!pakfire_on_root(jail
->pakfire
)) {
2174 r
= pakfire_jail_mount(jail
, ctx
);
2179 r
= pakfire_jail_switch_root(jail
, root
);
2185 unsigned long persona
= pakfire_arch_personality(arch
);
2187 r
= personality(persona
);
2189 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
2195 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2196 r
= pakfire_jail_setup_loopback(jail
);
2203 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
2205 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
2207 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
2212 // Create a new session
2215 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
2219 // Allocate a new PTY
2220 r
= pakfire_jail_open_pty(jail
, ctx
);
2222 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
2226 // Send the PTY master to the parent process
2227 r
= pakfire_jail_send_fd(jail
, socket_send
, ctx
->pty
.master
.fd
);
2229 CTX_ERROR(jail
->ctx
, "Failed sending the PTY master to the parent: %s\n", strerror(-r
));
2233 // Setup the terminal
2234 r
= pakfire_jail_setup_terminal(jail
, ctx
);
2238 // Close the master of the PTY
2239 close(ctx
->pty
.master
.fd
);
2240 ctx
->pty
.master
.fd
= -1;
2245 // Close other end of log pipes
2246 close(ctx
->pipes
.log_INFO
[0]);
2247 close(ctx
->pipes
.log_ERROR
[0]);
2249 close(ctx
->pipes
.log_DEBUG
[0]);
2250 #endif /* ENABLE_DEBUG */
2252 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2253 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
2258 r
= pakfire_jail_set_capabilities(jail
);
2262 // Show capabilities
2263 r
= pakfire_jail_show_capabilities(jail
);
2268 r
= pakfire_jail_limit_syscalls(jail
);
2272 DEBUG(jail
->pakfire
, "Child process initialization done\n");
2273 DEBUG(jail
->pakfire
, "Launching command:\n");
2276 for (unsigned int i
= 0; argv
[i
]; i
++)
2277 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
2280 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
2282 // Translate errno into regular exit code
2285 // Ignore if the command doesn't exist
2286 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
2297 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
2300 // We should not get here
2304 // Run a command in the jail
2305 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2309 // Check if argv is valid
2310 if (!argv
|| !argv
[0]) {
2315 // Initialize context for this call
2316 struct pakfire_jail_exec ctx
= {
2319 .socket
= { -1, -1 },
2322 .log_INFO
= { -1, -1 },
2323 .log_ERROR
= { -1, -1 },
2325 .log_DEBUG
= { -1, -1 },
2326 #endif /* ENABLE_DEBUG */
2331 .priority
= LOG_INFO
,
2335 .priority
= LOG_ERR
,
2340 .priority
= LOG_DEBUG
,
2342 #endif /* ENABLE_DEBUG */
2361 DEBUG(jail
->pakfire
, "Executing jail...\n");
2363 // Enable networking in interactive mode
2364 if (ctx
.flags
& PAKFIRE_JAIL_PTY_FORWARDING
)
2365 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2368 Setup a file descriptor which can be used to notify the client that the parent
2369 has completed configuration.
2371 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2372 if (ctx
.completed_fd
< 0) {
2373 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2377 // Create a UNIX domain socket
2378 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2380 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2385 // Setup pipes for logging
2387 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2392 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2398 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2401 #endif /* ENABLE_DEBUG */
2403 // Configure child process
2404 struct clone_args args
= {
2414 .exit_signal
= SIGCHLD
,
2415 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2418 // Launch the process in a cgroup that is a leaf of the configured cgroup
2420 args
.flags
|= CLONE_INTO_CGROUP
;
2423 const char* uuid
= pakfire_jail_uuid(jail
);
2425 // Create a temporary cgroup
2426 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2428 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2432 // Clone into this cgroup
2433 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2437 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2438 args
.flags
|= CLONE_NEWNET
;
2441 // Fork this process
2442 ctx
.pid
= clone3(&args
, sizeof(args
));
2444 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2448 } else if (ctx
.pid
== 0) {
2449 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2454 r
= pakfire_jail_parent(jail
, &ctx
);
2458 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2460 // Read output of the child process
2461 r
= pakfire_jail_wait(jail
, &ctx
);
2465 // Handle exit status
2466 switch (ctx
.status
.si_code
) {
2468 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2469 ctx
.status
.si_status
);
2472 exit
= ctx
.status
.si_status
;
2476 ERROR(jail
->pakfire
, "The child process was killed\n");
2481 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2484 // Log anything else
2486 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2491 // Reset all callbacks
2492 pakfire_jail_set_stdin_callback(jail
, NULL
, NULL
);
2493 pakfire_jail_set_stdout_callback(jail
, NULL
, NULL
);
2495 // Destroy the temporary cgroup (if any)
2497 // Read cgroup stats
2498 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2499 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2500 pakfire_cgroup_destroy(ctx
.cgroup
);
2501 pakfire_cgroup_unref(ctx
.cgroup
);
2504 // Close any file descriptors
2507 if (ctx
.pty
.master
.fd
>= 0)
2508 close(ctx
.pty
.master
.fd
);
2509 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2510 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2512 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2513 #endif /* ENABLE_DEBUG */
2514 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2519 static int pakfire_jail_exec_interactive(
2520 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2523 flags
|= PAKFIRE_JAIL_PTY_FORWARDING
;
2525 // Setup interactive stuff
2526 r
= pakfire_jail_setup_interactive_env(jail
);
2530 return pakfire_jail_exec(jail
, argv
, flags
);
2533 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2536 const char* args
[]) {
2537 char path
[PATH_MAX
];
2538 const char** argv
= NULL
;
2542 const char* root
= pakfire_get_path(jail
->pakfire
);
2544 // Write the scriptlet to disk
2545 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2549 // Create a temporary file
2550 f
= pakfire_mktemp(path
, 0700);
2552 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2556 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2559 r
= fprintf(f
, "%s", script
);
2561 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2568 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2574 // Count how many arguments were passed
2575 unsigned int argc
= 1;
2577 for (const char** arg
= args
; *arg
; arg
++)
2581 argv
= calloc(argc
+ 1, sizeof(*argv
));
2583 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2588 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2591 for (unsigned int i
= 1; i
< argc
; i
++)
2592 argv
[i
] = args
[i
-1];
2595 r
= pakfire_jail_exec(jail
, argv
, 0);
2603 // Remove script from disk
2611 A convenience function that creates a new jail, runs the given command and destroys
2614 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2615 struct pakfire_jail
* jail
= NULL
;
2618 // Create a new jail
2619 r
= pakfire_jail_create(&jail
, pakfire
);
2623 // Set the callback that captures the output
2624 pakfire_jail_set_stdout_callback(jail
, pakfire_jail_capture_stdout
, output
);
2626 // Execute the command
2627 r
= pakfire_jail_exec(jail
, argv
, 0);
2631 pakfire_jail_unref(jail
);
2636 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2637 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2638 struct pakfire_jail
* jail
= NULL
;
2641 // Create a new jail
2642 r
= pakfire_jail_create(&jail
, pakfire
);
2646 // Execute the command
2647 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
);
2651 pakfire_jail_unref(jail
);
2656 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2659 const char* argv
[] = {
2660 "/bin/bash", "--login", NULL
,
2663 // Execute /bin/bash
2664 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2670 // Ignore any return codes from the shell
2674 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2675 char path
[PATH_MAX
];
2678 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2682 // Check if the file is executable
2683 r
= access(path
, X_OK
);
2685 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2689 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2692 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2693 const char* argv
[] = {
2698 return pakfire_jail_run_if_possible(pakfire
, argv
);
2701 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2702 const char* argv
[] = {
2703 "/usr/bin/systemd-tmpfiles",
2708 return pakfire_jail_run_if_possible(pakfire
, argv
);