]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/jail.c
jail: Use struct in execution context
[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 <sched.h>
26 #include <signal.h>
27 #include <stdlib.h>
28 #include <syscall.h>
29 #include <sys/capability.h>
30 #include <sys/epoll.h>
31 #include <sys/eventfd.h>
32 #include <sys/personality.h>
33 #include <sys/prctl.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36
37 // libseccomp
38 #include <seccomp.h>
39
40 #include <pakfire/arch.h>
41 #include <pakfire/jail.h>
42 #include <pakfire/logging.h>
43 #include <pakfire/mount.h>
44 #include <pakfire/pakfire.h>
45 #include <pakfire/util.h>
46
47 #define BUFFER_SIZE 1024 * 64
48 #define ENVIRON_SIZE 128
49 #define EPOLL_MAX_EVENTS 2
50
51 // The default environment that will be set for every command
52 static const struct environ {
53 const char* key;
54 const char* val;
55 } ENV[] = {
56 { "LANG", "en_US.utf-8" },
57 { "TERM", "vt100" },
58 { NULL, NULL },
59 };
60
61 struct pakfire_jail {
62 struct pakfire* pakfire;
63 int nrefs;
64
65 // Flags
66 int flags;
67
68 // Environment
69 char* env[ENVIRON_SIZE];
70
71 // Logging
72 pakfire_jail_log_callback log_callback;
73 void* log_data;
74 };
75
76 struct pakfire_log_buffer {
77 char data[BUFFER_SIZE];
78 size_t used;
79 };
80
81 struct pakfire_jail_exec {
82 // PID (of the child)
83 pid_t pid;
84
85 // Process status (from waitpid)
86 int status;
87
88 // FD to notify the client that the parent has finished initialization
89 int completed_fd;
90
91 // Log pipes
92 struct {
93 int stdout[2];
94 int stderr[2];
95 } pipes;
96
97 // Log buffers
98 struct {
99 struct pakfire_log_buffer stdout;
100 struct pakfire_log_buffer stderr;
101 } buffers;
102 };
103
104 static int clone3(struct clone_args* args, size_t size) {
105 return syscall(__NR_clone3, args, size);
106 }
107
108 static void pakfire_jail_free(struct pakfire_jail* jail) {
109 DEBUG(jail->pakfire, "Freeing jail at %p\n", jail);
110
111 // Free environment
112 for (unsigned int i = 0; jail->env[i]; i++)
113 free(jail->env[i]);
114
115 pakfire_unref(jail->pakfire);
116 free(jail);
117 }
118
119 static int pakfire_jail_default_log_callback(struct pakfire* pakfire, void* data,
120 int priority, const char* line, size_t length) {
121 switch (priority) {
122 case LOG_INFO:
123 INFO(pakfire, "%s", line);
124 break;
125
126 case LOG_ERR:
127 ERROR(pakfire, "%s", line);
128 break;
129 }
130
131 return 0;
132 }
133
134 static int pakfire_jail_setup_interactive_env(struct pakfire_jail* jail) {
135 // Set PS1
136 int r = pakfire_jail_set_env(jail, "PS1", "pakfire-jail \\w> ");
137 if (r)
138 return r;
139
140 // Copy TERM
141 char* TERM = secure_getenv("TERM");
142 if (TERM) {
143 r = pakfire_jail_set_env(jail, "TERM", TERM);
144 if (r)
145 return r;
146 }
147
148 // Copy LANG
149 char* LANG = secure_getenv("LANG");
150 if (LANG) {
151 r = pakfire_jail_set_env(jail, "LANG", LANG);
152 if (r)
153 return r;
154 }
155
156 return 0;
157 }
158
159 int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire, int flags) {
160 int r;
161
162 // Allocate a new jail
163 struct pakfire_jail* j = calloc(1, sizeof(*j));
164 if (!j)
165 return 1;
166
167 // Reference Pakfire
168 j->pakfire = pakfire_ref(pakfire);
169
170 // Initialize reference counter
171 j->nrefs = 1;
172
173 // Store flags
174 j->flags = flags;
175
176 DEBUG(j->pakfire, "Allocated new jail at %p\n", j);
177
178 // Set default log callback
179 r = pakfire_jail_set_log_callback(j, pakfire_jail_default_log_callback, NULL);
180 if (r)
181 goto ERROR;
182
183 // Set default environment
184 for (const struct environ* e = ENV; e->key; e++) {
185 r = pakfire_jail_set_env(j, e->key, e->val);
186 if (r)
187 goto ERROR;
188 }
189
190 // Setup interactive stuff
191 if (j->flags & PAKFIRE_JAIL_INTERACTIVE) {
192 r = pakfire_jail_setup_interactive_env(j);
193 if (r)
194 goto ERROR;
195 }
196
197 // Done
198 *jail = j;
199 return 0;
200
201 ERROR:
202 pakfire_jail_free(j);
203
204 return r;
205 }
206
207 struct pakfire_jail* pakfire_jail_ref(struct pakfire_jail* jail) {
208 ++jail->nrefs;
209
210 return jail;
211 }
212
213 struct pakfire_jail* pakfire_jail_unref(struct pakfire_jail* jail) {
214 if (--jail->nrefs > 0)
215 return jail;
216
217 pakfire_jail_free(jail);
218 return NULL;
219 }
220
221 static int pakfire_jail_has_flag(struct pakfire_jail* jail, int flag) {
222 return jail->flags & flag;
223 }
224
225 // Environment
226
227 // Returns the length of the environment
228 static unsigned int pakfire_jail_env_length(struct pakfire_jail* jail) {
229 unsigned int i = 0;
230
231 // Count everything in the environment
232 for (char** e = jail->env; *e; e++)
233 i++;
234
235 return i;
236 }
237
238 // Finds an existing environment variable and returns its index or -1 if not found
239 static int pakfire_jail_find_env(struct pakfire_jail* jail, const char* key) {
240 if (!key) {
241 errno = EINVAL;
242 return -1;
243 }
244
245 char buffer[strlen(key) + 2];
246 pakfire_string_format(buffer, "%s=", key);
247
248 for (unsigned int i = 0; jail->env[i]; i++) {
249 if (pakfire_string_startswith(jail->env[i], buffer))
250 return i;
251 }
252
253 // Nothing found
254 return -1;
255 }
256
257 // Returns the value of an environment variable or NULL
258 const char* pakfire_jail_get_env(struct pakfire_jail* jail, const char* key) {
259 int i = pakfire_jail_find_env(jail, key);
260 if (i < 0)
261 return NULL;
262
263 return jail->env[i] + strlen(key) + 1;
264 }
265
266 // Sets an environment variable
267 int pakfire_jail_set_env(struct pakfire_jail* jail, const char* key, const char* value) {
268 // Find the index where to write this value to
269 int i = pakfire_jail_find_env(jail, key);
270 if (i < 0)
271 i = pakfire_jail_env_length(jail);
272
273 // Return -ENOSPC when the environment is full
274 if (i >= ENVIRON_SIZE) {
275 errno = ENOSPC;
276 return -1;
277 }
278
279 // Free any previous value
280 if (jail->env[i])
281 free(jail->env[i]);
282
283 // Format and set environment variable
284 asprintf(&jail->env[i], "%s=%s", key, value);
285
286 DEBUG(jail->pakfire, "Set environment variable: %s\n", jail->env[i]);
287
288 return 0;
289 }
290
291 // Imports an environment
292 int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]) {
293 if (!env)
294 return 0;
295
296 char* key;
297 char* val;
298 int r;
299
300 // Copy environment variables
301 for (unsigned int i = 0; env[i]; i++) {
302 r = pakfire_string_partition(env[i], "=", &key, &val);
303 if (r)
304 continue;
305
306 // Set value
307 r = pakfire_jail_set_env(jail, key, val);
308
309 if (key)
310 free(key);
311 if (val)
312 free(val);
313
314 // Break on error
315 if (r)
316 return r;
317 }
318
319 return 0;
320 }
321
322 // Logging
323
324 int pakfire_jail_set_log_callback(struct pakfire_jail* jail,
325 pakfire_jail_log_callback callback, void* data) {
326 jail->log_callback = callback;
327 jail->log_data = data;
328
329 return 0;
330 }
331
332 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer* buffer) {
333 return (sizeof(buffer->data) == buffer->used);
334 }
335
336 /*
337 This function reads as much data as it can from the file descriptor.
338 If it finds a whole line in it, it will send it to the logger and repeat the process.
339 If not newline character is found, it will try to read more data until it finds one.
340 */
341 static int pakfire_jail_handle_log(struct pakfire_jail* jail,
342 struct pakfire_jail_exec* ctx, int priority, int fd, struct pakfire_log_buffer* buffer) {
343 char line[BUFFER_SIZE + 1];
344
345 // Fill up buffer from fd
346 if (buffer->used < sizeof(buffer->data)) {
347 ssize_t bytes_read = read(fd, buffer->data + buffer->used,
348 sizeof(buffer->data) - buffer->used);
349
350 // Handle errors
351 if (bytes_read < 0) {
352 ERROR(jail->pakfire, "Could not read from fd %d: %m\n", fd);
353 return -1;
354 }
355
356 // Update buffer size
357 buffer->used += bytes_read;
358 }
359
360 // See if we have any lines that we can write
361 while (buffer->used) {
362 // Search for the end of the first line
363 char* eol = memchr(buffer->data, '\n', buffer->used);
364
365 // No newline found
366 if (!eol) {
367 // If the buffer is full, we send the content to the logger and try again
368 // This should not happen in practise
369 if (pakfire_jail_log_buffer_is_full(buffer)) {
370 DEBUG(jail->pakfire, "Logging buffer is full. Sending all content\n");
371
372 eol = buffer->data + sizeof(buffer->data) - 1;
373
374 // Otherwise we might have only read parts of the output
375 } else
376 break;
377 }
378
379 // Find the length of the string
380 size_t length = eol - buffer->data + 1;
381
382 // Copy the line into the buffer
383 memcpy(line, buffer->data, length);
384
385 // Terminate the string
386 line[length] = '\0';
387
388 // Log the line
389 if (jail->log_callback) {
390 int r = jail->log_callback(jail->pakfire, jail->log_data, priority, line, length);
391 if (r) {
392 ERROR(jail->pakfire, "The logging callback returned an error: %d\n", r);
393 return r;
394 }
395 }
396
397 // Remove line from buffer
398 memmove(buffer->data, buffer->data + length, buffer->used - length);
399 buffer->used -= length;
400 }
401
402 return 0;
403 }
404
405 static int pakfire_jail_logger(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
406 int epollfd = -1;
407 struct epoll_event ev;
408 struct epoll_event events[EPOLL_MAX_EVENTS];
409 int r = 0;
410
411 // Fetch file descriptors from context
412 const int stdout = ctx->pipes.stdout[1];
413 const int stderr = ctx->pipes.stderr[1];
414
415 int fds[2] = {
416 stdout, stderr,
417 };
418
419 // Setup epoll
420 epollfd = epoll_create1(0);
421 if (epollfd < 0) {
422 ERROR(jail->pakfire, "Could not initialize epoll(): %m\n");
423 r = 1;
424 goto OUT;
425 }
426
427 ev.events = EPOLLIN;
428
429 // Turn file descriptors into non-blocking mode and add them to epoll()
430 for (unsigned int i = 0; i < 2; i++) {
431 int fd = fds[i];
432
433 // Read flags
434 int flags = fcntl(fd, F_GETFL, 0);
435
436 // Set modified flags
437 if (fcntl(fd, F_SETFL, flags|O_NONBLOCK) < 0) {
438 ERROR(jail->pakfire,
439 "Could not set file descriptor %d into non-blocking mode: %m\n", fd);
440 r = 1;
441 goto OUT;
442 }
443
444 ev.data.fd = fd;
445
446 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
447 ERROR(jail->pakfire, "Could not add file descriptor %d to epoll(): %m\n", fd);
448 r = 1;
449 goto OUT;
450 }
451 }
452
453 int ended = 0;
454
455 // Loop for as long as the process is alive
456 while (!ended) {
457 // If waitpid() returns non-zero, the process has ended, but we want to perform
458 // one last iteration over the loop to read any remaining content from the file
459 // descriptor buffers.
460 r = waitpid(ctx->pid, &ctx->status, WNOHANG);
461 if (r)
462 ended = 1;
463
464 int num = epoll_wait(epollfd, events, EPOLL_MAX_EVENTS, -1);
465 if (num < 1) {
466 // Ignore if epoll_wait() has been interrupted
467 if (errno == EINTR)
468 continue;
469
470 ERROR(jail->pakfire, "epoll_wait() failed: %m\n");
471 r = 1;
472
473 goto OUT;
474 }
475
476 struct pakfire_log_buffer* buffer;
477 int priority;
478
479 for (int i = 0; i < num; i++) {
480 int fd = events[i].data.fd;
481
482 if (fd == stdout) {
483 buffer = &ctx->buffers.stdout;
484 priority = LOG_INFO;
485
486 } else if (fd == stderr) {
487 buffer = &ctx->buffers.stderr;
488 priority = LOG_ERR;
489
490 } else {
491 DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
492 continue;
493 }
494
495 // Handle log event
496 r = pakfire_jail_handle_log(jail, ctx, priority, fd, buffer);
497 if (r)
498 goto OUT;
499 }
500 }
501
502 OUT:
503 if (epollfd > 0)
504 close(epollfd);
505
506 return r;
507 }
508
509 // Capabilities
510
511 static int pakfire_jail_drop_capabilities(struct pakfire_jail* jail) {
512 const int capabilities[] = {
513 // Deny access to the kernel's audit system
514 CAP_AUDIT_CONTROL,
515 CAP_AUDIT_READ,
516 CAP_AUDIT_WRITE,
517
518 // Deny suspending block devices
519 CAP_BLOCK_SUSPEND,
520
521 // Deny any stuff with BPF
522 CAP_BPF,
523
524 // Deny checkpoint restore
525 CAP_CHECKPOINT_RESTORE,
526
527 // Deny opening files by inode number (open_by_handle_at)
528 CAP_DAC_READ_SEARCH,
529
530 // Deny setting SUID bits
531 CAP_FSETID,
532
533 // Deny locking more memory
534 CAP_IPC_LOCK,
535
536 // Deny modifying any Apparmor/SELinux/SMACK configuration
537 CAP_MAC_ADMIN,
538 CAP_MAC_OVERRIDE,
539
540 // Deny creating any special devices
541 CAP_MKNOD,
542
543 // Deny setting any capabilities
544 CAP_SETFCAP,
545
546 // Deny reading from syslog
547 CAP_SYSLOG,
548
549 // Deny any admin actions (mount, sethostname, ...)
550 CAP_SYS_ADMIN,
551
552 // Deny rebooting the system
553 CAP_SYS_BOOT,
554
555 // Deny loading kernel modules
556 CAP_SYS_MODULE,
557
558 // Deny setting nice level
559 CAP_SYS_NICE,
560
561 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
562 CAP_SYS_RAWIO,
563
564 // Deny circumventing any resource limits
565 CAP_SYS_RESOURCE,
566
567 // Deny setting the system time
568 CAP_SYS_TIME,
569
570 // Deny playing with suspend
571 CAP_WAKE_ALARM,
572
573 0,
574 };
575
576 DEBUG(jail->pakfire, "Dropping capabilities...\n");
577
578 size_t num_caps = 0;
579 int r;
580
581 // Drop any capabilities
582 for (const int* cap = capabilities; *cap; cap++) {
583 r = prctl(PR_CAPBSET_DROP, *cap, 0, 0, 0);
584 if (r) {
585 ERROR(jail->pakfire, "Could not drop capability %d: %m\n", *cap);
586 return r;
587 }
588
589 num_caps++;
590 }
591
592 // Fetch any capabilities
593 cap_t caps = cap_get_proc();
594 if (!caps) {
595 ERROR(jail->pakfire, "Could not read capabilities: %m\n");
596 return 1;
597 }
598
599 /*
600 Set inheritable capabilities
601
602 This ensures that no processes will be able to gain any of the listed
603 capabilities again.
604 */
605 r = cap_set_flag(caps, CAP_INHERITABLE, num_caps, capabilities, CAP_CLEAR);
606 if (r) {
607 ERROR(jail->pakfire, "cap_set_flag() failed: %m\n");
608 goto ERROR;
609 }
610
611 // Restore capabilities
612 r = cap_set_proc(caps);
613 if (r) {
614 ERROR(jail->pakfire, "Could not restore capabilities: %m\n");
615 goto ERROR;
616 }
617
618 ERROR:
619 if (caps)
620 cap_free(caps);
621
622 return r;
623 }
624
625 // Syscall Filter
626
627 static int pakfire_jail_limit_syscalls(struct pakfire_jail* jail) {
628 const int syscalls[] = {
629 // The kernel's keyring isn't namespaced
630 SCMP_SYS(keyctl),
631 SCMP_SYS(add_key),
632 SCMP_SYS(request_key),
633
634 // Disable userfaultfd
635 SCMP_SYS(userfaultfd),
636
637 // Disable perf which could leak a lot of information about the host
638 SCMP_SYS(perf_event_open),
639
640 0,
641 };
642 int r = 1;
643
644 DEBUG(jail->pakfire, "Applying syscall filter...\n");
645
646 // Setup a syscall filter which allows everything by default
647 scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
648 if (!ctx) {
649 ERROR(jail->pakfire, "Could not setup seccomp filter: %m\n");
650 goto ERROR;
651 }
652
653 // All all syscalls
654 for (const int* syscall = syscalls; *syscall; syscall++) {
655 r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), *syscall, 0);
656 if (r) {
657 ERROR(jail->pakfire, "Could not configure syscall %d: %m\n", *syscall);
658 goto ERROR;
659 }
660 }
661
662 // Load syscall filter into the kernel
663 r = seccomp_load(ctx);
664 if (r) {
665 ERROR(jail->pakfire, "Could not load syscall filter into the kernel: %m\n");
666 goto ERROR;
667 }
668
669 ERROR:
670 if (ctx)
671 seccomp_release(ctx);
672
673 return r;
674 }
675
676 // UID/GID Mapping
677
678 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail* jail,
679 const char* path, uid_t mapped_id, size_t length) {
680 int r = 1;
681
682 // Open file for writing
683 FILE* f = fopen(path, "w");
684 if (!f) {
685 ERROR(jail->pakfire, "Could not open %s for writing: %m\n", path);
686 goto ERROR;
687 }
688
689 // Write configuration
690 int bytes_written = fprintf(f, "%d %d %ld\n", 0, mapped_id, length);
691 if (bytes_written <= 0) {
692 ERROR(jail->pakfire, "Could not write UID/GID mapping: %m\n");
693 goto ERROR;
694 }
695
696 // Close the file
697 r = fclose(f);
698 f = NULL;
699 if (r) {
700 ERROR(jail->pakfire, "Could not write UID/GID mapping: %m\n");
701
702 goto ERROR;
703 }
704
705 // Success
706 r = 0;
707
708 ERROR:
709 if (f)
710 fclose(f);
711
712 return r;
713 }
714
715 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail* jail, pid_t pid) {
716 char path[PATH_MAX];
717 int r;
718
719 // XXX hard-coded values
720 const uid_t mapped_uid = 100000;
721 const size_t length = 64536;
722
723 // Make path
724 r = pakfire_string_format(path, "/proc/%d/uid_map", pid);
725 if (r < 0)
726 return 1;
727
728 DEBUG(jail->pakfire, "Mapping UID range (%u - %lu)\n", mapped_uid, mapped_uid + length);
729
730 return pakfire_jail_write_uidgid_mapping(jail, path, mapped_uid, length);
731 }
732
733 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail* jail, pid_t pid) {
734 char path[PATH_MAX];
735 int r;
736
737 // XXX hard-coded values
738 const uid_t mapped_gid = 100000;
739 const size_t length = 64536;
740
741 // Make path
742 r = pakfire_string_format(path, "/proc/%d/gid_map", pid);
743 if (r < 0)
744 return 1;
745
746 DEBUG(jail->pakfire, "Mapping GID range (%u - %lu)\n", mapped_gid, mapped_gid + length);
747
748 return pakfire_jail_write_uidgid_mapping(jail, path, mapped_gid, length);
749 }
750
751 static int pakfire_jail_setgroups(struct pakfire_jail* jail, pid_t pid) {
752 char path[PATH_MAX];
753 int r = 1;
754
755 // Make path
756 r = pakfire_string_format(path, "/proc/%d/setgroups", pid);
757 if (r < 0)
758 return 1;
759
760 // Open file for writing
761 FILE* f = fopen(path, "w");
762 if (!f) {
763 ERROR(jail->pakfire, "Could not open %s for writing: %m\n", path);
764 goto ERROR;
765 }
766
767 // Write content
768 int bytes_written = fprintf(f, "deny\n");
769 if (bytes_written <= 0) {
770 ERROR(jail->pakfire, "Could not write to %s: %m\n", path);
771 goto ERROR;
772 }
773
774 r = fclose(f);
775 f = NULL;
776 if (r) {
777 ERROR(jail->pakfire, "Could not close %s: %m\n", path);
778 goto ERROR;
779 }
780
781 ERROR:
782 if (f)
783 fclose(f);
784
785 return r;
786 }
787
788 static int pakfire_jail_send_signal(struct pakfire_jail* jail, int fd) {
789 const uint64_t val = 1;
790 int r = 0;
791
792 DEBUG(jail->pakfire, "Sending signal...\n");
793
794 // Write to the file descriptor
795 ssize_t bytes_written = write(fd, &val, sizeof(val));
796 if (bytes_written < 0 || (size_t)bytes_written < sizeof(val)) {
797 ERROR(jail->pakfire, "Could not send signal: %m\n");
798 r = 1;
799 }
800
801 // Close the file descriptor
802 close(fd);
803
804 return r;
805 }
806
807 static int pakfire_jail_wait_for_signal(struct pakfire_jail* jail, int fd) {
808 uint64_t val = 0;
809 int r = 0;
810
811 DEBUG(jail->pakfire, "Waiting for signal...\n");
812
813 ssize_t bytes_read = read(fd, &val, sizeof(val));
814 if (bytes_read < 0 || (size_t)bytes_read < sizeof(val)) {
815 ERROR(jail->pakfire, "Error waiting for signal: %m\n");
816 r = 1;
817 }
818
819 // Close the file descriptor
820 close(fd);
821
822 return r;
823 }
824
825 /*
826 Performs the initialisation that needs to happen in the parent part
827 */
828 static int pakfire_jail_parent(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
829 int r;
830
831 // Setup UID mapping
832 r = pakfire_jail_setup_uid_mapping(jail, ctx->pid);
833 if (r)
834 return r;
835
836 // Write "deny" to /proc/PID/setgroups
837 r = pakfire_jail_setgroups(jail, ctx->pid);
838 if (r)
839 return r;
840
841 // Setup GID mapping
842 r = pakfire_jail_setup_gid_mapping(jail, ctx->pid);
843 if (r)
844 return r;
845
846 // Parent has finished initialisation
847 DEBUG(jail->pakfire, "Parent has finished initialization\n");
848
849 // Send signal to client
850 r = pakfire_jail_send_signal(jail, ctx->completed_fd);
851 if (r)
852 return r;
853
854 return 0;
855 }
856
857 static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
858 const char* argv[]) {
859 int r;
860
861 // XXX do we have to reconfigure logging here?
862
863 DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", getpid());
864
865 // Wait for the parent to finish initialization
866 r = pakfire_jail_wait_for_signal(jail, ctx->completed_fd);
867 if (r)
868 return r;
869
870 // Perform further initialization
871
872 // Fetch UID/GID
873 uid_t uid = getuid();
874 gid_t gid = getgid();
875
876 // Fetch EUID/EGID
877 uid_t euid = geteuid();
878 gid_t egid = getegid();
879
880 DEBUG(jail->pakfire, " UID: %d (effective %d)\n", uid, euid);
881 DEBUG(jail->pakfire, " GID: %d (effective %d)\n", gid, egid);
882
883 // Check if we are (effectively running as root)
884 if (uid != 0 || gid != 0) {
885 ERROR(jail->pakfire, "Child process is not running as root\n");
886 return 126;
887 }
888
889 const char* root = pakfire_get_path(jail->pakfire);
890 const char* arch = pakfire_get_arch(jail->pakfire);
891
892 // Change root (unless root is /)
893 if (!pakfire_on_root(jail->pakfire)) {
894 // Mount everything
895 r = pakfire_mount_all(jail->pakfire);
896 if (r)
897 return r;
898
899 // Log all mountpoints
900 pakfire_mount_list(jail->pakfire);
901
902 // Call chroot()
903 r = chroot(root);
904 if (r) {
905 ERROR(jail->pakfire, "chroot() to %s failed: %m\n", root);
906 return 1;
907 }
908
909 // Change directory to /
910 r = chdir("/");
911 if (r) {
912 ERROR(jail->pakfire, "chdir() after chroot() failed: %m\n");
913 return 1;
914 }
915 }
916
917 // Set personality
918 unsigned long persona = pakfire_arch_personality(arch);
919 if (persona) {
920 r = personality(persona);
921 if (r < 0) {
922 ERROR(jail->pakfire, "Could not set personality (%x)\n", (unsigned int)persona);
923 return 1;
924 }
925 }
926
927 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
928 r = pakfire_rlimit_reset_nofile(jail->pakfire);
929 if (r)
930 return r;
931
932 // Drop capabilities
933 r = pakfire_jail_drop_capabilities(jail);
934 if (r)
935 return r;
936
937 // Filter syscalls
938 r = pakfire_jail_limit_syscalls(jail);
939 if (r)
940 return r;
941
942 // exec() command
943 r = execvpe(argv[0], (char**)argv, jail->env);
944 if (r < 0)
945 ERROR(jail->pakfire, "Could not execve(): %m\n");
946
947 // Translate errno into regular exit code
948 switch (errno) {
949 case ENOENT:
950 r = 127;
951 break;
952
953 default:
954 r = 1;
955 }
956
957 // We should not get here
958 return r;
959 }
960
961 // Run a command in the jail
962 int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[]) {
963 int exit = -1;
964 int r;
965
966 // Check if argv is valid
967 if (!argv || !argv[0]) {
968 errno = EINVAL;
969 return -1;
970 }
971
972 // Initialize context for this call
973 struct pakfire_jail_exec ctx = {
974 .pipes = {
975 .stdout = { 0, 0, },
976 .stderr = { 0, 0, },
977 },
978 .status = 0,
979 };
980
981 DEBUG(jail->pakfire, "Executing jail...\n");
982
983 /*
984 Setup a file descriptor which can be used to notify the client that the parent
985 has completed configuration.
986 */
987 ctx.completed_fd = eventfd(0, EFD_CLOEXEC);
988 if (ctx.completed_fd < 0) {
989 ERROR(jail->pakfire, "eventfd() failed: %m\n");
990 return -1;
991 }
992
993 // Create pipes to communicate with child process if we are not running interactively
994 if (!pakfire_jail_has_flag(jail, PAKFIRE_JAIL_INTERACTIVE)) {
995 // stdout
996 r = pipe(ctx.pipes.stdout);
997 if (r < 0) {
998 ERROR(jail->pakfire, "Could not create file descriptors for stdout: %m\n");
999 goto ERROR;
1000 }
1001
1002 // stderr
1003 r = pipe(ctx.pipes.stderr);
1004 if (r < 0) {
1005 ERROR(jail->pakfire, "Could not create file descriptors for stderr: %m\n");
1006 goto ERROR;
1007 }
1008 }
1009
1010 // Configure child process
1011 struct clone_args args = {
1012 .flags =
1013 CLONE_NEWCGROUP |
1014 CLONE_NEWIPC |
1015 CLONE_NEWNS |
1016 CLONE_NEWPID |
1017 CLONE_NEWUSER |
1018 CLONE_NEWUTS,
1019 .exit_signal = SIGCHLD,
1020 };
1021
1022 // Fork this process
1023 ctx.pid = clone3(&args, sizeof(args));
1024 if (ctx.pid < 0) {
1025 ERROR(jail->pakfire, "Could not clone: %m\n");
1026 return -1;
1027
1028 // Child process
1029 } else if (ctx.pid == 0) {
1030 r = pakfire_jail_child(jail, &ctx, argv);
1031 _exit(r);
1032 }
1033
1034 // Parent process
1035 r = pakfire_jail_parent(jail, &ctx);
1036 if (r)
1037 goto ERROR;
1038
1039 DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", ctx.pid);
1040
1041 // Read output of the child process
1042 if (!pakfire_jail_has_flag(jail, PAKFIRE_JAIL_INTERACTIVE)) {
1043 r = pakfire_jail_logger(jail, &ctx);
1044 if (r)
1045 ERROR(jail->pakfire, "Log reading aborted: %m\n");
1046 }
1047
1048 if (!ctx.status)
1049 waitpid(ctx.pid, &ctx.status, 0);
1050
1051 if (WIFEXITED(ctx.status)) {
1052 exit = WEXITSTATUS(ctx.status);
1053
1054 DEBUG(jail->pakfire, "Child process exited with code: %d\n", exit);
1055 } else {
1056 ERROR(jail->pakfire, "Could not determine the exit status of process %d\n", ctx.pid);
1057
1058 errno = ESRCH;
1059 exit = -1;
1060 }
1061
1062 ERROR:
1063 // Close any file descriptors
1064 if (ctx.pipes.stdout[0])
1065 close(ctx.pipes.stdout[0]);
1066 if (ctx.pipes.stdout[1])
1067 close(ctx.pipes.stdout[1]);
1068 if (ctx.pipes.stderr[0])
1069 close(ctx.pipes.stderr[0]);
1070 if (ctx.pipes.stderr[1])
1071 close(ctx.pipes.stderr[1]);
1072
1073 // Umount everything
1074 if (!pakfire_on_root(jail->pakfire))
1075 pakfire_umount_all(jail->pakfire);
1076
1077 return exit;
1078 }
1079
1080 int pakfire_jail_exec_script(struct pakfire_jail* jail,
1081 const char* script, const size_t size, const char* args[]) {
1082 char path[PATH_MAX];
1083 const char** argv = NULL;
1084 int r;
1085
1086 const char* root = pakfire_get_path(jail->pakfire);
1087
1088 // Write the scriptlet to disk
1089 r = pakfire_path_join(path, root, "pakfire-script.XXXXXX");
1090 if (r < 0)
1091 goto ERROR;
1092
1093 // Open a temporary file
1094 int fd = mkstemp(path);
1095 if (fd < 0) {
1096 ERROR(jail->pakfire, "Could not open a temporary file: %m\n");
1097 r = 1;
1098 goto ERROR;
1099 }
1100
1101 DEBUG(jail->pakfire, "Writing script to %s:\n%.*s\n", path, (int)size, script);
1102
1103 // Write data
1104 ssize_t bytes_written = write(fd, script, size);
1105 if (bytes_written < (ssize_t)size) {
1106 ERROR(jail->pakfire, "Could not write script to file %s: %m\n", path);
1107 r = 1;
1108 goto ERROR;
1109 }
1110
1111 // Make the script executable
1112 r = fchmod(fd, S_IRUSR|S_IWUSR|S_IXUSR);
1113 if (r) {
1114 ERROR(jail->pakfire, "Could not set executable permissions on %s: %m\n", path);
1115 goto ERROR;
1116 }
1117
1118 // Close file
1119 r = close(fd);
1120 if (r) {
1121 ERROR(jail->pakfire, "Could not close script file %s: %m\n", path);
1122 r = 1;
1123 goto ERROR;
1124 }
1125
1126 // Count how many arguments were passed
1127 unsigned int argc = 1;
1128 if (args) {
1129 for (const char** arg = args; *arg; arg++)
1130 argc++;
1131 }
1132
1133 argv = calloc(argc + 1, sizeof(*argv));
1134 if (!argv) {
1135 ERROR(jail->pakfire, "Could not allocate argv: %m\n");
1136 goto ERROR;
1137 }
1138
1139 // Set command
1140 argv[0] = (root) ? pakfire_path_relpath(root, path) : path;
1141
1142 // Copy args
1143 for (unsigned int i = 1; i < argc; i++)
1144 argv[i] = args[i-1];
1145
1146 // Run the script
1147 r = pakfire_jail_exec(jail, argv);
1148
1149 ERROR:
1150 if (argv)
1151 free(argv);
1152
1153 // Remove script from disk
1154 if (*path)
1155 unlink(path);
1156
1157 return r;
1158 }
1159
1160 /*
1161 A convenience function that creates a new jail, runs the given command and destroys
1162 the jail again.
1163 */
1164 int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], int flags) {
1165 struct pakfire_jail* jail = NULL;
1166 int r;
1167
1168 // Create a new jail
1169 r = pakfire_jail_create(&jail, pakfire, flags);
1170 if (r)
1171 goto ERROR;
1172
1173 // Execute the command
1174 r = pakfire_jail_exec(jail, argv);
1175
1176 ERROR:
1177 if (jail)
1178 pakfire_jail_unref(jail);
1179
1180 return r;
1181 }