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
) {
245 struct pakfire_ctx
* ctx
= pakfire_ctx(pakfire
);
247 if (pakfire_ctx_get_log_level(ctx
) >= priority
)
248 pakfire_ctx_log(ctx
, priority
, NULL
, 0, NULL
, "%.*s", (int)length
, line
);
250 pakfire_ctx_unref(ctx
);
255 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
257 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
262 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
264 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
269 char* TERM
= secure_getenv("TERM");
271 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
277 char* LANG
= secure_getenv("LANG");
279 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
287 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
290 const char* arch
= pakfire_get_effective_arch(pakfire
);
292 // Allocate a new jail
293 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
298 j
->ctx
= pakfire_ctx(pakfire
);
301 j
->pakfire
= pakfire_ref(pakfire
);
303 // Initialize reference counter
306 // Generate a random UUID
307 uuid_generate_random(j
->uuid
);
309 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
311 // Set the default logging callback
312 pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
314 // Set default environment
315 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
316 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
321 // Enable all CPU features that CPU has to offer
322 if (!pakfire_arch_is_supported_by_host(arch
)) {
323 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
328 // Set container UUID
329 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
333 // Disable systemctl to talk to systemd
334 if (!pakfire_on_root(j
->pakfire
)) {
335 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
345 pakfire_jail_free(j
);
350 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
356 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
357 if (--jail
->nrefs
> 0)
360 pakfire_jail_free(jail
);
366 PAKFIRE_EXPORT
void pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
367 pakfire_jail_log_callback callback
, void* data
) {
368 jail
->callbacks
.log
= callback
;
369 jail
->callbacks
.log_data
= data
;
374 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
375 // Check if nice level is in range
376 if (nice
< -19 || nice
> 20) {
387 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
388 // Free any previous cgroup
390 pakfire_cgroup_unref(jail
->cgroup
);
394 // Set any new cgroup
396 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
398 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
407 // Returns the length of the environment
408 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
411 // Count everything in the environment
412 for (char** e
= jail
->env
; *e
; e
++)
418 // Finds an existing environment variable and returns its index or -1 if not found
419 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
425 const size_t length
= strlen(key
);
427 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
428 if ((pakfire_string_startswith(jail
->env
[i
], key
)
429 && *(jail
->env
[i
] + length
) == '=')) {
438 // Returns the value of an environment variable or NULL
439 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
441 int i
= pakfire_jail_find_env(jail
, key
);
445 return jail
->env
[i
] + strlen(key
) + 1;
448 // Sets an environment variable
449 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
450 const char* key
, const char* value
) {
451 // Find the index where to write this value to
452 int i
= pakfire_jail_find_env(jail
, key
);
454 i
= pakfire_jail_env_length(jail
);
456 // Return -ENOSPC when the environment is full
457 if (i
>= ENVIRON_SIZE
) {
462 // Free any previous value
466 // Format and set environment variable
467 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
469 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
474 // Imports an environment
475 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
483 // Copy environment variables
484 for (unsigned int i
= 0; env
[i
]; i
++) {
485 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
490 r
= pakfire_jail_set_env(jail
, key
, val
);
507 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
508 struct pakfire_jail
* jail
, unsigned int timeout
) {
510 jail
->timeout
.it_value
.tv_sec
= timeout
;
513 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
515 DEBUG(jail
->pakfire
, "Timeout disabled\n");
520 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
523 // Nothing to do if no timeout has been set
524 if (!jail
->timeout
.it_value
.tv_sec
)
527 // Create a new timer
528 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
530 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
535 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
537 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
551 This function replaces any logging in the child process.
553 All log messages will be sent to the parent process through their respective pipes.
555 static void pakfire_jail_log_redirect(void* data
, int priority
, const char* file
,
556 int line
, const char* fn
, const char* format
, va_list args
) {
557 struct pakfire_jail_pipes
* pipes
= (struct pakfire_jail_pipes
*)data
;
562 fd
= pipes
->log_INFO
[1];
566 fd
= pipes
->log_ERROR
[1];
571 fd
= pipes
->log_DEBUG
[1];
573 #endif /* ENABLE_DEBUG */
575 // Ignore any messages of an unknown priority
580 // End if we do not have a file descriptor to write to
584 // Optionally log the function name
586 dprintf(fd
, "%s: ", fn
);
588 // Send the log message
589 vdprintf(fd
, format
, args
);
592 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
593 return (sizeof(buffer
->data
) == buffer
->used
);
596 static int pakfire_jail_fill_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
599 // Skip this if there is not space left in the buffer
600 if (buffer
->used
>= sizeof(buffer
->data
))
604 r
= read(fd
, buffer
->data
+ buffer
->used
, sizeof(buffer
->data
) - buffer
->used
);
619 // XXX What to do here?
629 static int pakfire_jail_drain_buffer_with_callback(struct pakfire_jail
* jail
,
630 struct pakfire_log_buffer
* buffer
, int priority
, pakfire_jail_communicate_out callback
, void* data
) {
631 const char* eol
= NULL
;
634 while (buffer
->used
) {
635 // Search for the end of the first line
636 eol
= memchr(buffer
->data
, '\n', buffer
->used
);
640 // If the buffer is full, we send the entire content to make space.
641 if (pakfire_jail_log_buffer_is_full(buffer
)) {
642 CTX_DEBUG(jail
->ctx
, "Buffer is full. Sending all content\n");
644 eol
= buffer
->data
+ buffer
->used
- 1;
646 // Otherwise we might have only read parts of the output...
652 // Find the length of the string
653 const size_t length
= eol
- buffer
->data
+ 1;
656 r
= callback(jail
->pakfire
, data
, priority
, buffer
->data
, length
);
658 CTX_ERROR(jail
->ctx
, "The logging callback returned an error: %d\n", r
);
662 // Remove line from buffer
663 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
664 buffer
->used
-= length
;
670 static int pakfire_jail_drain_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
673 // Nothing to do if the buffer is empty
677 // Do not try to write to an invalid file descriptor
682 r
= write(fd
, buffer
->data
, buffer
->used
);
697 memmove(buffer
->data
, buffer
->data
+ r
, buffer
->used
- r
);
706 This function reads as much data as it can from the file descriptor.
707 If it finds a whole line in it, it will send it to the logger and repeat the process.
708 If not newline character is found, it will try to read more data until it finds one.
710 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
711 int priority
, int fd
, struct pakfire_log_buffer
* buffer
,
712 pakfire_jail_communicate_out callback
, void* data
) {
715 // Fill up buffer from fd
716 r
= pakfire_jail_fill_buffer(jail
, fd
, buffer
);
721 r
= pakfire_jail_drain_buffer_with_callback(jail
, buffer
, priority
, callback
, data
);
729 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
730 struct pakfire_jail_exec
* ctx
, const int fd
) {
733 // Nothing to do if there is no stdin callback set
734 if (!ctx
->communicate
.in
) {
735 DEBUG(jail
->pakfire
, "Callback for standard input is not set\n");
739 // Skip if the writing pipe has already been closed
740 if (ctx
->pipes
.stdin
[1] < 0)
743 DEBUG(jail
->pakfire
, "Streaming standard input...\n");
745 // Calling the callback
746 r
= ctx
->communicate
.in(jail
->pakfire
, ctx
->communicate
.data
, fd
);
748 DEBUG(jail
->pakfire
, "Standard input callback finished: %d\n", r
);
750 // The callback signaled that it has written everything
752 DEBUG(jail
->pakfire
, "Closing standard input pipe\n");
754 // Close the file-descriptor
757 // Reset the file-descriptor so it won't be closed again later
758 ctx
->pipes
.stdin
[1] = -1;
768 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
769 const size_t payload_length
= sizeof(fd
);
770 char buffer
[CMSG_SPACE(payload_length
)];
773 struct msghdr msg
= {
774 .msg_control
= buffer
,
775 .msg_controllen
= sizeof(buffer
),
778 // Receive the message
779 r
= recvmsg(socket
, &msg
, 0);
781 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
786 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
790 *fd
= *((int*)CMSG_DATA(cmsg
));
792 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
797 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
798 const size_t payload_length
= sizeof(fd
);
799 char buffer
[CMSG_SPACE(payload_length
)];
802 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
805 struct msghdr msg
= {
806 .msg_control
= buffer
,
807 .msg_controllen
= sizeof(buffer
),
811 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
812 cmsg
->cmsg_level
= SOL_SOCKET
;
813 cmsg
->cmsg_type
= SCM_RIGHTS
;
814 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
817 *((int*)CMSG_DATA(cmsg
)) = fd
;
820 r
= sendmsg(socket
, &msg
, 0);
822 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
829 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
830 int r
= pipe2(*fds
, flags
);
832 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
839 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
840 for (unsigned int i
= 0; i
< 2; i
++)
846 This is a convenience function to fetch the reading end of a pipe and
847 closes the write end.
849 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
850 // Give the variables easier names to avoid confusion
851 int* fd_read
= &(*fds
)[0];
852 int* fd_write
= &(*fds
)[1];
854 // Close the write end of the pipe
855 if (*fd_write
>= 0) {
860 // Return the read end
867 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
868 // Give the variables easier names to avoid confusion
869 int* fd_read
= &(*fds
)[0];
870 int* fd_write
= &(*fds
)[1];
872 // Close the read end of the pipe
878 // Return the write end
885 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
886 struct epoll_event event
= {
887 .events
= events
|EPOLLHUP
,
895 int flags
= fcntl(fd
, F_GETFL
, 0);
897 // Set modified flags
898 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
900 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
901 fd
, strerror(errno
));
905 // Add the file descriptor to the loop
906 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
908 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
909 fd
, strerror(errno
));
918 static int pakfire_jail_enable_raw_mode(struct pakfire_jail
* jail
,
919 struct pakfire_jail_pty_stdio
* stdio
) {
920 struct termios raw_attrs
;
923 // Skip if we don't know the file descriptor
927 // Skip everything if fd is not a TTY
928 if (!isatty(stdio
->fd
))
932 stdio
->fdflags
= fcntl(stdio
->fd
, F_GETFL
);
933 if (stdio
->fdflags
< 0) {
934 CTX_ERROR(jail
->ctx
, "Could not fetch flags from fd %d: %s\n",
935 stdio
->fd
, strerror(errno
));
939 // Fetch all attributes
940 r
= tcgetattr(stdio
->fd
, &stdio
->attrs
);
942 CTX_ERROR(jail
->ctx
, "Could not fetch terminal attributes from fd %d: %s\n",
943 stdio
->fd
, strerror(errno
));
947 // Copy all attributes
948 raw_attrs
= stdio
->attrs
;
951 cfmakeraw(&raw_attrs
);
955 raw_attrs
.c_oflag
= stdio
->attrs
.c_oflag
;
959 raw_attrs
.c_iflag
= stdio
->attrs
.c_iflag
;
960 raw_attrs
.c_lflag
= stdio
->attrs
.c_lflag
;
964 // Restore the attributes
965 r
= tcsetattr(stdio
->fd
, TCSANOW
, &raw_attrs
);
967 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for fd %d: %s\n",
968 stdio
->fd
, strerror(errno
));
975 static int pakfire_jail_restore_attrs(struct pakfire_jail
* jail
,
976 const struct pakfire_jail_pty_stdio
* stdio
) {
979 // Skip if we don't know the file descriptor
983 // Skip everything if fd is not a TTY
984 if (!isatty(stdio
->fd
))
988 r
= fcntl(stdio
->fd
, F_SETFL
, stdio
->fdflags
);
990 CTX_ERROR(jail
->ctx
, "Could not set flags for file descriptor %d: %s\n",
991 stdio
->fd
, strerror(errno
));
995 // Restore the attributes
996 r
= tcsetattr(stdio
->fd
, TCSANOW
, &stdio
->attrs
);
998 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for %d, ignoring: %s\n",
999 stdio
->fd
, strerror(errno
));
1006 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail
* jail
,
1007 struct pakfire_jail_exec
* ctx
, const int epollfd
, const int fd
) {
1008 struct winsize size
;
1011 CTX_DEBUG(jail
->ctx
, "Setting up PTY forwarding on fd %d\n", fd
);
1013 // Store the file descriptor
1014 ctx
->pty
.master
.fd
= fd
;
1016 // Add the master to the event loop
1017 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.master
.fd
, EPOLLIN
|EPOLLOUT
|EPOLLET
);
1021 if (ctx
->flags
& PAKFIRE_JAIL_PTY_FORWARDING
) {
1022 // Configure stdin/stdout
1023 ctx
->pty
.stdin
.fd
= STDIN_FILENO
;
1024 ctx
->pty
.stdout
.fd
= STDOUT_FILENO
;
1027 if (isatty(ctx
->pty
.stdout
.fd
)) {
1028 r
= ioctl(ctx
->pty
.stdout
.fd
, TIOCGWINSZ
, &size
);
1030 CTX_ERROR(jail
->ctx
, "Failed to determine terminal dimensions: %s\n", strerror(errno
));
1035 r
= ioctl(ctx
->pty
.master
.fd
, TIOCSWINSZ
, &size
);
1037 CTX_ERROR(jail
->ctx
, "Failed setting dimensions: %s\n", strerror(errno
));
1042 // Enable RAW mode on standard input
1043 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdin
);
1047 // Enable RAW mode on standard output
1048 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdout
);
1052 // Add standard input to the event loop
1053 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdin
.fd
, EPOLLIN
|EPOLLET
);
1057 // Add standard output to the event loop
1058 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdout
.fd
, EPOLLOUT
|EPOLLET
);
1066 static int pakfire_jail_forward_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1069 // Read from standard input
1070 if (ctx
->pty
.stdin
.flags
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1071 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.stdin
.fd
, &ctx
->pty
.stdin
.buffer
);
1073 CTX_ERROR(jail
->ctx
, "Failed reading from standard input: %s\n", strerror(-r
));
1077 // We are done reading for now
1078 ctx
->pty
.stdin
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1080 // But we may have data to write
1081 if (ctx
->pty
.stdin
.buffer
.used
)
1082 ctx
->pty
.master
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1085 // Write to the master
1086 if (ctx
->pty
.master
.flags
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1087 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdin
.buffer
);
1089 CTX_ERROR(jail
->ctx
, "Failed writing to the PTY: %s\n", strerror(-r
));
1093 // We are done writing for now
1094 ctx
->pty
.master
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1097 // Read from the master
1098 if (ctx
->pty
.master
.flags
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1099 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdout
.buffer
);
1101 CTX_ERROR(jail
->ctx
, "Failed reading from the PTY: %s\n", strerror(-r
));
1105 // We are done reading for now
1106 ctx
->pty
.master
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1108 // But we may have data to write
1109 if (ctx
->pty
.stdout
.buffer
.used
)
1110 ctx
->pty
.stdout
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1113 // Write to standard output
1114 if (ctx
->pty
.stdout
.flags
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1115 // If we have a callback, we will send any output to the callback
1116 if (ctx
->communicate
.out
) {
1117 r
= pakfire_jail_drain_buffer_with_callback(jail
, &ctx
->pty
.stdout
.buffer
,
1118 LOG_INFO
, ctx
->communicate
.out
, ctx
->communicate
.data
);
1122 // If we have a file descriptor, we will forward any output
1123 } else if (ctx
->pty
.stdout
.fd
>= 0) {
1124 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.stdout
.fd
, &ctx
->pty
.stdout
.buffer
);
1126 CTX_ERROR(jail
->ctx
, "Failed writing to standard output: %s\n", strerror(-r
));
1130 // Otherwise we log a message
1132 CTX_ERROR(jail
->ctx
, "No output configured for the PTY\n");
1135 // We are done writing for now
1136 ctx
->pty
.stdout
.flags
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1142 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1144 struct epoll_event events
[EPOLL_MAX_EVENTS
];
1148 // Fetch file descriptors from context
1149 const int pidfd
= ctx
->pidfd
;
1151 // Fetch the UNIX domain socket
1152 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
1155 const int timerfd
= pakfire_jail_create_timer(jail
);
1158 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
1159 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
1161 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
1162 #endif /* ENABLE_DEBUG */
1164 // Make a list of all file descriptors we are interested in
1165 const struct pakfire_wait_fds
{
1170 { timerfd
, EPOLLIN
},
1173 { ctx
->pidfd
, EPOLLIN
},
1176 { log_INFO
, EPOLLIN
},
1177 { log_ERROR
, EPOLLIN
},
1179 { log_DEBUG
, EPOLLIN
},
1180 #endif /* ENABLE_DEBUG */
1182 // UNIX Domain Socket
1183 { socket_recv
, EPOLLIN
},
1190 epollfd
= epoll_create1(0);
1192 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
1197 // Turn file descriptors into non-blocking mode and add them to epoll()
1198 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
1199 // Skip fds which were not initialized
1203 // Add the FD to the event loop
1204 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
1211 // Loop for as long as the process is alive
1213 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
1215 // Ignore if epoll_wait() has been interrupted
1219 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
1225 for (int i
= 0; i
< num
; i
++) {
1226 int e
= events
[i
].events
;
1227 int fd
= events
[i
].data
.fd
;
1229 // Handle PTY forwarding events
1230 if (ctx
->pty
.master
.fd
== fd
) {
1231 if (e
& (EPOLLIN
|EPOLLHUP
))
1232 ctx
->pty
.master
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1234 if (e
& (EPOLLOUT
|EPOLLHUP
))
1235 ctx
->pty
.master
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1238 r
= pakfire_jail_forward_pty(jail
, ctx
);
1240 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1244 // Handle standard input
1245 } else if (ctx
->pty
.stdin
.fd
== fd
) {
1246 if (e
& (EPOLLIN
|EPOLLHUP
))
1247 ctx
->pty
.stdin
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1250 r
= pakfire_jail_forward_pty(jail
, ctx
);
1252 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1256 // Handle standard output
1257 } else if (ctx
->pty
.stdout
.fd
== fd
) {
1258 if (e
& (EPOLLOUT
|EPOLLHUP
))
1259 ctx
->pty
.stdout
.flags
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1262 r
= pakfire_jail_forward_pty(jail
, ctx
);
1264 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1268 // Handle any changes to the PIDFD
1269 } else if (pidfd
== fd
) {
1271 // Call waidid() and store the result
1272 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
1274 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
1278 // Mark that we have ended so that we will process the remaining
1279 // events from epoll() now, but won't restart the outer loop.
1283 // Handle timer events
1284 } else if (timerfd
== fd
) {
1286 DEBUG(jail
->pakfire
, "Timer event received\n");
1289 r
= read(timerfd
, garbage
, sizeof(garbage
));
1291 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
1296 // Terminate the process if it hasn't already ended
1298 DEBUG(jail
->pakfire
, "Terminating process...\n");
1300 // Send SIGTERM to the process
1301 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
1303 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
1309 // Handle socket messages
1310 } else if (socket_recv
== fd
) {
1312 // Receive the passed FD
1313 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1317 // Setup PTY forwarding
1318 if (ctx
->pty
.master
.fd
< 0) {
1319 r
= pakfire_jail_setup_pty_forwarding(jail
, ctx
, epollfd
, fd
);
1321 CTX_ERROR(jail
->ctx
, "Failed setting up PTY forwarding: %s\n", strerror(-r
));
1327 // Handle log INFO messages
1328 } else if (log_INFO
== fd
) {
1330 r
= pakfire_jail_handle_log(jail
, ctx
, LOG_INFO
, fd
,
1331 &ctx
->buffers
.log_INFO
, pakfire_jail_default_log_callback
, NULL
);
1336 // Handle log ERROR messages
1337 } else if (log_ERROR
== fd
) {
1339 r
= pakfire_jail_handle_log(jail
, ctx
, LOG_ERR
, fd
,
1340 &ctx
->buffers
.log_ERROR
, pakfire_jail_default_log_callback
, NULL
);
1346 // Handle log DEBUG messages
1347 } else if (log_DEBUG
== fd
) {
1349 r
= pakfire_jail_handle_log(jail
, ctx
, LOG_DEBUG
, fd
,
1350 &ctx
->buffers
.log_DEBUG
, pakfire_jail_default_log_callback
, NULL
);
1354 #endif /* ENABLE_DEBUG */
1356 // Log a message for anything else
1358 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1362 // Check if any file descriptors have been closed
1364 // Remove the file descriptor
1365 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1367 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1380 // Restore any changed terminal attributes
1381 if (ctx
->pty
.stdin
.fd
>= 0)
1382 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdin
);
1383 if (ctx
->pty
.stdout
.fd
>= 0)
1384 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdout
);
1389 int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
,
1390 int priority
, const char* line
, size_t length
) {
1391 char** output
= (char**)data
;
1394 // Append everything from stdout to a buffer
1395 if (output
&& priority
== LOG_INFO
) {
1396 r
= asprintf(output
, "%s%.*s", (output
&& *output
) ? *output
: "", (int)length
, line
);
1403 // Send everything else to the default logger
1404 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
1409 // Logs all capabilities of the current process
1410 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1413 cap_flag_value_t value_e
;
1414 cap_flag_value_t value_i
;
1415 cap_flag_value_t value_p
;
1419 pid_t pid
= getpid();
1421 // Fetch all capabilities
1422 caps
= cap_get_proc();
1424 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1429 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1431 // Iterate over all capabilities
1432 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1433 name
= cap_to_name(cap
);
1435 // Fetch effective value
1436 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1440 // Fetch inheritable value
1441 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1445 // Fetch permitted value
1446 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1450 DEBUG(jail
->pakfire
,
1451 " %-24s : %c%c%c\n",
1453 (value_e
== CAP_SET
) ? 'e' : '-',
1454 (value_i
== CAP_SET
) ? 'i' : '-',
1455 (value_p
== CAP_SET
) ? 'p' : '-'
1475 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1480 // Fetch capabilities
1481 caps
= cap_get_proc();
1483 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1488 // Walk through all capabilities
1489 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1490 cap_value_t _caps
[] = { cap
};
1492 // Fetch the name of the capability
1493 name
= cap_to_name(cap
);
1495 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1497 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1501 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1503 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1507 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1509 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1518 // Restore all capabilities
1519 r
= cap_set_proc(caps
);
1521 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1525 // Add all capabilities to the ambient set
1526 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1527 name
= cap_to_name(cap
);
1529 // Raise the capability
1530 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1532 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1555 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1556 const int syscalls
[] = {
1557 // The kernel's keyring isn't namespaced
1560 SCMP_SYS(request_key
),
1562 // Disable userfaultfd
1563 SCMP_SYS(userfaultfd
),
1565 // Disable perf which could leak a lot of information about the host
1566 SCMP_SYS(perf_event_open
),
1572 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1574 // Setup a syscall filter which allows everything by default
1575 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1577 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1582 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1583 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1585 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1590 // Load syscall filter into the kernel
1591 r
= seccomp_load(ctx
);
1593 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1599 seccomp_release(ctx
);
1606 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1607 const char* source
, const char* target
, int flags
) {
1608 struct pakfire_jail_mountpoint
* mp
= NULL
;
1611 // Check if there is any space left
1612 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1617 // Check for valid inputs
1618 if (!source
|| !target
) {
1623 // Select the next free slot
1624 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1627 r
= pakfire_string_set(mp
->source
, source
);
1629 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1634 r
= pakfire_string_set(mp
->target
, target
);
1636 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1643 // Increment counter
1644 jail
->num_mountpoints
++;
1649 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1652 const char* paths
[] = {
1658 // Bind-mount all paths read-only
1659 for (const char** path
= paths
; *path
; path
++) {
1660 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1663 // Ignore if we don't have permission
1678 Mounts everything that we require in the new namespace
1680 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1681 struct pakfire_jail_mountpoint
* mp
= NULL
;
1685 // Enable loop devices
1686 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1687 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1689 // Mount all default stuff
1690 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1695 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1699 // Mount the interpreter (if needed)
1700 r
= pakfire_mount_interpreter(jail
->pakfire
);
1704 // Mount networking stuff
1705 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1706 r
= pakfire_jail_mount_networking(jail
);
1711 // Mount all custom stuff
1712 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1714 mp
= &jail
->mountpoints
[i
];
1717 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1727 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1728 struct nl_sock
* nl
= NULL
;
1729 struct nl_cache
* cache
= NULL
;
1730 struct rtnl_link
* link
= NULL
;
1731 struct rtnl_link
* change
= NULL
;
1734 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1736 // Allocate a netlink socket
1737 nl
= nl_socket_alloc();
1739 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1744 // Connect the socket
1745 r
= nl_connect(nl
, NETLINK_ROUTE
);
1747 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1751 // Allocate the netlink cache
1752 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1754 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1758 // Fetch loopback interface
1759 link
= rtnl_link_get_by_name(cache
, "lo");
1761 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1766 // Allocate a new link
1767 change
= rtnl_link_alloc();
1769 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1774 // Set the link to UP
1775 rtnl_link_set_flags(change
, IFF_UP
);
1777 // Apply any changes
1778 r
= rtnl_link_change(nl
, link
, change
, 0);
1780 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1796 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1797 char path
[PATH_MAX
];
1800 // Skip mapping anything when running on /
1801 if (pakfire_on_root(jail
->pakfire
))
1805 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1810 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1813 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1817 /* When running as root, we will map the entire range.
1819 When running as a non-privileged user, we will map the root user inside the jail
1820 to the user's UID outside of the jail, and we will map the rest starting from one.
1825 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1826 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1828 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1829 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1833 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1840 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1841 char path
[PATH_MAX
];
1844 // Skip mapping anything when running on /
1845 if (pakfire_on_root(jail
->pakfire
))
1849 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1852 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1857 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1863 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1864 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1866 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1867 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1871 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1878 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1879 char path
[PATH_MAX
];
1883 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1887 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1889 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1896 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1897 const uint64_t val
= 1;
1900 DEBUG(jail
->pakfire
, "Sending signal...\n");
1902 // Write to the file descriptor
1903 r
= eventfd_write(fd
, val
);
1905 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1909 // Close the file descriptor
1915 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1919 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1921 r
= eventfd_read(fd
, &val
);
1923 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1927 // Close the file descriptor
1934 Performs the initialisation that needs to happen in the parent part
1936 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1939 // Setup UID mapping
1940 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1944 // Write "deny" to /proc/PID/setgroups
1945 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1949 // Setup GID mapping
1950 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1954 // Parent has finished initialisation
1955 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1957 // Send signal to client
1958 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1965 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1968 // Change to the new root
1971 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1976 r
= pivot_root(".", ".");
1978 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
1982 // Umount the old root
1983 r
= umount2(".", MNT_DETACH
);
1985 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
1992 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1995 // Allocate a new PTY
1996 ctx
->pty
.master
.fd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
1997 if (ctx
->pty
.master
.fd
< 0)
2001 r
= ptsname_r(ctx
->pty
.master
.fd
, ctx
->pty
.console
, sizeof(ctx
->pty
.console
));
2005 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->pty
.console
, ctx
->pty
.master
.fd
);
2007 // Unlock the master device
2008 r
= unlockpt(ctx
->pty
.master
.fd
);
2010 CTX_ERROR(jail
->ctx
, "Could not unlock the PTY: %s\n", strerror(errno
));
2015 r
= pakfire_symlink(jail
->ctx
, ctx
->pty
.console
, "/dev/console");
2022 static int pakfire_jail_setup_terminal(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
2026 // Open a new terminal
2027 fd
= open("/dev/console", O_RDWR
|O_NOCTTY
);
2029 CTX_ERROR(jail
->ctx
, "Failed to open a new terminal: %s\n", strerror(errno
));
2033 CTX_DEBUG(jail
->ctx
, "Opened a new terminal %d\n", fd
);
2035 // Connect the new terminal to standard input
2036 r
= dup2(fd
, STDIN_FILENO
);
2038 CTX_ERROR(jail
->ctx
, "Failed to open standard input: %s\n", strerror(errno
));
2042 // Connect the new terminal to standard output
2043 r
= dup2(fd
, STDOUT_FILENO
);
2045 CTX_ERROR(jail
->ctx
, "Failed to open standard output: %s\n", strerror(errno
));
2049 // Connect the new terminal to standard error
2050 r
= dup2(fd
, STDERR_FILENO
);
2052 CTX_ERROR(jail
->ctx
, "Failed to open standard error: %s\n", strerror(errno
));
2059 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
2060 const char* argv
[]) {
2063 // Redirect any logging to our log pipe
2064 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
2067 pid_t pid
= getpid();
2069 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
2071 // Wait for the parent to finish initialization
2072 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
2077 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
2079 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
2083 // Make this process dumpable
2084 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
2086 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
2090 // Don't drop any capabilities on setuid()
2091 r
= prctl(PR_SET_KEEPCAPS
, 1);
2093 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
2098 uid_t uid
= getuid();
2099 gid_t gid
= getgid();
2102 uid_t euid
= geteuid();
2103 gid_t egid
= getegid();
2105 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
2106 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
2108 // Log all mountpoints
2109 pakfire_mount_list(jail
->ctx
);
2111 // Fail if we are not PID 1
2113 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
2117 // Fail if we are not running as root
2118 if (uid
|| gid
|| euid
|| egid
) {
2119 ERROR(jail
->pakfire
, "Child process is not running as root\n");
2123 const int socket_send
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->socket
);
2125 // Mount all default stuff
2126 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
2130 const char* root
= pakfire_get_path(jail
->pakfire
);
2131 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
2133 // Change mount propagation to slave to receive anything from the parent namespace
2134 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
2138 // Make root a mountpoint in the new mount namespace
2139 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
2143 // Change mount propagation to private
2144 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
2148 // Change root (unless root is /)
2149 if (!pakfire_on_root(jail
->pakfire
)) {
2151 r
= pakfire_jail_mount(jail
, ctx
);
2156 r
= pakfire_jail_switch_root(jail
, root
);
2162 unsigned long persona
= pakfire_arch_personality(arch
);
2164 r
= personality(persona
);
2166 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
2172 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2173 r
= pakfire_jail_setup_loopback(jail
);
2180 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
2182 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
2184 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
2189 // Create a new session
2192 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
2196 // Allocate a new PTY
2197 r
= pakfire_jail_open_pty(jail
, ctx
);
2199 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
2203 // Send the PTY master to the parent process
2204 r
= pakfire_jail_send_fd(jail
, socket_send
, ctx
->pty
.master
.fd
);
2206 CTX_ERROR(jail
->ctx
, "Failed sending the PTY master to the parent: %s\n", strerror(-r
));
2210 // Setup the terminal
2211 r
= pakfire_jail_setup_terminal(jail
, ctx
);
2215 // Close the master of the PTY
2216 close(ctx
->pty
.master
.fd
);
2217 ctx
->pty
.master
.fd
= -1;
2222 // Close other end of log pipes
2223 close(ctx
->pipes
.log_INFO
[0]);
2224 close(ctx
->pipes
.log_ERROR
[0]);
2226 close(ctx
->pipes
.log_DEBUG
[0]);
2227 #endif /* ENABLE_DEBUG */
2229 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2230 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
2235 r
= pakfire_jail_set_capabilities(jail
);
2239 // Show capabilities
2240 r
= pakfire_jail_show_capabilities(jail
);
2245 r
= pakfire_jail_limit_syscalls(jail
);
2249 DEBUG(jail
->pakfire
, "Child process initialization done\n");
2250 DEBUG(jail
->pakfire
, "Launching command:\n");
2253 for (unsigned int i
= 0; argv
[i
]; i
++)
2254 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
2257 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
2259 // Translate errno into regular exit code
2262 // Ignore if the command doesn't exist
2263 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
2274 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
2277 // We should not get here
2281 // Run a command in the jail
2282 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[],
2283 pakfire_jail_communicate_in communicate_in
,
2284 pakfire_jail_communicate_out communicate_out
,
2285 void* data
, int flags
) {
2289 // Check if argv is valid
2290 if (!argv
|| !argv
[0]) {
2295 // Initialize context for this call
2296 struct pakfire_jail_exec ctx
= {
2299 .socket
= { -1, -1 },
2302 .log_INFO
= { -1, -1 },
2303 .log_ERROR
= { -1, -1 },
2305 .log_DEBUG
= { -1, -1 },
2306 #endif /* ENABLE_DEBUG */
2310 .in
= communicate_in
,
2311 .out
= communicate_out
,
2331 DEBUG(jail
->pakfire
, "Executing jail...\n");
2333 // Enable networking in interactive mode
2334 if (ctx
.flags
& PAKFIRE_JAIL_PTY_FORWARDING
)
2335 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2338 Setup a file descriptor which can be used to notify the client that the parent
2339 has completed configuration.
2341 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2342 if (ctx
.completed_fd
< 0) {
2343 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2347 // Create a UNIX domain socket
2348 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2350 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2355 // Setup pipes for logging
2357 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2362 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2368 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2371 #endif /* ENABLE_DEBUG */
2373 // Configure child process
2374 struct clone_args args
= {
2384 .exit_signal
= SIGCHLD
,
2385 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2388 // Launch the process in a cgroup that is a leaf of the configured cgroup
2390 args
.flags
|= CLONE_INTO_CGROUP
;
2393 const char* uuid
= pakfire_jail_uuid(jail
);
2395 // Create a temporary cgroup
2396 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2398 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2402 // Clone into this cgroup
2403 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2407 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2408 args
.flags
|= CLONE_NEWNET
;
2411 // Fork this process
2412 ctx
.pid
= clone3(&args
, sizeof(args
));
2414 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2418 } else if (ctx
.pid
== 0) {
2419 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2424 r
= pakfire_jail_parent(jail
, &ctx
);
2428 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2430 // Read output of the child process
2431 r
= pakfire_jail_wait(jail
, &ctx
);
2435 // Handle exit status
2436 switch (ctx
.status
.si_code
) {
2438 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2439 ctx
.status
.si_status
);
2442 exit
= ctx
.status
.si_status
;
2446 ERROR(jail
->pakfire
, "The child process was killed\n");
2451 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2454 // Log anything else
2456 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2461 // Destroy the temporary cgroup (if any)
2463 // Read cgroup stats
2464 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2465 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2466 pakfire_cgroup_destroy(ctx
.cgroup
);
2467 pakfire_cgroup_unref(ctx
.cgroup
);
2470 // Close any file descriptors
2473 if (ctx
.pty
.master
.fd
>= 0)
2474 close(ctx
.pty
.master
.fd
);
2475 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2476 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2478 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2479 #endif /* ENABLE_DEBUG */
2480 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2485 PAKFIRE_EXPORT
int pakfire_jail_exec(
2486 struct pakfire_jail
* jail
,
2488 pakfire_jail_communicate_in callback_in
,
2489 pakfire_jail_communicate_out callback_out
,
2490 void* data
, int flags
) {
2491 return __pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, flags
);
2494 static int pakfire_jail_exec_interactive(
2495 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2498 flags
|= PAKFIRE_JAIL_PTY_FORWARDING
;
2500 // Setup interactive stuff
2501 r
= pakfire_jail_setup_interactive_env(jail
);
2505 return __pakfire_jail_exec(jail
, argv
, NULL
, NULL
, NULL
, flags
);
2508 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2512 pakfire_jail_communicate_in callback_in
,
2513 pakfire_jail_communicate_out callback_out
,
2515 char path
[PATH_MAX
];
2516 const char** argv
= NULL
;
2520 const char* root
= pakfire_get_path(jail
->pakfire
);
2522 // Write the scriptlet to disk
2523 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2527 // Create a temporary file
2528 f
= pakfire_mktemp(path
, 0700);
2530 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2534 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2537 r
= fprintf(f
, "%s", script
);
2539 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2546 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2552 // Count how many arguments were passed
2553 unsigned int argc
= 1;
2555 for (const char** arg
= args
; *arg
; arg
++)
2559 argv
= calloc(argc
+ 1, sizeof(*argv
));
2561 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2566 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2569 for (unsigned int i
= 1; i
< argc
; i
++)
2570 argv
[i
] = args
[i
-1];
2573 r
= pakfire_jail_exec(jail
, argv
, callback_in
, callback_out
, data
, 0);
2581 // Remove script from disk
2589 A convenience function that creates a new jail, runs the given command and destroys
2592 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2593 struct pakfire_jail
* jail
= NULL
;
2596 // Create a new jail
2597 r
= pakfire_jail_create(&jail
, pakfire
);
2601 // Execute the command
2602 r
= pakfire_jail_exec(jail
, argv
, NULL
, pakfire_jail_capture_stdout
, output
, 0);
2606 pakfire_jail_unref(jail
);
2611 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2612 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2613 struct pakfire_jail
* jail
= NULL
;
2616 // Create a new jail
2617 r
= pakfire_jail_create(&jail
, pakfire
);
2621 // Execute the command
2622 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, NULL
, NULL
, NULL
);
2626 pakfire_jail_unref(jail
);
2631 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2634 const char* argv
[] = {
2635 "/bin/bash", "--login", NULL
,
2638 // Execute /bin/bash
2639 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2645 // Ignore any return codes from the shell
2649 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2650 char path
[PATH_MAX
];
2653 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2657 // Check if the file is executable
2658 r
= access(path
, X_OK
);
2660 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2664 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2667 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2668 const char* argv
[] = {
2673 return pakfire_jail_run_if_possible(pakfire
, argv
);
2676 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2677 const char* argv
[] = {
2678 "/usr/bin/systemd-tmpfiles",
2683 return pakfire_jail_run_if_possible(pakfire
, argv
);