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