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