]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/jail.c
45be6755ec437e226137dd172d1e9ae45de2c82b
[people/ms/pakfire.git] / src / libpakfire / jail.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2022 Pakfire development team #
5 # #
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. #
10 # #
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. #
15 # #
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/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <linux/capability.h>
24 #include <linux/sched.h>
25 #include <sys/wait.h>
26 #include <linux/wait.h>
27 #include <sched.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <syscall.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>
40 #include <sys/wait.h>
41 #include <termios.h>
42
43 // libnl3
44 #include <net/if.h>
45 #include <netlink/route/link.h>
46
47 // libseccomp
48 #include <seccomp.h>
49
50 // libuuid
51 #include <uuid.h>
52
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>
64
65 #define BUFFER_SIZE 1024 * 64
66 #define ENVIRON_SIZE 128
67 #define EPOLL_MAX_EVENTS 2
68 #define MAX_MOUNTPOINTS 8
69
70 // The default environment that will be set for every command
71 static const struct environ {
72 const char* key;
73 const char* val;
74 } ENV[] = {
75 { "HOME", "/root" },
76 { "LANG", "C.utf-8" },
77 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
78 { "TERM", "vt100" },
79
80 // Tell everything that it is running inside a Pakfire container
81 { "container", "pakfire" },
82 { NULL, NULL },
83 };
84
85 struct pakfire_jail_mountpoint {
86 char source[PATH_MAX];
87 char target[PATH_MAX];
88 int flags;
89 };
90
91 struct pakfire_jail {
92 struct pakfire_ctx* ctx;
93 struct pakfire* pakfire;
94 int nrefs;
95
96 // A unique ID for each jail
97 uuid_t uuid;
98 char __uuid[UUID_STR_LEN];
99
100 // Resource Limits
101 int nice;
102
103 // Timeout
104 struct itimerspec timeout;
105
106 // CGroup
107 struct pakfire_cgroup* cgroup;
108
109 // Environment
110 char* env[ENVIRON_SIZE];
111
112 // Mountpoints
113 struct pakfire_jail_mountpoint mountpoints[MAX_MOUNTPOINTS];
114 unsigned int num_mountpoints;
115
116 // Callbacks
117 struct pakfire_jail_callbacks {
118 // Log
119 pakfire_jail_log_callback log;
120 void* log_data;
121 } callbacks;
122 };
123
124 struct pakfire_log_buffer {
125 char data[BUFFER_SIZE];
126 size_t used;
127 };
128
129 struct pakfire_jail_exec {
130 int flags;
131
132 // PID (of the child)
133 pid_t pid;
134 int pidfd;
135
136 // Socket to pass FDs
137 int socket[2];
138
139 // Process status (from waitid)
140 siginfo_t status;
141
142 // FD to notify the client that the parent has finished initialization
143 int completed_fd;
144
145 // Log pipes
146 struct pakfire_jail_pipes {
147 // Logging
148 int log_INFO[2];
149 int log_ERROR[2];
150 #ifdef ENABLE_DEBUG
151 int log_DEBUG[2];
152 #endif /* ENABLE_DEBUG */
153 } pipes;
154
155 // Communicate
156 struct pakfire_jail_communicate {
157 pakfire_jail_communicate_in in;
158 pakfire_jail_communicate_out out;
159 void* data;
160 } communicate;
161
162 // Log buffers
163 struct pakfire_jail_buffers {
164 struct pakfire_log_buffer stdout;
165 struct pakfire_log_buffer stderr;
166
167 // Logging
168 struct pakfire_log_buffer log_INFO;
169 struct pakfire_log_buffer log_ERROR;
170 #ifdef ENABLE_DEBUG
171 struct pakfire_log_buffer log_DEBUG;
172 #endif /* ENABLE_DEBUG */
173 } buffers;
174
175 struct pakfire_cgroup* cgroup;
176 struct pakfire_cgroup_stats cgroup_stats;
177
178 // PTY
179 struct pakfire_jail_pty {
180 // The path to the console
181 char console[PATH_MAX];
182
183 // The master fd
184 struct pakfire_jail_pty_master {
185 int fd;
186
187 enum pakfire_jail_pty_flags {
188 PAKFIRE_JAIL_PTY_READY_TO_READ = (1 << 0),
189 PAKFIRE_JAIL_PTY_READY_TO_WRITE = (1 << 1),
190 } flags;
191 } master;
192
193 // Standard Input
194 struct pakfire_jail_pty_stdio {
195 int fd;
196 struct pakfire_log_buffer buffer;
197 struct termios attrs;
198 int fdflags;
199 enum pakfire_jail_pty_flags flags;
200 } stdin;
201
202 // Standard Output
203 struct pakfire_jail_pty_stdio stdout;
204 } pty;
205 };
206
207 static int clone3(struct clone_args* args, size_t size) {
208 return syscall(__NR_clone3, args, size);
209 }
210
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);
213 }
214
215 static int pivot_root(const char* new_root, const char* old_root) {
216 return syscall(SYS_pivot_root, new_root, old_root);
217 }
218
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;
222 }
223
224 static void pakfire_jail_free(struct pakfire_jail* jail) {
225 DEBUG(jail->pakfire, "Freeing jail at %p\n", jail);
226
227 // Free environment
228 for (unsigned int i = 0; jail->env[i]; i++)
229 free(jail->env[i]);
230
231 if (jail->cgroup)
232 pakfire_cgroup_unref(jail->cgroup);
233 if (jail->pakfire)
234 pakfire_unref(jail->pakfire);
235 if (jail->ctx)
236 pakfire_ctx_unref(jail->ctx);
237 free(jail);
238 }
239
240 /*
241 Passes any log messages on to the default pakfire log callback
242 */
243 static int pakfire_jail_default_log_callback(struct pakfire* pakfire, void* data,
244 int priority, const char* line, size_t length) {
245 switch (priority) {
246 case LOG_INFO:
247 INFO(pakfire, "%s", line);
248 break;
249
250 case LOG_ERR:
251 ERROR(pakfire, "%s", line);
252 break;
253
254 #ifdef ENABLE_DEBUG
255 case LOG_DEBUG:
256 DEBUG(pakfire, "%s", line);
257 break;
258 #endif
259 }
260
261 return 0;
262 }
263
264 static const char* pakfire_jail_uuid(struct pakfire_jail* jail) {
265 if (!*jail->__uuid)
266 uuid_unparse_lower(jail->uuid, jail->__uuid);
267
268 return jail->__uuid;
269 }
270
271 static int pakfire_jail_setup_interactive_env(struct pakfire_jail* jail) {
272 // Set PS1
273 int r = pakfire_jail_set_env(jail, "PS1", "pakfire-jail \\w> ");
274 if (r)
275 return r;
276
277 // Copy TERM
278 char* TERM = secure_getenv("TERM");
279 if (TERM) {
280 r = pakfire_jail_set_env(jail, "TERM", TERM);
281 if (r)
282 return r;
283 }
284
285 // Copy LANG
286 char* LANG = secure_getenv("LANG");
287 if (LANG) {
288 r = pakfire_jail_set_env(jail, "LANG", LANG);
289 if (r)
290 return r;
291 }
292
293 return 0;
294 }
295
296 PAKFIRE_EXPORT int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire) {
297 int r;
298
299 const char* arch = pakfire_get_effective_arch(pakfire);
300
301 // Allocate a new jail
302 struct pakfire_jail* j = calloc(1, sizeof(*j));
303 if (!j)
304 return 1;
305
306 // Reference context
307 j->ctx = pakfire_ctx(pakfire);
308
309 // Reference Pakfire
310 j->pakfire = pakfire_ref(pakfire);
311
312 // Initialize reference counter
313 j->nrefs = 1;
314
315 // Generate a random UUID
316 uuid_generate_random(j->uuid);
317
318 DEBUG(j->pakfire, "Allocated new jail at %p\n", j);
319
320 // Set the default logging callback
321 pakfire_jail_set_log_callback(j, pakfire_jail_default_log_callback, NULL);
322
323 // Set default environment
324 for (const struct environ* e = ENV; e->key; e++) {
325 r = pakfire_jail_set_env(j, e->key, e->val);
326 if (r)
327 goto ERROR;
328 }
329
330 // Enable all CPU features that CPU has to offer
331 if (!pakfire_arch_is_supported_by_host(arch)) {
332 r = pakfire_jail_set_env(j, "QEMU_CPU", "max");
333 if (r)
334 goto ERROR;
335 }
336
337 // Set container UUID
338 r = pakfire_jail_set_env(j, "container_uuid", pakfire_jail_uuid(j));
339 if (r)
340 goto ERROR;
341
342 // Disable systemctl to talk to systemd
343 if (!pakfire_on_root(j->pakfire)) {
344 r = pakfire_jail_set_env(j, "SYSTEMD_OFFLINE", "1");
345 if (r)
346 goto ERROR;
347 }
348
349 // Done
350 *jail = j;
351 return 0;
352
353 ERROR:
354 pakfire_jail_free(j);
355
356 return r;
357 }
358
359 PAKFIRE_EXPORT struct pakfire_jail* pakfire_jail_ref(struct pakfire_jail* jail) {
360 ++jail->nrefs;
361
362 return jail;
363 }
364
365 PAKFIRE_EXPORT struct pakfire_jail* pakfire_jail_unref(struct pakfire_jail* jail) {
366 if (--jail->nrefs > 0)
367 return jail;
368
369 pakfire_jail_free(jail);
370 return NULL;
371 }
372
373 // Logging Callback
374
375 PAKFIRE_EXPORT void pakfire_jail_set_log_callback(struct pakfire_jail* jail,
376 pakfire_jail_log_callback callback, void* data) {
377 jail->callbacks.log = callback;
378 jail->callbacks.log_data = data;
379 }
380
381 // Resource Limits
382
383 PAKFIRE_EXPORT int pakfire_jail_nice(struct pakfire_jail* jail, int nice) {
384 // Check if nice level is in range
385 if (nice < -19 || nice > 20) {
386 errno = EINVAL;
387 return 1;
388 }
389
390 // Store nice level
391 jail->nice = nice;
392
393 return 0;
394 }
395
396 int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cgroup) {
397 // Free any previous cgroup
398 if (jail->cgroup) {
399 pakfire_cgroup_unref(jail->cgroup);
400 jail->cgroup = NULL;
401 }
402
403 // Set any new cgroup
404 if (cgroup) {
405 DEBUG(jail->pakfire, "Setting cgroup %p\n", cgroup);
406
407 jail->cgroup = pakfire_cgroup_ref(cgroup);
408 }
409
410 // Done
411 return 0;
412 }
413
414 // Environment
415
416 // Returns the length of the environment
417 static unsigned int pakfire_jail_env_length(struct pakfire_jail* jail) {
418 unsigned int i = 0;
419
420 // Count everything in the environment
421 for (char** e = jail->env; *e; e++)
422 i++;
423
424 return i;
425 }
426
427 // Finds an existing environment variable and returns its index or -1 if not found
428 static int pakfire_jail_find_env(struct pakfire_jail* jail, const char* key) {
429 if (!key) {
430 errno = EINVAL;
431 return -1;
432 }
433
434 const size_t length = strlen(key);
435
436 for (unsigned int i = 0; jail->env[i]; i++) {
437 if ((pakfire_string_startswith(jail->env[i], key)
438 && *(jail->env[i] + length) == '=')) {
439 return i;
440 }
441 }
442
443 // Nothing found
444 return -1;
445 }
446
447 // Returns the value of an environment variable or NULL
448 PAKFIRE_EXPORT const char* pakfire_jail_get_env(struct pakfire_jail* jail,
449 const char* key) {
450 int i = pakfire_jail_find_env(jail, key);
451 if (i < 0)
452 return NULL;
453
454 return jail->env[i] + strlen(key) + 1;
455 }
456
457 // Sets an environment variable
458 PAKFIRE_EXPORT int pakfire_jail_set_env(struct pakfire_jail* jail,
459 const char* key, const char* value) {
460 // Find the index where to write this value to
461 int i = pakfire_jail_find_env(jail, key);
462 if (i < 0)
463 i = pakfire_jail_env_length(jail);
464
465 // Return -ENOSPC when the environment is full
466 if (i >= ENVIRON_SIZE) {
467 errno = ENOSPC;
468 return -1;
469 }
470
471 // Free any previous value
472 if (jail->env[i])
473 free(jail->env[i]);
474
475 // Format and set environment variable
476 asprintf(&jail->env[i], "%s=%s", key, value);
477
478 DEBUG(jail->pakfire, "Set environment variable: %s\n", jail->env[i]);
479
480 return 0;
481 }
482
483 // Imports an environment
484 PAKFIRE_EXPORT int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]) {
485 if (!env)
486 return 0;
487
488 char* key;
489 char* val;
490 int r;
491
492 // Copy environment variables
493 for (unsigned int i = 0; env[i]; i++) {
494 r = pakfire_string_partition(env[i], "=", &key, &val);
495 if (r)
496 continue;
497
498 // Set value
499 r = pakfire_jail_set_env(jail, key, val);
500
501 if (key)
502 free(key);
503 if (val)
504 free(val);
505
506 // Break on error
507 if (r)
508 return r;
509 }
510
511 return 0;
512 }
513
514 // Timeout
515
516 PAKFIRE_EXPORT int pakfire_jail_set_timeout(
517 struct pakfire_jail* jail, unsigned int timeout) {
518 // Store value
519 jail->timeout.it_value.tv_sec = timeout;
520
521 if (timeout > 0)
522 DEBUG(jail->pakfire, "Timeout set to %u second(s)\n", timeout);
523 else
524 DEBUG(jail->pakfire, "Timeout disabled\n");
525
526 return 0;
527 }
528
529 static int pakfire_jail_create_timer(struct pakfire_jail* jail) {
530 int r;
531
532 // Nothing to do if no timeout has been set
533 if (!jail->timeout.it_value.tv_sec)
534 return -1;
535
536 // Create a new timer
537 const int fd = timerfd_create(CLOCK_MONOTONIC, 0);
538 if (fd < 0) {
539 ERROR(jail->pakfire, "Could not create timer: %m\n");
540 goto ERROR;
541 }
542
543 // Arm timer
544 r = timerfd_settime(fd, 0, &jail->timeout, NULL);
545 if (r) {
546 ERROR(jail->pakfire, "Could not arm timer: %m\n");
547 goto ERROR;
548 }
549
550 return fd;
551
552 ERROR:
553 if (fd >= 0)
554 close(fd);
555
556 return -1;
557 }
558
559 /*
560 This function replaces any logging in the child process.
561
562 All log messages will be sent to the parent process through their respective pipes.
563 */
564 static void pakfire_jail_log_redirect(void* data, int priority, const char* file,
565 int line, const char* fn, const char* format, va_list args) {
566 struct pakfire_jail_pipes* pipes = (struct pakfire_jail_pipes*)data;
567 int fd;
568
569 switch (priority) {
570 case LOG_INFO:
571 fd = pipes->log_INFO[1];
572 break;
573
574 case LOG_ERR:
575 fd = pipes->log_ERROR[1];
576 break;
577
578 #ifdef ENABLE_DEBUG
579 case LOG_DEBUG:
580 fd = pipes->log_DEBUG[1];
581 break;
582 #endif /* ENABLE_DEBUG */
583
584 // Ignore any messages of an unknown priority
585 default:
586 return;
587 }
588
589 // Send the log message
590 if (fd >= 0)
591 vdprintf(fd, format, args);
592 }
593
594 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer* buffer) {
595 return (sizeof(buffer->data) == buffer->used);
596 }
597
598 /*
599 This function reads as much data as it can from the file descriptor.
600 If it finds a whole line in it, it will send it to the logger and repeat the process.
601 If not newline character is found, it will try to read more data until it finds one.
602 */
603 static int pakfire_jail_handle_log(struct pakfire_jail* jail,
604 struct pakfire_jail_exec* ctx, int priority, int fd,
605 struct pakfire_log_buffer* buffer, pakfire_jail_communicate_out callback, void* data) {
606 char line[BUFFER_SIZE + 1];
607
608 // Fill up buffer from fd
609 if (buffer->used < sizeof(buffer->data)) {
610 ssize_t bytes_read = read(fd, buffer->data + buffer->used,
611 sizeof(buffer->data) - buffer->used);
612
613 // Handle errors
614 if (bytes_read < 0) {
615 ERROR(jail->pakfire, "Could not read from fd %d: %m\n", fd);
616 return -1;
617 }
618
619 // Update buffer size
620 buffer->used += bytes_read;
621 }
622
623 // See if we have any lines that we can write
624 while (buffer->used) {
625 // Search for the end of the first line
626 char* eol = memchr(buffer->data, '\n', buffer->used);
627
628 // No newline found
629 if (!eol) {
630 // If the buffer is full, we send the content to the logger and try again
631 // This should not happen in practise
632 if (pakfire_jail_log_buffer_is_full(buffer)) {
633 DEBUG(jail->pakfire, "Logging buffer is full. Sending all content\n");
634
635 eol = buffer->data + sizeof(buffer->data) - 1;
636
637 // Otherwise we might have only read parts of the output
638 } else
639 break;
640 }
641
642 // Find the length of the string
643 size_t length = eol - buffer->data + 1;
644
645 // Copy the line into the buffer
646 memcpy(line, buffer->data, length);
647
648 // Terminate the string
649 line[length] = '\0';
650
651 // Log the line
652 if (callback) {
653 int r = callback(jail->pakfire, data, priority, line, length);
654 if (r) {
655 ERROR(jail->pakfire, "The logging callback returned an error: %d\n", r);
656 return r;
657 }
658 }
659
660 // Remove line from buffer
661 memmove(buffer->data, buffer->data + length, buffer->used - length);
662 buffer->used -= length;
663 }
664
665 return 0;
666 }
667
668 #if 0
669 static int pakfire_jail_stream_stdin(struct pakfire_jail* jail,
670 struct pakfire_jail_exec* ctx, const int fd) {
671 int r;
672
673 // Nothing to do if there is no stdin callback set
674 if (!ctx->communicate.in) {
675 DEBUG(jail->pakfire, "Callback for standard input is not set\n");
676 return 0;
677 }
678
679 // Skip if the writing pipe has already been closed
680 if (ctx->pipes.stdin[1] < 0)
681 return 0;
682
683 DEBUG(jail->pakfire, "Streaming standard input...\n");
684
685 // Calling the callback
686 r = ctx->communicate.in(jail->pakfire, ctx->communicate.data, fd);
687
688 DEBUG(jail->pakfire, "Standard input callback finished: %d\n", r);
689
690 // The callback signaled that it has written everything
691 if (r == EOF) {
692 DEBUG(jail->pakfire, "Closing standard input pipe\n");
693
694 // Close the file-descriptor
695 close(fd);
696
697 // Reset the file-descriptor so it won't be closed again later
698 ctx->pipes.stdin[1] = -1;
699
700 // Report success
701 r = 0;
702 }
703
704 return r;
705 }
706 #endif
707
708 static int pakfire_jail_recv_fd(struct pakfire_jail* jail, int socket, int* fd) {
709 const size_t payload_length = sizeof(fd);
710 char buffer[CMSG_SPACE(payload_length)];
711 int r;
712
713 struct msghdr msg = {
714 .msg_control = buffer,
715 .msg_controllen = sizeof(buffer),
716 };
717
718 // Receive the message
719 r = recvmsg(socket, &msg, 0);
720 if (r) {
721 CTX_ERROR(jail->ctx, "Could not receive file descriptor: %s\n", strerror(errno));
722 return -errno;
723 }
724
725 // Fetch the payload
726 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
727 if (!cmsg)
728 return -EBADMSG;
729
730 *fd = *((int*)CMSG_DATA(cmsg));
731
732 CTX_DEBUG(jail->ctx, "Received fd %d from socket %d\n", *fd, socket);
733
734 return 0;
735 }
736
737 static int pakfire_jail_send_fd(struct pakfire_jail* jail, int socket, int fd) {
738 const size_t payload_length = sizeof(fd);
739 char buffer[CMSG_SPACE(payload_length)];
740 int r;
741
742 CTX_DEBUG(jail->ctx, "Sending fd %d to socket %d\n", fd, socket);
743
744 // Header
745 struct msghdr msg = {
746 .msg_control = buffer,
747 .msg_controllen = sizeof(buffer),
748 };
749
750 // Payload
751 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
752 cmsg->cmsg_level = SOL_SOCKET;
753 cmsg->cmsg_type = SCM_RIGHTS;
754 cmsg->cmsg_len = CMSG_LEN(payload_length);
755
756 // Set payload
757 *((int*)CMSG_DATA(cmsg)) = fd;
758
759 // Send the message
760 r = sendmsg(socket, &msg, 0);
761 if (r) {
762 CTX_ERROR(jail->ctx, "Could not send file descriptor: %s\n", strerror(errno));
763 return -errno;
764 }
765
766 return 0;
767 }
768
769 static int pakfire_jail_setup_pipe(struct pakfire_jail* jail, int (*fds)[2], const int flags) {
770 int r = pipe2(*fds, flags);
771 if (r < 0) {
772 ERROR(jail->pakfire, "Could not setup pipe: %m\n");
773 return 1;
774 }
775
776 return 0;
777 }
778
779 static void pakfire_jail_close_pipe(struct pakfire_jail* jail, int fds[2]) {
780 for (unsigned int i = 0; i < 2; i++)
781 if (fds[i] >= 0)
782 close(fds[i]);
783 }
784
785 /*
786 This is a convenience function to fetch the reading end of a pipe and
787 closes the write end.
788 */
789 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail* jail, int (*fds)[2]) {
790 // Give the variables easier names to avoid confusion
791 int* fd_read = &(*fds)[0];
792 int* fd_write = &(*fds)[1];
793
794 // Close the write end of the pipe
795 if (*fd_write >= 0) {
796 close(*fd_write);
797 *fd_write = -1;
798 }
799
800 // Return the read end
801 if (*fd_read >= 0)
802 return *fd_read;
803
804 return -1;
805 }
806
807 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail* jail, int (*fds)[2]) {
808 // Give the variables easier names to avoid confusion
809 int* fd_read = &(*fds)[0];
810 int* fd_write = &(*fds)[1];
811
812 // Close the read end of the pipe
813 if (*fd_read >= 0) {
814 close(*fd_read);
815 *fd_read = -1;
816 }
817
818 // Return the write end
819 if (*fd_write >= 0)
820 return *fd_write;
821
822 return -1;
823 }
824
825 static int pakfire_jail_log(struct pakfire* pakfire, void* data, int priority,
826 const char* line, const size_t length) {
827 // Pass everything to the parent logger
828 pakfire_log_condition(pakfire, priority, 0, "%.*s", (int)length, line);
829
830 return 0;
831 }
832
833 static int pakfire_jail_epoll_add_fd(struct pakfire_jail* jail, int epollfd, int fd, int events) {
834 struct epoll_event event = {
835 .events = events|EPOLLHUP,
836 .data = {
837 .fd = fd,
838 },
839 };
840 int r;
841
842 // Read flags
843 int flags = fcntl(fd, F_GETFL, 0);
844
845 // Set modified flags
846 r = fcntl(fd, F_SETFL, flags|O_NONBLOCK);
847 if (r < 0) {
848 CTX_ERROR(jail->ctx, "Could not set file descriptor %d into non-blocking mode: %s\n",
849 fd, strerror(errno));
850 return -errno;
851 }
852
853 // Add the file descriptor to the loop
854 r = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
855 if (r < 0) {
856 ERROR(jail->pakfire, "Could not add file descriptor %d to epoll(): %s\n",
857 fd, strerror(errno));
858 return -errno;
859 }
860
861 return 0;
862 }
863
864 // PTY Forwarding
865
866 static int pakfire_jail_enable_raw_mode(struct pakfire_jail* jail,
867 struct pakfire_jail_pty_stdio* stdio) {
868 struct termios raw_attrs;
869 int r;
870
871 // Store flags
872 stdio->fdflags = fcntl(stdio->fd, F_GETFL);
873 if (stdio->fdflags < 0) {
874 CTX_ERROR(jail->ctx, "Could not fetch flags from fd %d: %s\n",
875 stdio->fd, strerror(errno));
876 return -errno;
877 }
878
879 // Fetch all attributes
880 r = tcgetattr(stdio->fd, &stdio->attrs);
881 if (r) {
882 CTX_ERROR(jail->ctx, "Could not fetch terminal attributes from fd %d: %s\n",
883 stdio->fd, strerror(errno));
884 return -errno;
885 }
886
887 // Copy all attributes
888 raw_attrs = stdio->attrs;
889
890 // Make it RAW
891 cfmakeraw(&raw_attrs);
892
893 switch (stdio->fd) {
894 case STDIN_FILENO:
895 raw_attrs.c_oflag = stdio->attrs.c_oflag;
896 break;
897
898 case STDOUT_FILENO:
899 raw_attrs.c_iflag = stdio->attrs.c_iflag;
900 raw_attrs.c_lflag = stdio->attrs.c_lflag;
901 break;
902 }
903
904 // Restore the attributes
905 r = tcsetattr(stdio->fd, TCSANOW, &raw_attrs);
906 if (r) {
907 CTX_ERROR(jail->ctx, "Could not restore terminal attributes for fd %d: %s\n",
908 stdio->fd, strerror(errno));
909 return -errno;
910 }
911
912 return 0;
913 }
914
915 static int pakfire_jail_restore_attrs(struct pakfire_jail* jail,
916 const struct pakfire_jail_pty_stdio* stdio) {
917 int r;
918
919 // Restore the flags
920 r = fcntl(stdio->fd, F_SETFL, stdio->fdflags);
921 if (r < 0) {
922 CTX_ERROR(jail->ctx, "Could not set flags for file descriptor %d: %s\n",
923 stdio->fd, strerror(errno));
924 return -errno;
925 }
926
927 // Restore the attributes
928 r = tcsetattr(stdio->fd, TCSANOW, &stdio->attrs);
929 if (r) {
930 CTX_ERROR(jail->ctx, "Could not restore terminal attributes for %d, ignoring: %s\n",
931 stdio->fd, strerror(errno));
932 return -errno;
933 }
934
935 return 0;
936 }
937
938 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail* jail,
939 struct pakfire_jail_exec* ctx, const int epollfd, const int fd) {
940 struct winsize size;
941 int r;
942
943 CTX_DEBUG(jail->ctx, "Setting up PTY forwarding on fd %d\n", fd);
944
945 // Store the file descriptor
946 ctx->pty.master.fd = fd;
947
948 // Configure stdin/stdout
949 ctx->pty.stdin.fd = STDIN_FILENO;
950 ctx->pty.stdout.fd = STDOUT_FILENO;
951
952 // Fetch dimensions
953 r = ioctl(ctx->pty.stdout.fd, TIOCGWINSZ, &size);
954 if (r) {
955 CTX_ERROR(jail->ctx, "Failed to determine terminal dimensions: %s\n", strerror(errno));
956 return -errno;
957 }
958
959 // Set dimensions
960 r = ioctl(ctx->pty.master.fd, TIOCSWINSZ, &size);
961 if (r) {
962 CTX_ERROR(jail->ctx, "Failed setting dimensions: %s\n", strerror(errno));
963 return -errno;
964 }
965
966 // Enable RAW mode on standard input
967 r = pakfire_jail_enable_raw_mode(jail, &ctx->pty.stdin);
968 if (r)
969 return r;
970
971 // Enable RAW mode on standard output
972 r = pakfire_jail_enable_raw_mode(jail, &ctx->pty.stdout);
973 if (r)
974 return r;
975
976 // Add the master to the event loop
977 r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.master.fd, EPOLLIN|EPOLLOUT|EPOLLET);
978 if (r)
979 return r;
980
981 // Add standard input to the event loop
982 r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.stdin.fd, EPOLLIN|EPOLLET);
983 if (r)
984 return r;
985
986 // Add standard output to the event loop
987 r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.stdout.fd, EPOLLOUT|EPOLLET);
988 if (r)
989 return r;
990
991 return 0;
992 }
993
994 static int pakfire_jail_fill_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
995 int r;
996
997 // Skip this if there is not space left in the buffer
998 if (buffer->used >= sizeof(buffer->data))
999 return 0;
1000
1001 // Fill the buffer
1002 r = read(fd, buffer->data + buffer->used, sizeof(buffer->data) - buffer->used);
1003
1004 // Handle errors
1005 if (r < 0) {
1006 switch (errno) {
1007 case EAGAIN:
1008 case EIO:
1009 break;
1010
1011 default:
1012 return -errno;
1013 }
1014
1015 // EOF
1016 } else if (r == 0) {
1017 // XXX What to do here?
1018
1019 // Successful read
1020 } else {
1021 buffer->used += r;
1022 }
1023
1024 return 0;
1025 }
1026
1027 static int pakfire_jail_drain_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
1028 int r;
1029
1030 // Nothing to do if the buffer is empty
1031 if (!buffer->used)
1032 return 0;
1033
1034 // Drain the buffer
1035 r = write(fd, buffer->data, buffer->used);
1036
1037 // Handle errors
1038 if (r < 0) {
1039 switch (errno) {
1040 case EAGAIN:
1041 case EIO:
1042 break;
1043
1044 default:
1045 return -errno;
1046 }
1047
1048 // Successful write
1049 } else {
1050 memmove(buffer->data, buffer->data + r, buffer->used - r);
1051
1052 buffer->used -= r;
1053 }
1054
1055 return 0;
1056 }
1057
1058 static int pakfire_jail_forward_pty(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1059 int r;
1060
1061 // Read from standard input
1062 if (ctx->pty.stdin.flags & PAKFIRE_JAIL_PTY_READY_TO_READ) {
1063 r = pakfire_jail_fill_buffer(jail, ctx->pty.stdin.fd, &ctx->pty.stdin.buffer);
1064 if (r) {
1065 CTX_ERROR(jail->ctx, "Failed reading from standard input: %s\n", strerror(-r));
1066 return r;
1067 }
1068
1069 // We are done reading for now
1070 ctx->pty.stdin.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_READ;
1071
1072 // But we may have data to write
1073 if (ctx->pty.stdin.buffer.used)
1074 ctx->pty.master.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1075 }
1076
1077 // Write to the master
1078 if (ctx->pty.master.flags & PAKFIRE_JAIL_PTY_READY_TO_WRITE) {
1079 r = pakfire_jail_drain_buffer(jail, ctx->pty.master.fd, &ctx->pty.stdin.buffer);
1080 if (r) {
1081 CTX_ERROR(jail->ctx, "Failed writing to the PTY: %s\n", strerror(-r));
1082 return r;
1083 }
1084
1085 // We are done writing for now
1086 ctx->pty.master.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1087 }
1088
1089 // Read from the master
1090 if (ctx->pty.master.flags & PAKFIRE_JAIL_PTY_READY_TO_READ) {
1091 r = pakfire_jail_fill_buffer(jail, ctx->pty.master.fd, &ctx->pty.stdout.buffer);
1092 if (r) {
1093 CTX_ERROR(jail->ctx, "Failed reading from the PTY: %s\n", strerror(-r));
1094 return r;
1095 }
1096
1097 // We are done reading for now
1098 ctx->pty.master.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_READ;
1099
1100 // But we may have data to write
1101 if (ctx->pty.stdout.buffer.used)
1102 ctx->pty.stdout.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1103 }
1104
1105 // Write to standard output
1106 if (ctx->pty.stdout.flags & PAKFIRE_JAIL_PTY_READY_TO_WRITE) {
1107 r = pakfire_jail_drain_buffer(jail, ctx->pty.stdout.fd, &ctx->pty.stdout.buffer);
1108 if (r) {
1109 CTX_ERROR(jail->ctx, "Failed writing to standard output: %s\n", strerror(-r));
1110 return r;
1111 }
1112
1113 // We are done writing for now
1114 ctx->pty.stdout.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1115 }
1116
1117 return 0;
1118 }
1119
1120 static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1121 int epollfd = -1;
1122 struct epoll_event events[EPOLL_MAX_EVENTS];
1123 char garbage[8];
1124 int r = 0;
1125
1126 // Fetch file descriptors from context
1127 const int pidfd = ctx->pidfd;
1128
1129 // Fetch the UNIX domain socket
1130 const int socket_recv = pakfire_jail_get_pipe_to_read(jail, &ctx->socket);
1131
1132 // Timer
1133 const int timerfd = pakfire_jail_create_timer(jail);
1134
1135 // Logging
1136 const int log_INFO = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_INFO);
1137 const int log_ERROR = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_ERROR);
1138 #ifdef ENABLE_DEBUG
1139 const int log_DEBUG = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_DEBUG);
1140 #endif /* ENABLE_DEBUG */
1141
1142 // Make a list of all file descriptors we are interested in
1143 const struct pakfire_wait_fds {
1144 const int fd;
1145 const int events;
1146 } fds[] = {
1147 // Timer
1148 { timerfd, EPOLLIN },
1149
1150 // Child Process
1151 { ctx->pidfd, EPOLLIN },
1152
1153 // Log Pipes
1154 { log_INFO, EPOLLIN },
1155 { log_ERROR, EPOLLIN },
1156 #ifdef ENABLE_DEBUG
1157 { log_DEBUG, EPOLLIN },
1158 #endif /* ENABLE_DEBUG */
1159
1160 // UNIX Domain Socket
1161 { socket_recv, EPOLLIN },
1162
1163 // Sentinel
1164 { -1, 0 },
1165 };
1166
1167 // Setup epoll
1168 epollfd = epoll_create1(0);
1169 if (epollfd < 0) {
1170 ERROR(jail->pakfire, "Could not initialize epoll(): %m\n");
1171 r = 1;
1172 goto ERROR;
1173 }
1174
1175 // Turn file descriptors into non-blocking mode and add them to epoll()
1176 for (const struct pakfire_wait_fds* fd = fds; fd->events; fd++) {
1177 // Skip fds which were not initialized
1178 if (fd->fd < 0)
1179 continue;
1180
1181 // Add the FD to the event loop
1182 r = pakfire_jail_epoll_add_fd(jail, epollfd, fd->fd, fd->events);
1183 if (r)
1184 goto ERROR;
1185 }
1186
1187 int ended = 0;
1188
1189 // Loop for as long as the process is alive
1190 while (!ended) {
1191 int num = epoll_wait(epollfd, events, EPOLL_MAX_EVENTS, -1);
1192 if (num < 1) {
1193 // Ignore if epoll_wait() has been interrupted
1194 if (errno == EINTR)
1195 continue;
1196
1197 ERROR(jail->pakfire, "epoll_wait() failed: %m\n");
1198 r = 1;
1199
1200 goto ERROR;
1201 }
1202
1203 for (int i = 0; i < num; i++) {
1204 int e = events[i].events;
1205 int fd = events[i].data.fd;
1206
1207 // Handle PTY forwarding events
1208 if (ctx->pty.master.fd == fd) {
1209 if (e & (EPOLLIN|EPOLLHUP))
1210 ctx->pty.master.flags |= PAKFIRE_JAIL_PTY_READY_TO_READ;
1211
1212 if (e & (EPOLLOUT|EPOLLHUP))
1213 ctx->pty.master.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1214
1215 // Perform the work
1216 r = pakfire_jail_forward_pty(jail, ctx);
1217 if (r) {
1218 CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
1219 goto ERROR;
1220 }
1221
1222 // Handle standard input
1223 } else if (ctx->pty.stdin.fd == fd) {
1224 if (e & (EPOLLIN|EPOLLHUP))
1225 ctx->pty.stdin.flags |= PAKFIRE_JAIL_PTY_READY_TO_READ;
1226
1227 // Perform the work
1228 r = pakfire_jail_forward_pty(jail, ctx);
1229 if (r) {
1230 CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
1231 goto ERROR;
1232 }
1233
1234 // Handle standard output
1235 } else if (ctx->pty.stdout.fd == fd) {
1236 if (e & (EPOLLOUT|EPOLLHUP))
1237 ctx->pty.stdout.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1238
1239 // Perform the work
1240 r = pakfire_jail_forward_pty(jail, ctx);
1241 if (r) {
1242 CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
1243 goto ERROR;
1244 }
1245
1246 // Handle any changes to the PIDFD
1247 } else if (pidfd == fd) {
1248 if (e & EPOLLIN) {
1249 // Call waidid() and store the result
1250 r = waitid(P_PIDFD, ctx->pidfd, &ctx->status, WEXITED);
1251 if (r) {
1252 ERROR(jail->pakfire, "waitid() failed: %m\n");
1253 goto ERROR;
1254 }
1255
1256 // Mark that we have ended so that we will process the remaining
1257 // events from epoll() now, but won't restart the outer loop.
1258 ended = 1;
1259 }
1260
1261 // Handle timer events
1262 } else if (timerfd == fd) {
1263 if (e & EPOLLIN) {
1264 DEBUG(jail->pakfire, "Timer event received\n");
1265
1266 // Disarm the timer
1267 r = read(timerfd, garbage, sizeof(garbage));
1268 if (r < 1) {
1269 ERROR(jail->pakfire, "Could not disarm timer: %m\n");
1270 r = 1;
1271 goto ERROR;
1272 }
1273
1274 // Terminate the process if it hasn't already ended
1275 if (!ended) {
1276 DEBUG(jail->pakfire, "Terminating process...\n");
1277
1278 // Send SIGTERM to the process
1279 r = pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
1280 if (r) {
1281 ERROR(jail->pakfire, "Could not kill process: %m\n");
1282 goto ERROR;
1283 }
1284 }
1285 }
1286
1287 // Handle socket messages
1288 } else if (socket_recv == fd) {
1289 if (e & EPOLLIN) {
1290 // Receive the passed FD
1291 r = pakfire_jail_recv_fd(jail, socket_recv, &fd);
1292 if (r)
1293 goto ERROR;
1294
1295 // Setup PTY forwarding
1296 if (ctx->pty.master.fd < 0) {
1297 r = pakfire_jail_setup_pty_forwarding(jail, ctx, epollfd, fd);
1298 if (r) {
1299 CTX_ERROR(jail->ctx, "Failed setting up PTY forwarding: %s\n", strerror(-r));
1300 goto ERROR;
1301 }
1302 }
1303 }
1304
1305 // Handle log INFO messages
1306 } else if (log_INFO == fd) {
1307 if (e & EPOLLIN) {
1308 r = pakfire_jail_handle_log(jail, ctx, LOG_INFO, fd,
1309 &ctx->buffers.log_INFO, pakfire_jail_log, NULL);
1310 if (r)
1311 goto ERROR;
1312 }
1313
1314 // Handle log ERROR messages
1315 } else if (log_ERROR == fd) {
1316 if (e & EPOLLIN) {
1317 r = pakfire_jail_handle_log(jail, ctx, LOG_ERR, fd,
1318 &ctx->buffers.log_ERROR, pakfire_jail_log, NULL);
1319 if (r)
1320 goto ERROR;
1321 }
1322
1323 #ifdef ENABLE_DEBUG
1324 // Handle log DEBUG messages
1325 } else if (log_DEBUG == fd) {
1326 if (e & EPOLLIN) {
1327 r = pakfire_jail_handle_log(jail, ctx, LOG_DEBUG, fd,
1328 &ctx->buffers.log_DEBUG, pakfire_jail_log, NULL);
1329 if (r)
1330 goto ERROR;
1331 }
1332 #endif /* ENABLE_DEBUG */
1333
1334 // Log a message for anything else
1335 } else {
1336 DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
1337 continue;
1338 }
1339
1340 // Check if any file descriptors have been closed
1341 if (e & EPOLLHUP) {
1342 // Remove the file descriptor
1343 r = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
1344 if (r) {
1345 ERROR(jail->pakfire, "Could not remove closed file-descriptor %d: %m\n", fd);
1346 goto ERROR;
1347 }
1348 }
1349 }
1350 }
1351
1352 ERROR:
1353 if (epollfd >= 0)
1354 close(epollfd);
1355 if (timerfd >= 0)
1356 close(timerfd);
1357
1358 // Restore any changed terminal attributes
1359 if (ctx->pty.stdin.fd >= 0)
1360 pakfire_jail_restore_attrs(jail, &ctx->pty.stdin);
1361 if (ctx->pty.stdout.fd >= 0)
1362 pakfire_jail_restore_attrs(jail, &ctx->pty.stdout);
1363
1364 return r;
1365 }
1366
1367 int pakfire_jail_capture_stdout(struct pakfire* pakfire, void* data,
1368 int priority, const char* line, size_t length) {
1369 char** output = (char**)data;
1370 int r;
1371
1372 // Append everything from stdout to a buffer
1373 if (output && priority == LOG_INFO) {
1374 r = asprintf(output, "%s%s", (output && *output) ? *output : "", line);
1375 if (r < 0)
1376 return 1;
1377 return 0;
1378 }
1379
1380 // Send everything else to the default logger
1381 return pakfire_jail_default_log_callback(pakfire, NULL, priority, line, length);
1382 }
1383
1384 // Capabilities
1385
1386 // Logs all capabilities of the current process
1387 static int pakfire_jail_show_capabilities(struct pakfire_jail* jail) {
1388 cap_t caps = NULL;
1389 char* name = NULL;
1390 cap_flag_value_t value_e;
1391 cap_flag_value_t value_i;
1392 cap_flag_value_t value_p;
1393 int r;
1394
1395 // Fetch PID
1396 pid_t pid = getpid();
1397
1398 // Fetch all capabilities
1399 caps = cap_get_proc();
1400 if (!caps) {
1401 ERROR(jail->pakfire, "Could not fetch capabilities: %m\n");
1402 r = 1;
1403 goto ERROR;
1404 }
1405
1406 DEBUG(jail->pakfire, "Capabilities of PID %d:\n", pid);
1407
1408 // Iterate over all capabilities
1409 for (unsigned int cap = 0; cap_valid(cap); cap++) {
1410 name = cap_to_name(cap);
1411
1412 // Fetch effective value
1413 r = cap_get_flag(caps, cap, CAP_EFFECTIVE, &value_e);
1414 if (r)
1415 goto ERROR;
1416
1417 // Fetch inheritable value
1418 r = cap_get_flag(caps, cap, CAP_INHERITABLE, &value_i);
1419 if (r)
1420 goto ERROR;
1421
1422 // Fetch permitted value
1423 r = cap_get_flag(caps, cap, CAP_PERMITTED, &value_p);
1424 if (r)
1425 goto ERROR;
1426
1427 DEBUG(jail->pakfire,
1428 " %-24s : %c%c%c\n",
1429 name,
1430 (value_e == CAP_SET) ? 'e' : '-',
1431 (value_i == CAP_SET) ? 'i' : '-',
1432 (value_p == CAP_SET) ? 'p' : '-'
1433 );
1434
1435 // Free name
1436 cap_free(name);
1437 name = NULL;
1438 }
1439
1440 // Success
1441 r = 0;
1442
1443 ERROR:
1444 if (name)
1445 cap_free(name);
1446 if (caps)
1447 cap_free(caps);
1448
1449 return r;
1450 }
1451
1452 static int pakfire_jail_set_capabilities(struct pakfire_jail* jail) {
1453 cap_t caps = NULL;
1454 char* name = NULL;
1455 int r;
1456
1457 // Fetch capabilities
1458 caps = cap_get_proc();
1459 if (!caps) {
1460 ERROR(jail->pakfire, "Could not read capabilities: %m\n");
1461 r = 1;
1462 goto ERROR;
1463 }
1464
1465 // Walk through all capabilities
1466 for (cap_value_t cap = 0; cap_valid(cap); cap++) {
1467 cap_value_t _caps[] = { cap };
1468
1469 // Fetch the name of the capability
1470 name = cap_to_name(cap);
1471
1472 r = cap_set_flag(caps, CAP_EFFECTIVE, 1, _caps, CAP_SET);
1473 if (r) {
1474 ERROR(jail->pakfire, "Could not set %s: %m\n", name);
1475 goto ERROR;
1476 }
1477
1478 r = cap_set_flag(caps, CAP_INHERITABLE, 1, _caps, CAP_SET);
1479 if (r) {
1480 ERROR(jail->pakfire, "Could not set %s: %m\n", name);
1481 goto ERROR;
1482 }
1483
1484 r = cap_set_flag(caps, CAP_PERMITTED, 1, _caps, CAP_SET);
1485 if (r) {
1486 ERROR(jail->pakfire, "Could not set %s: %m\n", name);
1487 goto ERROR;
1488 }
1489
1490 // Free name
1491 cap_free(name);
1492 name = NULL;
1493 }
1494
1495 // Restore all capabilities
1496 r = cap_set_proc(caps);
1497 if (r) {
1498 ERROR(jail->pakfire, "Restoring capabilities failed: %m\n");
1499 goto ERROR;
1500 }
1501
1502 // Add all capabilities to the ambient set
1503 for (unsigned int cap = 0; cap_valid(cap); cap++) {
1504 name = cap_to_name(cap);
1505
1506 // Raise the capability
1507 r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
1508 if (r) {
1509 ERROR(jail->pakfire, "Could not set ambient capability %s: %m\n", name);
1510 goto ERROR;
1511 }
1512
1513 // Free name
1514 cap_free(name);
1515 name = NULL;
1516 }
1517
1518 // Success
1519 r = 0;
1520
1521 ERROR:
1522 if (name)
1523 cap_free(name);
1524 if (caps)
1525 cap_free(caps);
1526
1527 return r;
1528 }
1529
1530 // Syscall Filter
1531
1532 static int pakfire_jail_limit_syscalls(struct pakfire_jail* jail) {
1533 const int syscalls[] = {
1534 // The kernel's keyring isn't namespaced
1535 SCMP_SYS(keyctl),
1536 SCMP_SYS(add_key),
1537 SCMP_SYS(request_key),
1538
1539 // Disable userfaultfd
1540 SCMP_SYS(userfaultfd),
1541
1542 // Disable perf which could leak a lot of information about the host
1543 SCMP_SYS(perf_event_open),
1544
1545 0,
1546 };
1547 int r = 1;
1548
1549 DEBUG(jail->pakfire, "Applying syscall filter...\n");
1550
1551 // Setup a syscall filter which allows everything by default
1552 scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
1553 if (!ctx) {
1554 ERROR(jail->pakfire, "Could not setup seccomp filter: %m\n");
1555 goto ERROR;
1556 }
1557
1558 // All all syscalls
1559 for (const int* syscall = syscalls; *syscall; syscall++) {
1560 r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), *syscall, 0);
1561 if (r) {
1562 ERROR(jail->pakfire, "Could not configure syscall %d: %m\n", *syscall);
1563 goto ERROR;
1564 }
1565 }
1566
1567 // Load syscall filter into the kernel
1568 r = seccomp_load(ctx);
1569 if (r) {
1570 ERROR(jail->pakfire, "Could not load syscall filter into the kernel: %m\n");
1571 goto ERROR;
1572 }
1573
1574 ERROR:
1575 if (ctx)
1576 seccomp_release(ctx);
1577
1578 return r;
1579 }
1580
1581 // Mountpoints
1582
1583 PAKFIRE_EXPORT int pakfire_jail_bind(struct pakfire_jail* jail,
1584 const char* source, const char* target, int flags) {
1585 struct pakfire_jail_mountpoint* mp = NULL;
1586 int r;
1587
1588 // Check if there is any space left
1589 if (jail->num_mountpoints >= MAX_MOUNTPOINTS) {
1590 errno = ENOSPC;
1591 return 1;
1592 }
1593
1594 // Check for valid inputs
1595 if (!source || !target) {
1596 errno = EINVAL;
1597 return 1;
1598 }
1599
1600 // Select the next free slot
1601 mp = &jail->mountpoints[jail->num_mountpoints];
1602
1603 // Copy source
1604 r = pakfire_string_set(mp->source, source);
1605 if (r) {
1606 ERROR(jail->pakfire, "Could not copy source: %m\n");
1607 return r;
1608 }
1609
1610 // Copy target
1611 r = pakfire_string_set(mp->target, target);
1612 if (r) {
1613 ERROR(jail->pakfire, "Could not copy target: %m\n");
1614 return r;
1615 }
1616
1617 // Copy flags
1618 mp->flags = flags;
1619
1620 // Increment counter
1621 jail->num_mountpoints++;
1622
1623 return 0;
1624 }
1625
1626 static int pakfire_jail_mount_networking(struct pakfire_jail* jail) {
1627 int r;
1628
1629 const char* paths[] = {
1630 "/etc/hosts",
1631 "/etc/resolv.conf",
1632 NULL,
1633 };
1634
1635 // Bind-mount all paths read-only
1636 for (const char** path = paths; *path; path++) {
1637 r = pakfire_bind(jail->pakfire, *path, NULL, MS_RDONLY);
1638 if (r) {
1639 switch (errno) {
1640 // Ignore if we don't have permission
1641 case EPERM:
1642 continue;
1643
1644 default:
1645 break;
1646 }
1647 return r;
1648 }
1649 }
1650
1651 return 0;
1652 }
1653
1654 /*
1655 Mounts everything that we require in the new namespace
1656 */
1657 static int pakfire_jail_mount(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1658 struct pakfire_jail_mountpoint* mp = NULL;
1659 int flags = 0;
1660 int r;
1661
1662 // Enable loop devices
1663 if (pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_LOOP_DEVICES))
1664 flags |= PAKFIRE_MOUNT_LOOP_DEVICES;
1665
1666 // Mount all default stuff
1667 r = pakfire_mount_all(jail->pakfire, PAKFIRE_MNTNS_OUTER, flags);
1668 if (r)
1669 return r;
1670
1671 // Populate /dev
1672 r = pakfire_populate_dev(jail->pakfire, flags);
1673 if (r)
1674 return r;
1675
1676 // Mount the interpreter (if needed)
1677 r = pakfire_mount_interpreter(jail->pakfire);
1678 if (r)
1679 return r;
1680
1681 // Mount networking stuff
1682 if (pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
1683 r = pakfire_jail_mount_networking(jail);
1684 if (r)
1685 return r;
1686 }
1687
1688 // Mount all custom stuff
1689 for (unsigned int i = 0; i < jail->num_mountpoints; i++) {
1690 // Fetch mountpoint
1691 mp = &jail->mountpoints[i];
1692
1693 // Mount it
1694 r = pakfire_bind(jail->pakfire, mp->source, mp->target, mp->flags);
1695 if (r)
1696 return r;
1697 }
1698
1699 return 0;
1700 }
1701
1702 // Networking
1703
1704 static int pakfire_jail_setup_loopback(struct pakfire_jail* jail) {
1705 struct nl_sock* nl = NULL;
1706 struct nl_cache* cache = NULL;
1707 struct rtnl_link* link = NULL;
1708 struct rtnl_link* change = NULL;
1709 int r;
1710
1711 DEBUG(jail->pakfire, "Setting up loopback...\n");
1712
1713 // Allocate a netlink socket
1714 nl = nl_socket_alloc();
1715 if (!nl) {
1716 ERROR(jail->pakfire, "Could not allocate a netlink socket: %m\n");
1717 r = 1;
1718 goto ERROR;
1719 }
1720
1721 // Connect the socket
1722 r = nl_connect(nl, NETLINK_ROUTE);
1723 if (r) {
1724 ERROR(jail->pakfire, "Could not connect netlink socket: %s\n", nl_geterror(r));
1725 goto ERROR;
1726 }
1727
1728 // Allocate the netlink cache
1729 r = rtnl_link_alloc_cache(nl, AF_UNSPEC, &cache);
1730 if (r < 0) {
1731 ERROR(jail->pakfire, "Unable to allocate netlink cache: %s\n", nl_geterror(r));
1732 goto ERROR;
1733 }
1734
1735 // Fetch loopback interface
1736 link = rtnl_link_get_by_name(cache, "lo");
1737 if (!link) {
1738 ERROR(jail->pakfire, "Could not find lo interface. Ignoring.\n");
1739 r = 0;
1740 goto ERROR;
1741 }
1742
1743 // Allocate a new link
1744 change = rtnl_link_alloc();
1745 if (!change) {
1746 ERROR(jail->pakfire, "Could not allocate change link\n");
1747 r = 1;
1748 goto ERROR;
1749 }
1750
1751 // Set the link to UP
1752 rtnl_link_set_flags(change, IFF_UP);
1753
1754 // Apply any changes
1755 r = rtnl_link_change(nl, link, change, 0);
1756 if (r) {
1757 ERROR(jail->pakfire, "Unable to activate loopback: %s\n", nl_geterror(r));
1758 goto ERROR;
1759 }
1760
1761 // Success
1762 r = 0;
1763
1764 ERROR:
1765 if (nl)
1766 nl_socket_free(nl);
1767
1768 return r;
1769 }
1770
1771 // UID/GID Mapping
1772
1773 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail* jail, pid_t pid) {
1774 char path[PATH_MAX];
1775 int r;
1776
1777 // Skip mapping anything when running on /
1778 if (pakfire_on_root(jail->pakfire))
1779 return 0;
1780
1781 // Make path
1782 r = pakfire_string_format(path, "/proc/%d/uid_map", pid);
1783 if (r)
1784 return r;
1785
1786 // Fetch UID
1787 const uid_t uid = pakfire_uid(jail->pakfire);
1788
1789 // Fetch SUBUID
1790 const struct pakfire_subid* subuid = pakfire_subuid(jail->pakfire);
1791 if (!subuid)
1792 return 1;
1793
1794 /* When running as root, we will map the entire range.
1795
1796 When running as a non-privileged user, we will map the root user inside the jail
1797 to the user's UID outside of the jail, and we will map the rest starting from one.
1798 */
1799
1800 // Running as root
1801 if (uid == 0) {
1802 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1803 "0 %lu %lu\n", subuid->id, subuid->length);
1804 } else {
1805 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1806 "0 %lu 1\n1 %lu %lu\n", uid, subuid->id, subuid->length);
1807 }
1808
1809 if (r) {
1810 ERROR(jail->pakfire, "Could not map UIDs: %m\n");
1811 return r;
1812 }
1813
1814 return r;
1815 }
1816
1817 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail* jail, pid_t pid) {
1818 char path[PATH_MAX];
1819 int r;
1820
1821 // Skip mapping anything when running on /
1822 if (pakfire_on_root(jail->pakfire))
1823 return 0;
1824
1825 // Fetch GID
1826 const gid_t gid = pakfire_gid(jail->pakfire);
1827
1828 // Fetch SUBGID
1829 const struct pakfire_subid* subgid = pakfire_subgid(jail->pakfire);
1830 if (!subgid)
1831 return 1;
1832
1833 // Make path
1834 r = pakfire_string_format(path, "/proc/%d/gid_map", pid);
1835 if (r)
1836 return r;
1837
1838 // Running as root
1839 if (gid == 0) {
1840 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1841 "0 %lu %lu\n", subgid->id, subgid->length);
1842 } else {
1843 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1844 "0 %lu 1\n1 %lu %lu\n", gid, subgid->id, subgid->length);
1845 }
1846
1847 if (r) {
1848 ERROR(jail->pakfire, "Could not map GIDs: %m\n");
1849 return r;
1850 }
1851
1852 return r;
1853 }
1854
1855 static int pakfire_jail_setgroups(struct pakfire_jail* jail, pid_t pid) {
1856 char path[PATH_MAX];
1857 int r;
1858
1859 // Make path
1860 r = pakfire_string_format(path, "/proc/%d/setgroups", pid);
1861 if (r)
1862 return r;
1863
1864 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0, "deny\n");
1865 if (r) {
1866 CTX_ERROR(jail->ctx, "Could not set setgroups to deny: %s\n", strerror(errno));
1867 r = -errno;
1868 }
1869
1870 return r;
1871 }
1872
1873 static int pakfire_jail_send_signal(struct pakfire_jail* jail, int fd) {
1874 const uint64_t val = 1;
1875 int r = 0;
1876
1877 DEBUG(jail->pakfire, "Sending signal...\n");
1878
1879 // Write to the file descriptor
1880 r = eventfd_write(fd, val);
1881 if (r < 0) {
1882 ERROR(jail->pakfire, "Could not send signal: %s\n", strerror(errno));
1883 r = -errno;
1884 }
1885
1886 // Close the file descriptor
1887 close(fd);
1888
1889 return r;
1890 }
1891
1892 static int pakfire_jail_wait_for_signal(struct pakfire_jail* jail, int fd) {
1893 uint64_t val = 0;
1894 int r = 0;
1895
1896 DEBUG(jail->pakfire, "Waiting for signal...\n");
1897
1898 r = eventfd_read(fd, &val);
1899 if (r < 0) {
1900 ERROR(jail->pakfire, "Error waiting for signal: %s\n", strerror(errno));
1901 r = -errno;
1902 }
1903
1904 // Close the file descriptor
1905 close(fd);
1906
1907 return r;
1908 }
1909
1910 /*
1911 Performs the initialisation that needs to happen in the parent part
1912 */
1913 static int pakfire_jail_parent(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1914 int r;
1915
1916 // Setup UID mapping
1917 r = pakfire_jail_setup_uid_mapping(jail, ctx->pid);
1918 if (r)
1919 return r;
1920
1921 // Write "deny" to /proc/PID/setgroups
1922 r = pakfire_jail_setgroups(jail, ctx->pid);
1923 if (r)
1924 return r;
1925
1926 // Setup GID mapping
1927 r = pakfire_jail_setup_gid_mapping(jail, ctx->pid);
1928 if (r)
1929 return r;
1930
1931 // Parent has finished initialisation
1932 DEBUG(jail->pakfire, "Parent has finished initialization\n");
1933
1934 // Send signal to client
1935 r = pakfire_jail_send_signal(jail, ctx->completed_fd);
1936 if (r)
1937 return r;
1938
1939 return 0;
1940 }
1941
1942 static int pakfire_jail_switch_root(struct pakfire_jail* jail, const char* root) {
1943 int r;
1944
1945 // Change to the new root
1946 r = chdir(root);
1947 if (r) {
1948 ERROR(jail->pakfire, "chdir(%s) failed: %m\n", root);
1949 return r;
1950 }
1951
1952 // Switch Root!
1953 r = pivot_root(".", ".");
1954 if (r) {
1955 ERROR(jail->pakfire, "Failed changing into the new root directory %s: %m\n", root);
1956 return r;
1957 }
1958
1959 // Umount the old root
1960 r = umount2(".", MNT_DETACH);
1961 if (r) {
1962 ERROR(jail->pakfire, "Could not umount the old root filesystem: %m\n");
1963 return r;
1964 }
1965
1966 return 0;
1967 }
1968
1969 static int pakfire_jail_open_pty(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1970 int r;
1971
1972 // Allocate a new PTY
1973 ctx->pty.master.fd = posix_openpt(O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
1974 if (ctx->pty.master.fd < 0)
1975 return -errno;
1976
1977 // Fetch the path
1978 r = ptsname_r(ctx->pty.master.fd, ctx->pty.console, sizeof(ctx->pty.console));
1979 if (r)
1980 return -r;
1981
1982 CTX_DEBUG(jail->ctx, "Allocated console at %s (%d)\n", ctx->pty.console, ctx->pty.master.fd);
1983
1984 // Unlock the master device
1985 r = unlockpt(ctx->pty.master.fd);
1986 if (r) {
1987 CTX_ERROR(jail->ctx, "Could not unlock the PTY: %s\n", strerror(errno));
1988 return -errno;
1989 }
1990
1991 // Create a symlink
1992 r = pakfire_symlink(jail->ctx, ctx->pty.console, "/dev/console");
1993 if (r)
1994 return r;
1995
1996 return r;
1997 }
1998
1999 static int pakfire_jail_setup_terminal(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
2000 int fd;
2001 int r;
2002
2003 // Open a new terminal
2004 fd = open("/dev/console", O_RDWR|O_NOCTTY);
2005 if (fd < 0) {
2006 CTX_ERROR(jail->ctx, "Failed to open a new terminal: %s\n", strerror(errno));
2007 return -errno;
2008 }
2009
2010 CTX_DEBUG(jail->ctx, "Opened a new terminal %d\n", fd);
2011
2012 // Connect the new terminal to standard input
2013 r = dup2(fd, STDIN_FILENO);
2014 if (r < 0) {
2015 CTX_ERROR(jail->ctx, "Failed to open standard input: %s\n", strerror(errno));
2016 return -errno;
2017 }
2018
2019 // Connect the new terminal to standard output
2020 r = dup2(fd, STDOUT_FILENO);
2021 if (r < 0) {
2022 CTX_ERROR(jail->ctx, "Failed to open standard output: %s\n", strerror(errno));
2023 return -errno;
2024 }
2025
2026 // Connect the new terminal to standard error
2027 r = dup2(fd, STDERR_FILENO);
2028 if (r < 0) {
2029 CTX_ERROR(jail->ctx, "Failed to open standard error: %s\n", strerror(errno));
2030 return -errno;
2031 }
2032
2033 return 0;
2034 }
2035
2036 static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
2037 const char* argv[]) {
2038 int r;
2039
2040 // Redirect any logging to our log pipe
2041 pakfire_ctx_set_log_callback(jail->ctx, pakfire_jail_log_redirect, &ctx->pipes);
2042
2043 // Fetch my own PID
2044 pid_t pid = getpid();
2045
2046 DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", pid);
2047
2048 // Wait for the parent to finish initialization
2049 r = pakfire_jail_wait_for_signal(jail, ctx->completed_fd);
2050 if (r)
2051 return r;
2052
2053 // Die with parent
2054 r = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
2055 if (r) {
2056 ERROR(jail->pakfire, "Could not configure to die with parent: %m\n");
2057 return 126;
2058 }
2059
2060 // Make this process dumpable
2061 r = prctl (PR_SET_DUMPABLE, 1, 0, 0, 0);
2062 if (r) {
2063 ERROR(jail->pakfire, "Could not make the process dumpable: %m\n");
2064 return 126;
2065 }
2066
2067 // Don't drop any capabilities on setuid()
2068 r = prctl(PR_SET_KEEPCAPS, 1);
2069 if (r) {
2070 ERROR(jail->pakfire, "Could not set PR_SET_KEEPCAPS: %m\n");
2071 return 126;
2072 }
2073
2074 // Fetch UID/GID
2075 uid_t uid = getuid();
2076 gid_t gid = getgid();
2077
2078 // Fetch EUID/EGID
2079 uid_t euid = geteuid();
2080 gid_t egid = getegid();
2081
2082 DEBUG(jail->pakfire, " UID: %u (effective %u)\n", uid, euid);
2083 DEBUG(jail->pakfire, " GID: %u (effective %u)\n", gid, egid);
2084
2085 // Log all mountpoints
2086 pakfire_mount_list(jail->ctx);
2087
2088 // Fail if we are not PID 1
2089 if (pid != 1) {
2090 CTX_ERROR(jail->ctx, "Child process is not PID 1\n");
2091 return 126;
2092 }
2093
2094 // Fail if we are not running as root
2095 if (uid || gid || euid || egid) {
2096 ERROR(jail->pakfire, "Child process is not running as root\n");
2097 return 126;
2098 }
2099
2100 const int socket_send = pakfire_jail_get_pipe_to_write(jail, &ctx->socket);
2101
2102 // Mount all default stuff
2103 r = pakfire_mount_all(jail->pakfire, PAKFIRE_MNTNS_INNER, 0);
2104 if (r)
2105 return 126;
2106
2107 const char* root = pakfire_get_path(jail->pakfire);
2108 const char* arch = pakfire_get_effective_arch(jail->pakfire);
2109
2110 // Change mount propagation to slave to receive anything from the parent namespace
2111 r = pakfire_mount_change_propagation(jail->ctx, "/", MS_SLAVE);
2112 if (r)
2113 return r;
2114
2115 // Make root a mountpoint in the new mount namespace
2116 r = pakfire_mount_make_mounpoint(jail->pakfire, root);
2117 if (r)
2118 return r;
2119
2120 // Change mount propagation to private
2121 r = pakfire_mount_change_propagation(jail->ctx, root, MS_PRIVATE);
2122 if (r)
2123 return r;
2124
2125 // Change root (unless root is /)
2126 if (!pakfire_on_root(jail->pakfire)) {
2127 // Mount everything
2128 r = pakfire_jail_mount(jail, ctx);
2129 if (r)
2130 return r;
2131
2132 // chroot()
2133 r = pakfire_jail_switch_root(jail, root);
2134 if (r)
2135 return r;
2136 }
2137
2138 // Set personality
2139 unsigned long persona = pakfire_arch_personality(arch);
2140 if (persona) {
2141 r = personality(persona);
2142 if (r < 0) {
2143 ERROR(jail->pakfire, "Could not set personality (%x)\n", (unsigned int)persona);
2144 return 1;
2145 }
2146 }
2147
2148 // Setup networking
2149 if (!pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
2150 r = pakfire_jail_setup_loopback(jail);
2151 if (r)
2152 return 1;
2153 }
2154
2155 // Set nice level
2156 if (jail->nice) {
2157 DEBUG(jail->pakfire, "Setting nice level to %d\n", jail->nice);
2158
2159 r = setpriority(PRIO_PROCESS, pid, jail->nice);
2160 if (r) {
2161 ERROR(jail->pakfire, "Could not set nice level: %m\n");
2162 return 1;
2163 }
2164 }
2165
2166 // Create a new session
2167 r = setsid();
2168 if (r < 0) {
2169 CTX_ERROR(jail->ctx, "Could not create a new session: %s\n", strerror(errno));
2170 return r;
2171 }
2172
2173 // Allocate a new PTY
2174 r = pakfire_jail_open_pty(jail, ctx);
2175 if (r) {
2176 CTX_ERROR(jail->ctx, "Could not allocate a new PTY: %s\n", strerror(-r));
2177 return r;
2178 }
2179
2180 // Send the PTY master to the parent process
2181 r = pakfire_jail_send_fd(jail, socket_send, ctx->pty.master.fd);
2182 if (r) {
2183 CTX_ERROR(jail->ctx, "Failed sending the PTY master to the parent: %s\n", strerror(-r));
2184 return r;
2185 }
2186
2187 // Setup the terminal
2188 r = pakfire_jail_setup_terminal(jail, ctx);
2189 if (r)
2190 return r;
2191
2192 // Close the master of the PTY
2193 close(ctx->pty.master.fd);
2194 ctx->pty.master.fd = -1;
2195
2196 // Close the socket
2197 close(socket_send);
2198
2199 // Close other end of log pipes
2200 close(ctx->pipes.log_INFO[0]);
2201 close(ctx->pipes.log_ERROR[0]);
2202 #ifdef ENABLE_DEBUG
2203 close(ctx->pipes.log_DEBUG[0]);
2204 #endif /* ENABLE_DEBUG */
2205
2206 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2207 r = pakfire_rlimit_reset_nofile(jail->pakfire);
2208 if (r)
2209 return r;
2210
2211 // Set capabilities
2212 r = pakfire_jail_set_capabilities(jail);
2213 if (r)
2214 return r;
2215
2216 // Show capabilities
2217 r = pakfire_jail_show_capabilities(jail);
2218 if (r)
2219 return r;
2220
2221 // Filter syscalls
2222 r = pakfire_jail_limit_syscalls(jail);
2223 if (r)
2224 return r;
2225
2226 DEBUG(jail->pakfire, "Child process initialization done\n");
2227 DEBUG(jail->pakfire, "Launching command:\n");
2228
2229 // Log argv
2230 for (unsigned int i = 0; argv[i]; i++)
2231 DEBUG(jail->pakfire, " argv[%u] = %s\n", i, argv[i]);
2232
2233 // exec() command
2234 r = execvpe(argv[0], (char**)argv, jail->env);
2235 if (r < 0) {
2236 // Translate errno into regular exit code
2237 switch (errno) {
2238 case ENOENT:
2239 // Ignore if the command doesn't exist
2240 if (ctx->flags & PAKFIRE_JAIL_NOENT_OK)
2241 r = 0;
2242 else
2243 r = 127;
2244
2245 break;
2246
2247 default:
2248 r = 1;
2249 }
2250
2251 ERROR(jail->pakfire, "Could not execve(%s): %m\n", argv[0]);
2252 }
2253
2254 // We should not get here
2255 return r;
2256 }
2257
2258 // Run a command in the jail
2259 static int __pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[],
2260 const int interactive,
2261 pakfire_jail_communicate_in communicate_in,
2262 pakfire_jail_communicate_out communicate_out,
2263 void* data, int flags) {
2264 int exit = -1;
2265 int r;
2266
2267 // Check if argv is valid
2268 if (!argv || !argv[0]) {
2269 errno = EINVAL;
2270 return -1;
2271 }
2272
2273 // Initialize context for this call
2274 struct pakfire_jail_exec ctx = {
2275 .flags = flags,
2276
2277 .socket = { -1, -1 },
2278
2279 .pipes = {
2280 .log_INFO = { -1, -1 },
2281 .log_ERROR = { -1, -1 },
2282 #ifdef ENABLE_DEBUG
2283 .log_DEBUG = { -1, -1 },
2284 #endif /* ENABLE_DEBUG */
2285 },
2286
2287 .communicate = {
2288 .in = communicate_in,
2289 .out = communicate_out,
2290 .data = data,
2291 },
2292
2293 .pidfd = -1,
2294
2295 // PTY
2296 .pty = {
2297 .master = {
2298 .fd = -1,
2299 },
2300 .stdin = {
2301 .fd = -1,
2302 },
2303 .stdout = {
2304 .fd = -1,
2305 },
2306 },
2307 };
2308
2309 DEBUG(jail->pakfire, "Executing jail...\n");
2310
2311 // Enable networking in interactive mode
2312 if (interactive)
2313 ctx.flags |= PAKFIRE_JAIL_HAS_NETWORKING;
2314
2315 /*
2316 Setup a file descriptor which can be used to notify the client that the parent
2317 has completed configuration.
2318 */
2319 ctx.completed_fd = eventfd(0, EFD_CLOEXEC);
2320 if (ctx.completed_fd < 0) {
2321 ERROR(jail->pakfire, "eventfd() failed: %m\n");
2322 return -1;
2323 }
2324
2325 // Create a UNIX domain socket
2326 r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ctx.socket);
2327 if (r < 0) {
2328 CTX_ERROR(jail->ctx, "Could not create UNIX socket: %s\n", strerror(errno));
2329 r = -errno;
2330 goto ERROR;
2331 }
2332
2333 // Setup pipes for logging
2334 // INFO
2335 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_INFO, O_CLOEXEC);
2336 if (r)
2337 goto ERROR;
2338
2339 // ERROR
2340 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_ERROR, O_CLOEXEC);
2341 if (r)
2342 goto ERROR;
2343
2344 #ifdef ENABLE_DEBUG
2345 // DEBUG
2346 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_DEBUG, O_CLOEXEC);
2347 if (r)
2348 goto ERROR;
2349 #endif /* ENABLE_DEBUG */
2350
2351 // Configure child process
2352 struct clone_args args = {
2353 .flags =
2354 CLONE_NEWCGROUP |
2355 CLONE_NEWIPC |
2356 CLONE_NEWNS |
2357 CLONE_NEWPID |
2358 CLONE_NEWTIME |
2359 CLONE_NEWUSER |
2360 CLONE_NEWUTS |
2361 CLONE_PIDFD,
2362 .exit_signal = SIGCHLD,
2363 .pidfd = (long long unsigned int)&ctx.pidfd,
2364 };
2365
2366 // Launch the process in a cgroup that is a leaf of the configured cgroup
2367 if (jail->cgroup) {
2368 args.flags |= CLONE_INTO_CGROUP;
2369
2370 // Fetch our UUID
2371 const char* uuid = pakfire_jail_uuid(jail);
2372
2373 // Create a temporary cgroup
2374 r = pakfire_cgroup_child(&ctx.cgroup, jail->cgroup, uuid, 0);
2375 if (r) {
2376 ERROR(jail->pakfire, "Could not create cgroup for jail: %m\n");
2377 goto ERROR;
2378 }
2379
2380 // Clone into this cgroup
2381 args.cgroup = pakfire_cgroup_fd(ctx.cgroup);
2382 }
2383
2384 // Setup networking
2385 if (!pakfire_jail_exec_has_flag(&ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
2386 args.flags |= CLONE_NEWNET;
2387 }
2388
2389 // Fork this process
2390 ctx.pid = clone3(&args, sizeof(args));
2391 if (ctx.pid < 0) {
2392 ERROR(jail->pakfire, "Could not clone: %m\n");
2393 return -1;
2394
2395 // Child process
2396 } else if (ctx.pid == 0) {
2397 r = pakfire_jail_child(jail, &ctx, argv);
2398 _exit(r);
2399 }
2400
2401 // Parent process
2402 r = pakfire_jail_parent(jail, &ctx);
2403 if (r)
2404 goto ERROR;
2405
2406 DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", ctx.pid);
2407
2408 // Read output of the child process
2409 r = pakfire_jail_wait(jail, &ctx);
2410 if (r)
2411 goto ERROR;
2412
2413 // Handle exit status
2414 switch (ctx.status.si_code) {
2415 case CLD_EXITED:
2416 DEBUG(jail->pakfire, "The child process exited with code %d\n",
2417 ctx.status.si_status);
2418
2419 // Pass exit code
2420 exit = ctx.status.si_status;
2421 break;
2422
2423 case CLD_KILLED:
2424 ERROR(jail->pakfire, "The child process was killed\n");
2425 exit = 139;
2426 break;
2427
2428 case CLD_DUMPED:
2429 ERROR(jail->pakfire, "The child process terminated abnormally\n");
2430 break;
2431
2432 // Log anything else
2433 default:
2434 ERROR(jail->pakfire, "Unknown child exit code: %d\n", ctx.status.si_code);
2435 break;
2436 }
2437
2438 ERROR:
2439 // Destroy the temporary cgroup (if any)
2440 if (ctx.cgroup) {
2441 // Read cgroup stats
2442 pakfire_cgroup_stat(ctx.cgroup, &ctx.cgroup_stats);
2443 pakfire_cgroup_stat_dump(ctx.cgroup, &ctx.cgroup_stats);
2444 pakfire_cgroup_destroy(ctx.cgroup);
2445 pakfire_cgroup_unref(ctx.cgroup);
2446 }
2447
2448 // Close any file descriptors
2449 if (ctx.pidfd >= 0)
2450 close(ctx.pidfd);
2451 if (ctx.pty.master.fd >= 0)
2452 close(ctx.pty.master.fd);
2453 pakfire_jail_close_pipe(jail, ctx.pipes.log_INFO);
2454 pakfire_jail_close_pipe(jail, ctx.pipes.log_ERROR);
2455 #ifdef ENABLE_DEBUG
2456 pakfire_jail_close_pipe(jail, ctx.pipes.log_DEBUG);
2457 #endif /* ENABLE_DEBUG */
2458 pakfire_jail_close_pipe(jail, ctx.socket);
2459
2460 return exit;
2461 }
2462
2463 PAKFIRE_EXPORT int pakfire_jail_exec(
2464 struct pakfire_jail* jail,
2465 const char* argv[],
2466 pakfire_jail_communicate_in callback_in,
2467 pakfire_jail_communicate_out callback_out,
2468 void* data, int flags) {
2469 return __pakfire_jail_exec(jail, argv, 0, callback_in, callback_out, data, flags);
2470 }
2471
2472 static int pakfire_jail_exec_interactive(
2473 struct pakfire_jail* jail, const char* argv[], int flags) {
2474 int r;
2475
2476 // Setup interactive stuff
2477 r = pakfire_jail_setup_interactive_env(jail);
2478 if (r)
2479 return r;
2480
2481 return __pakfire_jail_exec(jail, argv, 1, NULL, NULL, NULL, flags);
2482 }
2483
2484 int pakfire_jail_exec_script(struct pakfire_jail* jail,
2485 const char* script,
2486 const size_t size,
2487 const char* args[],
2488 pakfire_jail_communicate_in callback_in,
2489 pakfire_jail_communicate_out callback_out,
2490 void* data) {
2491 char path[PATH_MAX];
2492 const char** argv = NULL;
2493 FILE* f = NULL;
2494 int r;
2495
2496 const char* root = pakfire_get_path(jail->pakfire);
2497
2498 // Write the scriptlet to disk
2499 r = pakfire_path_append(path, root, PAKFIRE_TMP_DIR "/pakfire-script.XXXXXX");
2500 if (r)
2501 goto ERROR;
2502
2503 // Create a temporary file
2504 f = pakfire_mktemp(path, 0700);
2505 if (!f) {
2506 ERROR(jail->pakfire, "Could not create temporary file: %m\n");
2507 goto ERROR;
2508 }
2509
2510 DEBUG(jail->pakfire, "Writing script to %s:\n%.*s\n", path, (int)size, script);
2511
2512 // Write data
2513 r = fprintf(f, "%s", script);
2514 if (r < 0) {
2515 ERROR(jail->pakfire, "Could not write script to file %s: %m\n", path);
2516 goto ERROR;
2517 }
2518
2519 // Close file
2520 r = fclose(f);
2521 if (r) {
2522 ERROR(jail->pakfire, "Could not close script file %s: %m\n", path);
2523 goto ERROR;
2524 }
2525
2526 f = NULL;
2527
2528 // Count how many arguments were passed
2529 unsigned int argc = 1;
2530 if (args) {
2531 for (const char** arg = args; *arg; arg++)
2532 argc++;
2533 }
2534
2535 argv = calloc(argc + 1, sizeof(*argv));
2536 if (!argv) {
2537 ERROR(jail->pakfire, "Could not allocate argv: %m\n");
2538 goto ERROR;
2539 }
2540
2541 // Set command
2542 argv[0] = (root) ? pakfire_path_relpath(root, path) : path;
2543
2544 // Copy args
2545 for (unsigned int i = 1; i < argc; i++)
2546 argv[i] = args[i-1];
2547
2548 // Run the script
2549 r = pakfire_jail_exec(jail, argv, callback_in, callback_out, data, 0);
2550
2551 ERROR:
2552 if (argv)
2553 free(argv);
2554 if (f)
2555 fclose(f);
2556
2557 // Remove script from disk
2558 if (*path)
2559 unlink(path);
2560
2561 return r;
2562 }
2563
2564 /*
2565 A convenience function that creates a new jail, runs the given command and destroys
2566 the jail again.
2567 */
2568 int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], int flags, char** output) {
2569 struct pakfire_jail* jail = NULL;
2570 int r;
2571
2572 // Create a new jail
2573 r = pakfire_jail_create(&jail, pakfire);
2574 if (r)
2575 goto ERROR;
2576
2577 // Execute the command
2578 r = pakfire_jail_exec(jail, argv, NULL, pakfire_jail_capture_stdout, output, 0);
2579
2580 ERROR:
2581 if (jail)
2582 pakfire_jail_unref(jail);
2583
2584 return r;
2585 }
2586
2587 int pakfire_jail_run_script(struct pakfire* pakfire,
2588 const char* script, const size_t length, const char* argv[], int flags) {
2589 struct pakfire_jail* jail = NULL;
2590 int r;
2591
2592 // Create a new jail
2593 r = pakfire_jail_create(&jail, pakfire);
2594 if (r)
2595 goto ERROR;
2596
2597 // Execute the command
2598 r = pakfire_jail_exec_script(jail, script, length, argv, NULL, NULL, NULL);
2599
2600 ERROR:
2601 if (jail)
2602 pakfire_jail_unref(jail);
2603
2604 return r;
2605 }
2606
2607 int pakfire_jail_shell(struct pakfire_jail* jail) {
2608 int r;
2609
2610 const char* argv[] = {
2611 "/bin/bash", "--login", NULL,
2612 };
2613
2614 // Execute /bin/bash
2615 r = pakfire_jail_exec_interactive(jail, argv, 0);
2616
2617 // Raise any errors
2618 if (r < 0)
2619 return r;
2620
2621 // Ignore any return codes from the shell
2622 return 0;
2623 }
2624
2625 static int pakfire_jail_run_if_possible(struct pakfire* pakfire, const char** argv) {
2626 char path[PATH_MAX];
2627 int r;
2628
2629 r = pakfire_path(pakfire, path, "%s", *argv);
2630 if (r)
2631 return r;
2632
2633 // Check if the file is executable
2634 r = access(path, X_OK);
2635 if (r) {
2636 DEBUG(pakfire, "%s is not executable. Skipping...\n", *argv);
2637 return 0;
2638 }
2639
2640 return pakfire_jail_run(pakfire, argv, 0, NULL);
2641 }
2642
2643 int pakfire_jail_ldconfig(struct pakfire* pakfire) {
2644 const char* argv[] = {
2645 "/sbin/ldconfig",
2646 NULL,
2647 };
2648
2649 return pakfire_jail_run_if_possible(pakfire, argv);
2650 }
2651
2652 int pakfire_jail_run_systemd_tmpfiles(struct pakfire* pakfire) {
2653 const char* argv[] = {
2654 "/usr/bin/systemd-tmpfiles",
2655 "--create",
2656 NULL,
2657 };
2658
2659 return pakfire_jail_run_if_possible(pakfire, argv);
2660 }