]> git.ipfire.org Git - pakfire.git/blob - src/libpakfire/jail.c
jail: Do not try to attempt any TTY operations if we don't have a TTY
[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_with_callback(struct pakfire_jail* jail,
632 struct pakfire_log_buffer* buffer, int priority, pakfire_jail_communicate_out callback, void* data) {
633 const char* eol = NULL;
634 int r;
635
636 while (buffer->used) {
637 // Search for the end of the first line
638 eol = memchr(buffer->data, '\n', buffer->used);
639
640 // No newline found
641 if (!eol) {
642 // If the buffer is full, we send the entire content to make space.
643 if (pakfire_jail_log_buffer_is_full(buffer)) {
644 CTX_DEBUG(jail->ctx, "Buffer is full. Sending all content\n");
645
646 eol = buffer->data + buffer->used - 1;
647
648 // Otherwise we might have only read parts of the output...
649 } else {
650 break;
651 }
652 }
653
654 // Find the length of the string
655 const size_t length = eol - buffer->data + 1;
656
657 // Call the callback
658 r = callback(jail->pakfire, data, priority, buffer->data, length);
659 if (r) {
660 CTX_ERROR(jail->ctx, "The logging callback returned an error: %d\n", r);
661 return r;
662 }
663
664 // Remove line from buffer
665 memmove(buffer->data, buffer->data + length, buffer->used - length);
666 buffer->used -= length;
667 }
668
669 return 0;
670 }
671
672 static int pakfire_jail_drain_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
673 int r;
674
675 // Nothing to do if the buffer is empty
676 if (!buffer->used)
677 return 0;
678
679 // Drain the buffer
680 r = write(fd, buffer->data, buffer->used);
681
682 // Handle errors
683 if (r < 0) {
684 switch (errno) {
685 case EAGAIN:
686 case EIO:
687 break;
688
689 default:
690 return -errno;
691 }
692
693 // Successful write
694 } else {
695 memmove(buffer->data, buffer->data + r, buffer->used - r);
696
697 buffer->used -= r;
698 }
699
700 return 0;
701 }
702
703 /*
704 This function reads as much data as it can from the file descriptor.
705 If it finds a whole line in it, it will send it to the logger and repeat the process.
706 If not newline character is found, it will try to read more data until it finds one.
707 */
708 static int pakfire_jail_handle_log(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
709 int priority, int fd, struct pakfire_log_buffer* buffer,
710 pakfire_jail_communicate_out callback, void* data) {
711 int r;
712
713 // Fill up buffer from fd
714 r = pakfire_jail_fill_buffer(jail, fd, buffer);
715 if (r)
716 return r;
717
718 // Drain the buffer
719 r = pakfire_jail_drain_buffer_with_callback(jail, buffer, priority, callback, data);
720 if (r)
721 return r;
722
723 return 0;
724 }
725
726 #if 0
727 static int pakfire_jail_stream_stdin(struct pakfire_jail* jail,
728 struct pakfire_jail_exec* ctx, const int fd) {
729 int r;
730
731 // Nothing to do if there is no stdin callback set
732 if (!ctx->communicate.in) {
733 DEBUG(jail->pakfire, "Callback for standard input is not set\n");
734 return 0;
735 }
736
737 // Skip if the writing pipe has already been closed
738 if (ctx->pipes.stdin[1] < 0)
739 return 0;
740
741 DEBUG(jail->pakfire, "Streaming standard input...\n");
742
743 // Calling the callback
744 r = ctx->communicate.in(jail->pakfire, ctx->communicate.data, fd);
745
746 DEBUG(jail->pakfire, "Standard input callback finished: %d\n", r);
747
748 // The callback signaled that it has written everything
749 if (r == EOF) {
750 DEBUG(jail->pakfire, "Closing standard input pipe\n");
751
752 // Close the file-descriptor
753 close(fd);
754
755 // Reset the file-descriptor so it won't be closed again later
756 ctx->pipes.stdin[1] = -1;
757
758 // Report success
759 r = 0;
760 }
761
762 return r;
763 }
764 #endif
765
766 static int pakfire_jail_recv_fd(struct pakfire_jail* jail, int socket, int* fd) {
767 const size_t payload_length = sizeof(fd);
768 char buffer[CMSG_SPACE(payload_length)];
769 int r;
770
771 struct msghdr msg = {
772 .msg_control = buffer,
773 .msg_controllen = sizeof(buffer),
774 };
775
776 // Receive the message
777 r = recvmsg(socket, &msg, 0);
778 if (r) {
779 CTX_ERROR(jail->ctx, "Could not receive file descriptor: %s\n", strerror(errno));
780 return -errno;
781 }
782
783 // Fetch the payload
784 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
785 if (!cmsg)
786 return -EBADMSG;
787
788 *fd = *((int*)CMSG_DATA(cmsg));
789
790 CTX_DEBUG(jail->ctx, "Received fd %d from socket %d\n", *fd, socket);
791
792 return 0;
793 }
794
795 static int pakfire_jail_send_fd(struct pakfire_jail* jail, int socket, int fd) {
796 const size_t payload_length = sizeof(fd);
797 char buffer[CMSG_SPACE(payload_length)];
798 int r;
799
800 CTX_DEBUG(jail->ctx, "Sending fd %d to socket %d\n", fd, socket);
801
802 // Header
803 struct msghdr msg = {
804 .msg_control = buffer,
805 .msg_controllen = sizeof(buffer),
806 };
807
808 // Payload
809 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
810 cmsg->cmsg_level = SOL_SOCKET;
811 cmsg->cmsg_type = SCM_RIGHTS;
812 cmsg->cmsg_len = CMSG_LEN(payload_length);
813
814 // Set payload
815 *((int*)CMSG_DATA(cmsg)) = fd;
816
817 // Send the message
818 r = sendmsg(socket, &msg, 0);
819 if (r) {
820 CTX_ERROR(jail->ctx, "Could not send file descriptor: %s\n", strerror(errno));
821 return -errno;
822 }
823
824 return 0;
825 }
826
827 static int pakfire_jail_setup_pipe(struct pakfire_jail* jail, int (*fds)[2], const int flags) {
828 int r = pipe2(*fds, flags);
829 if (r < 0) {
830 ERROR(jail->pakfire, "Could not setup pipe: %m\n");
831 return 1;
832 }
833
834 return 0;
835 }
836
837 static void pakfire_jail_close_pipe(struct pakfire_jail* jail, int fds[2]) {
838 for (unsigned int i = 0; i < 2; i++)
839 if (fds[i] >= 0)
840 close(fds[i]);
841 }
842
843 /*
844 This is a convenience function to fetch the reading end of a pipe and
845 closes the write end.
846 */
847 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail* jail, int (*fds)[2]) {
848 // Give the variables easier names to avoid confusion
849 int* fd_read = &(*fds)[0];
850 int* fd_write = &(*fds)[1];
851
852 // Close the write end of the pipe
853 if (*fd_write >= 0) {
854 close(*fd_write);
855 *fd_write = -1;
856 }
857
858 // Return the read end
859 if (*fd_read >= 0)
860 return *fd_read;
861
862 return -1;
863 }
864
865 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail* jail, int (*fds)[2]) {
866 // Give the variables easier names to avoid confusion
867 int* fd_read = &(*fds)[0];
868 int* fd_write = &(*fds)[1];
869
870 // Close the read end of the pipe
871 if (*fd_read >= 0) {
872 close(*fd_read);
873 *fd_read = -1;
874 }
875
876 // Return the write end
877 if (*fd_write >= 0)
878 return *fd_write;
879
880 return -1;
881 }
882
883 static int pakfire_jail_log(struct pakfire* pakfire, void* data, int priority,
884 const char* line, const size_t length) {
885 // Pass everything to the parent logger
886 pakfire_log_condition(pakfire, priority, 0, "%.*s", (int)length, line);
887
888 return 0;
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 everything if fd is not a TTY
930 if (!isatty(stdio->fd))
931 return 0;
932
933 // Store flags
934 stdio->fdflags = fcntl(stdio->fd, F_GETFL);
935 if (stdio->fdflags < 0) {
936 CTX_ERROR(jail->ctx, "Could not fetch flags from fd %d: %s\n",
937 stdio->fd, strerror(errno));
938 return -errno;
939 }
940
941 // Fetch all attributes
942 r = tcgetattr(stdio->fd, &stdio->attrs);
943 if (r) {
944 CTX_ERROR(jail->ctx, "Could not fetch terminal attributes from fd %d: %s\n",
945 stdio->fd, strerror(errno));
946 return -errno;
947 }
948
949 // Copy all attributes
950 raw_attrs = stdio->attrs;
951
952 // Make it RAW
953 cfmakeraw(&raw_attrs);
954
955 switch (stdio->fd) {
956 case STDIN_FILENO:
957 raw_attrs.c_oflag = stdio->attrs.c_oflag;
958 break;
959
960 case STDOUT_FILENO:
961 raw_attrs.c_iflag = stdio->attrs.c_iflag;
962 raw_attrs.c_lflag = stdio->attrs.c_lflag;
963 break;
964 }
965
966 // Restore the attributes
967 r = tcsetattr(stdio->fd, TCSANOW, &raw_attrs);
968 if (r) {
969 CTX_ERROR(jail->ctx, "Could not restore terminal attributes for fd %d: %s\n",
970 stdio->fd, strerror(errno));
971 return -errno;
972 }
973
974 return 0;
975 }
976
977 static int pakfire_jail_restore_attrs(struct pakfire_jail* jail,
978 const struct pakfire_jail_pty_stdio* stdio) {
979 int r;
980
981 // Skip everything if fd is not a TTY
982 if (!isatty(stdio->fd))
983 return 0;
984
985 // Restore the flags
986 r = fcntl(stdio->fd, F_SETFL, stdio->fdflags);
987 if (r < 0) {
988 CTX_ERROR(jail->ctx, "Could not set flags for file descriptor %d: %s\n",
989 stdio->fd, strerror(errno));
990 return -errno;
991 }
992
993 // Restore the attributes
994 r = tcsetattr(stdio->fd, TCSANOW, &stdio->attrs);
995 if (r) {
996 CTX_ERROR(jail->ctx, "Could not restore terminal attributes for %d, ignoring: %s\n",
997 stdio->fd, strerror(errno));
998 return -errno;
999 }
1000
1001 return 0;
1002 }
1003
1004 static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail* jail,
1005 struct pakfire_jail_exec* ctx, const int epollfd, const int fd) {
1006 struct winsize size;
1007 int r;
1008
1009 CTX_DEBUG(jail->ctx, "Setting up PTY forwarding on fd %d\n", fd);
1010
1011 // Store the file descriptor
1012 ctx->pty.master.fd = fd;
1013
1014 // Configure stdin/stdout
1015 ctx->pty.stdin.fd = STDIN_FILENO;
1016 ctx->pty.stdout.fd = STDOUT_FILENO;
1017
1018 // Fetch dimensions
1019 if (isatty(ctx->pty.stdout.fd)) {
1020 r = ioctl(ctx->pty.stdout.fd, TIOCGWINSZ, &size);
1021 if (r) {
1022 CTX_ERROR(jail->ctx, "Failed to determine terminal dimensions: %s\n", strerror(errno));
1023 return -errno;
1024 }
1025
1026 // Set dimensions
1027 r = ioctl(ctx->pty.master.fd, TIOCSWINSZ, &size);
1028 if (r) {
1029 CTX_ERROR(jail->ctx, "Failed setting dimensions: %s\n", strerror(errno));
1030 return -errno;
1031 }
1032 }
1033
1034 // Enable RAW mode on standard input
1035 r = pakfire_jail_enable_raw_mode(jail, &ctx->pty.stdin);
1036 if (r)
1037 return r;
1038
1039 // Enable RAW mode on standard output
1040 r = pakfire_jail_enable_raw_mode(jail, &ctx->pty.stdout);
1041 if (r)
1042 return r;
1043
1044 // Add the master to the event loop
1045 r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.master.fd, EPOLLIN|EPOLLOUT|EPOLLET);
1046 if (r)
1047 return r;
1048
1049 // Add standard input to the event loop
1050 r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.stdin.fd, EPOLLIN|EPOLLET);
1051 if (r)
1052 return r;
1053
1054 // Add standard output to the event loop
1055 r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.stdout.fd, EPOLLOUT|EPOLLET);
1056 if (r)
1057 return r;
1058
1059 return 0;
1060 }
1061
1062 static int pakfire_jail_forward_pty(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1063 int r;
1064
1065 // Read from standard input
1066 if (ctx->pty.stdin.flags & PAKFIRE_JAIL_PTY_READY_TO_READ) {
1067 r = pakfire_jail_fill_buffer(jail, ctx->pty.stdin.fd, &ctx->pty.stdin.buffer);
1068 if (r) {
1069 CTX_ERROR(jail->ctx, "Failed reading from standard input: %s\n", strerror(-r));
1070 return r;
1071 }
1072
1073 // We are done reading for now
1074 ctx->pty.stdin.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_READ;
1075
1076 // But we may have data to write
1077 if (ctx->pty.stdin.buffer.used)
1078 ctx->pty.master.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1079 }
1080
1081 // Write to the master
1082 if (ctx->pty.master.flags & PAKFIRE_JAIL_PTY_READY_TO_WRITE) {
1083 r = pakfire_jail_drain_buffer(jail, ctx->pty.master.fd, &ctx->pty.stdin.buffer);
1084 if (r) {
1085 CTX_ERROR(jail->ctx, "Failed writing to the PTY: %s\n", strerror(-r));
1086 return r;
1087 }
1088
1089 // We are done writing for now
1090 ctx->pty.master.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1091 }
1092
1093 // Read from the master
1094 if (ctx->pty.master.flags & PAKFIRE_JAIL_PTY_READY_TO_READ) {
1095 r = pakfire_jail_fill_buffer(jail, ctx->pty.master.fd, &ctx->pty.stdout.buffer);
1096 if (r) {
1097 CTX_ERROR(jail->ctx, "Failed reading from the PTY: %s\n", strerror(-r));
1098 return r;
1099 }
1100
1101 // We are done reading for now
1102 ctx->pty.master.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_READ;
1103
1104 // But we may have data to write
1105 if (ctx->pty.stdout.buffer.used)
1106 ctx->pty.stdout.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1107 }
1108
1109 // Write to standard output
1110 if (ctx->pty.stdout.flags & PAKFIRE_JAIL_PTY_READY_TO_WRITE) {
1111 r = pakfire_jail_drain_buffer(jail, ctx->pty.stdout.fd, &ctx->pty.stdout.buffer);
1112 if (r) {
1113 CTX_ERROR(jail->ctx, "Failed writing to standard output: %s\n", strerror(-r));
1114 return r;
1115 }
1116
1117 // We are done writing for now
1118 ctx->pty.stdout.flags &= ~PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1119 }
1120
1121 return 0;
1122 }
1123
1124 static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1125 int epollfd = -1;
1126 struct epoll_event events[EPOLL_MAX_EVENTS];
1127 char garbage[8];
1128 int r = 0;
1129
1130 // Fetch file descriptors from context
1131 const int pidfd = ctx->pidfd;
1132
1133 // Fetch the UNIX domain socket
1134 const int socket_recv = pakfire_jail_get_pipe_to_read(jail, &ctx->socket);
1135
1136 // Timer
1137 const int timerfd = pakfire_jail_create_timer(jail);
1138
1139 // Logging
1140 const int log_INFO = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_INFO);
1141 const int log_ERROR = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_ERROR);
1142 #ifdef ENABLE_DEBUG
1143 const int log_DEBUG = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_DEBUG);
1144 #endif /* ENABLE_DEBUG */
1145
1146 // Make a list of all file descriptors we are interested in
1147 const struct pakfire_wait_fds {
1148 const int fd;
1149 const int events;
1150 } fds[] = {
1151 // Timer
1152 { timerfd, EPOLLIN },
1153
1154 // Child Process
1155 { ctx->pidfd, EPOLLIN },
1156
1157 // Log Pipes
1158 { log_INFO, EPOLLIN },
1159 { log_ERROR, EPOLLIN },
1160 #ifdef ENABLE_DEBUG
1161 { log_DEBUG, EPOLLIN },
1162 #endif /* ENABLE_DEBUG */
1163
1164 // UNIX Domain Socket
1165 { socket_recv, EPOLLIN },
1166
1167 // Sentinel
1168 { -1, 0 },
1169 };
1170
1171 // Setup epoll
1172 epollfd = epoll_create1(0);
1173 if (epollfd < 0) {
1174 ERROR(jail->pakfire, "Could not initialize epoll(): %m\n");
1175 r = 1;
1176 goto ERROR;
1177 }
1178
1179 // Turn file descriptors into non-blocking mode and add them to epoll()
1180 for (const struct pakfire_wait_fds* fd = fds; fd->events; fd++) {
1181 // Skip fds which were not initialized
1182 if (fd->fd < 0)
1183 continue;
1184
1185 // Add the FD to the event loop
1186 r = pakfire_jail_epoll_add_fd(jail, epollfd, fd->fd, fd->events);
1187 if (r)
1188 goto ERROR;
1189 }
1190
1191 int ended = 0;
1192
1193 // Loop for as long as the process is alive
1194 while (!ended) {
1195 int num = epoll_wait(epollfd, events, EPOLL_MAX_EVENTS, -1);
1196 if (num < 1) {
1197 // Ignore if epoll_wait() has been interrupted
1198 if (errno == EINTR)
1199 continue;
1200
1201 ERROR(jail->pakfire, "epoll_wait() failed: %m\n");
1202 r = 1;
1203
1204 goto ERROR;
1205 }
1206
1207 for (int i = 0; i < num; i++) {
1208 int e = events[i].events;
1209 int fd = events[i].data.fd;
1210
1211 // Handle PTY forwarding events
1212 if (ctx->pty.master.fd == fd) {
1213 if (e & (EPOLLIN|EPOLLHUP))
1214 ctx->pty.master.flags |= PAKFIRE_JAIL_PTY_READY_TO_READ;
1215
1216 if (e & (EPOLLOUT|EPOLLHUP))
1217 ctx->pty.master.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1218
1219 // Perform the work
1220 r = pakfire_jail_forward_pty(jail, ctx);
1221 if (r) {
1222 CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
1223 goto ERROR;
1224 }
1225
1226 // Handle standard input
1227 } else if (ctx->pty.stdin.fd == fd) {
1228 if (e & (EPOLLIN|EPOLLHUP))
1229 ctx->pty.stdin.flags |= PAKFIRE_JAIL_PTY_READY_TO_READ;
1230
1231 // Perform the work
1232 r = pakfire_jail_forward_pty(jail, ctx);
1233 if (r) {
1234 CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
1235 goto ERROR;
1236 }
1237
1238 // Handle standard output
1239 } else if (ctx->pty.stdout.fd == fd) {
1240 if (e & (EPOLLOUT|EPOLLHUP))
1241 ctx->pty.stdout.flags |= PAKFIRE_JAIL_PTY_READY_TO_WRITE;
1242
1243 // Perform the work
1244 r = pakfire_jail_forward_pty(jail, ctx);
1245 if (r) {
1246 CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
1247 goto ERROR;
1248 }
1249
1250 // Handle any changes to the PIDFD
1251 } else if (pidfd == fd) {
1252 if (e & EPOLLIN) {
1253 // Call waidid() and store the result
1254 r = waitid(P_PIDFD, ctx->pidfd, &ctx->status, WEXITED);
1255 if (r) {
1256 ERROR(jail->pakfire, "waitid() failed: %m\n");
1257 goto ERROR;
1258 }
1259
1260 // Mark that we have ended so that we will process the remaining
1261 // events from epoll() now, but won't restart the outer loop.
1262 ended = 1;
1263 }
1264
1265 // Handle timer events
1266 } else if (timerfd == fd) {
1267 if (e & EPOLLIN) {
1268 DEBUG(jail->pakfire, "Timer event received\n");
1269
1270 // Disarm the timer
1271 r = read(timerfd, garbage, sizeof(garbage));
1272 if (r < 1) {
1273 ERROR(jail->pakfire, "Could not disarm timer: %m\n");
1274 r = 1;
1275 goto ERROR;
1276 }
1277
1278 // Terminate the process if it hasn't already ended
1279 if (!ended) {
1280 DEBUG(jail->pakfire, "Terminating process...\n");
1281
1282 // Send SIGTERM to the process
1283 r = pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
1284 if (r) {
1285 ERROR(jail->pakfire, "Could not kill process: %m\n");
1286 goto ERROR;
1287 }
1288 }
1289 }
1290
1291 // Handle socket messages
1292 } else if (socket_recv == fd) {
1293 if (e & EPOLLIN) {
1294 // Receive the passed FD
1295 r = pakfire_jail_recv_fd(jail, socket_recv, &fd);
1296 if (r)
1297 goto ERROR;
1298
1299 // Setup PTY forwarding
1300 if (ctx->pty.master.fd < 0) {
1301 r = pakfire_jail_setup_pty_forwarding(jail, ctx, epollfd, fd);
1302 if (r) {
1303 CTX_ERROR(jail->ctx, "Failed setting up PTY forwarding: %s\n", strerror(-r));
1304 goto ERROR;
1305 }
1306 }
1307 }
1308
1309 // Handle log INFO messages
1310 } else if (log_INFO == fd) {
1311 if (e & EPOLLIN) {
1312 r = pakfire_jail_handle_log(jail, ctx, LOG_INFO, fd,
1313 &ctx->buffers.log_INFO, pakfire_jail_log, NULL);
1314 if (r)
1315 goto ERROR;
1316 }
1317
1318 // Handle log ERROR messages
1319 } else if (log_ERROR == fd) {
1320 if (e & EPOLLIN) {
1321 r = pakfire_jail_handle_log(jail, ctx, LOG_ERR, fd,
1322 &ctx->buffers.log_ERROR, pakfire_jail_log, NULL);
1323 if (r)
1324 goto ERROR;
1325 }
1326
1327 #ifdef ENABLE_DEBUG
1328 // Handle log DEBUG messages
1329 } else if (log_DEBUG == fd) {
1330 if (e & EPOLLIN) {
1331 r = pakfire_jail_handle_log(jail, ctx, LOG_DEBUG, fd,
1332 &ctx->buffers.log_DEBUG, pakfire_jail_log, NULL);
1333 if (r)
1334 goto ERROR;
1335 }
1336 #endif /* ENABLE_DEBUG */
1337
1338 // Log a message for anything else
1339 } else {
1340 DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
1341 continue;
1342 }
1343
1344 // Check if any file descriptors have been closed
1345 if (e & EPOLLHUP) {
1346 // Remove the file descriptor
1347 r = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
1348 if (r) {
1349 ERROR(jail->pakfire, "Could not remove closed file-descriptor %d: %m\n", fd);
1350 goto ERROR;
1351 }
1352 }
1353 }
1354 }
1355
1356 ERROR:
1357 if (epollfd >= 0)
1358 close(epollfd);
1359 if (timerfd >= 0)
1360 close(timerfd);
1361
1362 // Restore any changed terminal attributes
1363 if (ctx->pty.stdin.fd >= 0)
1364 pakfire_jail_restore_attrs(jail, &ctx->pty.stdin);
1365 if (ctx->pty.stdout.fd >= 0)
1366 pakfire_jail_restore_attrs(jail, &ctx->pty.stdout);
1367
1368 return r;
1369 }
1370
1371 int pakfire_jail_capture_stdout(struct pakfire* pakfire, void* data,
1372 int priority, const char* line, size_t length) {
1373 char** output = (char**)data;
1374 int r;
1375
1376 // Append everything from stdout to a buffer
1377 if (output && priority == LOG_INFO) {
1378 r = asprintf(output, "%s%s", (output && *output) ? *output : "", line);
1379 if (r < 0)
1380 return 1;
1381 return 0;
1382 }
1383
1384 // Send everything else to the default logger
1385 return pakfire_jail_default_log_callback(pakfire, NULL, priority, line, length);
1386 }
1387
1388 // Capabilities
1389
1390 // Logs all capabilities of the current process
1391 static int pakfire_jail_show_capabilities(struct pakfire_jail* jail) {
1392 cap_t caps = NULL;
1393 char* name = NULL;
1394 cap_flag_value_t value_e;
1395 cap_flag_value_t value_i;
1396 cap_flag_value_t value_p;
1397 int r;
1398
1399 // Fetch PID
1400 pid_t pid = getpid();
1401
1402 // Fetch all capabilities
1403 caps = cap_get_proc();
1404 if (!caps) {
1405 ERROR(jail->pakfire, "Could not fetch capabilities: %m\n");
1406 r = 1;
1407 goto ERROR;
1408 }
1409
1410 DEBUG(jail->pakfire, "Capabilities of PID %d:\n", pid);
1411
1412 // Iterate over all capabilities
1413 for (unsigned int cap = 0; cap_valid(cap); cap++) {
1414 name = cap_to_name(cap);
1415
1416 // Fetch effective value
1417 r = cap_get_flag(caps, cap, CAP_EFFECTIVE, &value_e);
1418 if (r)
1419 goto ERROR;
1420
1421 // Fetch inheritable value
1422 r = cap_get_flag(caps, cap, CAP_INHERITABLE, &value_i);
1423 if (r)
1424 goto ERROR;
1425
1426 // Fetch permitted value
1427 r = cap_get_flag(caps, cap, CAP_PERMITTED, &value_p);
1428 if (r)
1429 goto ERROR;
1430
1431 DEBUG(jail->pakfire,
1432 " %-24s : %c%c%c\n",
1433 name,
1434 (value_e == CAP_SET) ? 'e' : '-',
1435 (value_i == CAP_SET) ? 'i' : '-',
1436 (value_p == CAP_SET) ? 'p' : '-'
1437 );
1438
1439 // Free name
1440 cap_free(name);
1441 name = NULL;
1442 }
1443
1444 // Success
1445 r = 0;
1446
1447 ERROR:
1448 if (name)
1449 cap_free(name);
1450 if (caps)
1451 cap_free(caps);
1452
1453 return r;
1454 }
1455
1456 static int pakfire_jail_set_capabilities(struct pakfire_jail* jail) {
1457 cap_t caps = NULL;
1458 char* name = NULL;
1459 int r;
1460
1461 // Fetch capabilities
1462 caps = cap_get_proc();
1463 if (!caps) {
1464 ERROR(jail->pakfire, "Could not read capabilities: %m\n");
1465 r = 1;
1466 goto ERROR;
1467 }
1468
1469 // Walk through all capabilities
1470 for (cap_value_t cap = 0; cap_valid(cap); cap++) {
1471 cap_value_t _caps[] = { cap };
1472
1473 // Fetch the name of the capability
1474 name = cap_to_name(cap);
1475
1476 r = cap_set_flag(caps, CAP_EFFECTIVE, 1, _caps, CAP_SET);
1477 if (r) {
1478 ERROR(jail->pakfire, "Could not set %s: %m\n", name);
1479 goto ERROR;
1480 }
1481
1482 r = cap_set_flag(caps, CAP_INHERITABLE, 1, _caps, CAP_SET);
1483 if (r) {
1484 ERROR(jail->pakfire, "Could not set %s: %m\n", name);
1485 goto ERROR;
1486 }
1487
1488 r = cap_set_flag(caps, CAP_PERMITTED, 1, _caps, CAP_SET);
1489 if (r) {
1490 ERROR(jail->pakfire, "Could not set %s: %m\n", name);
1491 goto ERROR;
1492 }
1493
1494 // Free name
1495 cap_free(name);
1496 name = NULL;
1497 }
1498
1499 // Restore all capabilities
1500 r = cap_set_proc(caps);
1501 if (r) {
1502 ERROR(jail->pakfire, "Restoring capabilities failed: %m\n");
1503 goto ERROR;
1504 }
1505
1506 // Add all capabilities to the ambient set
1507 for (unsigned int cap = 0; cap_valid(cap); cap++) {
1508 name = cap_to_name(cap);
1509
1510 // Raise the capability
1511 r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
1512 if (r) {
1513 ERROR(jail->pakfire, "Could not set ambient capability %s: %m\n", name);
1514 goto ERROR;
1515 }
1516
1517 // Free name
1518 cap_free(name);
1519 name = NULL;
1520 }
1521
1522 // Success
1523 r = 0;
1524
1525 ERROR:
1526 if (name)
1527 cap_free(name);
1528 if (caps)
1529 cap_free(caps);
1530
1531 return r;
1532 }
1533
1534 // Syscall Filter
1535
1536 static int pakfire_jail_limit_syscalls(struct pakfire_jail* jail) {
1537 const int syscalls[] = {
1538 // The kernel's keyring isn't namespaced
1539 SCMP_SYS(keyctl),
1540 SCMP_SYS(add_key),
1541 SCMP_SYS(request_key),
1542
1543 // Disable userfaultfd
1544 SCMP_SYS(userfaultfd),
1545
1546 // Disable perf which could leak a lot of information about the host
1547 SCMP_SYS(perf_event_open),
1548
1549 0,
1550 };
1551 int r = 1;
1552
1553 DEBUG(jail->pakfire, "Applying syscall filter...\n");
1554
1555 // Setup a syscall filter which allows everything by default
1556 scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
1557 if (!ctx) {
1558 ERROR(jail->pakfire, "Could not setup seccomp filter: %m\n");
1559 goto ERROR;
1560 }
1561
1562 // All all syscalls
1563 for (const int* syscall = syscalls; *syscall; syscall++) {
1564 r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), *syscall, 0);
1565 if (r) {
1566 ERROR(jail->pakfire, "Could not configure syscall %d: %m\n", *syscall);
1567 goto ERROR;
1568 }
1569 }
1570
1571 // Load syscall filter into the kernel
1572 r = seccomp_load(ctx);
1573 if (r) {
1574 ERROR(jail->pakfire, "Could not load syscall filter into the kernel: %m\n");
1575 goto ERROR;
1576 }
1577
1578 ERROR:
1579 if (ctx)
1580 seccomp_release(ctx);
1581
1582 return r;
1583 }
1584
1585 // Mountpoints
1586
1587 PAKFIRE_EXPORT int pakfire_jail_bind(struct pakfire_jail* jail,
1588 const char* source, const char* target, int flags) {
1589 struct pakfire_jail_mountpoint* mp = NULL;
1590 int r;
1591
1592 // Check if there is any space left
1593 if (jail->num_mountpoints >= MAX_MOUNTPOINTS) {
1594 errno = ENOSPC;
1595 return 1;
1596 }
1597
1598 // Check for valid inputs
1599 if (!source || !target) {
1600 errno = EINVAL;
1601 return 1;
1602 }
1603
1604 // Select the next free slot
1605 mp = &jail->mountpoints[jail->num_mountpoints];
1606
1607 // Copy source
1608 r = pakfire_string_set(mp->source, source);
1609 if (r) {
1610 ERROR(jail->pakfire, "Could not copy source: %m\n");
1611 return r;
1612 }
1613
1614 // Copy target
1615 r = pakfire_string_set(mp->target, target);
1616 if (r) {
1617 ERROR(jail->pakfire, "Could not copy target: %m\n");
1618 return r;
1619 }
1620
1621 // Copy flags
1622 mp->flags = flags;
1623
1624 // Increment counter
1625 jail->num_mountpoints++;
1626
1627 return 0;
1628 }
1629
1630 static int pakfire_jail_mount_networking(struct pakfire_jail* jail) {
1631 int r;
1632
1633 const char* paths[] = {
1634 "/etc/hosts",
1635 "/etc/resolv.conf",
1636 NULL,
1637 };
1638
1639 // Bind-mount all paths read-only
1640 for (const char** path = paths; *path; path++) {
1641 r = pakfire_bind(jail->pakfire, *path, NULL, MS_RDONLY);
1642 if (r) {
1643 switch (errno) {
1644 // Ignore if we don't have permission
1645 case EPERM:
1646 continue;
1647
1648 default:
1649 break;
1650 }
1651 return r;
1652 }
1653 }
1654
1655 return 0;
1656 }
1657
1658 /*
1659 Mounts everything that we require in the new namespace
1660 */
1661 static int pakfire_jail_mount(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1662 struct pakfire_jail_mountpoint* mp = NULL;
1663 int flags = 0;
1664 int r;
1665
1666 // Enable loop devices
1667 if (pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_LOOP_DEVICES))
1668 flags |= PAKFIRE_MOUNT_LOOP_DEVICES;
1669
1670 // Mount all default stuff
1671 r = pakfire_mount_all(jail->pakfire, PAKFIRE_MNTNS_OUTER, flags);
1672 if (r)
1673 return r;
1674
1675 // Populate /dev
1676 r = pakfire_populate_dev(jail->pakfire, flags);
1677 if (r)
1678 return r;
1679
1680 // Mount the interpreter (if needed)
1681 r = pakfire_mount_interpreter(jail->pakfire);
1682 if (r)
1683 return r;
1684
1685 // Mount networking stuff
1686 if (pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
1687 r = pakfire_jail_mount_networking(jail);
1688 if (r)
1689 return r;
1690 }
1691
1692 // Mount all custom stuff
1693 for (unsigned int i = 0; i < jail->num_mountpoints; i++) {
1694 // Fetch mountpoint
1695 mp = &jail->mountpoints[i];
1696
1697 // Mount it
1698 r = pakfire_bind(jail->pakfire, mp->source, mp->target, mp->flags);
1699 if (r)
1700 return r;
1701 }
1702
1703 return 0;
1704 }
1705
1706 // Networking
1707
1708 static int pakfire_jail_setup_loopback(struct pakfire_jail* jail) {
1709 struct nl_sock* nl = NULL;
1710 struct nl_cache* cache = NULL;
1711 struct rtnl_link* link = NULL;
1712 struct rtnl_link* change = NULL;
1713 int r;
1714
1715 DEBUG(jail->pakfire, "Setting up loopback...\n");
1716
1717 // Allocate a netlink socket
1718 nl = nl_socket_alloc();
1719 if (!nl) {
1720 ERROR(jail->pakfire, "Could not allocate a netlink socket: %m\n");
1721 r = 1;
1722 goto ERROR;
1723 }
1724
1725 // Connect the socket
1726 r = nl_connect(nl, NETLINK_ROUTE);
1727 if (r) {
1728 ERROR(jail->pakfire, "Could not connect netlink socket: %s\n", nl_geterror(r));
1729 goto ERROR;
1730 }
1731
1732 // Allocate the netlink cache
1733 r = rtnl_link_alloc_cache(nl, AF_UNSPEC, &cache);
1734 if (r < 0) {
1735 ERROR(jail->pakfire, "Unable to allocate netlink cache: %s\n", nl_geterror(r));
1736 goto ERROR;
1737 }
1738
1739 // Fetch loopback interface
1740 link = rtnl_link_get_by_name(cache, "lo");
1741 if (!link) {
1742 ERROR(jail->pakfire, "Could not find lo interface. Ignoring.\n");
1743 r = 0;
1744 goto ERROR;
1745 }
1746
1747 // Allocate a new link
1748 change = rtnl_link_alloc();
1749 if (!change) {
1750 ERROR(jail->pakfire, "Could not allocate change link\n");
1751 r = 1;
1752 goto ERROR;
1753 }
1754
1755 // Set the link to UP
1756 rtnl_link_set_flags(change, IFF_UP);
1757
1758 // Apply any changes
1759 r = rtnl_link_change(nl, link, change, 0);
1760 if (r) {
1761 ERROR(jail->pakfire, "Unable to activate loopback: %s\n", nl_geterror(r));
1762 goto ERROR;
1763 }
1764
1765 // Success
1766 r = 0;
1767
1768 ERROR:
1769 if (nl)
1770 nl_socket_free(nl);
1771
1772 return r;
1773 }
1774
1775 // UID/GID Mapping
1776
1777 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail* jail, pid_t pid) {
1778 char path[PATH_MAX];
1779 int r;
1780
1781 // Skip mapping anything when running on /
1782 if (pakfire_on_root(jail->pakfire))
1783 return 0;
1784
1785 // Make path
1786 r = pakfire_string_format(path, "/proc/%d/uid_map", pid);
1787 if (r)
1788 return r;
1789
1790 // Fetch UID
1791 const uid_t uid = pakfire_uid(jail->pakfire);
1792
1793 // Fetch SUBUID
1794 const struct pakfire_subid* subuid = pakfire_subuid(jail->pakfire);
1795 if (!subuid)
1796 return 1;
1797
1798 /* When running as root, we will map the entire range.
1799
1800 When running as a non-privileged user, we will map the root user inside the jail
1801 to the user's UID outside of the jail, and we will map the rest starting from one.
1802 */
1803
1804 // Running as root
1805 if (uid == 0) {
1806 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1807 "0 %lu %lu\n", subuid->id, subuid->length);
1808 } else {
1809 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1810 "0 %lu 1\n1 %lu %lu\n", uid, subuid->id, subuid->length);
1811 }
1812
1813 if (r) {
1814 ERROR(jail->pakfire, "Could not map UIDs: %m\n");
1815 return r;
1816 }
1817
1818 return r;
1819 }
1820
1821 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail* jail, pid_t pid) {
1822 char path[PATH_MAX];
1823 int r;
1824
1825 // Skip mapping anything when running on /
1826 if (pakfire_on_root(jail->pakfire))
1827 return 0;
1828
1829 // Fetch GID
1830 const gid_t gid = pakfire_gid(jail->pakfire);
1831
1832 // Fetch SUBGID
1833 const struct pakfire_subid* subgid = pakfire_subgid(jail->pakfire);
1834 if (!subgid)
1835 return 1;
1836
1837 // Make path
1838 r = pakfire_string_format(path, "/proc/%d/gid_map", pid);
1839 if (r)
1840 return r;
1841
1842 // Running as root
1843 if (gid == 0) {
1844 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1845 "0 %lu %lu\n", subgid->id, subgid->length);
1846 } else {
1847 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1848 "0 %lu 1\n1 %lu %lu\n", gid, subgid->id, subgid->length);
1849 }
1850
1851 if (r) {
1852 ERROR(jail->pakfire, "Could not map GIDs: %m\n");
1853 return r;
1854 }
1855
1856 return r;
1857 }
1858
1859 static int pakfire_jail_setgroups(struct pakfire_jail* jail, pid_t pid) {
1860 char path[PATH_MAX];
1861 int r;
1862
1863 // Make path
1864 r = pakfire_string_format(path, "/proc/%d/setgroups", pid);
1865 if (r)
1866 return r;
1867
1868 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0, "deny\n");
1869 if (r) {
1870 CTX_ERROR(jail->ctx, "Could not set setgroups to deny: %s\n", strerror(errno));
1871 r = -errno;
1872 }
1873
1874 return r;
1875 }
1876
1877 static int pakfire_jail_send_signal(struct pakfire_jail* jail, int fd) {
1878 const uint64_t val = 1;
1879 int r = 0;
1880
1881 DEBUG(jail->pakfire, "Sending signal...\n");
1882
1883 // Write to the file descriptor
1884 r = eventfd_write(fd, val);
1885 if (r < 0) {
1886 ERROR(jail->pakfire, "Could not send signal: %s\n", strerror(errno));
1887 r = -errno;
1888 }
1889
1890 // Close the file descriptor
1891 close(fd);
1892
1893 return r;
1894 }
1895
1896 static int pakfire_jail_wait_for_signal(struct pakfire_jail* jail, int fd) {
1897 uint64_t val = 0;
1898 int r = 0;
1899
1900 DEBUG(jail->pakfire, "Waiting for signal...\n");
1901
1902 r = eventfd_read(fd, &val);
1903 if (r < 0) {
1904 ERROR(jail->pakfire, "Error waiting for signal: %s\n", strerror(errno));
1905 r = -errno;
1906 }
1907
1908 // Close the file descriptor
1909 close(fd);
1910
1911 return r;
1912 }
1913
1914 /*
1915 Performs the initialisation that needs to happen in the parent part
1916 */
1917 static int pakfire_jail_parent(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1918 int r;
1919
1920 // Setup UID mapping
1921 r = pakfire_jail_setup_uid_mapping(jail, ctx->pid);
1922 if (r)
1923 return r;
1924
1925 // Write "deny" to /proc/PID/setgroups
1926 r = pakfire_jail_setgroups(jail, ctx->pid);
1927 if (r)
1928 return r;
1929
1930 // Setup GID mapping
1931 r = pakfire_jail_setup_gid_mapping(jail, ctx->pid);
1932 if (r)
1933 return r;
1934
1935 // Parent has finished initialisation
1936 DEBUG(jail->pakfire, "Parent has finished initialization\n");
1937
1938 // Send signal to client
1939 r = pakfire_jail_send_signal(jail, ctx->completed_fd);
1940 if (r)
1941 return r;
1942
1943 return 0;
1944 }
1945
1946 static int pakfire_jail_switch_root(struct pakfire_jail* jail, const char* root) {
1947 int r;
1948
1949 // Change to the new root
1950 r = chdir(root);
1951 if (r) {
1952 ERROR(jail->pakfire, "chdir(%s) failed: %m\n", root);
1953 return r;
1954 }
1955
1956 // Switch Root!
1957 r = pivot_root(".", ".");
1958 if (r) {
1959 ERROR(jail->pakfire, "Failed changing into the new root directory %s: %m\n", root);
1960 return r;
1961 }
1962
1963 // Umount the old root
1964 r = umount2(".", MNT_DETACH);
1965 if (r) {
1966 ERROR(jail->pakfire, "Could not umount the old root filesystem: %m\n");
1967 return r;
1968 }
1969
1970 return 0;
1971 }
1972
1973 static int pakfire_jail_open_pty(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1974 int r;
1975
1976 // Allocate a new PTY
1977 ctx->pty.master.fd = posix_openpt(O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
1978 if (ctx->pty.master.fd < 0)
1979 return -errno;
1980
1981 // Fetch the path
1982 r = ptsname_r(ctx->pty.master.fd, ctx->pty.console, sizeof(ctx->pty.console));
1983 if (r)
1984 return -r;
1985
1986 CTX_DEBUG(jail->ctx, "Allocated console at %s (%d)\n", ctx->pty.console, ctx->pty.master.fd);
1987
1988 // Unlock the master device
1989 r = unlockpt(ctx->pty.master.fd);
1990 if (r) {
1991 CTX_ERROR(jail->ctx, "Could not unlock the PTY: %s\n", strerror(errno));
1992 return -errno;
1993 }
1994
1995 // Create a symlink
1996 r = pakfire_symlink(jail->ctx, ctx->pty.console, "/dev/console");
1997 if (r)
1998 return r;
1999
2000 return r;
2001 }
2002
2003 static int pakfire_jail_setup_terminal(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
2004 int fd;
2005 int r;
2006
2007 // Open a new terminal
2008 fd = open("/dev/console", O_RDWR|O_NOCTTY);
2009 if (fd < 0) {
2010 CTX_ERROR(jail->ctx, "Failed to open a new terminal: %s\n", strerror(errno));
2011 return -errno;
2012 }
2013
2014 CTX_DEBUG(jail->ctx, "Opened a new terminal %d\n", fd);
2015
2016 // Connect the new terminal to standard input
2017 r = dup2(fd, STDIN_FILENO);
2018 if (r < 0) {
2019 CTX_ERROR(jail->ctx, "Failed to open standard input: %s\n", strerror(errno));
2020 return -errno;
2021 }
2022
2023 // Connect the new terminal to standard output
2024 r = dup2(fd, STDOUT_FILENO);
2025 if (r < 0) {
2026 CTX_ERROR(jail->ctx, "Failed to open standard output: %s\n", strerror(errno));
2027 return -errno;
2028 }
2029
2030 // Connect the new terminal to standard error
2031 r = dup2(fd, STDERR_FILENO);
2032 if (r < 0) {
2033 CTX_ERROR(jail->ctx, "Failed to open standard error: %s\n", strerror(errno));
2034 return -errno;
2035 }
2036
2037 return 0;
2038 }
2039
2040 static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
2041 const char* argv[]) {
2042 int r;
2043
2044 // Redirect any logging to our log pipe
2045 pakfire_ctx_set_log_callback(jail->ctx, pakfire_jail_log_redirect, &ctx->pipes);
2046
2047 // Fetch my own PID
2048 pid_t pid = getpid();
2049
2050 DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", pid);
2051
2052 // Wait for the parent to finish initialization
2053 r = pakfire_jail_wait_for_signal(jail, ctx->completed_fd);
2054 if (r)
2055 return r;
2056
2057 // Die with parent
2058 r = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
2059 if (r) {
2060 ERROR(jail->pakfire, "Could not configure to die with parent: %m\n");
2061 return 126;
2062 }
2063
2064 // Make this process dumpable
2065 r = prctl (PR_SET_DUMPABLE, 1, 0, 0, 0);
2066 if (r) {
2067 ERROR(jail->pakfire, "Could not make the process dumpable: %m\n");
2068 return 126;
2069 }
2070
2071 // Don't drop any capabilities on setuid()
2072 r = prctl(PR_SET_KEEPCAPS, 1);
2073 if (r) {
2074 ERROR(jail->pakfire, "Could not set PR_SET_KEEPCAPS: %m\n");
2075 return 126;
2076 }
2077
2078 // Fetch UID/GID
2079 uid_t uid = getuid();
2080 gid_t gid = getgid();
2081
2082 // Fetch EUID/EGID
2083 uid_t euid = geteuid();
2084 gid_t egid = getegid();
2085
2086 DEBUG(jail->pakfire, " UID: %u (effective %u)\n", uid, euid);
2087 DEBUG(jail->pakfire, " GID: %u (effective %u)\n", gid, egid);
2088
2089 // Log all mountpoints
2090 pakfire_mount_list(jail->ctx);
2091
2092 // Fail if we are not PID 1
2093 if (pid != 1) {
2094 CTX_ERROR(jail->ctx, "Child process is not PID 1\n");
2095 return 126;
2096 }
2097
2098 // Fail if we are not running as root
2099 if (uid || gid || euid || egid) {
2100 ERROR(jail->pakfire, "Child process is not running as root\n");
2101 return 126;
2102 }
2103
2104 const int socket_send = pakfire_jail_get_pipe_to_write(jail, &ctx->socket);
2105
2106 // Mount all default stuff
2107 r = pakfire_mount_all(jail->pakfire, PAKFIRE_MNTNS_INNER, 0);
2108 if (r)
2109 return 126;
2110
2111 const char* root = pakfire_get_path(jail->pakfire);
2112 const char* arch = pakfire_get_effective_arch(jail->pakfire);
2113
2114 // Change mount propagation to slave to receive anything from the parent namespace
2115 r = pakfire_mount_change_propagation(jail->ctx, "/", MS_SLAVE);
2116 if (r)
2117 return r;
2118
2119 // Make root a mountpoint in the new mount namespace
2120 r = pakfire_mount_make_mounpoint(jail->pakfire, root);
2121 if (r)
2122 return r;
2123
2124 // Change mount propagation to private
2125 r = pakfire_mount_change_propagation(jail->ctx, root, MS_PRIVATE);
2126 if (r)
2127 return r;
2128
2129 // Change root (unless root is /)
2130 if (!pakfire_on_root(jail->pakfire)) {
2131 // Mount everything
2132 r = pakfire_jail_mount(jail, ctx);
2133 if (r)
2134 return r;
2135
2136 // chroot()
2137 r = pakfire_jail_switch_root(jail, root);
2138 if (r)
2139 return r;
2140 }
2141
2142 // Set personality
2143 unsigned long persona = pakfire_arch_personality(arch);
2144 if (persona) {
2145 r = personality(persona);
2146 if (r < 0) {
2147 ERROR(jail->pakfire, "Could not set personality (%x)\n", (unsigned int)persona);
2148 return 1;
2149 }
2150 }
2151
2152 // Setup networking
2153 if (!pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
2154 r = pakfire_jail_setup_loopback(jail);
2155 if (r)
2156 return 1;
2157 }
2158
2159 // Set nice level
2160 if (jail->nice) {
2161 DEBUG(jail->pakfire, "Setting nice level to %d\n", jail->nice);
2162
2163 r = setpriority(PRIO_PROCESS, pid, jail->nice);
2164 if (r) {
2165 ERROR(jail->pakfire, "Could not set nice level: %m\n");
2166 return 1;
2167 }
2168 }
2169
2170 // Create a new session
2171 r = setsid();
2172 if (r < 0) {
2173 CTX_ERROR(jail->ctx, "Could not create a new session: %s\n", strerror(errno));
2174 return r;
2175 }
2176
2177 // Allocate a new PTY
2178 r = pakfire_jail_open_pty(jail, ctx);
2179 if (r) {
2180 CTX_ERROR(jail->ctx, "Could not allocate a new PTY: %s\n", strerror(-r));
2181 return r;
2182 }
2183
2184 // Send the PTY master to the parent process
2185 r = pakfire_jail_send_fd(jail, socket_send, ctx->pty.master.fd);
2186 if (r) {
2187 CTX_ERROR(jail->ctx, "Failed sending the PTY master to the parent: %s\n", strerror(-r));
2188 return r;
2189 }
2190
2191 // Setup the terminal
2192 r = pakfire_jail_setup_terminal(jail, ctx);
2193 if (r)
2194 return r;
2195
2196 // Close the master of the PTY
2197 close(ctx->pty.master.fd);
2198 ctx->pty.master.fd = -1;
2199
2200 // Close the socket
2201 close(socket_send);
2202
2203 // Close other end of log pipes
2204 close(ctx->pipes.log_INFO[0]);
2205 close(ctx->pipes.log_ERROR[0]);
2206 #ifdef ENABLE_DEBUG
2207 close(ctx->pipes.log_DEBUG[0]);
2208 #endif /* ENABLE_DEBUG */
2209
2210 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
2211 r = pakfire_rlimit_reset_nofile(jail->pakfire);
2212 if (r)
2213 return r;
2214
2215 // Set capabilities
2216 r = pakfire_jail_set_capabilities(jail);
2217 if (r)
2218 return r;
2219
2220 // Show capabilities
2221 r = pakfire_jail_show_capabilities(jail);
2222 if (r)
2223 return r;
2224
2225 // Filter syscalls
2226 r = pakfire_jail_limit_syscalls(jail);
2227 if (r)
2228 return r;
2229
2230 DEBUG(jail->pakfire, "Child process initialization done\n");
2231 DEBUG(jail->pakfire, "Launching command:\n");
2232
2233 // Log argv
2234 for (unsigned int i = 0; argv[i]; i++)
2235 DEBUG(jail->pakfire, " argv[%u] = %s\n", i, argv[i]);
2236
2237 // exec() command
2238 r = execvpe(argv[0], (char**)argv, jail->env);
2239 if (r < 0) {
2240 // Translate errno into regular exit code
2241 switch (errno) {
2242 case ENOENT:
2243 // Ignore if the command doesn't exist
2244 if (ctx->flags & PAKFIRE_JAIL_NOENT_OK)
2245 r = 0;
2246 else
2247 r = 127;
2248
2249 break;
2250
2251 default:
2252 r = 1;
2253 }
2254
2255 ERROR(jail->pakfire, "Could not execve(%s): %m\n", argv[0]);
2256 }
2257
2258 // We should not get here
2259 return r;
2260 }
2261
2262 // Run a command in the jail
2263 static int __pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[],
2264 pakfire_jail_communicate_in communicate_in,
2265 pakfire_jail_communicate_out communicate_out,
2266 void* data, int flags) {
2267 int exit = -1;
2268 int r;
2269
2270 // Check if argv is valid
2271 if (!argv || !argv[0]) {
2272 errno = EINVAL;
2273 return -1;
2274 }
2275
2276 // Initialize context for this call
2277 struct pakfire_jail_exec ctx = {
2278 .flags = flags,
2279
2280 .socket = { -1, -1 },
2281
2282 .pipes = {
2283 .log_INFO = { -1, -1 },
2284 .log_ERROR = { -1, -1 },
2285 #ifdef ENABLE_DEBUG
2286 .log_DEBUG = { -1, -1 },
2287 #endif /* ENABLE_DEBUG */
2288 },
2289
2290 .communicate = {
2291 .in = communicate_in,
2292 .out = communicate_out,
2293 .data = data,
2294 },
2295
2296 .pidfd = -1,
2297
2298 // PTY
2299 .pty = {
2300 .master = {
2301 .fd = -1,
2302 },
2303 .stdin = {
2304 .fd = -1,
2305 },
2306 .stdout = {
2307 .fd = -1,
2308 },
2309 },
2310 };
2311
2312 DEBUG(jail->pakfire, "Executing jail...\n");
2313
2314 // Enable networking in interactive mode
2315 if (ctx.flags & PAKFIRE_JAIL_PTY_FORWARDING)
2316 ctx.flags |= PAKFIRE_JAIL_HAS_NETWORKING;
2317
2318 /*
2319 Setup a file descriptor which can be used to notify the client that the parent
2320 has completed configuration.
2321 */
2322 ctx.completed_fd = eventfd(0, EFD_CLOEXEC);
2323 if (ctx.completed_fd < 0) {
2324 ERROR(jail->pakfire, "eventfd() failed: %m\n");
2325 return -1;
2326 }
2327
2328 // Create a UNIX domain socket
2329 r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ctx.socket);
2330 if (r < 0) {
2331 CTX_ERROR(jail->ctx, "Could not create UNIX socket: %s\n", strerror(errno));
2332 r = -errno;
2333 goto ERROR;
2334 }
2335
2336 // Setup pipes for logging
2337 // INFO
2338 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_INFO, O_CLOEXEC);
2339 if (r)
2340 goto ERROR;
2341
2342 // ERROR
2343 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_ERROR, O_CLOEXEC);
2344 if (r)
2345 goto ERROR;
2346
2347 #ifdef ENABLE_DEBUG
2348 // DEBUG
2349 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_DEBUG, O_CLOEXEC);
2350 if (r)
2351 goto ERROR;
2352 #endif /* ENABLE_DEBUG */
2353
2354 // Configure child process
2355 struct clone_args args = {
2356 .flags =
2357 CLONE_NEWCGROUP |
2358 CLONE_NEWIPC |
2359 CLONE_NEWNS |
2360 CLONE_NEWPID |
2361 CLONE_NEWTIME |
2362 CLONE_NEWUSER |
2363 CLONE_NEWUTS |
2364 CLONE_PIDFD,
2365 .exit_signal = SIGCHLD,
2366 .pidfd = (long long unsigned int)&ctx.pidfd,
2367 };
2368
2369 // Launch the process in a cgroup that is a leaf of the configured cgroup
2370 if (jail->cgroup) {
2371 args.flags |= CLONE_INTO_CGROUP;
2372
2373 // Fetch our UUID
2374 const char* uuid = pakfire_jail_uuid(jail);
2375
2376 // Create a temporary cgroup
2377 r = pakfire_cgroup_child(&ctx.cgroup, jail->cgroup, uuid, 0);
2378 if (r) {
2379 ERROR(jail->pakfire, "Could not create cgroup for jail: %m\n");
2380 goto ERROR;
2381 }
2382
2383 // Clone into this cgroup
2384 args.cgroup = pakfire_cgroup_fd(ctx.cgroup);
2385 }
2386
2387 // Setup networking
2388 if (!pakfire_jail_exec_has_flag(&ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
2389 args.flags |= CLONE_NEWNET;
2390 }
2391
2392 // Fork this process
2393 ctx.pid = clone3(&args, sizeof(args));
2394 if (ctx.pid < 0) {
2395 ERROR(jail->pakfire, "Could not clone: %m\n");
2396 return -1;
2397
2398 // Child process
2399 } else if (ctx.pid == 0) {
2400 r = pakfire_jail_child(jail, &ctx, argv);
2401 _exit(r);
2402 }
2403
2404 // Parent process
2405 r = pakfire_jail_parent(jail, &ctx);
2406 if (r)
2407 goto ERROR;
2408
2409 DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", ctx.pid);
2410
2411 // Read output of the child process
2412 r = pakfire_jail_wait(jail, &ctx);
2413 if (r)
2414 goto ERROR;
2415
2416 // Handle exit status
2417 switch (ctx.status.si_code) {
2418 case CLD_EXITED:
2419 DEBUG(jail->pakfire, "The child process exited with code %d\n",
2420 ctx.status.si_status);
2421
2422 // Pass exit code
2423 exit = ctx.status.si_status;
2424 break;
2425
2426 case CLD_KILLED:
2427 ERROR(jail->pakfire, "The child process was killed\n");
2428 exit = 139;
2429 break;
2430
2431 case CLD_DUMPED:
2432 ERROR(jail->pakfire, "The child process terminated abnormally\n");
2433 break;
2434
2435 // Log anything else
2436 default:
2437 ERROR(jail->pakfire, "Unknown child exit code: %d\n", ctx.status.si_code);
2438 break;
2439 }
2440
2441 ERROR:
2442 // Destroy the temporary cgroup (if any)
2443 if (ctx.cgroup) {
2444 // Read cgroup stats
2445 pakfire_cgroup_stat(ctx.cgroup, &ctx.cgroup_stats);
2446 pakfire_cgroup_stat_dump(ctx.cgroup, &ctx.cgroup_stats);
2447 pakfire_cgroup_destroy(ctx.cgroup);
2448 pakfire_cgroup_unref(ctx.cgroup);
2449 }
2450
2451 // Close any file descriptors
2452 if (ctx.pidfd >= 0)
2453 close(ctx.pidfd);
2454 if (ctx.pty.master.fd >= 0)
2455 close(ctx.pty.master.fd);
2456 pakfire_jail_close_pipe(jail, ctx.pipes.log_INFO);
2457 pakfire_jail_close_pipe(jail, ctx.pipes.log_ERROR);
2458 #ifdef ENABLE_DEBUG
2459 pakfire_jail_close_pipe(jail, ctx.pipes.log_DEBUG);
2460 #endif /* ENABLE_DEBUG */
2461 pakfire_jail_close_pipe(jail, ctx.socket);
2462
2463 return exit;
2464 }
2465
2466 PAKFIRE_EXPORT int pakfire_jail_exec(
2467 struct pakfire_jail* jail,
2468 const char* argv[],
2469 pakfire_jail_communicate_in callback_in,
2470 pakfire_jail_communicate_out callback_out,
2471 void* data, int flags) {
2472 return __pakfire_jail_exec(jail, argv, callback_in, callback_out, data, flags);
2473 }
2474
2475 static int pakfire_jail_exec_interactive(
2476 struct pakfire_jail* jail, const char* argv[], int flags) {
2477 int r;
2478
2479 flags |= PAKFIRE_JAIL_PTY_FORWARDING;
2480
2481 // Setup interactive stuff
2482 r = pakfire_jail_setup_interactive_env(jail);
2483 if (r)
2484 return r;
2485
2486 return __pakfire_jail_exec(jail, argv, NULL, NULL, NULL, flags);
2487 }
2488
2489 int pakfire_jail_exec_script(struct pakfire_jail* jail,
2490 const char* script,
2491 const size_t size,
2492 const char* args[],
2493 pakfire_jail_communicate_in callback_in,
2494 pakfire_jail_communicate_out callback_out,
2495 void* data) {
2496 char path[PATH_MAX];
2497 const char** argv = NULL;
2498 FILE* f = NULL;
2499 int r;
2500
2501 const char* root = pakfire_get_path(jail->pakfire);
2502
2503 // Write the scriptlet to disk
2504 r = pakfire_path_append(path, root, PAKFIRE_TMP_DIR "/pakfire-script.XXXXXX");
2505 if (r)
2506 goto ERROR;
2507
2508 // Create a temporary file
2509 f = pakfire_mktemp(path, 0700);
2510 if (!f) {
2511 ERROR(jail->pakfire, "Could not create temporary file: %m\n");
2512 goto ERROR;
2513 }
2514
2515 DEBUG(jail->pakfire, "Writing script to %s:\n%.*s\n", path, (int)size, script);
2516
2517 // Write data
2518 r = fprintf(f, "%s", script);
2519 if (r < 0) {
2520 ERROR(jail->pakfire, "Could not write script to file %s: %m\n", path);
2521 goto ERROR;
2522 }
2523
2524 // Close file
2525 r = fclose(f);
2526 if (r) {
2527 ERROR(jail->pakfire, "Could not close script file %s: %m\n", path);
2528 goto ERROR;
2529 }
2530
2531 f = NULL;
2532
2533 // Count how many arguments were passed
2534 unsigned int argc = 1;
2535 if (args) {
2536 for (const char** arg = args; *arg; arg++)
2537 argc++;
2538 }
2539
2540 argv = calloc(argc + 1, sizeof(*argv));
2541 if (!argv) {
2542 ERROR(jail->pakfire, "Could not allocate argv: %m\n");
2543 goto ERROR;
2544 }
2545
2546 // Set command
2547 argv[0] = (root) ? pakfire_path_relpath(root, path) : path;
2548
2549 // Copy args
2550 for (unsigned int i = 1; i < argc; i++)
2551 argv[i] = args[i-1];
2552
2553 // Run the script
2554 r = pakfire_jail_exec(jail, argv, callback_in, callback_out, data, 0);
2555
2556 ERROR:
2557 if (argv)
2558 free(argv);
2559 if (f)
2560 fclose(f);
2561
2562 // Remove script from disk
2563 if (*path)
2564 unlink(path);
2565
2566 return r;
2567 }
2568
2569 /*
2570 A convenience function that creates a new jail, runs the given command and destroys
2571 the jail again.
2572 */
2573 int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], int flags, char** output) {
2574 struct pakfire_jail* jail = NULL;
2575 int r;
2576
2577 // Create a new jail
2578 r = pakfire_jail_create(&jail, pakfire);
2579 if (r)
2580 goto ERROR;
2581
2582 // Execute the command
2583 r = pakfire_jail_exec(jail, argv, NULL, pakfire_jail_capture_stdout, output, 0);
2584
2585 ERROR:
2586 if (jail)
2587 pakfire_jail_unref(jail);
2588
2589 return r;
2590 }
2591
2592 int pakfire_jail_run_script(struct pakfire* pakfire,
2593 const char* script, const size_t length, const char* argv[], int flags) {
2594 struct pakfire_jail* jail = NULL;
2595 int r;
2596
2597 // Create a new jail
2598 r = pakfire_jail_create(&jail, pakfire);
2599 if (r)
2600 goto ERROR;
2601
2602 // Execute the command
2603 r = pakfire_jail_exec_script(jail, script, length, argv, NULL, NULL, NULL);
2604
2605 ERROR:
2606 if (jail)
2607 pakfire_jail_unref(jail);
2608
2609 return r;
2610 }
2611
2612 int pakfire_jail_shell(struct pakfire_jail* jail) {
2613 int r;
2614
2615 const char* argv[] = {
2616 "/bin/bash", "--login", NULL,
2617 };
2618
2619 // Execute /bin/bash
2620 r = pakfire_jail_exec_interactive(jail, argv, 0);
2621
2622 // Raise any errors
2623 if (r < 0)
2624 return r;
2625
2626 // Ignore any return codes from the shell
2627 return 0;
2628 }
2629
2630 static int pakfire_jail_run_if_possible(struct pakfire* pakfire, const char** argv) {
2631 char path[PATH_MAX];
2632 int r;
2633
2634 r = pakfire_path(pakfire, path, "%s", *argv);
2635 if (r)
2636 return r;
2637
2638 // Check if the file is executable
2639 r = access(path, X_OK);
2640 if (r) {
2641 DEBUG(pakfire, "%s is not executable. Skipping...\n", *argv);
2642 return 0;
2643 }
2644
2645 return pakfire_jail_run(pakfire, argv, 0, NULL);
2646 }
2647
2648 int pakfire_jail_ldconfig(struct pakfire* pakfire) {
2649 const char* argv[] = {
2650 "/sbin/ldconfig",
2651 NULL,
2652 };
2653
2654 return pakfire_jail_run_if_possible(pakfire, argv);
2655 }
2656
2657 int pakfire_jail_run_systemd_tmpfiles(struct pakfire* pakfire) {
2658 const char* argv[] = {
2659 "/usr/bin/systemd-tmpfiles",
2660 "--create",
2661 NULL,
2662 };
2663
2664 return pakfire_jail_run_if_possible(pakfire, argv);
2665 }