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