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