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