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