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