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