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