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