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