/* * A cut-down version of common/flatpak-utils from Flatpak * Last updated: Flatpak 1.6.1 * * Copyright © 2014-2019 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * * Authors: * Alexander Larsson <alexl@redhat.com> */ #include "config.h" #include <string.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/stat.h> #include <sys/file.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/utsname.h> #include <sys/ioctl.h> #include <termios.h> #include <glib.h> #include "flatpak-utils-base-private.h" #include "flatpak-utils-private.h" /* To keep this more similar to the original file, we explicitly disable * this warning rather than fixing it */ #pragma GCC diagnostic ignored "-Wshadow" #define RUNNING_ON_VALGRIND 0 /* Sometimes this is /var/run which is a symlink, causing weird issues when we pass * it as a path into the sandbox */ char * flatpak_get_real_xdg_runtime_dir (void) { return realpath (g_get_user_runtime_dir (), NULL); } static gboolean needs_quoting (const char *arg) { while (*arg != 0) { char c = *arg; if (!g_ascii_isalnum (c) && !(c == '-' || c == '/' || c == '~' || c == ':' || c == '.' || c == '_' || c == '=' || c == '@')) return TRUE; arg++; } return FALSE; } char * flatpak_quote_argv (const char *argv[], gssize len) { GString *res = g_string_new (""); int i; if (len == -1) len = g_strv_length ((char **) argv); for (i = 0; i < len; i++) { if (i != 0) g_string_append_c (res, ' '); if (needs_quoting (argv[i])) { g_autofree char *quoted = g_shell_quote (argv[i]); g_string_append (res, quoted); } else g_string_append (res, argv[i]); } return g_string_free (res, FALSE); } /* If memfd_create() is available, generate a sealed memfd with contents of * @str. Otherwise use an O_TMPFILE @tmpf in anonymous mode, write @str to * @tmpf, and lseek() back to the start. See also similar uses in e.g. * rpm-ostree for running dracut. */ gboolean flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf, const char *name, const char *str, size_t len, GError **error) { if (len == -1) len = strlen (str); glnx_autofd int memfd = memfd_create (name, MFD_CLOEXEC | MFD_ALLOW_SEALING); int fd; /* Unowned */ if (memfd != -1) { fd = memfd; } else { /* We use an anonymous fd (i.e. O_EXCL) since we don't want * the target container to potentially be able to re-link it. */ if (!G_IN_SET (errno, ENOSYS, EOPNOTSUPP)) return glnx_throw_errno_prefix (error, "memfd_create"); if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error)) return FALSE; fd = tmpf->fd; } if (ftruncate (fd, len) < 0) return glnx_throw_errno_prefix (error, "ftruncate"); if (glnx_loop_write (fd, str, len) < 0) return glnx_throw_errno_prefix (error, "write"); if (lseek (fd, 0, SEEK_SET) < 0) return glnx_throw_errno_prefix (error, "lseek"); if (memfd != -1) { /* Valgrind doesn't currently handle G_ADD_SEALS, so lets not seal when debugging... */ if ((!RUNNING_ON_VALGRIND) && fcntl (memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) < 0) return glnx_throw_errno_prefix (error, "fcntl(F_ADD_SEALS)"); /* The other values can stay default */ tmpf->fd = glnx_steal_fd (&memfd); tmpf->initialized = TRUE; } return TRUE; }