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