]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/jail.c
jail: Set LANG to C.utf-8 by default
[people/ms/pakfire.git] / src / libpakfire / jail.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2022 Pakfire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <linux/capability.h>
24 #include <linux/sched.h>
25 #include <sys/wait.h>
26 #include <linux/wait.h>
27 #include <sched.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <syscall.h>
31 #include <sys/capability.h>
32 #include <sys/epoll.h>
33 #include <sys/eventfd.h>
34 #include <sys/mount.h>
35 #include <sys/personality.h>
36 #include <sys/prctl.h>
37 #include <sys/resource.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40
41 // libseccomp
42 #include <seccomp.h>
43
44 // libuuid
45 #include <uuid.h>
46
47 #include <pakfire/arch.h>
48 #include <pakfire/cgroup.h>
49 #include <pakfire/jail.h>
50 #include <pakfire/logging.h>
51 #include <pakfire/mount.h>
52 #include <pakfire/pakfire.h>
53 #include <pakfire/private.h>
54 #include <pakfire/pwd.h>
55 #include <pakfire/string.h>
56 #include <pakfire/util.h>
57
58 #define BUFFER_SIZE 1024 * 64
59 #define ENVIRON_SIZE 128
60 #define EPOLL_MAX_EVENTS 2
61 #define MAX_MOUNTPOINTS 8
62
63 // The default environment that will be set for every command
64 static const struct environ {
65 const char* key;
66 const char* val;
67 } ENV[] = {
68 { "HOME", "/root" },
69 { "LANG", "C.utf-8" },
70 { "PATH", "/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin", },
71 { "TERM", "vt100" },
72 { NULL, NULL },
73 };
74
75 struct pakfire_jail_mountpoint {
76 char source[PATH_MAX];
77 char target[PATH_MAX];
78 int flags;
79 };
80
81 struct pakfire_jail {
82 struct pakfire* pakfire;
83 int nrefs;
84
85 // A unique ID for each jail
86 uuid_t uuid;
87 char __uuid[UUID_STR_LEN];
88
89 // Flags
90 int flags;
91
92 // Resource Limits
93 int nice;
94
95 // CGroup
96 struct pakfire_cgroup* cgroup;
97
98 // Environment
99 char* env[ENVIRON_SIZE];
100
101 // Mountpoints
102 struct pakfire_jail_mountpoint mountpoints[MAX_MOUNTPOINTS];
103 unsigned int num_mountpoints;
104 };
105
106 struct pakfire_log_buffer {
107 char data[BUFFER_SIZE];
108 size_t used;
109 };
110
111 enum pakfire_jail_exec_flags {
112 PAKFIRE_JAIL_HAS_NETWORKING = (1 << 0),
113 };
114
115 struct pakfire_jail_exec {
116 int flags;
117
118 // PID (of the child)
119 pid_t pid;
120 int pidfd;
121
122 // Process status (from waitid)
123 siginfo_t status;
124
125 // FD to notify the client that the parent has finished initialization
126 int completed_fd;
127
128 // Log pipes
129 struct pakfire_jail_pipes {
130 int stdin[2];
131 int stdout[2];
132 int stderr[2];
133
134 // Logging
135 int log_INFO[2];
136 int log_ERROR[2];
137 int log_DEBUG[2];
138 } pipes;
139
140 // Communicate
141 struct pakfire_jail_communicate {
142 pakfire_jail_communicate_in in;
143 pakfire_jail_communicate_out out;
144 void* data;
145 } communicate;
146
147 // Log buffers
148 struct pakfire_jail_buffers {
149 struct pakfire_log_buffer stdout;
150 struct pakfire_log_buffer stderr;
151
152 // Logging
153 struct pakfire_log_buffer log_INFO;
154 struct pakfire_log_buffer log_ERROR;
155 struct pakfire_log_buffer log_DEBUG;
156 } buffers;
157
158 struct pakfire_cgroup* cgroup;
159 struct pakfire_cgroup_stats cgroup_stats;
160 };
161
162 static int clone3(struct clone_args* args, size_t size) {
163 return syscall(__NR_clone3, args, size);
164 }
165
166 static int pakfire_jail_exec_has_flag(
167 const struct pakfire_jail_exec* ctx, const enum pakfire_jail_exec_flags flag) {
168 return ctx->flags & flag;
169 }
170
171 static void pakfire_jail_free(struct pakfire_jail* jail) {
172 DEBUG(jail->pakfire, "Freeing jail at %p\n", jail);
173
174 // Free environment
175 for (unsigned int i = 0; jail->env[i]; i++)
176 free(jail->env[i]);
177
178 if (jail->cgroup)
179 pakfire_cgroup_unref(jail->cgroup);
180
181 pakfire_unref(jail->pakfire);
182 free(jail);
183 }
184
185 /*
186 Passes any log messages on to the default pakfire log callback
187 */
188 static int pakfire_jail_default_log_callback(struct pakfire* pakfire, void* data,
189 int priority, const char* line, size_t length) {
190 switch (priority) {
191 case LOG_INFO:
192 INFO(pakfire, "%s", line);
193 break;
194
195 case LOG_ERR:
196 ERROR(pakfire, "%s", line);
197 break;
198
199 #ifdef ENABLE_DEBUG
200 case LOG_DEBUG:
201 DEBUG(pakfire, "%s", line);
202 break;
203 #endif
204 }
205
206 return 0;
207 }
208
209 static int pakfire_jail_setup_interactive_env(struct pakfire_jail* jail) {
210 // Set PS1
211 int r = pakfire_jail_set_env(jail, "PS1", "pakfire-jail \\w> ");
212 if (r)
213 return r;
214
215 // Copy TERM
216 char* TERM = secure_getenv("TERM");
217 if (TERM) {
218 r = pakfire_jail_set_env(jail, "TERM", TERM);
219 if (r)
220 return r;
221 }
222
223 // Copy LANG
224 char* LANG = secure_getenv("LANG");
225 if (LANG) {
226 r = pakfire_jail_set_env(jail, "LANG", LANG);
227 if (r)
228 return r;
229 }
230
231 return 0;
232 }
233
234 PAKFIRE_EXPORT int pakfire_jail_create(struct pakfire_jail** jail,
235 struct pakfire* pakfire, int flags) {
236 int r;
237
238 // Allocate a new jail
239 struct pakfire_jail* j = calloc(1, sizeof(*j));
240 if (!j)
241 return 1;
242
243 // Reference Pakfire
244 j->pakfire = pakfire_ref(pakfire);
245
246 // Initialize reference counter
247 j->nrefs = 1;
248
249 // Store flags
250 j->flags = flags;
251
252 // Generate a random UUID
253 uuid_generate_random(j->uuid);
254
255 DEBUG(j->pakfire, "Allocated new jail at %p\n", j);
256
257 // Set default environment
258 for (const struct environ* e = ENV; e->key; e++) {
259 r = pakfire_jail_set_env(j, e->key, e->val);
260 if (r)
261 goto ERROR;
262 }
263
264 // Done
265 *jail = j;
266 return 0;
267
268 ERROR:
269 pakfire_jail_free(j);
270
271 return r;
272 }
273
274 PAKFIRE_EXPORT struct pakfire_jail* pakfire_jail_ref(struct pakfire_jail* jail) {
275 ++jail->nrefs;
276
277 return jail;
278 }
279
280 PAKFIRE_EXPORT struct pakfire_jail* pakfire_jail_unref(struct pakfire_jail* jail) {
281 if (--jail->nrefs > 0)
282 return jail;
283
284 pakfire_jail_free(jail);
285 return NULL;
286 }
287
288 static const char* pakfire_jail_uuid(struct pakfire_jail* jail) {
289 if (!*jail->__uuid)
290 uuid_unparse_lower(jail->uuid, jail->__uuid);
291
292 return jail->__uuid;
293 }
294
295 // Resource Limits
296
297 PAKFIRE_EXPORT int pakfire_jail_nice(struct pakfire_jail* jail, int nice) {
298 // Check if nice level is in range
299 if (nice < -19 || nice > 20) {
300 errno = EINVAL;
301 return 1;
302 }
303
304 // Store nice level
305 jail->nice = nice;
306
307 return 0;
308 }
309
310 int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cgroup) {
311 // Free any previous cgroup
312 if (jail->cgroup) {
313 pakfire_cgroup_unref(jail->cgroup);
314 jail->cgroup = NULL;
315 }
316
317 // Set any new cgroup
318 if (cgroup) {
319 DEBUG(jail->pakfire, "Setting cgroup %p\n", cgroup);
320
321 jail->cgroup = pakfire_cgroup_ref(cgroup);
322 }
323
324 // Done
325 return 0;
326 }
327
328 // Environment
329
330 // Returns the length of the environment
331 static unsigned int pakfire_jail_env_length(struct pakfire_jail* jail) {
332 unsigned int i = 0;
333
334 // Count everything in the environment
335 for (char** e = jail->env; *e; e++)
336 i++;
337
338 return i;
339 }
340
341 // Finds an existing environment variable and returns its index or -1 if not found
342 static int pakfire_jail_find_env(struct pakfire_jail* jail, const char* key) {
343 if (!key) {
344 errno = EINVAL;
345 return -1;
346 }
347
348 char buffer[strlen(key) + 2];
349 pakfire_string_format(buffer, "%s=", key);
350
351 for (unsigned int i = 0; jail->env[i]; i++) {
352 if (pakfire_string_startswith(jail->env[i], buffer))
353 return i;
354 }
355
356 // Nothing found
357 return -1;
358 }
359
360 // Returns the value of an environment variable or NULL
361 PAKFIRE_EXPORT const char* pakfire_jail_get_env(struct pakfire_jail* jail,
362 const char* key) {
363 int i = pakfire_jail_find_env(jail, key);
364 if (i < 0)
365 return NULL;
366
367 return jail->env[i] + strlen(key) + 1;
368 }
369
370 // Sets an environment variable
371 PAKFIRE_EXPORT int pakfire_jail_set_env(struct pakfire_jail* jail,
372 const char* key, const char* value) {
373 // Find the index where to write this value to
374 int i = pakfire_jail_find_env(jail, key);
375 if (i < 0)
376 i = pakfire_jail_env_length(jail);
377
378 // Return -ENOSPC when the environment is full
379 if (i >= ENVIRON_SIZE) {
380 errno = ENOSPC;
381 return -1;
382 }
383
384 // Free any previous value
385 if (jail->env[i])
386 free(jail->env[i]);
387
388 // Format and set environment variable
389 asprintf(&jail->env[i], "%s=%s", key, value);
390
391 DEBUG(jail->pakfire, "Set environment variable: %s\n", jail->env[i]);
392
393 return 0;
394 }
395
396 // Imports an environment
397 PAKFIRE_EXPORT int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]) {
398 if (!env)
399 return 0;
400
401 char* key;
402 char* val;
403 int r;
404
405 // Copy environment variables
406 for (unsigned int i = 0; env[i]; i++) {
407 r = pakfire_string_partition(env[i], "=", &key, &val);
408 if (r)
409 continue;
410
411 // Set value
412 r = pakfire_jail_set_env(jail, key, val);
413
414 if (key)
415 free(key);
416 if (val)
417 free(val);
418
419 // Break on error
420 if (r)
421 return r;
422 }
423
424 return 0;
425 }
426
427 /*
428 This function replaces any logging in the child process.
429
430 All log messages will be sent to the parent process through their respective pipes.
431 */
432 static void pakfire_jail_log(void* data, int priority, const char* file,
433 int line, const char* fn, const char* format, va_list args) {
434 struct pakfire_jail_pipes* pipes = (struct pakfire_jail_pipes*)data;
435 int fd;
436
437 switch (priority) {
438 case LOG_INFO:
439 fd = pipes->log_INFO[1];
440 break;
441
442 case LOG_ERR:
443 fd = pipes->log_ERROR[1];
444 break;
445
446 #ifdef ENABLE_DEBUG
447 case LOG_DEBUG:
448 fd = pipes->log_DEBUG[1];
449 break;
450 #endif /* ENABLE_DEBUG */
451
452 // Ignore any messages of an unknown priority
453 default:
454 return;
455 }
456
457 // Send the log message
458 if (fd)
459 vdprintf(fd, format, args);
460 }
461
462 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer* buffer) {
463 return (sizeof(buffer->data) == buffer->used);
464 }
465
466 /*
467 This function reads as much data as it can from the file descriptor.
468 If it finds a whole line in it, it will send it to the logger and repeat the process.
469 If not newline character is found, it will try to read more data until it finds one.
470 */
471 static int pakfire_jail_handle_log(struct pakfire_jail* jail,
472 struct pakfire_jail_exec* ctx, int priority, int fd,
473 struct pakfire_log_buffer* buffer, pakfire_jail_communicate_out callback, void* data) {
474 char line[BUFFER_SIZE + 1];
475
476 // Fill up buffer from fd
477 if (buffer->used < sizeof(buffer->data)) {
478 ssize_t bytes_read = read(fd, buffer->data + buffer->used,
479 sizeof(buffer->data) - buffer->used);
480
481 // Handle errors
482 if (bytes_read < 0) {
483 ERROR(jail->pakfire, "Could not read from fd %d: %m\n", fd);
484 return -1;
485 }
486
487 // Update buffer size
488 buffer->used += bytes_read;
489 }
490
491 // See if we have any lines that we can write
492 while (buffer->used) {
493 // Search for the end of the first line
494 char* eol = memchr(buffer->data, '\n', buffer->used);
495
496 // No newline found
497 if (!eol) {
498 // If the buffer is full, we send the content to the logger and try again
499 // This should not happen in practise
500 if (pakfire_jail_log_buffer_is_full(buffer)) {
501 DEBUG(jail->pakfire, "Logging buffer is full. Sending all content\n");
502
503 eol = buffer->data + sizeof(buffer->data) - 1;
504
505 // Otherwise we might have only read parts of the output
506 } else
507 break;
508 }
509
510 // Find the length of the string
511 size_t length = eol - buffer->data + 1;
512
513 // Copy the line into the buffer
514 memcpy(line, buffer->data, length);
515
516 // Terminate the string
517 line[length] = '\0';
518
519 // Log the line
520 if (callback) {
521 int r = callback(jail->pakfire, data, priority, line, length);
522 if (r) {
523 ERROR(jail->pakfire, "The logging callback returned an error: %d\n", r);
524 return r;
525 }
526 }
527
528 // Remove line from buffer
529 memmove(buffer->data, buffer->data + length, buffer->used - length);
530 buffer->used -= length;
531 }
532
533 return 0;
534 }
535
536 static int pakfire_jail_stream_stdin(struct pakfire_jail* jail,
537 struct pakfire_jail_exec* ctx, const int fd) {
538 int r;
539
540 // Nothing to do if there is no stdin callback set
541 if (!ctx->communicate.in) {
542 DEBUG(jail->pakfire, "Callback for standard input is not set\n");
543 return 0;
544 }
545
546 // Skip if the writing pipe has already been closed
547 if (!ctx->pipes.stdin[1])
548 return 0;
549
550 DEBUG(jail->pakfire, "Streaming standard input...\n");
551
552 // Calling the callback
553 r = ctx->communicate.in(jail->pakfire, ctx->communicate.data, fd);
554
555 DEBUG(jail->pakfire, "Standard input callback finished: %d\n", r);
556
557 // The callback signaled that it has written everything
558 if (r == EOF) {
559 DEBUG(jail->pakfire, "Closing standard input pipe\n");
560
561 // Close the file-descriptor
562 close(fd);
563
564 // Reset the file-descriptor so it won't be closed again later
565 ctx->pipes.stdin[1] = 0;
566
567 // Report success
568 r = 0;
569 }
570
571 return r;
572 }
573
574 static int pakfire_jail_setup_pipe(struct pakfire_jail* jail, int (*fds)[2], const int flags) {
575 int r = pipe2(*fds, flags);
576 if (r < 0) {
577 ERROR(jail->pakfire, "Could not setup pipe: %m\n");
578 return 1;
579 }
580
581 return 0;
582 }
583
584 static void pakfire_jail_close_pipe(struct pakfire_jail* jail, int fds[2]) {
585 for (unsigned int i = 0; i < 2; i++)
586 if (fds[i])
587 close(fds[i]);
588 }
589
590 /*
591 This is a convenience function to fetch the reading end of a pipe and
592 closes the write end.
593 */
594 static int pakfire_jail_get_pipe_to_read(struct pakfire_jail* jail, int (*fds)[2]) {
595 // Give the variables easier names to avoid confusion
596 int* fd_read = &(*fds)[0];
597 int* fd_write = &(*fds)[1];
598
599 // Close the write end of the pipe
600 if (*fd_write) {
601 close(*fd_write);
602 *fd_write = 0;
603 }
604
605 // Return the read end
606 return *fd_read;
607 }
608
609 static int pakfire_jail_get_pipe_to_write(struct pakfire_jail* jail, int (*fds)[2]) {
610 // Give the variables easier names to avoid confusion
611 int* fd_read = &(*fds)[0];
612 int* fd_write = &(*fds)[1];
613
614 // Close the read end of the pipe
615 if (*fd_read) {
616 close(*fd_read);
617 *fd_read = 0;
618 }
619
620 // Return the write end
621 return *fd_write;
622 }
623
624 static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
625 int epollfd = -1;
626 struct epoll_event ev;
627 struct epoll_event events[EPOLL_MAX_EVENTS];
628 int r = 0;
629
630 // Fetch file descriptors from context
631 const int stdin = pakfire_jail_get_pipe_to_write(jail, &ctx->pipes.stdin);
632 const int stdout = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.stdout);
633 const int stderr = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.stderr);
634 const int pidfd = ctx->pidfd;
635
636 // Logging
637 const int log_INFO = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_INFO);
638 const int log_ERROR = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_ERROR);
639 const int log_DEBUG = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_DEBUG);
640
641 // Make a list of all file descriptors we are interested in
642 int fds[] = {
643 stdin, stdout, stderr, pidfd, log_INFO, log_ERROR, log_DEBUG,
644 };
645
646 // Setup epoll
647 epollfd = epoll_create1(0);
648 if (epollfd < 0) {
649 ERROR(jail->pakfire, "Could not initialize epoll(): %m\n");
650 r = 1;
651 goto ERROR;
652 }
653
654 // Turn file descriptors into non-blocking mode and add them to epoll()
655 for (unsigned int i = 0; i < sizeof(fds) / sizeof(*fds); i++) {
656 int fd = fds[i];
657
658 // Skip fds which were not initialized
659 if (fd <= 0)
660 continue;
661
662 ev.events = EPOLLHUP;
663
664 if (fd == stdin)
665 ev.events |= EPOLLOUT;
666 else
667 ev.events |= EPOLLIN;
668
669 // Read flags
670 int flags = fcntl(fd, F_GETFL, 0);
671
672 // Set modified flags
673 if (fcntl(fd, F_SETFL, flags|O_NONBLOCK) < 0) {
674 ERROR(jail->pakfire,
675 "Could not set file descriptor %d into non-blocking mode: %m\n", fd);
676 r = 1;
677 goto ERROR;
678 }
679
680 ev.data.fd = fd;
681
682 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
683 ERROR(jail->pakfire, "Could not add file descriptor %d to epoll(): %m\n", fd);
684 r = 1;
685 goto ERROR;
686 }
687 }
688
689 int ended = 0;
690
691 // Loop for as long as the process is alive
692 while (!ended) {
693 int num = epoll_wait(epollfd, events, EPOLL_MAX_EVENTS, -1);
694 if (num < 1) {
695 // Ignore if epoll_wait() has been interrupted
696 if (errno == EINTR)
697 continue;
698
699 ERROR(jail->pakfire, "epoll_wait() failed: %m\n");
700 r = 1;
701
702 goto ERROR;
703 }
704
705 for (int i = 0; i < num; i++) {
706 int e = events[i].events;
707 int fd = events[i].data.fd;
708
709 struct pakfire_log_buffer* buffer = NULL;
710 pakfire_jail_communicate_out callback = NULL;
711 void* data = NULL;
712 int priority;
713
714 // Check if there is any data to be read
715 if (e & EPOLLIN) {
716 // Handle any changes to the PIDFD
717 if (fd == pidfd) {
718 // Call waidid() and store the result
719 r = waitid(P_PIDFD, ctx->pidfd, &ctx->status, WEXITED);
720 if (r) {
721 ERROR(jail->pakfire, "waitid() failed: %m\n");
722 goto ERROR;
723 }
724
725 // Mark that we have ended so that we will process the remaining
726 // events from epoll() now, but won't restart the outer loop.
727 ended = 1;
728 continue;
729
730 // Handle logging messages
731 } else if (fd == log_INFO) {
732 buffer = &ctx->buffers.log_INFO;
733 priority = LOG_INFO;
734
735 callback = pakfire_jail_default_log_callback;
736
737 } else if (fd == log_ERROR) {
738 buffer = &ctx->buffers.log_ERROR;
739 priority = LOG_ERR;
740
741 callback = pakfire_jail_default_log_callback;
742
743 } else if (fd == log_DEBUG) {
744 buffer = &ctx->buffers.log_DEBUG;
745 priority = LOG_DEBUG;
746
747 callback = pakfire_jail_default_log_callback;
748
749 // Handle anything from the log pipes
750 } else if (fd == stdout) {
751 buffer = &ctx->buffers.stdout;
752 priority = LOG_INFO;
753
754 callback = ctx->communicate.out;
755 data = ctx->communicate.data;
756
757 } else if (fd == stderr) {
758 buffer = &ctx->buffers.stderr;
759 priority = LOG_ERR;
760
761 callback = ctx->communicate.out;
762 data = ctx->communicate.data;
763
764 } else {
765 DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
766 continue;
767 }
768
769 // Handle log event
770 r = pakfire_jail_handle_log(jail, ctx, priority, fd, buffer, callback, data);
771 if (r)
772 goto ERROR;
773 }
774
775 if (e & EPOLLOUT) {
776 // Handle standard input
777 if (fd == stdin) {
778 r = pakfire_jail_stream_stdin(jail, ctx, fd);
779 if (r) {
780 switch (errno) {
781 // Ignore if we filled up the buffer
782 case EAGAIN:
783 break;
784
785 default:
786 ERROR(jail->pakfire, "Could not write to stdin: %m\n");
787 goto ERROR;
788 }
789 }
790 }
791 }
792
793 // Check if any file descriptors have been closed
794 if (e & EPOLLHUP) {
795 // Remove the file descriptor
796 r = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
797 if (r) {
798 ERROR(jail->pakfire, "Could not remove closed file-descriptor %d: %m\n", fd);
799 goto ERROR;
800 }
801 }
802 }
803 }
804
805 ERROR:
806 if (epollfd > 0)
807 close(epollfd);
808
809 return r;
810 }
811
812 int pakfire_jail_capture_stdout(struct pakfire* pakfire, void* data,
813 int priority, const char* line, size_t length) {
814 char** output = (char**)data;
815 int r;
816
817 // Append everything from stdout to a buffer
818 if (output && priority == LOG_INFO) {
819 r = asprintf(output, "%s%s", (output && *output) ? *output : "", line);
820 if (r < 0)
821 return 1;
822 return 0;
823 }
824
825 // Send everything else to the default logger
826 return pakfire_jail_default_log_callback(pakfire, NULL, priority, line, length);
827 }
828
829 // Capabilities
830
831 static int pakfire_jail_drop_capabilities(struct pakfire_jail* jail) {
832 const int capabilities[] = {
833 // Deny access to the kernel's audit system
834 CAP_AUDIT_CONTROL,
835 CAP_AUDIT_READ,
836 CAP_AUDIT_WRITE,
837
838 // Deny suspending block devices
839 CAP_BLOCK_SUSPEND,
840
841 // Deny any stuff with BPF
842 CAP_BPF,
843
844 // Deny checkpoint restore
845 CAP_CHECKPOINT_RESTORE,
846
847 // Deny opening files by inode number (open_by_handle_at)
848 CAP_DAC_READ_SEARCH,
849
850 // Deny setting SUID bits
851 CAP_FSETID,
852
853 // Deny locking more memory
854 CAP_IPC_LOCK,
855
856 // Deny modifying any Apparmor/SELinux/SMACK configuration
857 CAP_MAC_ADMIN,
858 CAP_MAC_OVERRIDE,
859
860 // Deny creating any special devices
861 CAP_MKNOD,
862
863 // Deny setting any capabilities
864 CAP_SETFCAP,
865
866 // Deny reading from syslog
867 CAP_SYSLOG,
868
869 // Deny any admin actions (mount, sethostname, ...)
870 CAP_SYS_ADMIN,
871
872 // Deny rebooting the system
873 CAP_SYS_BOOT,
874
875 // Deny loading kernel modules
876 CAP_SYS_MODULE,
877
878 // Deny setting nice level
879 CAP_SYS_NICE,
880
881 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
882 CAP_SYS_RAWIO,
883
884 // Deny circumventing any resource limits
885 CAP_SYS_RESOURCE,
886
887 // Deny setting the system time
888 CAP_SYS_TIME,
889
890 // Deny playing with suspend
891 CAP_WAKE_ALARM,
892
893 0,
894 };
895
896 DEBUG(jail->pakfire, "Dropping capabilities...\n");
897
898 size_t num_caps = 0;
899 int r;
900
901 // Drop any capabilities
902 for (const int* cap = capabilities; *cap; cap++) {
903 r = prctl(PR_CAPBSET_DROP, *cap, 0, 0, 0);
904 if (r) {
905 ERROR(jail->pakfire, "Could not drop capability %d: %m\n", *cap);
906 return r;
907 }
908
909 num_caps++;
910 }
911
912 // Fetch any capabilities
913 cap_t caps = cap_get_proc();
914 if (!caps) {
915 ERROR(jail->pakfire, "Could not read capabilities: %m\n");
916 return 1;
917 }
918
919 /*
920 Set inheritable capabilities
921
922 This ensures that no processes will be able to gain any of the listed
923 capabilities again.
924 */
925 r = cap_set_flag(caps, CAP_INHERITABLE, num_caps, capabilities, CAP_CLEAR);
926 if (r) {
927 ERROR(jail->pakfire, "cap_set_flag() failed: %m\n");
928 goto ERROR;
929 }
930
931 // Restore capabilities
932 r = cap_set_proc(caps);
933 if (r) {
934 ERROR(jail->pakfire, "Could not restore capabilities: %m\n");
935 goto ERROR;
936 }
937
938 ERROR:
939 if (caps)
940 cap_free(caps);
941
942 return r;
943 }
944
945 // Syscall Filter
946
947 static int pakfire_jail_limit_syscalls(struct pakfire_jail* jail) {
948 const int syscalls[] = {
949 // The kernel's keyring isn't namespaced
950 SCMP_SYS(keyctl),
951 SCMP_SYS(add_key),
952 SCMP_SYS(request_key),
953
954 // Disable userfaultfd
955 SCMP_SYS(userfaultfd),
956
957 // Disable perf which could leak a lot of information about the host
958 SCMP_SYS(perf_event_open),
959
960 0,
961 };
962 int r = 1;
963
964 DEBUG(jail->pakfire, "Applying syscall filter...\n");
965
966 // Setup a syscall filter which allows everything by default
967 scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
968 if (!ctx) {
969 ERROR(jail->pakfire, "Could not setup seccomp filter: %m\n");
970 goto ERROR;
971 }
972
973 // All all syscalls
974 for (const int* syscall = syscalls; *syscall; syscall++) {
975 r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), *syscall, 0);
976 if (r) {
977 ERROR(jail->pakfire, "Could not configure syscall %d: %m\n", *syscall);
978 goto ERROR;
979 }
980 }
981
982 // Load syscall filter into the kernel
983 r = seccomp_load(ctx);
984 if (r) {
985 ERROR(jail->pakfire, "Could not load syscall filter into the kernel: %m\n");
986 goto ERROR;
987 }
988
989 ERROR:
990 if (ctx)
991 seccomp_release(ctx);
992
993 return r;
994 }
995
996 // Mountpoints
997
998 PAKFIRE_EXPORT int pakfire_jail_bind(struct pakfire_jail* jail,
999 const char* source, const char* target, int flags) {
1000 struct pakfire_jail_mountpoint* mp = NULL;
1001 int r;
1002
1003 // Check if there is any space left
1004 if (jail->num_mountpoints >= MAX_MOUNTPOINTS) {
1005 errno = ENOSPC;
1006 return 1;
1007 }
1008
1009 // Check for valid inputs
1010 if (!source || !target) {
1011 errno = EINVAL;
1012 return 1;
1013 }
1014
1015 // Select the next free slot
1016 mp = &jail->mountpoints[jail->num_mountpoints];
1017
1018 // Copy source
1019 r = pakfire_string_set(mp->source, source);
1020 if (r) {
1021 ERROR(jail->pakfire, "Could not copy source: %m\n");
1022 return r;
1023 }
1024
1025 // Copy target
1026 r = pakfire_string_set(mp->target, target);
1027 if (r) {
1028 ERROR(jail->pakfire, "Could not copy target: %m\n");
1029 return r;
1030 }
1031
1032 // Copy flags
1033 mp->flags = flags;
1034
1035 // Increment counter
1036 jail->num_mountpoints++;
1037
1038 return 0;
1039 }
1040
1041 static int pakfire_jail_mount_networking(struct pakfire_jail* jail) {
1042 int r;
1043
1044 const char* paths[] = {
1045 "/etc/hosts",
1046 "/etc/resolv.conf",
1047 NULL,
1048 };
1049
1050 // Bind-mount all paths read-only
1051 for (const char** path = paths; *path; path++) {
1052 r = pakfire_bind(jail->pakfire, *path, NULL, MS_RDONLY);
1053 if (r)
1054 return r;
1055 }
1056
1057 return 0;
1058 }
1059
1060 /*
1061 Mounts everything that we require in the new namespace
1062 */
1063 static int pakfire_jail_mount(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1064 struct pakfire_jail_mountpoint* mp = NULL;
1065 int r;
1066
1067 // Mount all default stuff
1068 r = pakfire_mount_all(jail->pakfire);
1069 if (r)
1070 return r;
1071
1072 // Mount networking stuff
1073 if (pakfire_jail_exec_has_flag(ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
1074 r = pakfire_jail_mount_networking(jail);
1075 if (r)
1076 return r;
1077 }
1078
1079 // Mount all custom stuff
1080 for (unsigned int i = 0; i < jail->num_mountpoints; i++) {
1081 // Fetch mountpoint
1082 mp = &jail->mountpoints[i];
1083
1084 // Mount it
1085 r = pakfire_bind(jail->pakfire, mp->source, mp->target, mp->flags);
1086 if (r)
1087 return r;
1088 }
1089
1090 // Log all mountpoints
1091 pakfire_mount_list(jail->pakfire);
1092
1093 return 0;
1094 }
1095
1096 // UID/GID Mapping
1097
1098 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail* jail, pid_t pid) {
1099 char path[PATH_MAX];
1100 int r;
1101
1102 // Skip mapping anything when running on /
1103 if (pakfire_on_root(jail->pakfire))
1104 return 0;
1105
1106 // Make path
1107 r = pakfire_string_format(path, "/proc/%d/uid_map", pid);
1108 if (r)
1109 return r;
1110
1111 // Fetch UID
1112 const uid_t uid = pakfire_uid(jail->pakfire);
1113
1114 // Fetch SUBUID
1115 const struct pakfire_subid* subuid = pakfire_subuid(jail->pakfire);
1116 if (!subuid)
1117 return 1;
1118
1119 /* When running as root, we will map the entire range.
1120
1121 When running as a non-privileged user, we will map the root user inside the jail
1122 to the user's UID outside of the jail, and we will map the rest starting from one.
1123 */
1124
1125 // Running as root
1126 if (uid == 0) {
1127 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1128 "0 %lu %lu\n", subuid->id, subuid->length);
1129 } else {
1130 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1131 "0 %lu 1\n1 %lu %lu\n", uid, subuid->id, subuid->length);
1132 }
1133
1134 if (r) {
1135 ERROR(jail->pakfire, "Could not map UIDs: %m\n");
1136 return r;
1137 }
1138
1139 return r;
1140 }
1141
1142 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail* jail, pid_t pid) {
1143 char path[PATH_MAX];
1144 int r;
1145
1146 // Skip mapping anything when running on /
1147 if (pakfire_on_root(jail->pakfire))
1148 return 0;
1149
1150 // Fetch GID
1151 const gid_t gid = pakfire_gid(jail->pakfire);
1152
1153 // Fetch SUBGID
1154 const struct pakfire_subid* subgid = pakfire_subgid(jail->pakfire);
1155 if (!subgid)
1156 return 1;
1157
1158 // Make path
1159 r = pakfire_string_format(path, "/proc/%d/gid_map", pid);
1160 if (r)
1161 return r;
1162
1163 // Running as root
1164 if (gid == 0) {
1165 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1166 "0 %lu %lu\n", subgid->id, subgid->length);
1167 } else {
1168 r = pakfire_file_write(jail->pakfire, path, 0, 0, 0,
1169 "0 %lu 1\n%1 %lu %lu\n", gid, subgid->id, subgid->length);
1170 }
1171
1172 if (r) {
1173 ERROR(jail->pakfire, "Could not map GIDs: %m\n");
1174 return r;
1175 }
1176
1177 return r;
1178 }
1179
1180 static int pakfire_jail_setgroups(struct pakfire_jail* jail, pid_t pid) {
1181 char path[PATH_MAX];
1182 int r = 1;
1183
1184 // Make path
1185 r = pakfire_string_format(path, "/proc/%d/setgroups", pid);
1186 if (r)
1187 return r;
1188
1189 // Open file for writing
1190 FILE* f = fopen(path, "w");
1191 if (!f) {
1192 ERROR(jail->pakfire, "Could not open %s for writing: %m\n", path);
1193 goto ERROR;
1194 }
1195
1196 // Write content
1197 int bytes_written = fprintf(f, "deny\n");
1198 if (bytes_written <= 0) {
1199 ERROR(jail->pakfire, "Could not write to %s: %m\n", path);
1200 goto ERROR;
1201 }
1202
1203 r = fclose(f);
1204 f = NULL;
1205 if (r) {
1206 ERROR(jail->pakfire, "Could not close %s: %m\n", path);
1207 goto ERROR;
1208 }
1209
1210 ERROR:
1211 if (f)
1212 fclose(f);
1213
1214 return r;
1215 }
1216
1217 static int pakfire_jail_send_signal(struct pakfire_jail* jail, int fd) {
1218 const uint64_t val = 1;
1219 int r = 0;
1220
1221 DEBUG(jail->pakfire, "Sending signal...\n");
1222
1223 // Write to the file descriptor
1224 ssize_t bytes_written = write(fd, &val, sizeof(val));
1225 if (bytes_written < 0 || (size_t)bytes_written < sizeof(val)) {
1226 ERROR(jail->pakfire, "Could not send signal: %m\n");
1227 r = 1;
1228 }
1229
1230 // Close the file descriptor
1231 close(fd);
1232
1233 return r;
1234 }
1235
1236 static int pakfire_jail_wait_for_signal(struct pakfire_jail* jail, int fd) {
1237 uint64_t val = 0;
1238 int r = 0;
1239
1240 DEBUG(jail->pakfire, "Waiting for signal...\n");
1241
1242 ssize_t bytes_read = read(fd, &val, sizeof(val));
1243 if (bytes_read < 0 || (size_t)bytes_read < sizeof(val)) {
1244 ERROR(jail->pakfire, "Error waiting for signal: %m\n");
1245 r = 1;
1246 }
1247
1248 // Close the file descriptor
1249 close(fd);
1250
1251 return r;
1252 }
1253
1254 /*
1255 Performs the initialisation that needs to happen in the parent part
1256 */
1257 static int pakfire_jail_parent(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
1258 int r;
1259
1260 // Setup UID mapping
1261 r = pakfire_jail_setup_uid_mapping(jail, ctx->pid);
1262 if (r)
1263 return r;
1264
1265 // Write "deny" to /proc/PID/setgroups
1266 r = pakfire_jail_setgroups(jail, ctx->pid);
1267 if (r)
1268 return r;
1269
1270 // Setup GID mapping
1271 r = pakfire_jail_setup_gid_mapping(jail, ctx->pid);
1272 if (r)
1273 return r;
1274
1275 // Parent has finished initialisation
1276 DEBUG(jail->pakfire, "Parent has finished initialization\n");
1277
1278 // Send signal to client
1279 r = pakfire_jail_send_signal(jail, ctx->completed_fd);
1280 if (r)
1281 return r;
1282
1283 return 0;
1284 }
1285
1286 static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
1287 const char* argv[]) {
1288 int r;
1289
1290 // Redirect any logging to our log pipe
1291 pakfire_set_log_callback(jail->pakfire, pakfire_jail_log, &ctx->pipes);
1292
1293 // Die with parent
1294 r = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
1295 if (r) {
1296 ERROR(jail->pakfire, "Could not configure to die with parent: %m\n");
1297 return 126;
1298 }
1299
1300 // Fetch my own PID
1301 pid_t pid = getpid();
1302
1303 DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", pid);
1304
1305 // Wait for the parent to finish initialization
1306 r = pakfire_jail_wait_for_signal(jail, ctx->completed_fd);
1307 if (r)
1308 return r;
1309
1310 // Perform further initialization
1311
1312 // Fetch UID/GID
1313 uid_t uid = getuid();
1314 gid_t gid = getgid();
1315
1316 // Fetch EUID/EGID
1317 uid_t euid = geteuid();
1318 gid_t egid = getegid();
1319
1320 DEBUG(jail->pakfire, " UID: %d (effective %d)\n", uid, euid);
1321 DEBUG(jail->pakfire, " GID: %d (effective %d)\n", gid, egid);
1322
1323 // Check if we are (effectively running as root)
1324 if (uid || gid || euid || egid) {
1325 ERROR(jail->pakfire, "Child process is not running as root\n");
1326 return 126;
1327 }
1328
1329 const char* root = pakfire_get_path(jail->pakfire);
1330 const char* arch = pakfire_get_arch(jail->pakfire);
1331
1332 // Change root (unless root is /)
1333 if (!pakfire_on_root(jail->pakfire)) {
1334 // Mount everything
1335 r = pakfire_jail_mount(jail, ctx);
1336 if (r)
1337 return r;
1338
1339 // Call chroot()
1340 r = chroot(root);
1341 if (r) {
1342 ERROR(jail->pakfire, "chroot() to %s failed: %m\n", root);
1343 return 1;
1344 }
1345
1346 // Change directory to /
1347 r = chdir("/");
1348 if (r) {
1349 ERROR(jail->pakfire, "chdir() after chroot() failed: %m\n");
1350 return 1;
1351 }
1352 }
1353
1354 // Set personality
1355 unsigned long persona = pakfire_arch_personality(arch);
1356 if (persona) {
1357 r = personality(persona);
1358 if (r < 0) {
1359 ERROR(jail->pakfire, "Could not set personality (%x)\n", (unsigned int)persona);
1360 return 1;
1361 }
1362 }
1363
1364 // Set nice level
1365 if (jail->nice) {
1366 DEBUG(jail->pakfire, "Setting nice level to %d\n", jail->nice);
1367
1368 r = setpriority(PRIO_PROCESS, pid, jail->nice);
1369 if (r) {
1370 ERROR(jail->pakfire, "Could not set nice level: %m\n");
1371 return 1;
1372 }
1373 }
1374
1375 // Close other end of log pipes
1376 close(ctx->pipes.log_INFO[0]);
1377 close(ctx->pipes.log_ERROR[0]);
1378 #ifdef ENABLE_DEBUG
1379 close(ctx->pipes.log_DEBUG[0]);
1380 #endif /* ENABLE_DEBUG */
1381
1382 // Connect standard input
1383 if (ctx->pipes.stdin[0]) {
1384 r = dup2(ctx->pipes.stdin[0], STDIN_FILENO);
1385 if (r < 0) {
1386 ERROR(jail->pakfire, "Could not connect fd %d to stdin: %m\n",
1387 ctx->pipes.stdin[0]);
1388
1389 return 1;
1390 }
1391 }
1392
1393 // Connect standard output and error
1394 if (ctx->pipes.stdout[1] && ctx->pipes.stderr[1]) {
1395 r = dup2(ctx->pipes.stdout[1], STDOUT_FILENO);
1396 if (r < 0) {
1397 ERROR(jail->pakfire, "Could not connect fd %d to stdout: %m\n",
1398 ctx->pipes.stdout[1]);
1399
1400 return 1;
1401 }
1402
1403 r = dup2(ctx->pipes.stderr[1], STDERR_FILENO);
1404 if (r < 0) {
1405 ERROR(jail->pakfire, "Could not connect fd %d to stderr: %m\n",
1406 ctx->pipes.stderr[1]);
1407
1408 return 1;
1409 }
1410
1411 // Close the pipe (as we have moved the original file descriptors)
1412 pakfire_jail_close_pipe(jail, ctx->pipes.stdin);
1413 pakfire_jail_close_pipe(jail, ctx->pipes.stdout);
1414 pakfire_jail_close_pipe(jail, ctx->pipes.stderr);
1415 }
1416
1417 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
1418 r = pakfire_rlimit_reset_nofile(jail->pakfire);
1419 if (r)
1420 return r;
1421
1422 // Drop capabilities
1423 r = pakfire_jail_drop_capabilities(jail);
1424 if (r)
1425 return r;
1426
1427 // Filter syscalls
1428 r = pakfire_jail_limit_syscalls(jail);
1429 if (r)
1430 return r;
1431
1432 DEBUG(jail->pakfire, "Child process initialization done\n");
1433 DEBUG(jail->pakfire, "Launching command:\n");
1434
1435 // Log argv
1436 for (unsigned int i = 0; argv[i]; i++)
1437 DEBUG(jail->pakfire, " argv[%d] = %s\n", i, argv[i]);
1438
1439 // exec() command
1440 r = execvpe(argv[0], (char**)argv, jail->env);
1441 if (r < 0)
1442 ERROR(jail->pakfire, "Could not execve(): %m\n");
1443
1444 // Translate errno into regular exit code
1445 switch (errno) {
1446 case ENOENT:
1447 r = 127;
1448 break;
1449
1450 default:
1451 r = 1;
1452 }
1453
1454 // We should not get here
1455 return r;
1456 }
1457
1458 // Run a command in the jail
1459 static int __pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[],
1460 const int interactive,
1461 pakfire_jail_communicate_in communicate_in,
1462 pakfire_jail_communicate_out communicate_out,
1463 void* data) {
1464 int exit = -1;
1465 int r;
1466
1467 // Check if argv is valid
1468 if (!argv || !argv[0]) {
1469 errno = EINVAL;
1470 return -1;
1471 }
1472
1473 // Send any output to the default logger if no callback is set
1474 if (!communicate_out)
1475 communicate_out = pakfire_jail_default_log_callback;
1476
1477 // Initialize context for this call
1478 struct pakfire_jail_exec ctx = {
1479 .flags = 0,
1480
1481 .pipes = {
1482 .stdin = { 0, 0 },
1483 .stdout = { 0, 0 },
1484 .stderr = { 0, 0 },
1485 },
1486
1487 .communicate = {
1488 .in = communicate_in,
1489 .out = communicate_out,
1490 .data = data,
1491 },
1492 };
1493
1494 DEBUG(jail->pakfire, "Executing jail...\n");
1495
1496 // Enable networking in interactive mode
1497 if (interactive)
1498 ctx.flags |= PAKFIRE_JAIL_HAS_NETWORKING;
1499
1500 /*
1501 Setup a file descriptor which can be used to notify the client that the parent
1502 has completed configuration.
1503 */
1504 ctx.completed_fd = eventfd(0, EFD_CLOEXEC);
1505 if (ctx.completed_fd < 0) {
1506 ERROR(jail->pakfire, "eventfd() failed: %m\n");
1507 return -1;
1508 }
1509
1510 // Create pipes to communicate with child process if we are not running interactively
1511 if (!interactive) {
1512 // stdin (only if callback is set)
1513 if (ctx.communicate.in) {
1514 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.stdin, 0);
1515 if (r)
1516 goto ERROR;
1517 }
1518
1519 // stdout
1520 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.stdout, 0);
1521 if (r)
1522 goto ERROR;
1523
1524 // stderr
1525 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.stderr, 0);
1526 if (r)
1527 goto ERROR;
1528 }
1529
1530 // Setup pipes for logging
1531 // INFO
1532 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_INFO, O_CLOEXEC);
1533 if (r)
1534 goto ERROR;
1535
1536 // ERROR
1537 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_ERROR, O_CLOEXEC);
1538 if (r)
1539 goto ERROR;
1540
1541 #ifdef ENABLE_DEBUG
1542 // DEBUG
1543 r = pakfire_jail_setup_pipe(jail, &ctx.pipes.log_DEBUG, O_CLOEXEC);
1544 if (r)
1545 goto ERROR;
1546 #endif /* ENABLE_DEBUG */
1547
1548 // Configure child process
1549 struct clone_args args = {
1550 .flags =
1551 CLONE_NEWCGROUP |
1552 CLONE_NEWIPC |
1553 CLONE_NEWNS |
1554 CLONE_NEWPID |
1555 CLONE_NEWUSER |
1556 CLONE_NEWUTS |
1557 CLONE_PIDFD,
1558 .exit_signal = SIGCHLD,
1559 .pidfd = (long long unsigned int)&ctx.pidfd,
1560 };
1561
1562 // Launch the process in a cgroup that is a leaf of the configured cgroup
1563 if (jail->cgroup) {
1564 args.flags |= CLONE_INTO_CGROUP;
1565
1566 // Fetch our UUID
1567 const char* uuid = pakfire_jail_uuid(jail);
1568
1569 // Create a temporary cgroup
1570 r = pakfire_cgroup_child(&ctx.cgroup, jail->cgroup, uuid, 0);
1571 if (r) {
1572 ERROR(jail->pakfire, "Could not create cgroup for jail: %m\n");
1573 goto ERROR;
1574 }
1575
1576 // Clone into this cgroup
1577 args.cgroup = pakfire_cgroup_fd(ctx.cgroup);
1578 }
1579
1580 // Setup networking
1581 if (!pakfire_jail_exec_has_flag(&ctx, PAKFIRE_JAIL_HAS_NETWORKING)) {
1582 args.flags |= CLONE_NEWNET;
1583 }
1584
1585 // Fork this process
1586 ctx.pid = clone3(&args, sizeof(args));
1587 if (ctx.pid < 0) {
1588 ERROR(jail->pakfire, "Could not clone: %m\n");
1589 return -1;
1590
1591 // Child process
1592 } else if (ctx.pid == 0) {
1593 r = pakfire_jail_child(jail, &ctx, argv);
1594 _exit(r);
1595 }
1596
1597 // Parent process
1598 r = pakfire_jail_parent(jail, &ctx);
1599 if (r)
1600 goto ERROR;
1601
1602 DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", ctx.pid);
1603
1604 // Read output of the child process
1605 r = pakfire_jail_wait(jail, &ctx);
1606 if (r)
1607 goto ERROR;
1608
1609 // Handle exit status
1610 switch (ctx.status.si_code) {
1611 case CLD_EXITED:
1612 DEBUG(jail->pakfire, "The child process exited with code %d\n",
1613 ctx.status.si_status);
1614
1615 // Pass exit code
1616 exit = ctx.status.si_status;
1617 break;
1618
1619 case CLD_KILLED:
1620 ERROR(jail->pakfire, "The child process was killed\n");
1621 exit = 139;
1622 break;
1623
1624 case CLD_DUMPED:
1625 ERROR(jail->pakfire, "The child process terminated abnormally\n");
1626 break;
1627
1628 // Log anything else
1629 default:
1630 ERROR(jail->pakfire, "Unknown child exit code: %d\n", ctx.status.si_code);
1631 break;
1632 }
1633
1634 ERROR:
1635 // Destroy the temporary cgroup (if any)
1636 if (ctx.cgroup) {
1637 // Read cgroup stats
1638 r = pakfire_cgroup_stat(ctx.cgroup, &ctx.cgroup_stats);
1639 if (r) {
1640 ERROR(jail->pakfire, "Could not read cgroup stats: %m\n");
1641 } else {
1642 pakfire_cgroup_stat_dump(ctx.cgroup, &ctx.cgroup_stats);
1643 }
1644
1645 pakfire_cgroup_destroy(ctx.cgroup);
1646 pakfire_cgroup_unref(ctx.cgroup);
1647 }
1648
1649 // Close any file descriptors
1650 pakfire_jail_close_pipe(jail, ctx.pipes.stdin);
1651 pakfire_jail_close_pipe(jail, ctx.pipes.stdout);
1652 pakfire_jail_close_pipe(jail, ctx.pipes.stderr);
1653 if (ctx.pidfd)
1654 close(ctx.pidfd);
1655 pakfire_jail_close_pipe(jail, ctx.pipes.log_INFO);
1656 pakfire_jail_close_pipe(jail, ctx.pipes.log_ERROR);
1657 pakfire_jail_close_pipe(jail, ctx.pipes.log_DEBUG);
1658
1659 return exit;
1660 }
1661
1662 PAKFIRE_EXPORT int pakfire_jail_exec(
1663 struct pakfire_jail* jail,
1664 const char* argv[],
1665 pakfire_jail_communicate_in callback_in,
1666 pakfire_jail_communicate_out callback_out,
1667 void* data) {
1668 return __pakfire_jail_exec(jail, argv, 0, callback_in, callback_out, data);
1669 }
1670
1671 static int pakfire_jail_exec_interactive(
1672 struct pakfire_jail* jail, const char* argv[]) {
1673 int r;
1674
1675 // Setup interactive stuff
1676 r = pakfire_jail_setup_interactive_env(jail);
1677 if (r)
1678 return r;
1679
1680 return __pakfire_jail_exec(jail, argv, 1, NULL, NULL, NULL);
1681 }
1682
1683 int pakfire_jail_exec_script(struct pakfire_jail* jail,
1684 const char* script,
1685 const size_t size,
1686 const char* args[],
1687 pakfire_jail_communicate_in callback_in,
1688 pakfire_jail_communicate_out callback_out,
1689 void* data) {
1690 char path[PATH_MAX];
1691 const char** argv = NULL;
1692 FILE* f = NULL;
1693 int r;
1694
1695 const char* root = pakfire_get_path(jail->pakfire);
1696
1697 // Write the scriptlet to disk
1698 r = pakfire_path_join(path, root, PAKFIRE_TMP_DIR "/pakfire-script.XXXXXX");
1699 if (r)
1700 goto ERROR;
1701
1702 // Create a temporary file
1703 f = pakfire_mktemp(path, 0700);
1704 if (!f) {
1705 ERROR(jail->pakfire, "Could not create temporary file: %m\n");
1706 goto ERROR;
1707 }
1708
1709 DEBUG(jail->pakfire, "Writing script to %s:\n%.*s\n", path, (int)size, script);
1710
1711 // Write data
1712 r = fprintf(f, "%s", script);
1713 if (r < 0) {
1714 ERROR(jail->pakfire, "Could not write script to file %s: %m\n", path);
1715 goto ERROR;
1716 }
1717
1718 // Close file
1719 r = fclose(f);
1720 if (r) {
1721 ERROR(jail->pakfire, "Could not close script file %s: %m\n", path);
1722 goto ERROR;
1723 }
1724
1725 f = NULL;
1726
1727 // Count how many arguments were passed
1728 unsigned int argc = 1;
1729 if (args) {
1730 for (const char** arg = args; *arg; arg++)
1731 argc++;
1732 }
1733
1734 argv = calloc(argc + 1, sizeof(*argv));
1735 if (!argv) {
1736 ERROR(jail->pakfire, "Could not allocate argv: %m\n");
1737 goto ERROR;
1738 }
1739
1740 // Set command
1741 argv[0] = (root) ? pakfire_path_relpath(root, path) : path;
1742
1743 // Copy args
1744 for (unsigned int i = 1; i < argc; i++)
1745 argv[i] = args[i-1];
1746
1747 // Run the script
1748 r = pakfire_jail_exec(jail, argv, callback_in, callback_out, data);
1749
1750 ERROR:
1751 if (argv)
1752 free(argv);
1753 if (f)
1754 fclose(f);
1755
1756 // Remove script from disk
1757 if (*path)
1758 unlink(path);
1759
1760 return r;
1761 }
1762
1763 /*
1764 A convenience function that creates a new jail, runs the given command and destroys
1765 the jail again.
1766 */
1767 int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], int flags, char** output) {
1768 struct pakfire_jail* jail = NULL;
1769 int r;
1770
1771 // Create a new jail
1772 r = pakfire_jail_create(&jail, pakfire, flags);
1773 if (r)
1774 goto ERROR;
1775
1776 // Execute the command
1777 r = pakfire_jail_exec(jail, argv, NULL, pakfire_jail_capture_stdout, output);
1778
1779 ERROR:
1780 if (jail)
1781 pakfire_jail_unref(jail);
1782
1783 return r;
1784 }
1785
1786 int pakfire_jail_run_script(struct pakfire* pakfire,
1787 const char* script, const size_t length, const char* argv[], int flags) {
1788 struct pakfire_jail* jail = NULL;
1789 int r;
1790
1791 // Create a new jail
1792 r = pakfire_jail_create(&jail, pakfire, flags);
1793 if (r)
1794 goto ERROR;
1795
1796 // Execute the command
1797 r = pakfire_jail_exec_script(jail, script, length, argv, NULL, NULL, NULL);
1798
1799 ERROR:
1800 if (jail)
1801 pakfire_jail_unref(jail);
1802
1803 return r;
1804 }
1805
1806 int pakfire_jail_shell(struct pakfire_jail* jail) {
1807 const char* argv[] = {
1808 "/bin/bash", "--login", NULL,
1809 };
1810
1811 // Execute /bin/bash
1812 return pakfire_jail_exec_interactive(jail, argv);
1813 }
1814
1815 int pakfire_jail_ldconfig(struct pakfire* pakfire) {
1816 char path[PATH_MAX];
1817
1818 const char* ldconfig = "/sbin/ldconfig";
1819
1820 // Check if ldconfig exists before calling it to avoid overhead
1821 int r = pakfire_path(pakfire, path, "%s", ldconfig);
1822 if (r)
1823 return r;
1824
1825 // Check if ldconfig is executable
1826 r = access(path, X_OK);
1827 if (r) {
1828 DEBUG(pakfire, "%s is not executable. Skipping...\n", ldconfig);
1829 return 0;
1830 }
1831
1832 const char* argv[] = {
1833 ldconfig, NULL,
1834 };
1835
1836 // Run ldconfig
1837 return pakfire_jail_run(pakfire, argv, 0, NULL);
1838 }