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