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_log_buffer
{
86 char data
[BUFFER_SIZE
];
91 enum pakfire_jail_pty_io
{
92 PAKFIRE_JAIL_PTY_READY_TO_READ
= (1 << 0),
93 PAKFIRE_JAIL_PTY_READY_TO_WRITE
= (1 << 1),
96 struct pakfire_jail_pty_stdio
{
101 struct pakfire_log_buffer buffer
;
103 // Terminal Attributes
104 struct termios attrs
;
106 // File Descriptor Flags
110 enum pakfire_jail_pty_io io
;
113 struct pakfire_jail_mountpoint
{
114 char source
[PATH_MAX
];
115 char target
[PATH_MAX
];
119 struct pakfire_jail
{
120 struct pakfire_ctx
* ctx
;
121 struct pakfire
* pakfire
;
124 // A unique ID for each jail
126 char __uuid
[UUID_STR_LEN
];
132 struct itimerspec timeout
;
135 struct pakfire_cgroup
* cgroup
;
138 char* env
[ENVIRON_SIZE
];
140 struct pakfire_jail_callbacks
{
142 struct pakfire_jail_callbacks_stdin
{
143 pakfire_jail_stdin_callback callback
;
148 struct pakfire_jail_callbacks_stdout
{
149 pakfire_jail_stdout_callback callback
;
155 struct pakfire_jail_mountpoint mountpoints
[MAX_MOUNTPOINTS
];
156 unsigned int num_mountpoints
;
159 struct pakfire_jail_exec
{
162 // PID (of the child)
166 // Socket to pass FDs
169 // Process status (from waitid)
172 // FD to notify the client that the parent has finished initialization
176 struct pakfire_jail_pipes
{
182 #endif /* ENABLE_DEBUG */
186 struct pakfire_jail_buffers
{
188 struct pakfire_log_buffer log_INFO
;
189 struct pakfire_log_buffer log_ERROR
;
191 struct pakfire_log_buffer log_DEBUG
;
192 #endif /* ENABLE_DEBUG */
195 struct pakfire_cgroup
* cgroup
;
196 struct pakfire_cgroup_stats cgroup_stats
;
199 struct pakfire_jail_pty
{
200 // The path to the console
201 char console
[PATH_MAX
];
204 struct pakfire_jail_pty_master
{
206 enum pakfire_jail_pty_io io
;
209 // Standard Input/Output
210 struct pakfire_jail_pty_stdio stdin
;
211 struct pakfire_jail_pty_stdio stdout
;
215 static int clone3(struct clone_args
* args
, size_t size
) {
216 return syscall(__NR_clone3
, args
, size
);
219 static int pidfd_send_signal(int pidfd
, int sig
, siginfo_t
* info
, unsigned int flags
) {
220 return syscall(SYS_pidfd_send_signal
, pidfd
, sig
, info
, flags
);
223 static int pivot_root(const char* new_root
, const char* old_root
) {
224 return syscall(SYS_pivot_root
, new_root
, old_root
);
227 static int pakfire_jail_exec_has_flag(
228 const struct pakfire_jail_exec
* ctx
, const enum pakfire_jail_exec_flags flag
) {
229 return ctx
->flags
& flag
;
232 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
233 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
236 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
240 pakfire_cgroup_unref(jail
->cgroup
);
242 pakfire_unref(jail
->pakfire
);
244 pakfire_ctx_unref(jail
->ctx
);
248 static const char* pakfire_jail_uuid(struct pakfire_jail
* jail
) {
250 uuid_unparse_lower(jail
->uuid
, jail
->__uuid
);
255 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
257 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
262 char* TERM
= secure_getenv("TERM");
264 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
270 char* LANG
= secure_getenv("LANG");
272 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
280 PAKFIRE_EXPORT
int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
) {
283 const char* arch
= pakfire_get_effective_arch(pakfire
);
285 // Allocate a new jail
286 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
291 j
->ctx
= pakfire_ctx(pakfire
);
294 j
->pakfire
= pakfire_ref(pakfire
);
296 // Initialize reference counter
299 // Generate a random UUID
300 uuid_generate_random(j
->uuid
);
302 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
304 // Set default environment
305 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
306 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
311 // Enable all CPU features that CPU has to offer
312 if (!pakfire_arch_is_supported_by_host(arch
)) {
313 r
= pakfire_jail_set_env(j
, "QEMU_CPU", "max");
318 // Set container UUID
319 r
= pakfire_jail_set_env(j
, "container_uuid", pakfire_jail_uuid(j
));
323 // Disable systemctl to talk to systemd
324 if (!pakfire_on_root(j
->pakfire
)) {
325 r
= pakfire_jail_set_env(j
, "SYSTEMD_OFFLINE", "1");
335 pakfire_jail_free(j
);
340 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
346 PAKFIRE_EXPORT
struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
347 if (--jail
->nrefs
> 0)
350 pakfire_jail_free(jail
);
356 PAKFIRE_EXPORT
int pakfire_jail_nice(struct pakfire_jail
* jail
, int nice
) {
357 // Check if nice level is in range
358 if (nice
< -19 || nice
> 20) {
369 int pakfire_jail_set_cgroup(struct pakfire_jail
* jail
, struct pakfire_cgroup
* cgroup
) {
370 // Free any previous cgroup
372 pakfire_cgroup_unref(jail
->cgroup
);
376 // Set any new cgroup
378 DEBUG(jail
->pakfire
, "Setting cgroup %p\n", cgroup
);
380 jail
->cgroup
= pakfire_cgroup_ref(cgroup
);
389 // Returns the length of the environment
390 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
393 // Count everything in the environment
394 for (char** e
= jail
->env
; *e
; e
++)
400 // Finds an existing environment variable and returns its index or -1 if not found
401 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
407 const size_t length
= strlen(key
);
409 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
410 if ((pakfire_string_startswith(jail
->env
[i
], key
)
411 && *(jail
->env
[i
] + length
) == '=')) {
420 // Returns the value of an environment variable or NULL
421 PAKFIRE_EXPORT
const char* pakfire_jail_get_env(struct pakfire_jail
* jail
,
423 int i
= pakfire_jail_find_env(jail
, key
);
427 return jail
->env
[i
] + strlen(key
) + 1;
430 // Sets an environment variable
431 PAKFIRE_EXPORT
int pakfire_jail_set_env(struct pakfire_jail
* jail
,
432 const char* key
, const char* value
) {
433 // Find the index where to write this value to
434 int i
= pakfire_jail_find_env(jail
, key
);
436 i
= pakfire_jail_env_length(jail
);
438 // Return -ENOSPC when the environment is full
439 if (i
>= ENVIRON_SIZE
) {
444 // Free any previous value
448 // Format and set environment variable
449 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
451 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
456 // Imports an environment
457 PAKFIRE_EXPORT
int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
465 // Copy environment variables
466 for (unsigned int i
= 0; env
[i
]; i
++) {
467 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
472 r
= pakfire_jail_set_env(jail
, key
, val
);
489 PAKFIRE_EXPORT
int pakfire_jail_set_timeout(
490 struct pakfire_jail
* jail
, unsigned int timeout
) {
492 jail
->timeout
.it_value
.tv_sec
= timeout
;
495 DEBUG(jail
->pakfire
, "Timeout set to %u second(s)\n", timeout
);
497 DEBUG(jail
->pakfire
, "Timeout disabled\n");
502 static int pakfire_jail_create_timer(struct pakfire_jail
* jail
) {
505 // Nothing to do if no timeout has been set
506 if (!jail
->timeout
.it_value
.tv_sec
)
509 // Create a new timer
510 const int fd
= timerfd_create(CLOCK_MONOTONIC
, 0);
512 ERROR(jail
->pakfire
, "Could not create timer: %m\n");
517 r
= timerfd_settime(fd
, 0, &jail
->timeout
, NULL
);
519 ERROR(jail
->pakfire
, "Could not arm timer: %m\n");
535 PAKFIRE_EXPORT
void pakfire_jail_set_stdin_callback(struct pakfire_jail
* jail
,
536 pakfire_jail_stdin_callback callback
, void* data
) {
537 jail
->callbacks
.stdin
.callback
= callback
;
538 jail
->callbacks
.stdin
.data
= data
;
544 PAKFIRE_EXPORT
void pakfire_jail_set_stdout_callback(struct pakfire_jail
* jail
,
545 pakfire_jail_stdout_callback callback
, void* data
) {
546 jail
->callbacks
.stdout
.callback
= callback
;
547 jail
->callbacks
.stdout
.data
= data
;
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_fill_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
595 // Skip this if there is not space left in the buffer
596 if (buffer
->used
>= sizeof(buffer
->data
))
600 r
= read(fd
, buffer
->data
+ buffer
->used
, sizeof(buffer
->data
) - buffer
->used
);
615 // XXX What to do here?
625 static int pakfire_jail_drain_buffer_with_callback(struct pakfire_jail
* jail
,
626 struct pakfire_log_buffer
* buffer
, pakfire_jail_stdout_callback callback
, void* data
) {
627 const char* eol
= NULL
;
630 while (buffer
->used
) {
631 // Search for the end of the first line
632 eol
= memchr(buffer
->data
, '\n', buffer
->used
);
636 // If the buffer is full, we send the entire content to make space.
637 if (buffer
->used
>= sizeof(buffer
->data
)) {
638 CTX_DEBUG(jail
->ctx
, "Buffer is full. Sending all content\n");
640 eol
= buffer
->data
+ buffer
->used
- 1;
642 // Otherwise we might have only read parts of the output...
648 // Find the length of the string
649 const size_t length
= eol
- buffer
->data
+ 1;
652 r
= callback(jail
->ctx
, jail
, data
, buffer
->data
, length
);
654 CTX_ERROR(jail
->ctx
, "The standard output callback returned an error: %d\n", r
);
658 // Remove line from buffer
659 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
660 buffer
->used
-= length
;
666 static int pakfire_jail_drain_buffer(struct pakfire_jail
* jail
, int fd
, struct pakfire_log_buffer
* buffer
) {
669 // Nothing to do if the buffer is empty
673 // Do not try to write to an invalid file descriptor
678 r
= write(fd
, buffer
->data
, buffer
->used
);
693 memmove(buffer
->data
, buffer
->data
+ r
, buffer
->used
- r
);
702 Passes any log messages on to the default pakfire log callback
704 static int pakfire_jail_log(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
705 void* data
, const char* line
, size_t length
) {
706 int* priority
= data
;
708 if (pakfire_ctx_get_log_level(jail
->ctx
) >= *priority
)
709 pakfire_ctx_log(jail
->ctx
, *priority
, NULL
, 0, NULL
, "%.*s", (int)length
, line
);
715 This function reads as much data as it can from the file descriptor.
716 If it finds a whole line in it, it will send it to the logger and repeat the process.
717 If not newline character is found, it will try to read more data until it finds one.
719 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
720 int fd
, struct pakfire_log_buffer
* buffer
, pakfire_jail_stdout_callback callback
, void* data
) {
723 // Fill up buffer from fd
724 r
= pakfire_jail_fill_buffer(jail
, fd
, buffer
);
729 r
= pakfire_jail_drain_buffer_with_callback(jail
, buffer
, callback
, data
);
736 static int pakfire_jail_stream_stdin(struct pakfire_jail
* jail
,
737 struct pakfire_jail_exec
* ctx
, const int fd
) {
738 const char eof
= 0x04;
741 // Skip if the writing pipe has already been closed
745 CTX_DEBUG(jail
->ctx
, "Streaming standard input...\n");
747 // Calling the callback
748 r
= jail
->callbacks
.stdin
.callback(jail
->ctx
, jail
, jail
->callbacks
.stdin
.data
, fd
);
752 // The callback signaled that it has written everything
753 CTX_DEBUG(jail
->ctx
, "Closing standard input pipe\n");
756 r
= write(fd
, &eof
, sizeof(eof
));
758 CTX_ERROR(jail
->ctx
, "Could not write EOF: %s\n", strerror(errno
));
765 CTX_DEBUG(jail
->ctx
, "Standard input callback finished\n");
769 CTX_ERROR(jail
->ctx
, "Standard input callback failed: %s\n", strerror(-r
));
774 static int pakfire_jail_recv_fd(struct pakfire_jail
* jail
, int socket
, int* fd
) {
775 const size_t payload_length
= sizeof(fd
);
776 char buffer
[CMSG_SPACE(payload_length
)];
779 struct msghdr msg
= {
780 .msg_control
= buffer
,
781 .msg_controllen
= sizeof(buffer
),
784 // Receive the message
785 r
= recvmsg(socket
, &msg
, 0);
787 CTX_ERROR(jail
->ctx
, "Could not receive file descriptor: %s\n", strerror(errno
));
792 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
796 *fd
= *((int*)CMSG_DATA(cmsg
));
798 CTX_DEBUG(jail
->ctx
, "Received fd %d from socket %d\n", *fd
, socket
);
803 static int pakfire_jail_send_fd(struct pakfire_jail
* jail
, int socket
, int fd
) {
804 const size_t payload_length
= sizeof(fd
);
805 char buffer
[CMSG_SPACE(payload_length
)];
808 CTX_DEBUG(jail
->ctx
, "Sending fd %d to socket %d\n", fd
, socket
);
811 struct msghdr msg
= {
812 .msg_control
= buffer
,
813 .msg_controllen
= sizeof(buffer
),
817 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
818 cmsg
->cmsg_level
= SOL_SOCKET
;
819 cmsg
->cmsg_type
= SCM_RIGHTS
;
820 cmsg
->cmsg_len
= CMSG_LEN(payload_length
);
823 *((int*)CMSG_DATA(cmsg
)) = fd
;
826 r
= sendmsg(socket
, &msg
, 0);
828 CTX_ERROR(jail
->ctx
, "Could not send file descriptor: %s\n", strerror(errno
));
835 static int pakfire_jail_setup_pipe(struct pakfire_jail
* jail
, int (*fds
)[2], const int flags
) {
836 int r
= pipe2(*fds
, flags
);
838 ERROR(jail
->pakfire
, "Could not setup pipe: %m\n");
845 static void pakfire_jail_close_pipe(struct pakfire_jail
* jail
, int fds
[2]) {
846 for (unsigned int i
= 0; i
< 2; i
++)
852 This is a convenience function to fetch the reading end of a pipe and
853 closes the write end.
855 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail
* jail
, int (*fds
)[2]) {
856 // Give the variables easier names to avoid confusion
857 int* fd_read
= &(*fds
)[0];
858 int* fd_write
= &(*fds
)[1];
860 // Close the write end of the pipe
861 if (*fd_write
>= 0) {
866 // Return the read end
873 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail
* jail
, int (*fds
)[2]) {
874 // Give the variables easier names to avoid confusion
875 int* fd_read
= &(*fds
)[0];
876 int* fd_write
= &(*fds
)[1];
878 // Close the read end of the pipe
884 // Return the write end
891 static int pakfire_jail_epoll_add_fd(struct pakfire_jail
* jail
, int epollfd
, int fd
, int events
) {
892 struct epoll_event event
= {
893 .events
= events
|EPOLLHUP
,
901 int flags
= fcntl(fd
, F_GETFL
, 0);
903 // Set modified flags
904 r
= fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
);
906 CTX_ERROR(jail
->ctx
, "Could not set file descriptor %d into non-blocking mode: %s\n",
907 fd
, strerror(errno
));
911 // Add the file descriptor to the loop
912 r
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
);
914 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %s\n",
915 fd
, strerror(errno
));
924 static int pakfire_jail_enable_raw_mode(struct pakfire_jail
* jail
,
925 struct pakfire_jail_pty_stdio
* stdio
) {
926 struct termios raw_attrs
;
929 // Skip if we don't know the file descriptor
933 // Skip everything if fd is not a TTY
934 if (!isatty(stdio
->fd
))
938 stdio
->flags
= fcntl(stdio
->fd
, F_GETFL
);
939 if (stdio
->flags
< 0) {
940 CTX_ERROR(jail
->ctx
, "Could not fetch flags from fd %d: %s\n",
941 stdio
->fd
, strerror(errno
));
945 // Fetch all attributes
946 r
= tcgetattr(stdio
->fd
, &stdio
->attrs
);
948 CTX_ERROR(jail
->ctx
, "Could not fetch terminal attributes from fd %d: %s\n",
949 stdio
->fd
, strerror(errno
));
953 // Copy all attributes
954 raw_attrs
= stdio
->attrs
;
957 cfmakeraw(&raw_attrs
);
961 raw_attrs
.c_oflag
= stdio
->attrs
.c_oflag
;
965 raw_attrs
.c_iflag
= stdio
->attrs
.c_iflag
;
966 raw_attrs
.c_lflag
= stdio
->attrs
.c_lflag
;
970 // Restore the attributes
971 r
= tcsetattr(stdio
->fd
, TCSANOW
, &raw_attrs
);
973 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for fd %d: %s\n",
974 stdio
->fd
, strerror(errno
));
981 static int pakfire_jail_restore_attrs(struct pakfire_jail
* jail
,
982 const struct pakfire_jail_pty_stdio
* stdio
) {
985 // Skip if we don't know the file descriptor
989 // Skip everything if fd is not a TTY
990 if (!isatty(stdio
->fd
))
994 r
= fcntl(stdio
->fd
, F_SETFL
, stdio
->flags
);
996 CTX_ERROR(jail
->ctx
, "Could not set flags for file descriptor %d: %s\n",
997 stdio
->fd
, strerror(errno
));
1001 // Restore the attributes
1002 r
= tcsetattr(stdio
->fd
, TCSANOW
, &stdio
->attrs
);
1004 CTX_ERROR(jail
->ctx
, "Could not restore terminal attributes for %d, ignoring: %s\n",
1005 stdio
->fd
, strerror(errno
));
1012 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail
* jail
,
1013 struct pakfire_jail_exec
* ctx
, const int epollfd
, const int fd
) {
1014 struct winsize size
;
1017 CTX_DEBUG(jail
->ctx
, "Setting up PTY forwarding on fd %d\n", fd
);
1019 // Store the file descriptor
1020 ctx
->pty
.master
.fd
= fd
;
1022 // Add the master to the event loop
1023 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.master
.fd
, EPOLLIN
|EPOLLOUT
|EPOLLET
);
1027 if (ctx
->flags
& PAKFIRE_JAIL_PTY_FORWARDING
) {
1028 // Configure stdin/stdout
1029 ctx
->pty
.stdin
.fd
= STDIN_FILENO
;
1030 ctx
->pty
.stdout
.fd
= STDOUT_FILENO
;
1033 if (isatty(ctx
->pty
.stdout
.fd
)) {
1034 r
= ioctl(ctx
->pty
.stdout
.fd
, TIOCGWINSZ
, &size
);
1036 CTX_ERROR(jail
->ctx
, "Failed to determine terminal dimensions: %s\n", strerror(errno
));
1041 r
= ioctl(ctx
->pty
.master
.fd
, TIOCSWINSZ
, &size
);
1043 CTX_ERROR(jail
->ctx
, "Failed setting dimensions: %s\n", strerror(errno
));
1048 // Enable RAW mode on standard input
1049 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdin
);
1053 // Enable RAW mode on standard output
1054 r
= pakfire_jail_enable_raw_mode(jail
, &ctx
->pty
.stdout
);
1058 // Add standard input to the event loop
1059 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdin
.fd
, EPOLLIN
|EPOLLET
);
1063 // Add standard output to the event loop
1064 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, ctx
->pty
.stdout
.fd
, EPOLLOUT
|EPOLLET
);
1072 static int pakfire_jail_command_output(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
1073 void* data
, const char* line
, const size_t length
) {
1074 CTX_INFO(ctx
, "Command Output: %.*s", (int)length
, line
);
1079 static int pakfire_jail_forward_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1082 while (ctx
->pty
.master
.io
|| ctx
->pty
.stdin
.io
|| ctx
->pty
.stdout
.io
) {
1083 // Read from standard input
1084 if (ctx
->pty
.stdin
.io
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1085 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.stdin
.fd
, &ctx
->pty
.stdin
.buffer
);
1087 CTX_ERROR(jail
->ctx
, "Failed reading from standard input: %s\n", strerror(-r
));
1091 // We are done reading for now
1092 ctx
->pty
.stdin
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1094 // But we may have data to write
1095 if (ctx
->pty
.stdin
.buffer
.used
)
1096 ctx
->pty
.master
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1099 // Write to the master
1100 if (ctx
->pty
.master
.io
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1101 if (jail
->callbacks
.stdin
.callback
) {
1102 r
= pakfire_jail_stream_stdin(jail
, ctx
, ctx
->pty
.master
.fd
);
1107 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdin
.buffer
);
1109 CTX_ERROR(jail
->ctx
, "Failed writing to the PTY: %s\n", strerror(-r
));
1114 // We are done writing for now
1115 ctx
->pty
.master
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1118 // Read from the master
1119 if (ctx
->pty
.master
.io
& PAKFIRE_JAIL_PTY_READY_TO_READ
) {
1120 r
= pakfire_jail_fill_buffer(jail
, ctx
->pty
.master
.fd
, &ctx
->pty
.stdout
.buffer
);
1122 CTX_ERROR(jail
->ctx
, "Failed reading from the PTY: %s\n", strerror(-r
));
1126 // We are done reading for now
1127 ctx
->pty
.master
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_READ
;
1129 // But we may have data to write
1130 if (ctx
->pty
.stdout
.buffer
.used
)
1131 ctx
->pty
.stdout
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1134 // Write to standard output
1135 if (ctx
->pty
.stdout
.io
& PAKFIRE_JAIL_PTY_READY_TO_WRITE
) {
1136 // If we have a callback, we will send any output to the callback
1137 if (jail
->callbacks
.stdout
.callback
) {
1138 r
= pakfire_jail_drain_buffer_with_callback(jail
, &ctx
->pty
.stdout
.buffer
,
1139 jail
->callbacks
.stdout
.callback
, jail
->callbacks
.stdout
.data
);
1143 // If we have a file descriptor, we will forward any output
1144 } else if (ctx
->pty
.stdout
.fd
>= 0) {
1145 r
= pakfire_jail_drain_buffer(jail
, ctx
->pty
.stdout
.fd
, &ctx
->pty
.stdout
.buffer
);
1147 CTX_ERROR(jail
->ctx
, "Failed writing to standard output: %s\n", strerror(-r
));
1151 // Otherwise send the output to the default logger
1153 r
= pakfire_jail_drain_buffer_with_callback(jail
, &ctx
->pty
.stdout
.buffer
,
1154 pakfire_jail_command_output
, NULL
);
1159 // We are done writing for now
1160 ctx
->pty
.stdout
.io
&= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1167 static int pakfire_jail_wait(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1169 struct epoll_event events
[EPOLL_MAX_EVENTS
];
1173 // Fetch file descriptors from context
1174 const int pidfd
= ctx
->pidfd
;
1176 // Fetch the UNIX domain socket
1177 const int socket_recv
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->socket
);
1180 const int timerfd
= pakfire_jail_create_timer(jail
);
1183 const int log_INFO
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_INFO
);
1184 const int log_ERROR
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_ERROR
);
1186 const int log_DEBUG
= pakfire_jail_get_pipe_to_read(jail
, &ctx
->pipes
.log_DEBUG
);
1187 #endif /* ENABLE_DEBUG */
1189 // Make a list of all file descriptors we are interested in
1190 const struct pakfire_wait_fds
{
1195 { timerfd
, EPOLLIN
},
1198 { ctx
->pidfd
, EPOLLIN
},
1201 { log_INFO
, EPOLLIN
},
1202 { log_ERROR
, EPOLLIN
},
1204 { log_DEBUG
, EPOLLIN
},
1205 #endif /* ENABLE_DEBUG */
1207 // UNIX Domain Socket
1208 { socket_recv
, EPOLLIN
},
1215 epollfd
= epoll_create1(0);
1217 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
1222 // Turn file descriptors into non-blocking mode and add them to epoll()
1223 for (const struct pakfire_wait_fds
* fd
= fds
; fd
->events
; fd
++) {
1224 // Skip fds which were not initialized
1228 // Add the FD to the event loop
1229 r
= pakfire_jail_epoll_add_fd(jail
, epollfd
, fd
->fd
, fd
->events
);
1236 // Loop for as long as the process is alive
1238 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
1240 // Ignore if epoll_wait() has been interrupted
1244 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
1250 for (int i
= 0; i
< num
; i
++) {
1251 int e
= events
[i
].events
;
1252 int fd
= events
[i
].data
.fd
;
1254 // Handle PTY forwarding events
1255 if (ctx
->pty
.master
.fd
== fd
) {
1256 if (e
& (EPOLLIN
|EPOLLHUP
))
1257 ctx
->pty
.master
.io
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1259 if (e
& (EPOLLOUT
|EPOLLHUP
))
1260 ctx
->pty
.master
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1263 r
= pakfire_jail_forward_pty(jail
, ctx
);
1265 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1269 // Handle standard input
1270 } else if (ctx
->pty
.stdin
.fd
== fd
) {
1271 if (e
& (EPOLLIN
|EPOLLHUP
))
1272 ctx
->pty
.stdin
.io
|= PAKFIRE_JAIL_PTY_READY_TO_READ
;
1275 r
= pakfire_jail_forward_pty(jail
, ctx
);
1277 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1281 // Handle standard output
1282 } else if (ctx
->pty
.stdout
.fd
== fd
) {
1283 if (e
& (EPOLLOUT
|EPOLLHUP
))
1284 ctx
->pty
.stdout
.io
|= PAKFIRE_JAIL_PTY_READY_TO_WRITE
;
1287 r
= pakfire_jail_forward_pty(jail
, ctx
);
1289 CTX_ERROR(jail
->ctx
, "Failed forwarding the PTY: %s\n", strerror(-r
));
1293 // Handle any changes to the PIDFD
1294 } else if (pidfd
== fd
) {
1296 // Call waidid() and store the result
1297 r
= waitid(P_PIDFD
, ctx
->pidfd
, &ctx
->status
, WEXITED
);
1299 ERROR(jail
->pakfire
, "waitid() failed: %m\n");
1303 // Mark that we have ended so that we will process the remaining
1304 // events from epoll() now, but won't restart the outer loop.
1308 // Handle timer events
1309 } else if (timerfd
== fd
) {
1311 DEBUG(jail
->pakfire
, "Timer event received\n");
1314 r
= read(timerfd
, garbage
, sizeof(garbage
));
1316 ERROR(jail
->pakfire
, "Could not disarm timer: %m\n");
1321 // Terminate the process if it hasn't already ended
1323 DEBUG(jail
->pakfire
, "Terminating process...\n");
1325 // Send SIGTERM to the process
1326 r
= pidfd_send_signal(pidfd
, SIGKILL
, NULL
, 0);
1328 ERROR(jail
->pakfire
, "Could not kill process: %m\n");
1334 // Handle socket messages
1335 } else if (socket_recv
== fd
) {
1337 // Receive the passed FD
1338 r
= pakfire_jail_recv_fd(jail
, socket_recv
, &fd
);
1342 // Setup PTY forwarding
1343 if (ctx
->pty
.master
.fd
< 0) {
1344 r
= pakfire_jail_setup_pty_forwarding(jail
, ctx
, epollfd
, fd
);
1346 CTX_ERROR(jail
->ctx
, "Failed setting up PTY forwarding: %s\n", strerror(-r
));
1352 // Handle log INFO messages
1353 } else if (log_INFO
== fd
) {
1355 r
= pakfire_jail_handle_log(jail
, ctx
, fd
, &ctx
->buffers
.log_INFO
,
1356 pakfire_jail_log
, &ctx
->buffers
.log_INFO
.priority
);
1361 // Handle log ERROR messages
1362 } else if (log_ERROR
== fd
) {
1364 r
= pakfire_jail_handle_log(jail
, ctx
, fd
, &ctx
->buffers
.log_ERROR
,
1365 pakfire_jail_log
, &ctx
->buffers
.log_ERROR
.priority
);
1371 // Handle log DEBUG messages
1372 } else if (log_DEBUG
== fd
) {
1374 r
= pakfire_jail_handle_log(jail
, ctx
, fd
, &ctx
->buffers
.log_DEBUG
,
1375 pakfire_jail_log
, &ctx
->buffers
.log_DEBUG
.priority
);
1379 #endif /* ENABLE_DEBUG */
1381 // Log a message for anything else
1383 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
1387 // Check if any file descriptors have been closed
1389 // Remove the file descriptor
1390 r
= epoll_ctl(epollfd
, EPOLL_CTL_DEL
, fd
, NULL
);
1392 ERROR(jail
->pakfire
, "Could not remove closed file-descriptor %d: %m\n", fd
);
1405 // Restore any changed terminal attributes
1406 if (ctx
->pty
.stdin
.fd
>= 0)
1407 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdin
);
1408 if (ctx
->pty
.stdout
.fd
>= 0)
1409 pakfire_jail_restore_attrs(jail
, &ctx
->pty
.stdout
);
1414 int pakfire_jail_capture_stdout(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
1415 void* data
, const char* line
, size_t length
) {
1416 char** output
= (char**)data
;
1419 // Append everything from stdout to a buffer
1420 r
= asprintf(output
, "%s%.*s", (output
&& *output
) ? *output
: "", (int)length
, line
);
1429 // Logs all capabilities of the current process
1430 static int pakfire_jail_show_capabilities(struct pakfire_jail
* jail
) {
1433 cap_flag_value_t value_e
;
1434 cap_flag_value_t value_i
;
1435 cap_flag_value_t value_p
;
1439 pid_t pid
= getpid();
1441 // Fetch all capabilities
1442 caps
= cap_get_proc();
1444 ERROR(jail
->pakfire
, "Could not fetch capabilities: %m\n");
1449 DEBUG(jail
->pakfire
, "Capabilities of PID %d:\n", pid
);
1451 // Iterate over all capabilities
1452 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1453 name
= cap_to_name(cap
);
1455 // Fetch effective value
1456 r
= cap_get_flag(caps
, cap
, CAP_EFFECTIVE
, &value_e
);
1460 // Fetch inheritable value
1461 r
= cap_get_flag(caps
, cap
, CAP_INHERITABLE
, &value_i
);
1465 // Fetch permitted value
1466 r
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &value_p
);
1470 DEBUG(jail
->pakfire
,
1471 " %-24s : %c%c%c\n",
1473 (value_e
== CAP_SET
) ? 'e' : '-',
1474 (value_i
== CAP_SET
) ? 'i' : '-',
1475 (value_p
== CAP_SET
) ? 'p' : '-'
1495 static int pakfire_jail_set_capabilities(struct pakfire_jail
* jail
) {
1500 // Fetch capabilities
1501 caps
= cap_get_proc();
1503 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
1508 // Walk through all capabilities
1509 for (cap_value_t cap
= 0; cap_valid(cap
); cap
++) {
1510 cap_value_t _caps
[] = { cap
};
1512 // Fetch the name of the capability
1513 name
= cap_to_name(cap
);
1515 r
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, _caps
, CAP_SET
);
1517 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1521 r
= cap_set_flag(caps
, CAP_INHERITABLE
, 1, _caps
, CAP_SET
);
1523 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1527 r
= cap_set_flag(caps
, CAP_PERMITTED
, 1, _caps
, CAP_SET
);
1529 ERROR(jail
->pakfire
, "Could not set %s: %m\n", name
);
1538 // Restore all capabilities
1539 r
= cap_set_proc(caps
);
1541 ERROR(jail
->pakfire
, "Restoring capabilities failed: %m\n");
1545 // Add all capabilities to the ambient set
1546 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
1547 name
= cap_to_name(cap
);
1549 // Raise the capability
1550 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_RAISE
, cap
, 0, 0);
1552 ERROR(jail
->pakfire
, "Could not set ambient capability %s: %m\n", name
);
1575 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
1576 const int syscalls
[] = {
1577 // The kernel's keyring isn't namespaced
1580 SCMP_SYS(request_key
),
1582 // Disable userfaultfd
1583 SCMP_SYS(userfaultfd
),
1585 // Disable perf which could leak a lot of information about the host
1586 SCMP_SYS(perf_event_open
),
1592 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
1594 // Setup a syscall filter which allows everything by default
1595 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
1597 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
1602 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
1603 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
1605 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
1610 // Load syscall filter into the kernel
1611 r
= seccomp_load(ctx
);
1613 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
1619 seccomp_release(ctx
);
1626 PAKFIRE_EXPORT
int pakfire_jail_bind(struct pakfire_jail
* jail
,
1627 const char* source
, const char* target
, int flags
) {
1628 struct pakfire_jail_mountpoint
* mp
= NULL
;
1631 // Check if there is any space left
1632 if (jail
->num_mountpoints
>= MAX_MOUNTPOINTS
) {
1637 // Check for valid inputs
1638 if (!source
|| !target
) {
1643 // Select the next free slot
1644 mp
= &jail
->mountpoints
[jail
->num_mountpoints
];
1647 r
= pakfire_string_set(mp
->source
, source
);
1649 ERROR(jail
->pakfire
, "Could not copy source: %m\n");
1654 r
= pakfire_string_set(mp
->target
, target
);
1656 ERROR(jail
->pakfire
, "Could not copy target: %m\n");
1663 // Increment counter
1664 jail
->num_mountpoints
++;
1669 static int pakfire_jail_mount_networking(struct pakfire_jail
* jail
) {
1672 const char* paths
[] = {
1678 // Bind-mount all paths read-only
1679 for (const char** path
= paths
; *path
; path
++) {
1680 r
= pakfire_bind(jail
->pakfire
, *path
, NULL
, MS_RDONLY
);
1683 // Ignore if we don't have permission
1698 Mounts everything that we require in the new namespace
1700 static int pakfire_jail_mount(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1701 struct pakfire_jail_mountpoint
* mp
= NULL
;
1705 // Enable loop devices
1706 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_LOOP_DEVICES
))
1707 flags
|= PAKFIRE_MOUNT_LOOP_DEVICES
;
1709 // Mount all default stuff
1710 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_OUTER
, flags
);
1715 r
= pakfire_populate_dev(jail
->pakfire
, flags
);
1719 // Mount the interpreter (if needed)
1720 r
= pakfire_mount_interpreter(jail
->pakfire
);
1724 // Mount networking stuff
1725 if (pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
1726 r
= pakfire_jail_mount_networking(jail
);
1731 // Mount all custom stuff
1732 for (unsigned int i
= 0; i
< jail
->num_mountpoints
; i
++) {
1734 mp
= &jail
->mountpoints
[i
];
1737 r
= pakfire_bind(jail
->pakfire
, mp
->source
, mp
->target
, mp
->flags
);
1747 static int pakfire_jail_setup_loopback(struct pakfire_jail
* jail
) {
1748 struct nl_sock
* nl
= NULL
;
1749 struct nl_cache
* cache
= NULL
;
1750 struct rtnl_link
* link
= NULL
;
1751 struct rtnl_link
* change
= NULL
;
1754 DEBUG(jail
->pakfire
, "Setting up loopback...\n");
1756 // Allocate a netlink socket
1757 nl
= nl_socket_alloc();
1759 ERROR(jail
->pakfire
, "Could not allocate a netlink socket: %m\n");
1764 // Connect the socket
1765 r
= nl_connect(nl
, NETLINK_ROUTE
);
1767 ERROR(jail
->pakfire
, "Could not connect netlink socket: %s\n", nl_geterror(r
));
1771 // Allocate the netlink cache
1772 r
= rtnl_link_alloc_cache(nl
, AF_UNSPEC
, &cache
);
1774 ERROR(jail
->pakfire
, "Unable to allocate netlink cache: %s\n", nl_geterror(r
));
1778 // Fetch loopback interface
1779 link
= rtnl_link_get_by_name(cache
, "lo");
1781 ERROR(jail
->pakfire
, "Could not find lo interface. Ignoring.\n");
1786 // Allocate a new link
1787 change
= rtnl_link_alloc();
1789 ERROR(jail
->pakfire
, "Could not allocate change link\n");
1794 // Set the link to UP
1795 rtnl_link_set_flags(change
, IFF_UP
);
1797 // Apply any changes
1798 r
= rtnl_link_change(nl
, link
, change
, 0);
1800 ERROR(jail
->pakfire
, "Unable to activate loopback: %s\n", nl_geterror(r
));
1816 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1817 char path
[PATH_MAX
];
1820 // Skip mapping anything when running on /
1821 if (pakfire_on_root(jail
->pakfire
))
1825 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
1830 const uid_t uid
= pakfire_uid(jail
->pakfire
);
1833 const struct pakfire_subid
* subuid
= pakfire_subuid(jail
->pakfire
);
1837 /* When running as root, we will map the entire range.
1839 When running as a non-privileged user, we will map the root user inside the jail
1840 to the user's UID outside of the jail, and we will map the rest starting from one.
1845 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1846 "0 %lu %lu\n", subuid
->id
, subuid
->length
);
1848 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1849 "0 %lu 1\n1 %lu %lu\n", uid
, subuid
->id
, subuid
->length
);
1853 ERROR(jail
->pakfire
, "Could not map UIDs: %m\n");
1860 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
1861 char path
[PATH_MAX
];
1864 // Skip mapping anything when running on /
1865 if (pakfire_on_root(jail
->pakfire
))
1869 const gid_t gid
= pakfire_gid(jail
->pakfire
);
1872 const struct pakfire_subid
* subgid
= pakfire_subgid(jail
->pakfire
);
1877 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
1883 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1884 "0 %lu %lu\n", subgid
->id
, subgid
->length
);
1886 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0,
1887 "0 %lu 1\n1 %lu %lu\n", gid
, subgid
->id
, subgid
->length
);
1891 ERROR(jail
->pakfire
, "Could not map GIDs: %m\n");
1898 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
1899 char path
[PATH_MAX
];
1903 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
1907 r
= pakfire_file_write(jail
->pakfire
, path
, 0, 0, 0, "deny\n");
1909 CTX_ERROR(jail
->ctx
, "Could not set setgroups to deny: %s\n", strerror(errno
));
1916 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
1917 const uint64_t val
= 1;
1920 DEBUG(jail
->pakfire
, "Sending signal...\n");
1922 // Write to the file descriptor
1923 r
= eventfd_write(fd
, val
);
1925 ERROR(jail
->pakfire
, "Could not send signal: %s\n", strerror(errno
));
1929 // Close the file descriptor
1935 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
1939 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
1941 r
= eventfd_read(fd
, &val
);
1943 ERROR(jail
->pakfire
, "Error waiting for signal: %s\n", strerror(errno
));
1947 // Close the file descriptor
1954 Performs the initialisation that needs to happen in the parent part
1956 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
1959 // Setup UID mapping
1960 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
1964 // Write "deny" to /proc/PID/setgroups
1965 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
1969 // Setup GID mapping
1970 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
1974 // Parent has finished initialisation
1975 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
1977 // Send signal to client
1978 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
1985 static int pakfire_jail_switch_root(struct pakfire_jail
* jail
, const char* root
) {
1988 // Change to the new root
1991 ERROR(jail
->pakfire
, "chdir(%s) failed: %m\n", root
);
1996 r
= pivot_root(".", ".");
1998 ERROR(jail
->pakfire
, "Failed changing into the new root directory %s: %m\n", root
);
2002 // Umount the old root
2003 r
= umount2(".", MNT_DETACH
);
2005 ERROR(jail
->pakfire
, "Could not umount the old root filesystem: %m\n");
2012 static int pakfire_jail_open_pty(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
2015 // Allocate a new PTY
2016 ctx
->pty
.master
.fd
= posix_openpt(O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
2017 if (ctx
->pty
.master
.fd
< 0)
2021 r
= ptsname_r(ctx
->pty
.master
.fd
, ctx
->pty
.console
, sizeof(ctx
->pty
.console
));
2025 CTX_DEBUG(jail
->ctx
, "Allocated console at %s (%d)\n", ctx
->pty
.console
, ctx
->pty
.master
.fd
);
2027 // Unlock the master device
2028 r
= unlockpt(ctx
->pty
.master
.fd
);
2030 CTX_ERROR(jail
->ctx
, "Could not unlock the PTY: %s\n", strerror(errno
));
2035 r
= pakfire_symlink(jail
->ctx
, ctx
->pty
.console
, "/dev/console");
2042 static int pakfire_jail_setup_terminal(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
2046 // Open a new terminal
2047 fd
= open("/dev/console", O_RDWR
|O_NOCTTY
);
2049 CTX_ERROR(jail
->ctx
, "Failed to open a new terminal: %s\n", strerror(errno
));
2053 CTX_DEBUG(jail
->ctx
, "Opened a new terminal %d\n", fd
);
2055 // Connect the new terminal to standard input
2056 r
= dup2(fd
, STDIN_FILENO
);
2058 CTX_ERROR(jail
->ctx
, "Failed to open standard input: %s\n", strerror(errno
));
2062 // Connect the new terminal to standard output
2063 r
= dup2(fd
, STDOUT_FILENO
);
2065 CTX_ERROR(jail
->ctx
, "Failed to open standard output: %s\n", strerror(errno
));
2069 // Connect the new terminal to standard error
2070 r
= dup2(fd
, STDERR_FILENO
);
2072 CTX_ERROR(jail
->ctx
, "Failed to open standard error: %s\n", strerror(errno
));
2079 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
2080 const char* argv
[]) {
2083 // Redirect any logging to our log pipe
2084 pakfire_ctx_set_log_callback(jail
->ctx
, pakfire_jail_log_redirect
, &ctx
->pipes
);
2087 pid_t pid
= getpid();
2089 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", pid
);
2091 // Wait for the parent to finish initialization
2092 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
2097 r
= prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0);
2099 ERROR(jail
->pakfire
, "Could not configure to die with parent: %m\n");
2103 // Make this process dumpable
2104 r
= prctl (PR_SET_DUMPABLE
, 1, 0, 0, 0);
2106 ERROR(jail
->pakfire
, "Could not make the process dumpable: %m\n");
2110 // Don't drop any capabilities on setuid()
2111 r
= prctl(PR_SET_KEEPCAPS
, 1);
2113 ERROR(jail
->pakfire
, "Could not set PR_SET_KEEPCAPS: %m\n");
2118 uid_t uid
= getuid();
2119 gid_t gid
= getgid();
2122 uid_t euid
= geteuid();
2123 gid_t egid
= getegid();
2125 DEBUG(jail
->pakfire
, " UID: %u (effective %u)\n", uid
, euid
);
2126 DEBUG(jail
->pakfire
, " GID: %u (effective %u)\n", gid
, egid
);
2128 // Log all mountpoints
2129 pakfire_mount_list(jail
->ctx
);
2131 // Fail if we are not PID 1
2133 CTX_ERROR(jail
->ctx
, "Child process is not PID 1\n");
2137 // Fail if we are not running as root
2138 if (uid
|| gid
|| euid
|| egid
) {
2139 ERROR(jail
->pakfire
, "Child process is not running as root\n");
2143 const int socket_send
= pakfire_jail_get_pipe_to_write(jail
, &ctx
->socket
);
2145 // Mount all default stuff
2146 r
= pakfire_mount_all(jail
->pakfire
, PAKFIRE_MNTNS_INNER
, 0);
2150 const char* root
= pakfire_get_path(jail
->pakfire
);
2151 const char* arch
= pakfire_get_effective_arch(jail
->pakfire
);
2153 // Change mount propagation to slave to receive anything from the parent namespace
2154 r
= pakfire_mount_change_propagation(jail
->ctx
, "/", MS_SLAVE
);
2158 // Make root a mountpoint in the new mount namespace
2159 r
= pakfire_mount_make_mounpoint(jail
->pakfire
, root
);
2163 // Change mount propagation to private
2164 r
= pakfire_mount_change_propagation(jail
->ctx
, root
, MS_PRIVATE
);
2168 // Change root (unless root is /)
2169 if (!pakfire_on_root(jail
->pakfire
)) {
2171 r
= pakfire_jail_mount(jail
, ctx
);
2176 r
= pakfire_jail_switch_root(jail
, root
);
2182 unsigned long persona
= pakfire_arch_personality(arch
);
2184 r
= personality(persona
);
2186 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
2192 if (!pakfire_jail_exec_has_flag(ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2193 r
= pakfire_jail_setup_loopback(jail
);
2200 DEBUG(jail
->pakfire
, "Setting nice level to %d\n", jail
->nice
);
2202 r
= setpriority(PRIO_PROCESS
, pid
, jail
->nice
);
2204 ERROR(jail
->pakfire
, "Could not set nice level: %m\n");
2209 // Create a new session
2212 CTX_ERROR(jail
->ctx
, "Could not create a new session: %s\n", strerror(errno
));
2216 // Allocate a new PTY
2217 r
= pakfire_jail_open_pty(jail
, ctx
);
2219 CTX_ERROR(jail
->ctx
, "Could not allocate a new PTY: %s\n", strerror(-r
));
2223 // Send the PTY master to the parent process
2224 r
= pakfire_jail_send_fd(jail
, socket_send
, ctx
->pty
.master
.fd
);
2226 CTX_ERROR(jail
->ctx
, "Failed sending the PTY master to the parent: %s\n", strerror(-r
));
2230 // Setup the terminal
2231 r
= pakfire_jail_setup_terminal(jail
, ctx
);
2235 // Close the master of the PTY
2236 close(ctx
->pty
.master
.fd
);
2237 ctx
->pty
.master
.fd
= -1;
2242 // Close other end of log pipes
2243 close(ctx
->pipes
.log_INFO
[0]);
2244 close(ctx
->pipes
.log_ERROR
[0]);
2246 close(ctx
->pipes
.log_DEBUG
[0]);
2247 #endif /* ENABLE_DEBUG */
2249 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2250 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
2255 r
= pakfire_jail_set_capabilities(jail
);
2259 // Show capabilities
2260 r
= pakfire_jail_show_capabilities(jail
);
2265 r
= pakfire_jail_limit_syscalls(jail
);
2269 DEBUG(jail
->pakfire
, "Child process initialization done\n");
2270 DEBUG(jail
->pakfire
, "Launching command:\n");
2273 for (unsigned int i
= 0; argv
[i
]; i
++)
2274 DEBUG(jail
->pakfire
, " argv[%u] = %s\n", i
, argv
[i
]);
2277 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
2279 // Translate errno into regular exit code
2282 // Ignore if the command doesn't exist
2283 if (ctx
->flags
& PAKFIRE_JAIL_NOENT_OK
)
2294 ERROR(jail
->pakfire
, "Could not execve(%s): %m\n", argv
[0]);
2297 // We should not get here
2301 // Run a command in the jail
2302 PAKFIRE_EXPORT
int pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2306 // Check if argv is valid
2307 if (!argv
|| !argv
[0]) {
2312 // Initialize context for this call
2313 struct pakfire_jail_exec ctx
= {
2316 .socket
= { -1, -1 },
2319 .log_INFO
= { -1, -1 },
2320 .log_ERROR
= { -1, -1 },
2322 .log_DEBUG
= { -1, -1 },
2323 #endif /* ENABLE_DEBUG */
2328 .priority
= LOG_INFO
,
2332 .priority
= LOG_ERR
,
2337 .priority
= LOG_DEBUG
,
2339 #endif /* ENABLE_DEBUG */
2358 DEBUG(jail
->pakfire
, "Executing jail...\n");
2360 // Enable networking in interactive mode
2361 if (ctx
.flags
& PAKFIRE_JAIL_PTY_FORWARDING
)
2362 ctx
.flags
|= PAKFIRE_JAIL_HAS_NETWORKING
;
2365 Setup a file descriptor which can be used to notify the client that the parent
2366 has completed configuration.
2368 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
2369 if (ctx
.completed_fd
< 0) {
2370 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
2374 // Create a UNIX domain socket
2375 r
= socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ctx
.socket
);
2377 CTX_ERROR(jail
->ctx
, "Could not create UNIX socket: %s\n", strerror(errno
));
2382 // Setup pipes for logging
2384 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_INFO
, O_CLOEXEC
);
2389 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_ERROR
, O_CLOEXEC
);
2395 r
= pakfire_jail_setup_pipe(jail
, &ctx
.pipes
.log_DEBUG
, O_CLOEXEC
);
2398 #endif /* ENABLE_DEBUG */
2400 // Configure child process
2401 struct clone_args args
= {
2411 .exit_signal
= SIGCHLD
,
2412 .pidfd
= (long long unsigned int)&ctx
.pidfd
,
2415 // Launch the process in a cgroup that is a leaf of the configured cgroup
2417 args
.flags
|= CLONE_INTO_CGROUP
;
2420 const char* uuid
= pakfire_jail_uuid(jail
);
2422 // Create a temporary cgroup
2423 r
= pakfire_cgroup_child(&ctx
.cgroup
, jail
->cgroup
, uuid
, 0);
2425 ERROR(jail
->pakfire
, "Could not create cgroup for jail: %m\n");
2429 // Clone into this cgroup
2430 args
.cgroup
= pakfire_cgroup_fd(ctx
.cgroup
);
2434 if (!pakfire_jail_exec_has_flag(&ctx
, PAKFIRE_JAIL_HAS_NETWORKING
)) {
2435 args
.flags
|= CLONE_NEWNET
;
2438 // Fork this process
2439 ctx
.pid
= clone3(&args
, sizeof(args
));
2441 ERROR(jail
->pakfire
, "Could not clone: %m\n");
2445 } else if (ctx
.pid
== 0) {
2446 r
= pakfire_jail_child(jail
, &ctx
, argv
);
2451 r
= pakfire_jail_parent(jail
, &ctx
);
2455 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
2457 // Read output of the child process
2458 r
= pakfire_jail_wait(jail
, &ctx
);
2462 // Handle exit status
2463 switch (ctx
.status
.si_code
) {
2465 DEBUG(jail
->pakfire
, "The child process exited with code %d\n",
2466 ctx
.status
.si_status
);
2469 exit
= ctx
.status
.si_status
;
2473 ERROR(jail
->pakfire
, "The child process was killed\n");
2478 ERROR(jail
->pakfire
, "The child process terminated abnormally\n");
2481 // Log anything else
2483 ERROR(jail
->pakfire
, "Unknown child exit code: %d\n", ctx
.status
.si_code
);
2488 // Reset all callbacks
2489 pakfire_jail_set_stdin_callback(jail
, NULL
, NULL
);
2490 pakfire_jail_set_stdout_callback(jail
, NULL
, NULL
);
2492 // Destroy the temporary cgroup (if any)
2494 // Read cgroup stats
2495 pakfire_cgroup_stat(ctx
.cgroup
, &ctx
.cgroup_stats
);
2496 pakfire_cgroup_stat_dump(ctx
.cgroup
, &ctx
.cgroup_stats
);
2497 pakfire_cgroup_destroy(ctx
.cgroup
);
2498 pakfire_cgroup_unref(ctx
.cgroup
);
2501 // Close any file descriptors
2504 if (ctx
.pty
.master
.fd
>= 0)
2505 close(ctx
.pty
.master
.fd
);
2506 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_INFO
);
2507 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_ERROR
);
2509 pakfire_jail_close_pipe(jail
, ctx
.pipes
.log_DEBUG
);
2510 #endif /* ENABLE_DEBUG */
2511 pakfire_jail_close_pipe(jail
, ctx
.socket
);
2516 static int pakfire_jail_exec_interactive(
2517 struct pakfire_jail
* jail
, const char* argv
[], int flags
) {
2520 flags
|= PAKFIRE_JAIL_PTY_FORWARDING
;
2522 // Setup interactive stuff
2523 r
= pakfire_jail_setup_interactive_env(jail
);
2527 return pakfire_jail_exec(jail
, argv
, flags
);
2530 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
2533 const char* args
[]) {
2534 char path
[PATH_MAX
];
2535 const char** argv
= NULL
;
2539 const char* root
= pakfire_get_path(jail
->pakfire
);
2541 // Write the scriptlet to disk
2542 r
= pakfire_path_append(path
, root
, PAKFIRE_TMP_DIR
"/pakfire-script.XXXXXX");
2546 // Create a temporary file
2547 f
= pakfire_mktemp(path
, 0700);
2549 ERROR(jail
->pakfire
, "Could not create temporary file: %m\n");
2553 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
2556 r
= fprintf(f
, "%s", script
);
2558 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
2565 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
2571 // Count how many arguments were passed
2572 unsigned int argc
= 1;
2574 for (const char** arg
= args
; *arg
; arg
++)
2578 argv
= calloc(argc
+ 1, sizeof(*argv
));
2580 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
2585 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
2588 for (unsigned int i
= 1; i
< argc
; i
++)
2589 argv
[i
] = args
[i
-1];
2592 r
= pakfire_jail_exec(jail
, argv
, 0);
2600 // Remove script from disk
2608 A convenience function that creates a new jail, runs the given command and destroys
2611 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char** output
) {
2612 struct pakfire_jail
* jail
= NULL
;
2615 // Create a new jail
2616 r
= pakfire_jail_create(&jail
, pakfire
);
2620 // Set the callback that captures the output
2621 pakfire_jail_set_stdout_callback(jail
, pakfire_jail_capture_stdout
, output
);
2623 // Execute the command
2624 r
= pakfire_jail_exec(jail
, argv
, 0);
2628 pakfire_jail_unref(jail
);
2633 int pakfire_jail_run_script(struct pakfire
* pakfire
,
2634 const char* script
, const size_t length
, const char* argv
[], int flags
) {
2635 struct pakfire_jail
* jail
= NULL
;
2638 // Create a new jail
2639 r
= pakfire_jail_create(&jail
, pakfire
);
2643 // Execute the command
2644 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
);
2648 pakfire_jail_unref(jail
);
2653 int pakfire_jail_shell(struct pakfire_jail
* jail
) {
2656 const char* argv
[] = {
2657 "/bin/bash", "--login", NULL
,
2660 // Execute /bin/bash
2661 r
= pakfire_jail_exec_interactive(jail
, argv
, 0);
2667 // Ignore any return codes from the shell
2671 static int pakfire_jail_run_if_possible(struct pakfire
* pakfire
, const char** argv
) {
2672 char path
[PATH_MAX
];
2675 r
= pakfire_path(pakfire
, path
, "%s", *argv
);
2679 // Check if the file is executable
2680 r
= access(path
, X_OK
);
2682 DEBUG(pakfire
, "%s is not executable. Skipping...\n", *argv
);
2686 return pakfire_jail_run(pakfire
, argv
, 0, NULL
);
2689 int pakfire_jail_ldconfig(struct pakfire
* pakfire
) {
2690 const char* argv
[] = {
2695 return pakfire_jail_run_if_possible(pakfire
, argv
);
2698 int pakfire_jail_run_systemd_tmpfiles(struct pakfire
* pakfire
) {
2699 const char* argv
[] = {
2700 "/usr/bin/systemd-tmpfiles",
2705 return pakfire_jail_run_if_possible(pakfire
, argv
);