diff -Nuar flatpak-1.0.0.orig/bubblewrap/autogen.sh flatpak-1.0.0/bubblewrap/autogen.sh --- flatpak-1.0.0.orig/bubblewrap/autogen.sh 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/autogen.sh 2018-02-03 21:26:06.272233339 +0300 @@ -0,0 +1,19 @@ +#!/bin/sh + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +olddir=`pwd` +cd $srcdir + +if ! (autoreconf --version >/dev/null 2>&1); then + echo "*** No autoreconf found, please install it ***" + exit 1 +fi + +mkdir -p m4 + +autoreconf --force --install --verbose + +cd $olddir +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff -Nuar flatpak-1.0.0.orig/bubblewrap/bind-mount.c flatpak-1.0.0/bubblewrap/bind-mount.c --- flatpak-1.0.0.orig/bubblewrap/bind-mount.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/bind-mount.c 2018-02-03 21:26:06.272233339 +0300 @@ -0,0 +1,440 @@ +/* bubblewrap + * Copyright (C) 2016 Alexander Larsson + * + * 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 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 . + * + */ + +#include "config.h" + +#include + +#include "utils.h" +#include "bind-mount.h" + +static char * +skip_token (char *line, bool eat_whitespace) +{ + while (*line != ' ' && *line != '\n') + line++; + + if (eat_whitespace && *line == ' ') + line++; + + return line; +} + +static char * +unescape_inline (char *escaped) +{ + char *unescaped, *res; + const char *end; + + res = escaped; + end = escaped + strlen (escaped); + + unescaped = escaped; + while (escaped < end) + { + if (*escaped == '\\') + { + *unescaped++ = + ((escaped[1] - '0') << 6) | + ((escaped[2] - '0') << 3) | + ((escaped[3] - '0') << 0); + escaped += 4; + } + else + { + *unescaped++ = *escaped++; + } + } + *unescaped = 0; + return res; +} + +static bool +match_token (const char *token, const char *token_end, const char *str) +{ + while (token != token_end && *token == *str) + { + token++; + str++; + } + if (token == token_end) + return *str == 0; + + return FALSE; +} + +static unsigned long +decode_mountoptions (const char *options) +{ + const char *token, *end_token; + int i; + unsigned long flags = 0; + static const struct { int flag; + char *name; + } flags_data[] = { + { 0, "rw" }, + { MS_RDONLY, "ro" }, + { MS_NOSUID, "nosuid" }, + { MS_NODEV, "nodev" }, + { MS_NOEXEC, "noexec" }, + { MS_NOATIME, "noatime" }, + { MS_NODIRATIME, "nodiratime" }, + { MS_RELATIME, "relatime" }, + { 0, NULL } + }; + + token = options; + do + { + end_token = strchr (token, ','); + if (end_token == NULL) + end_token = token + strlen (token); + + for (i = 0; flags_data[i].name != NULL; i++) + { + if (match_token (token, end_token, flags_data[i].name)) + { + flags |= flags_data[i].flag; + break; + } + } + + if (*end_token != 0) + token = end_token + 1; + else + token = NULL; + } + while (token != NULL); + + return flags; +} + +typedef struct MountInfo MountInfo; +struct MountInfo { + char *mountpoint; + unsigned long options; +}; + +typedef MountInfo *MountTab; + +static void +mount_tab_free (MountTab tab) +{ + int i; + + for (i = 0; tab[i].mountpoint != NULL; i++) + free (tab[i].mountpoint); + free (tab); +} + +static inline void +cleanup_mount_tabp (void *p) +{ + void **pp = (void **) p; + + if (*pp) + mount_tab_free ((MountTab)*pp); +} + +#define cleanup_mount_tab __attribute__((cleanup (cleanup_mount_tabp))) + +typedef struct MountInfoLine MountInfoLine; +struct MountInfoLine { + const char *mountpoint; + const char *options; + bool covered; + int id; + int parent_id; + MountInfoLine *first_child; + MountInfoLine *next_sibling; +}; + +static unsigned int +count_lines (const char *data) +{ + unsigned int count = 0; + const char *p = data; + + while (*p != 0) + { + if (*p == '\n') + count++; + p++; + } + + /* If missing final newline, add one */ + if (p > data && *(p-1) != '\n') + count++; + + return count; +} + +static int +count_mounts (MountInfoLine *line) +{ + MountInfoLine *child; + int res = 0; + + if (!line->covered) + res += 1; + + child = line->first_child; + while (child != NULL) + { + res += count_mounts (child); + child = child->next_sibling; + } + + return res; +} + +static MountInfo * +collect_mounts (MountInfo *info, MountInfoLine *line) +{ + MountInfoLine *child; + + if (!line->covered) + { + info->mountpoint = xstrdup (line->mountpoint); + info->options = decode_mountoptions (line->options); + info ++; + } + + child = line->first_child; + while (child != NULL) + { + info = collect_mounts (info, child); + child = child->next_sibling; + } + + return info; +} + +static MountTab +parse_mountinfo (int proc_fd, + const char *root_mount) +{ + cleanup_free char *mountinfo = NULL; + cleanup_free MountInfoLine *lines = NULL; + cleanup_free MountInfoLine **by_id = NULL; + cleanup_mount_tab MountTab mount_tab = NULL; + MountInfo *end_tab; + int n_mounts; + char *line; + int i; + int max_id; + unsigned int n_lines; + int root; + + mountinfo = load_file_at (proc_fd, "self/mountinfo"); + if (mountinfo == NULL) + die_with_error ("Can't open /proc/self/mountinfo"); + + n_lines = count_lines (mountinfo); + lines = xcalloc (n_lines * sizeof (MountInfoLine)); + + max_id = 0; + line = mountinfo; + i = 0; + root = -1; + while (*line != 0) + { + int rc, consumed = 0; + unsigned int maj, min; + char *end; + char *rest; + char *mountpoint; + char *mountpoint_end; + char *options; + char *options_end; + char *next_line; + + assert (i < n_lines); + + end = strchr (line, '\n'); + if (end != NULL) + { + *end = 0; + next_line = end + 1; + } + else + next_line = line + strlen (line); + + rc = sscanf (line, "%d %d %u:%u %n", &lines[i].id, &lines[i].parent_id, &maj, &min, &consumed); + if (rc != 4) + die ("Can't parse mountinfo line"); + rest = line + consumed; + + rest = skip_token (rest, TRUE); /* mountroot */ + mountpoint = rest; + rest = skip_token (rest, FALSE); /* mountpoint */ + mountpoint_end = rest++; + options = rest; + rest = skip_token (rest, FALSE); /* vfs options */ + options_end = rest; + + *mountpoint_end = 0; + lines[i].mountpoint = unescape_inline (mountpoint); + + *options_end = 0; + lines[i].options = options; + + if (lines[i].id > max_id) + max_id = lines[i].id; + if (lines[i].parent_id > max_id) + max_id = lines[i].parent_id; + + if (path_equal (lines[i].mountpoint, root_mount)) + root = i; + + i++; + line = next_line; + } + assert (i == n_lines); + + if (root == -1) + { + mount_tab = xcalloc (sizeof (MountInfo) * (1)); + return steal_pointer (&mount_tab); + } + + by_id = xcalloc ((max_id + 1) * sizeof (MountInfoLine*)); + for (i = 0; i < n_lines; i++) + by_id[lines[i].id] = &lines[i]; + + for (i = 0; i < n_lines; i++) + { + MountInfoLine *this = &lines[i]; + MountInfoLine *parent = by_id[this->parent_id]; + MountInfoLine **to_sibling; + MountInfoLine *sibling; + bool covered = FALSE; + + if (!has_path_prefix (this->mountpoint, root_mount)) + continue; + + if (parent == NULL) + continue; + + if (strcmp (parent->mountpoint, this->mountpoint) == 0) + parent->covered = TRUE; + + to_sibling = &parent->first_child; + sibling = parent->first_child; + while (sibling != NULL) + { + /* If this mountpoint is a path prefix of the sibling, + * say this->mp=/foo/bar and sibling->mp=/foo, then it is + * covered by the sibling, and we drop it. */ + if (has_path_prefix (this->mountpoint, sibling->mountpoint)) + { + covered = TRUE; + break; + } + + /* If the sibling is a path prefix of this mount point, + * say this->mp=/foo and sibling->mp=/foo/bar, then the sibling + * is covered, and we drop it. + */ + if (has_path_prefix (sibling->mountpoint, this->mountpoint)) + *to_sibling = sibling->next_sibling; + else + to_sibling = &sibling->next_sibling; + sibling = sibling->next_sibling; + } + + if (covered) + continue; + + *to_sibling = this; + } + + n_mounts = count_mounts (&lines[root]); + mount_tab = xcalloc (sizeof (MountInfo) * (n_mounts + 1)); + + end_tab = collect_mounts (&mount_tab[0], &lines[root]); + assert (end_tab == &mount_tab[n_mounts]); + + return steal_pointer (&mount_tab); +} + +int +bind_mount (int proc_fd, + const char *src, + const char *dest, + bind_option_t options) +{ + bool readonly = (options & BIND_READONLY) != 0; + bool devices = (options & BIND_DEVICES) != 0; + bool recursive = (options & BIND_RECURSIVE) != 0; + unsigned long current_flags, new_flags; + cleanup_mount_tab MountTab mount_tab = NULL; + cleanup_free char *resolved_dest = NULL; + int i; + + if (src) + { + if (mount (src, dest, NULL, MS_MGC_VAL | MS_BIND | (recursive ? MS_REC : 0), NULL) != 0) + return 1; + } + + /* The mount operation will resolve any symlinks in the destination + path, so to find it in the mount table we need to do that too. */ + resolved_dest = realpath (dest, NULL); + if (resolved_dest == NULL) + return 2; + + mount_tab = parse_mountinfo (proc_fd, resolved_dest); + if (mount_tab[0].mountpoint == NULL) + { + errno = EINVAL; + return 2; /* No mountpoint at dest */ + } + + assert (path_equal (mount_tab[0].mountpoint, resolved_dest)); + current_flags = mount_tab[0].options; + new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0); + if (new_flags != current_flags && + mount ("none", resolved_dest, + NULL, MS_MGC_VAL | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0) + return 3; + + /* We need to work around the fact that a bind mount does not apply the flags, so we need to manually + * apply the flags to all submounts in the recursive case. + * Note: This does not apply the flags to mounts which are later propagated into this namespace. + */ + if (recursive) + { + for (i = 1; mount_tab[i].mountpoint != NULL; i++) + { + current_flags = mount_tab[i].options; + new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0); + if (new_flags != current_flags && + mount ("none", mount_tab[i].mountpoint, + NULL, MS_MGC_VAL | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0) + { + /* If we can't read the mountpoint we can't remount it, but that should + be safe to ignore because its not something the user can access. */ + if (errno != EACCES) + return 5; + } + } + } + + return 0; +} diff -Nuar flatpak-1.0.0.orig/bubblewrap/bind-mount.h flatpak-1.0.0/bubblewrap/bind-mount.h --- flatpak-1.0.0.orig/bubblewrap/bind-mount.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/bind-mount.h 2018-02-03 21:26:06.272233339 +0300 @@ -0,0 +1,30 @@ +/* bubblewrap + * Copyright (C) 2016 Alexander Larsson + * + * 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 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 . + * + */ + +#pragma once + +typedef enum { + BIND_READONLY = (1 << 0), + BIND_DEVICES = (1 << 2), + BIND_RECURSIVE = (1 << 3), +} bind_option_t; + +int bind_mount (int proc_fd, + const char *src, + const char *dest, + bind_option_t options); diff -Nuar flatpak-1.0.0.orig/bubblewrap/bubblewrap.c flatpak-1.0.0/bubblewrap/bubblewrap.c --- flatpak-1.0.0.orig/bubblewrap/bubblewrap.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/bubblewrap.c 2018-02-03 21:26:06.272233339 +0300 @@ -0,0 +1,2223 @@ +/* bubblewrap + * Copyright (C) 2016 Alexander Larsson + * + * 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 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 . + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "network.h" +#include "bind-mount.h" + +#ifndef CLONE_NEWCGROUP +#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ +#endif + +/* Globals to avoid having to use getuid(), since the uid/gid changes during runtime */ +static uid_t real_uid; +static gid_t real_gid; +static uid_t overflow_uid; +static gid_t overflow_gid; +static bool is_privileged; +static const char *argv0; +static const char *host_tty_dev; +static int proc_fd = -1; +static char *opt_exec_label = NULL; +static char *opt_file_label = NULL; + +char *opt_chdir_path = NULL; +bool opt_unshare_user = FALSE; +bool opt_unshare_user_try = FALSE; +bool opt_unshare_pid = FALSE; +bool opt_unshare_ipc = FALSE; +bool opt_unshare_net = FALSE; +bool opt_unshare_uts = FALSE; +bool opt_unshare_cgroup = FALSE; +bool opt_unshare_cgroup_try = FALSE; +bool opt_needs_devpts = FALSE; +bool opt_new_session = FALSE; +bool opt_die_with_parent = FALSE; +uid_t opt_sandbox_uid = -1; +gid_t opt_sandbox_gid = -1; +int opt_sync_fd = -1; +int opt_block_fd = -1; +int opt_info_fd = -1; +int opt_seccomp_fd = -1; +char *opt_sandbox_hostname = NULL; + +typedef enum { + SETUP_BIND_MOUNT, + SETUP_RO_BIND_MOUNT, + SETUP_DEV_BIND_MOUNT, + SETUP_MOUNT_PROC, + SETUP_MOUNT_DEV, + SETUP_MOUNT_TMPFS, + SETUP_MOUNT_MQUEUE, + SETUP_MAKE_DIR, + SETUP_MAKE_FILE, + SETUP_MAKE_BIND_FILE, + SETUP_MAKE_RO_BIND_FILE, + SETUP_MAKE_SYMLINK, + SETUP_REMOUNT_RO_NO_RECURSIVE, + SETUP_SET_HOSTNAME, +} SetupOpType; + +typedef enum { + NO_CREATE_DEST = (1 << 0), +} SetupOpFlag; + +typedef struct _SetupOp SetupOp; + +struct _SetupOp +{ + SetupOpType type; + const char *source; + const char *dest; + int fd; + SetupOpFlag flags; + SetupOp *next; +}; + +typedef struct _LockFile LockFile; + +struct _LockFile +{ + const char *path; + LockFile *next; +}; + +static SetupOp *ops = NULL; +static SetupOp *last_op = NULL; +static LockFile *lock_files = NULL; +static LockFile *last_lock_file = NULL; + +enum { + PRIV_SEP_OP_DONE, + PRIV_SEP_OP_BIND_MOUNT, + PRIV_SEP_OP_PROC_MOUNT, + PRIV_SEP_OP_TMPFS_MOUNT, + PRIV_SEP_OP_DEVPTS_MOUNT, + PRIV_SEP_OP_MQUEUE_MOUNT, + PRIV_SEP_OP_REMOUNT_RO_NO_RECURSIVE, + PRIV_SEP_OP_SET_HOSTNAME, +}; + +typedef struct +{ + uint32_t op; + uint32_t flags; + uint32_t arg1_offset; + uint32_t arg2_offset; +} PrivSepOp; + +static SetupOp * +setup_op_new (SetupOpType type) +{ + SetupOp *op = xcalloc (sizeof (SetupOp)); + + op->type = type; + op->fd = -1; + op->flags = 0; + if (last_op != NULL) + last_op->next = op; + else + ops = op; + + last_op = op; + return op; +} + +static LockFile * +lock_file_new (const char *path) +{ + LockFile *lock = xcalloc (sizeof (LockFile)); + + lock->path = path; + if (last_lock_file != NULL) + last_lock_file->next = lock; + else + lock_files = lock; + + last_lock_file = lock; + return lock; +} + + +static void +usage (int ecode, FILE *out) +{ + fprintf (out, "usage: %s [OPTIONS...] COMMAND [ARGS...]\n\n", argv0); + + fprintf (out, + " --help Print this help\n" + " --version Print version\n" + " --args FD Parse nul-separated args from FD\n" + " --unshare-all Unshare every namespace we support by default\n" + " --share-net Retain the network namespace (can only combine with --unshare-all)\n" + " --unshare-user Create new user namespace (may be automatically implied if not setuid)\n" + " --unshare-user-try Create new user namespace if possible else continue by skipping it\n" + " --unshare-ipc Create new ipc namespace\n" + " --unshare-pid Create new pid namespace\n" + " --unshare-net Create new network namespace\n" + " --unshare-uts Create new uts namespace\n" + " --unshare-cgroup Create new cgroup namespace\n" + " --unshare-cgroup-try Create new cgroup namespace if possible else continue by skipping it\n" + " --uid UID Custom uid in the sandbox (requires --unshare-user)\n" + " --gid GID Custon gid in the sandbox (requires --unshare-user)\n" + " --hostname NAME Custom hostname in the sandbox (requires --unshare-uts)\n" + " --chdir DIR Change directory to DIR\n" + " --setenv VAR VALUE Set an environment variable\n" + " --unsetenv VAR Unset an environment variable\n" + " --lock-file DEST Take a lock on DEST while sandbox is running\n" + " --sync-fd FD Keep this fd open while sandbox is running\n" + " --bind SRC DEST Bind mount the host path SRC on DEST\n" + " --dev-bind SRC DEST Bind mount the host path SRC on DEST, allowing device access\n" + " --ro-bind SRC DEST Bind mount the host path SRC readonly on DEST\n" + " --remount-ro DEST Remount DEST as readonly, it doesn't recursively remount\n" + " --exec-label LABEL Exec Label for the sandbox\n" + " --file-label LABEL File label for temporary sandbox content\n" + " --proc DEST Mount procfs on DEST\n" + " --dev DEST Mount new dev on DEST\n" + " --tmpfs DEST Mount new tmpfs on DEST\n" + " --mqueue DEST Mount new mqueue on DEST\n" + " --dir DEST Create dir at DEST\n" + " --file FD DEST Copy from FD to dest DEST\n" + " --bind-data FD DEST Copy from FD to file which is bind-mounted on DEST\n" + " --ro-bind-data FD DEST Copy from FD to file which is readonly bind-mounted on DEST\n" + " --symlink SRC DEST Create symlink at DEST with target SRC\n" + " --seccomp FD Load and use seccomp rules from FD\n" + " --block-fd FD Block on FD until some data to read is available\n" + " --info-fd FD Write information about the running container to FD\n" + " --new-session Create a new terminal session\n" + " --die-with-parent Kills with SIGKILL child process (COMMAND) when bwrap or bwrap's parent dies.\n" + ); + exit (ecode); +} + +/* If --die-with-parent was specified, use PDEATHSIG to ensure SIGKILL + * is sent to the current process when our parent dies. + */ +static void +handle_die_with_parent (void) +{ + if (opt_die_with_parent && prctl (PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) != 0) + die_with_error ("prctl"); +} + +static void +block_sigchild (void) +{ + sigset_t mask; + int status; + + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + + if (sigprocmask (SIG_BLOCK, &mask, NULL) == -1) + die_with_error ("sigprocmask"); + + /* Reap any outstanding zombies that we may have inherited */ + while (waitpid (-1, &status, WNOHANG) > 0) + ; +} + +static void +unblock_sigchild (void) +{ + sigset_t mask; + + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + + if (sigprocmask (SIG_UNBLOCK, &mask, NULL) == -1) + die_with_error ("sigprocmask"); +} + +/* Closes all fd:s except 0,1,2 and the passed in array of extra fds */ +static int +close_extra_fds (void *data, int fd) +{ + int *extra_fds = (int *) data; + int i; + + for (i = 0; extra_fds[i] != -1; i++) + if (fd == extra_fds[i]) + return 0; + + if (fd <= 2) + return 0; + + close (fd); + return 0; +} + +static int +propagate_exit_status (int status) +{ + if (WIFEXITED (status)) + return WEXITSTATUS (status); + + /* The process died of a signal, we can't really report that, but we + * can at least be bash-compatible. The bash manpage says: + * The return value of a simple command is its + * exit status, or 128+n if the command is + * terminated by signal n. + */ + if (WIFSIGNALED (status)) + return 128 + WTERMSIG (status); + + /* Weird? */ + return 255; +} + +/* This stays around for as long as the initial process in the app does + * and when that exits it exits, propagating the exit status. We do this + * by having pid 1 in the sandbox detect this exit and tell the monitor + * the exit status via a eventfd. We also track the exit of the sandbox + * pid 1 via a signalfd for SIGCHLD, and exit with an error in this case. + * This is to catch e.g. problems during setup. */ +static void +monitor_child (int event_fd, pid_t child_pid) +{ + int res; + uint64_t val; + ssize_t s; + int signal_fd; + sigset_t mask; + struct pollfd fds[2]; + int num_fds; + struct signalfd_siginfo fdsi; + int dont_close[] = { event_fd, -1 }; + pid_t died_pid; + int died_status; + + /* Close all extra fds in the monitoring process. + Any passed in fds have been passed on to the child anyway. */ + fdwalk (proc_fd, close_extra_fds, dont_close); + + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + + signal_fd = signalfd (-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK); + if (signal_fd == -1) + die_with_error ("Can't create signalfd"); + + num_fds = 1; + fds[0].fd = signal_fd; + fds[0].events = POLLIN; + if (event_fd != -1) + { + fds[1].fd = event_fd; + fds[1].events = POLLIN; + num_fds++; + } + + while (1) + { + fds[0].revents = fds[1].revents = 0; + res = poll (fds, num_fds, -1); + if (res == -1 && errno != EINTR) + die_with_error ("poll"); + + /* Always read from the eventfd first, if pid 2 died then pid 1 often + * dies too, and we could race, reporting that first and we'd lose + * the real exit status. */ + if (event_fd != -1) + { + s = read (event_fd, &val, 8); + if (s == -1 && errno != EINTR && errno != EAGAIN) + die_with_error ("read eventfd"); + else if (s == 8) + exit ((int) val - 1); + } + + /* We need to read the signal_fd, or it will keep polling as read, + * however we ignore the details as we get them from waitpid + * below anway */ + s = read (signal_fd, &fdsi, sizeof (struct signalfd_siginfo)); + if (s == -1 && errno != EINTR && errno != EAGAIN) + die_with_error ("read signalfd"); + + /* We may actually get several sigchld compressed into one + SIGCHLD, so we have to handle all of them. */ + while ((died_pid = waitpid (-1, &died_status, WNOHANG)) > 0) + { + /* We may be getting sigchild from other children too. For instance if + someone created a child process, and then exec:ed bubblewrap. Ignore them */ + if (died_pid == child_pid) + exit (propagate_exit_status (died_status)); + } + } +} + +/* This is pid 1 in the app sandbox. It is needed because we're using + * pid namespaces, and someone has to reap zombies in it. We also detect + * when the initial process (pid 2) dies and report its exit status to + * the monitor so that it can return it to the original spawner. + * + * When there are no other processes in the sandbox the wait will return + * ECHILD, and we then exit pid 1 to clean up the sandbox. */ +static int +do_init (int event_fd, pid_t initial_pid, struct sock_fprog *seccomp_prog) +{ + int initial_exit_status = 1; + LockFile *lock; + + for (lock = lock_files; lock != NULL; lock = lock->next) + { + int fd = open (lock->path, O_RDONLY | O_CLOEXEC); + if (fd == -1) + die_with_error ("Unable to open lock file %s", lock->path); + + struct flock l = { + .l_type = F_RDLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0 + }; + + if (fcntl (fd, F_SETLK, &l) < 0) + die_with_error ("Unable to lock file %s", lock->path); + + /* Keep fd open to hang on to lock */ + } + + /* Optionally bind our lifecycle to that of the caller */ + handle_die_with_parent (); + + if (seccomp_prog != NULL && + prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, seccomp_prog) != 0) + die_with_error ("prctl(PR_SET_SECCOMP)"); + + while (TRUE) + { + pid_t child; + int status; + + child = wait (&status); + if (child == initial_pid && event_fd != -1) + { + uint64_t val; + int res UNUSED; + + initial_exit_status = propagate_exit_status (status); + + val = initial_exit_status + 1; + res = write (event_fd, &val, 8); + /* Ignore res, if e.g. the parent died and closed event_fd + we don't want to error out here */ + } + + if (child == -1 && errno != EINTR) + { + if (errno != ECHILD) + die_with_error ("init wait()"); + break; + } + } + + return initial_exit_status; +} + +/* low 32bit caps needed */ +#define REQUIRED_CAPS_0 (CAP_TO_MASK (CAP_SYS_ADMIN) | CAP_TO_MASK (CAP_SYS_CHROOT) | CAP_TO_MASK (CAP_NET_ADMIN) | CAP_TO_MASK (CAP_SETUID) | CAP_TO_MASK (CAP_SETGID)) +/* high 32bit caps needed */ +#define REQUIRED_CAPS_1 0 + +static void +set_required_caps (void) +{ + struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 }; + struct __user_cap_data_struct data[2] = { { 0 } }; + + /* Drop all non-require capabilities */ + data[0].effective = REQUIRED_CAPS_0; + data[0].permitted = REQUIRED_CAPS_0; + data[0].inheritable = 0; + data[1].effective = REQUIRED_CAPS_1; + data[1].permitted = REQUIRED_CAPS_1; + data[1].inheritable = 0; + if (capset (&hdr, data) < 0) + die_with_error ("capset failed"); +} + +static void +drop_all_caps (void) +{ + struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 }; + struct __user_cap_data_struct data[2] = { { 0 } }; + + if (capset (&hdr, data) < 0) + die_with_error ("capset failed"); +} + +static bool +has_caps (void) +{ + struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 }; + struct __user_cap_data_struct data[2] = { { 0 } }; + + if (capget (&hdr, data) < 0) + die_with_error ("capget failed"); + + return data[0].permitted != 0 || data[1].permitted != 0; +} + +static void +drop_cap_bounding_set (void) +{ + unsigned long cap; + + /* We ignore both EINVAL and EPERM, as we are actually relying + * on PR_SET_NO_NEW_PRIVS to ensure the right capabilities are + * available. EPERM in particular can happen with old, buggy + * kernels. See: + * https://github.com/projectatomic/bubblewrap/pull/175#issuecomment-278051373 + * https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/security/commoncap.c?id=160da84dbb39443fdade7151bc63a88f8e953077 + */ + for (cap = 0; cap <= 63; cap++) + { + int res = prctl (PR_CAPBSET_DROP, cap, 0, 0, 0); + if (res == -1 && !(errno == EINVAL || errno == EPERM)) + die_with_error ("Dropping capability %ld from bounds", cap); + } +} + +/* This acquires the privileges that the bwrap will need it to work. + * If bwrap is not setuid, then this does nothing, and it relies on + * unprivileged user namespaces to be used. This case is + * "is_privileged = FALSE". + * + * If bwrap is setuid, then we do things in phases. + * The first part is run as euid 0, but with with fsuid as the real user. + * The second part, inside the child, is run as the real user but with + * capabilities. + * And finally we drop all capabilities. + * The reason for the above dance is to avoid having the setup phase + * being able to read files the user can't, while at the same time + * working around various kernel issues. See below for details. + */ +static void +acquire_privs (void) +{ + uid_t euid, new_fsuid; + + euid = geteuid (); + + /* Are we setuid ? */ + if (real_uid != euid) + { + if (euid == 0) + is_privileged = TRUE; + else + die ("Unexpected setuid user %d, should be 0", euid); + + /* We want to keep running as euid=0 until at the clone() + * operation because doing so will make the user namespace be + * owned by root, which makes it not ptrace:able by the user as + * it otherwise would be. After that we will run fully as the + * user, which is necessary e.g. to be able to read from a fuse + * mount from the user. + * + * However, we don't want to accidentally mis-use euid=0 for + * escalated filesystem access before the clone(), so we set + * fsuid to the uid. + */ + if (setfsuid (real_uid) < 0) + die_with_error ("Unable to set fsuid"); + + /* setfsuid can't properly report errors, check that it worked (as per manpage) */ + new_fsuid = setfsuid (-1); + if (new_fsuid != real_uid) + die ("Unable to set fsuid (was %d)", (int)new_fsuid); + + /* We never need capabilies after execve(), so lets drop everything from the bounding set */ + drop_cap_bounding_set (); + + /* Keep only the required capabilities for setup */ + set_required_caps (); + } + else if (real_uid != 0 && has_caps ()) + { + /* We have some capabilities in the non-setuid case, which should not happen. + Probably caused by the binary being setcap instead of setuid which we + don't support anymore */ + die ("Unexpected capabilities but not setuid, old file caps config?"); + } + + /* Else, we try unprivileged user namespaces */ +} + +/* This is called once we're inside the namespace */ +static void +switch_to_user_with_privs (void) +{ + /* If we're in a new user namespace, we got back the bounding set, clear it again */ + if (opt_unshare_user) + drop_cap_bounding_set (); + + if (!is_privileged) + return; + + /* Tell kernel not clear capabilities when later dropping root uid */ + if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) + die_with_error ("prctl(PR_SET_KEEPCAPS) failed"); + + if (setuid (opt_sandbox_uid) < 0) + die_with_error ("unable to drop root uid"); + + /* Regain effective required capabilities from permitted */ + set_required_caps (); +} + +static void +drop_privs (void) +{ + if (!is_privileged) + return; + + /* Drop root uid */ + if (setuid (opt_sandbox_uid) < 0) + die_with_error ("unable to drop root uid"); + + drop_all_caps (); +} + +static char * +get_newroot_path (const char *path) +{ + while (*path == '/') + path++; + return strconcat ("/newroot/", path); +} + +static char * +get_oldroot_path (const char *path) +{ + while (*path == '/') + path++; + return strconcat ("/oldroot/", path); +} + +static void +write_uid_gid_map (uid_t sandbox_uid, + uid_t parent_uid, + uid_t sandbox_gid, + uid_t parent_gid, + pid_t pid, + bool deny_groups, + bool map_root) +{ + cleanup_free char *uid_map = NULL; + cleanup_free char *gid_map = NULL; + cleanup_free char *dir = NULL; + cleanup_fd int dir_fd = -1; + uid_t old_fsuid = -1; + + if (pid == -1) + dir = xstrdup ("self"); + else + dir = xasprintf ("%d", pid); + + dir_fd = openat (proc_fd, dir, O_RDONLY | O_PATH); + if (dir_fd < 0) + die_with_error ("open /proc/%s failed", dir); + + if (map_root && parent_uid != 0 && sandbox_uid != 0) + uid_map = xasprintf ("0 %d 1\n" + "%d %d 1\n", overflow_uid, sandbox_uid, parent_uid); + else + uid_map = xasprintf ("%d %d 1\n", sandbox_uid, parent_uid); + + if (map_root && parent_gid != 0 && sandbox_gid != 0) + gid_map = xasprintf ("0 %d 1\n" + "%d %d 1\n", overflow_gid, sandbox_gid, parent_gid); + else + gid_map = xasprintf ("%d %d 1\n", sandbox_gid, parent_gid); + + /* We have to be root to be allowed to write to the uid map + * for setuid apps, so temporary set fsuid to 0 */ + if (is_privileged) + old_fsuid = setfsuid (0); + + if (write_file_at (dir_fd, "uid_map", uid_map) != 0) + die_with_error ("setting up uid map"); + + if (deny_groups && + write_file_at (dir_fd, "setgroups", "deny\n") != 0) + { + /* If /proc/[pid]/setgroups does not exist, assume we are + * running a linux kernel < 3.19, i.e. we live with the + * vulnerability known as CVE-2014-8989 in older kernels + * where setgroups does not exist. + */ + if (errno != ENOENT) + die_with_error ("error writing to setgroups"); + } + + if (write_file_at (dir_fd, "gid_map", gid_map) != 0) + die_with_error ("setting up gid map"); + + if (is_privileged) + { + setfsuid (old_fsuid); + if (setfsuid (-1) != real_uid) + die ("Unable to re-set fsuid"); + } +} + +static void +privileged_op (int privileged_op_socket, + uint32_t op, + uint32_t flags, + const char *arg1, + const char *arg2) +{ + if (privileged_op_socket != -1) + { + uint32_t buffer[2048]; /* 8k, but is int32 to guarantee nice alignment */ + PrivSepOp *op_buffer = (PrivSepOp *) buffer; + size_t buffer_size = sizeof (PrivSepOp); + uint32_t arg1_offset = 0, arg2_offset = 0; + + /* We're unprivileged, send this request to the privileged part */ + + if (arg1 != NULL) + { + arg1_offset = buffer_size; + buffer_size += strlen (arg1) + 1; + } + if (arg2 != NULL) + { + arg2_offset = buffer_size; + buffer_size += strlen (arg2) + 1; + } + + if (buffer_size >= sizeof (buffer)) + die ("privilege separation operation to large"); + + op_buffer->op = op; + op_buffer->flags = flags; + op_buffer->arg1_offset = arg1_offset; + op_buffer->arg2_offset = arg2_offset; + if (arg1 != NULL) + strcpy ((char *) buffer + arg1_offset, arg1); + if (arg2 != NULL) + strcpy ((char *) buffer + arg2_offset, arg2); + + if (write (privileged_op_socket, buffer, buffer_size) != buffer_size) + die ("Can't write to privileged_op_socket"); + + if (read (privileged_op_socket, buffer, 1) != 1) + die ("Can't read from privileged_op_socket"); + + return; + } + + /* + * This runs a privileged request for the unprivileged setup + * code. Note that since the setup code is unprivileged it is not as + * trusted, so we need to verify that all requests only affect the + * child namespace as set up by the privileged parts of the setup, + * and that all the code is very careful about handling input. + * + * This means: + * * Bind mounts are safe, since we always use filesystem namespace. They + * must be recursive though, as otherwise you can use a non-recursive bind + * mount to access an otherwise over-mounted mountpoint. + * * Mounting proc, tmpfs, mqueue, devpts in the child namespace is assumed to + * be safe. + * * Remounting RO (even non-recursive) is safe because it decreases privileges. + * * sethostname() is safe only if we set up a UTS namespace + */ + switch (op) + { + case PRIV_SEP_OP_DONE: + break; + + case PRIV_SEP_OP_REMOUNT_RO_NO_RECURSIVE: + if (bind_mount (proc_fd, NULL, arg2, BIND_READONLY) != 0) + die_with_error ("Can't remount readonly on %s", arg2); + break; + + case PRIV_SEP_OP_BIND_MOUNT: + /* We always bind directories recursively, otherwise this would let us + access files that are otherwise covered on the host */ + if (bind_mount (proc_fd, arg1, arg2, BIND_RECURSIVE | flags) != 0) + die_with_error ("Can't bind mount %s on %s", arg1, arg2); + break; + + case PRIV_SEP_OP_PROC_MOUNT: + if (mount ("proc", arg1, "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL) != 0) + die_with_error ("Can't mount proc on %s", arg1); + break; + + case PRIV_SEP_OP_TMPFS_MOUNT: + { + cleanup_free char *opt = label_mount ("mode=0755", opt_file_label); + if (mount ("tmpfs", arg1, "tmpfs", MS_MGC_VAL | MS_NOSUID | MS_NODEV, opt) != 0) + die_with_error ("Can't mount tmpfs on %s", arg1); + break; + } + + case PRIV_SEP_OP_DEVPTS_MOUNT: + if (mount ("devpts", arg1, "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC, + "newinstance,ptmxmode=0666,mode=620") != 0) + die_with_error ("Can't mount devpts on %s", arg1); + break; + + case PRIV_SEP_OP_MQUEUE_MOUNT: + if (mount ("mqueue", arg1, "mqueue", 0, NULL) != 0) + die_with_error ("Can't mount mqueue on %s", arg1); + break; + + case PRIV_SEP_OP_SET_HOSTNAME: + /* This is checked at the start, but lets verify it here in case + something manages to send hacked priv-sep operation requests. */ + if (!opt_unshare_uts) + die ("Refusing to set hostname in original namespace"); + if (sethostname (arg1, strlen(arg1)) != 0) + die_with_error ("Can't set hostname to %s", arg1); + break; + + default: + die ("Unexpected privileged op %d", op); + } +} + +/* This is run unprivileged in the child namespace but can request + * some privileged operations (also in the child namespace) via the + * privileged_op_socket. + */ +static void +setup_newroot (bool unshare_pid, + int privileged_op_socket) +{ + SetupOp *op; + + for (op = ops; op != NULL; op = op->next) + { + cleanup_free char *source = NULL; + cleanup_free char *dest = NULL; + int source_mode = 0; + int i; + + if (op->source && + op->type != SETUP_MAKE_SYMLINK) + { + source = get_oldroot_path (op->source); + source_mode = get_file_mode (source); + if (source_mode < 0) + die_with_error ("Can't get type of source %s", op->source); + } + + if (op->dest && + (op->flags & NO_CREATE_DEST) == 0) + { + dest = get_newroot_path (op->dest); + if (mkdir_with_parents (dest, 0755, FALSE) != 0) + die_with_error ("Can't mkdir parents for %s", op->dest); + } + + switch (op->type) + { + case SETUP_RO_BIND_MOUNT: + case SETUP_DEV_BIND_MOUNT: + case SETUP_BIND_MOUNT: + if (source_mode == S_IFDIR) + { + if (mkdir (dest, 0755) != 0 && errno != EEXIST) + die_with_error ("Can't mkdir %s", op->dest); + } + else if (ensure_file (dest, 0666) != 0) + die_with_error ("Can't create file at %s", op->dest); + + privileged_op (privileged_op_socket, + PRIV_SEP_OP_BIND_MOUNT, + (op->type == SETUP_RO_BIND_MOUNT ? BIND_READONLY : 0) | + (op->type == SETUP_DEV_BIND_MOUNT ? BIND_DEVICES : 0), + source, dest); + break; + + case SETUP_REMOUNT_RO_NO_RECURSIVE: + privileged_op (privileged_op_socket, + PRIV_SEP_OP_REMOUNT_RO_NO_RECURSIVE, 0, NULL, dest); + break; + + case SETUP_MOUNT_PROC: + if (mkdir (dest, 0755) != 0 && errno != EEXIST) + die_with_error ("Can't mkdir %s", op->dest); + + if (unshare_pid) + { + /* Our own procfs */ + privileged_op (privileged_op_socket, + PRIV_SEP_OP_PROC_MOUNT, 0, + dest, NULL); + } + else + { + /* Use system procfs, as we share pid namespace anyway */ + privileged_op (privileged_op_socket, + PRIV_SEP_OP_BIND_MOUNT, 0, + "oldroot/proc", dest); + } + + /* There are a bunch of weird old subdirs of /proc that could potentially be + problematic (for instance /proc/sysrq-trigger lets you shut down the machine + if you have write access). We should not have access to these as a non-privileged + user, but lets cover them anyway just to make sure */ + const char *cover_proc_dirs[] = { "sys", "sysrq-trigger", "irq", "bus" }; + for (i = 0; i < N_ELEMENTS (cover_proc_dirs); i++) + { + cleanup_free char *subdir = strconcat3 (dest, "/", cover_proc_dirs[i]); + /* Some of these may not exist */ + if (get_file_mode (subdir) == -1) + continue; + privileged_op (privileged_op_socket, + PRIV_SEP_OP_BIND_MOUNT, BIND_READONLY, + subdir, subdir); + } + + break; + + case SETUP_MOUNT_DEV: + if (mkdir (dest, 0755) != 0 && errno != EEXIST) + die_with_error ("Can't mkdir %s", op->dest); + + privileged_op (privileged_op_socket, + PRIV_SEP_OP_TMPFS_MOUNT, 0, + dest, NULL); + + static const char *const devnodes[] = { "null", "zero", "full", "random", "urandom", "tty" }; + for (i = 0; i < N_ELEMENTS (devnodes); i++) + { + cleanup_free char *node_dest = strconcat3 (dest, "/", devnodes[i]); + cleanup_free char *node_src = strconcat ("/oldroot/dev/", devnodes[i]); + if (create_file (node_dest, 0666, NULL) != 0) + die_with_error ("Can't create file %s/%s", op->dest, devnodes[i]); + privileged_op (privileged_op_socket, + PRIV_SEP_OP_BIND_MOUNT, BIND_DEVICES, + node_src, node_dest); + } + + static const char *const stdionodes[] = { "stdin", "stdout", "stderr" }; + for (i = 0; i < N_ELEMENTS (stdionodes); i++) + { + cleanup_free char *target = xasprintf ("/proc/self/fd/%d", i); + cleanup_free char *node_dest = strconcat3 (dest, "/", stdionodes[i]); + if (symlink (target, node_dest) < 0) + die_with_error ("Can't create symlink %s/%s", op->dest, stdionodes[i]); + } + + { + cleanup_free char *pts = strconcat (dest, "/pts"); + cleanup_free char *ptmx = strconcat (dest, "/ptmx"); + cleanup_free char *shm = strconcat (dest, "/shm"); + + if (mkdir (shm, 0755) == -1) + die_with_error ("Can't create %s/shm", op->dest); + + if (mkdir (pts, 0755) == -1) + die_with_error ("Can't create %s/devpts", op->dest); + privileged_op (privileged_op_socket, + PRIV_SEP_OP_DEVPTS_MOUNT, 0, pts, NULL); + + if (symlink ("pts/ptmx", ptmx) != 0) + die_with_error ("Can't make symlink at %s/ptmx", op->dest); + } + + /* If stdout is a tty, that means the sandbox can write to the + outside-sandbox tty. In that case we also create a /dev/console + that points to this tty device. This should not cause any more + access than we already have, and it makes ttyname() work in the + sandbox. */ + if (host_tty_dev != NULL && *host_tty_dev != 0) + { + cleanup_free char *src_tty_dev = strconcat ("/oldroot", host_tty_dev); + cleanup_free char *dest_console = strconcat (dest, "/console"); + + if (create_file (dest_console, 0666, NULL) != 0) + die_with_error ("creating %s/console", op->dest); + + privileged_op (privileged_op_socket, + PRIV_SEP_OP_BIND_MOUNT, BIND_DEVICES, + src_tty_dev, dest_console); + } + + break; + + case SETUP_MOUNT_TMPFS: + if (mkdir (dest, 0755) != 0 && errno != EEXIST) + die_with_error ("Can't mkdir %s", op->dest); + + privileged_op (privileged_op_socket, + PRIV_SEP_OP_TMPFS_MOUNT, 0, + dest, NULL); + break; + + case SETUP_MOUNT_MQUEUE: + if (mkdir (dest, 0755) != 0 && errno != EEXIST) + die_with_error ("Can't mkdir %s", op->dest); + + privileged_op (privileged_op_socket, + PRIV_SEP_OP_MQUEUE_MOUNT, 0, + dest, NULL); + break; + + case SETUP_MAKE_DIR: + if (mkdir (dest, 0755) != 0 && errno != EEXIST) + die_with_error ("Can't mkdir %s", op->dest); + + break; + + case SETUP_MAKE_FILE: + { + cleanup_fd int dest_fd = -1; + + dest_fd = creat (dest, 0666); + if (dest_fd == -1) + die_with_error ("Can't create file %s", op->dest); + + if (copy_file_data (op->fd, dest_fd) != 0) + die_with_error ("Can't write data to file %s", op->dest); + + close (op->fd); + } + break; + + case SETUP_MAKE_BIND_FILE: + case SETUP_MAKE_RO_BIND_FILE: + { + cleanup_fd int dest_fd = -1; + char tempfile[] = "/bindfileXXXXXX"; + + dest_fd = mkstemp (tempfile); + if (dest_fd == -1) + die_with_error ("Can't create tmpfile for %s", op->dest); + + if (copy_file_data (op->fd, dest_fd) != 0) + die_with_error ("Can't write data to file %s", op->dest); + + close (op->fd); + + if (ensure_file (dest, 0666) != 0) + die_with_error ("Can't create file at %s", op->dest); + + privileged_op (privileged_op_socket, + PRIV_SEP_OP_BIND_MOUNT, + (op->type == SETUP_MAKE_RO_BIND_FILE ? BIND_READONLY : 0), + tempfile, dest); + + /* Remove the file so we're sure the app can't get to it in any other way. + Its outside the container chroot, so it shouldn't be possible, but lets + make it really sure. */ + unlink (tempfile); + } + break; + + case SETUP_MAKE_SYMLINK: + if (symlink (op->source, dest) != 0) + die_with_error ("Can't make symlink at %s", op->dest); + break; + + case SETUP_SET_HOSTNAME: + privileged_op (privileged_op_socket, + PRIV_SEP_OP_SET_HOSTNAME, 0, + op->dest, NULL); + break; + + default: + die ("Unexpected type %d", op->type); + } + } + privileged_op (privileged_op_socket, + PRIV_SEP_OP_DONE, 0, NULL, NULL); +} + +/* We need to resolve relative symlinks in the sandbox before we + chroot so that absolute symlinks are handled correctly. We also + need to do this after we've switched to the real uid so that + e.g. paths on fuse mounts work */ +static void +resolve_symlinks_in_ops (void) +{ + SetupOp *op; + + for (op = ops; op != NULL; op = op->next) + { + const char *old_source; + + switch (op->type) + { + case SETUP_RO_BIND_MOUNT: + case SETUP_DEV_BIND_MOUNT: + case SETUP_BIND_MOUNT: + old_source = op->source; + op->source = realpath (old_source, NULL); + if (op->source == NULL) + die_with_error ("Can't find source path %s", old_source); + break; + default: + break; + } + } +} + + +static const char * +resolve_string_offset (void *buffer, + size_t buffer_size, + uint32_t offset) +{ + if (offset == 0) + return NULL; + + if (offset > buffer_size) + die ("Invalid string offset %d (buffer size %zd)", offset, buffer_size); + + return (const char *) buffer + offset; +} + +static uint32_t +read_priv_sec_op (int read_socket, + void *buffer, + size_t buffer_size, + uint32_t *flags, + const char **arg1, + const char **arg2) +{ + const PrivSepOp *op = (const PrivSepOp *) buffer; + ssize_t rec_len; + + do + rec_len = read (read_socket, buffer, buffer_size - 1); + while (rec_len == -1 && errno == EINTR); + + if (rec_len < 0) + die_with_error ("Can't read from unprivileged helper"); + + if (rec_len == 0) + exit (1); /* Privileged helper died and printed error, so exit silently */ + + if (rec_len < sizeof (PrivSepOp)) + die ("Invalid size %zd from unprivileged helper", rec_len); + + /* Guarantee zero termination of any strings */ + ((char *) buffer)[rec_len] = 0; + + *flags = op->flags; + *arg1 = resolve_string_offset (buffer, rec_len, op->arg1_offset); + *arg2 = resolve_string_offset (buffer, rec_len, op->arg2_offset); + + return op->op; +} + +static void __attribute__ ((noreturn)) +print_version_and_exit (void) +{ + printf ("%s\n", PACKAGE_STRING); + exit (0); +} + +static void +parse_args_recurse (int *argcp, + char ***argvp, + bool in_file, + int *total_parsed_argc_p) +{ + SetupOp *op; + int argc = *argcp; + char **argv = *argvp; + /* I can't imagine a case where someone wants more than this. + * If you do...you should be able to pass multiple files + * via a single tmpfs and linking them there, etc. + * + * We're adding this hardening due to precedent from + * http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html + * + * I picked 9000 because the Internet told me to and it was hard to + * resist. + */ + static const uint32_t MAX_ARGS = 9000; + + if (*total_parsed_argc_p > MAX_ARGS) + die ("Exceeded maximum number of arguments %u", MAX_ARGS); + + while (argc > 0) + { + const char *arg = argv[0]; + + if (strcmp (arg, "--help") == 0) + { + usage (EXIT_SUCCESS, stdout); + } + else if (strcmp (arg, "--version") == 0) + { + print_version_and_exit (); + } + else if (strcmp (arg, "--args") == 0) + { + int the_fd; + char *endptr; + char *data, *p; + char *data_end; + size_t data_len; + cleanup_free char **data_argv = NULL; + char **data_argv_copy; + int data_argc; + int i; + + if (in_file) + die ("--args not supported in arguments file"); + + if (argc < 2) + die ("--args takes an argument"); + + the_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) + die ("Invalid fd: %s", argv[1]); + + data = load_file_data (the_fd, &data_len); + if (data == NULL) + die_with_error ("Can't read --args data"); + + data_end = data + data_len; + data_argc = 0; + + p = data; + while (p != NULL && p < data_end) + { + data_argc++; + (*total_parsed_argc_p)++; + if (*total_parsed_argc_p > MAX_ARGS) + die ("Exceeded maximum number of arguments %u", MAX_ARGS); + p = memchr (p, 0, data_end - p); + if (p != NULL) + p++; + } + + data_argv = xcalloc (sizeof (char *) * (data_argc + 1)); + + i = 0; + p = data; + while (p != NULL && p < data_end) + { + /* Note: load_file_data always adds a nul terminator, so this is safe + * even for the last string. */ + data_argv[i++] = p; + p = memchr (p, 0, data_end - p); + if (p != NULL) + p++; + } + + data_argv_copy = data_argv; /* Don't change data_argv, we need to free it */ + parse_args_recurse (&data_argc, &data_argv_copy, TRUE, total_parsed_argc_p); + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--unshare-all") == 0) + { + /* Keep this in order with the older (legacy) --unshare arguments, + * we use the --try variants of user and cgroup, since we want + * to support systems/kernels without support for those. + */ + opt_unshare_user_try = opt_unshare_ipc = opt_unshare_pid = + opt_unshare_uts = opt_unshare_cgroup_try = + opt_unshare_net = TRUE; + } + /* Begin here the older individual --unshare variants */ + else if (strcmp (arg, "--unshare-user") == 0) + { + opt_unshare_user = TRUE; + } + else if (strcmp (arg, "--unshare-user-try") == 0) + { + opt_unshare_user_try = TRUE; + } + else if (strcmp (arg, "--unshare-ipc") == 0) + { + opt_unshare_ipc = TRUE; + } + else if (strcmp (arg, "--unshare-pid") == 0) + { + opt_unshare_pid = TRUE; + } + else if (strcmp (arg, "--unshare-net") == 0) + { + opt_unshare_net = TRUE; + } + else if (strcmp (arg, "--unshare-uts") == 0) + { + opt_unshare_uts = TRUE; + } + else if (strcmp (arg, "--unshare-cgroup") == 0) + { + opt_unshare_cgroup = TRUE; + } + else if (strcmp (arg, "--unshare-cgroup-try") == 0) + { + opt_unshare_cgroup_try = TRUE; + } + /* Begin here the newer --share variants */ + else if (strcmp (arg, "--share-net") == 0) + { + opt_unshare_net = FALSE; + } + /* End --share variants, other arguments begin */ + else if (strcmp (arg, "--chdir") == 0) + { + if (argc < 2) + die ("--chdir takes one argument"); + + opt_chdir_path = argv[1]; + argv++; + argc--; + } + else if (strcmp (arg, "--remount-ro") == 0) + { + if (argc < 2) + die ("--remount-ro takes one argument"); + + SetupOp *op = setup_op_new (SETUP_REMOUNT_RO_NO_RECURSIVE); + op->dest = argv[1]; + + argv++; + argc--; + } + else if (strcmp (arg, "--bind") == 0) + { + if (argc < 3) + die ("--bind takes two arguments"); + + op = setup_op_new (SETUP_BIND_MOUNT); + op->source = argv[1]; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--ro-bind") == 0) + { + if (argc < 3) + die ("--ro-bind takes two arguments"); + + op = setup_op_new (SETUP_RO_BIND_MOUNT); + op->source = argv[1]; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--dev-bind") == 0) + { + if (argc < 3) + die ("--dev-bind takes two arguments"); + + op = setup_op_new (SETUP_DEV_BIND_MOUNT); + op->source = argv[1]; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--proc") == 0) + { + if (argc < 2) + die ("--proc takes an argument"); + + op = setup_op_new (SETUP_MOUNT_PROC); + op->dest = argv[1]; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--exec-label") == 0) + { + if (argc < 2) + die ("--exec-label takes an argument"); + opt_exec_label = argv[1]; + die_unless_label_valid (opt_exec_label); + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--file-label") == 0) + { + if (argc < 2) + die ("--file-label takes an argument"); + opt_file_label = argv[1]; + die_unless_label_valid (opt_file_label); + if (label_create_file (opt_file_label)) + die_with_error ("--file-label setup failed"); + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--dev") == 0) + { + if (argc < 2) + die ("--dev takes an argument"); + + op = setup_op_new (SETUP_MOUNT_DEV); + op->dest = argv[1]; + opt_needs_devpts = TRUE; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--tmpfs") == 0) + { + if (argc < 2) + die ("--tmpfs takes an argument"); + + op = setup_op_new (SETUP_MOUNT_TMPFS); + op->dest = argv[1]; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--mqueue") == 0) + { + if (argc < 2) + die ("--mqueue takes an argument"); + + op = setup_op_new (SETUP_MOUNT_MQUEUE); + op->dest = argv[1]; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--dir") == 0) + { + if (argc < 2) + die ("--dir takes an argument"); + + op = setup_op_new (SETUP_MAKE_DIR); + op->dest = argv[1]; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--file") == 0) + { + int file_fd; + char *endptr; + + if (argc < 3) + die ("--file takes two arguments"); + + file_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || file_fd < 0) + die ("Invalid fd: %s", argv[1]); + + op = setup_op_new (SETUP_MAKE_FILE); + op->fd = file_fd; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--bind-data") == 0) + { + int file_fd; + char *endptr; + + if (argc < 3) + die ("--bind-data takes two arguments"); + + file_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || file_fd < 0) + die ("Invalid fd: %s", argv[1]); + + op = setup_op_new (SETUP_MAKE_BIND_FILE); + op->fd = file_fd; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--ro-bind-data") == 0) + { + int file_fd; + char *endptr; + + if (argc < 3) + die ("--ro-bind-data takes two arguments"); + + file_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || file_fd < 0) + die ("Invalid fd: %s", argv[1]); + + op = setup_op_new (SETUP_MAKE_RO_BIND_FILE); + op->fd = file_fd; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--symlink") == 0) + { + if (argc < 3) + die ("--symlink takes two arguments"); + + op = setup_op_new (SETUP_MAKE_SYMLINK); + op->source = argv[1]; + op->dest = argv[2]; + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--lock-file") == 0) + { + if (argc < 2) + die ("--lock-file takes an argument"); + + (void) lock_file_new (argv[1]); + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--sync-fd") == 0) + { + int the_fd; + char *endptr; + + if (argc < 2) + die ("--sync-fd takes an argument"); + + the_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) + die ("Invalid fd: %s", argv[1]); + + opt_sync_fd = the_fd; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--block-fd") == 0) + { + int the_fd; + char *endptr; + + if (argc < 2) + die ("--block-fd takes an argument"); + + the_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) + die ("Invalid fd: %s", argv[1]); + + opt_block_fd = the_fd; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--info-fd") == 0) + { + int the_fd; + char *endptr; + + if (argc < 2) + die ("--info-fd takes an argument"); + + the_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) + die ("Invalid fd: %s", argv[1]); + + opt_info_fd = the_fd; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--seccomp") == 0) + { + int the_fd; + char *endptr; + + if (argc < 2) + die ("--seccomp takes an argument"); + + the_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) + die ("Invalid fd: %s", argv[1]); + + opt_seccomp_fd = the_fd; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--setenv") == 0) + { + if (argc < 3) + die ("--setenv takes two arguments"); + + xsetenv (argv[1], argv[2], 1); + + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--unsetenv") == 0) + { + if (argc < 2) + die ("--unsetenv takes an argument"); + + xunsetenv (argv[1]); + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--uid") == 0) + { + int the_uid; + char *endptr; + + if (argc < 2) + die ("--uid takes an argument"); + + the_uid = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_uid < 0) + die ("Invalid uid: %s", argv[1]); + + opt_sandbox_uid = the_uid; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--gid") == 0) + { + int the_gid; + char *endptr; + + if (argc < 2) + die ("--gid takes an argument"); + + the_gid = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || the_gid < 0) + die ("Invalid gid: %s", argv[1]); + + opt_sandbox_gid = the_gid; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--hostname") == 0) + { + if (argc < 2) + die ("--hostname takes an argument"); + + op = setup_op_new (SETUP_SET_HOSTNAME); + op->dest = argv[1]; + op->flags = NO_CREATE_DEST; + + opt_sandbox_hostname = argv[1]; + + argv += 1; + argc -= 1; + } + else if (strcmp (arg, "--new-session") == 0) + { + opt_new_session = TRUE; + } + else if (strcmp (arg, "--die-with-parent") == 0) + { + opt_die_with_parent = TRUE; + } + else if (*arg == '-') + { + die ("Unknown option %s", arg); + } + else + { + break; + } + + argv++; + argc--; + } + + *argcp = argc; + *argvp = argv; +} + +static void +parse_args (int *argcp, + char ***argvp) +{ + int total_parsed_argc = *argcp; + + parse_args_recurse (argcp, argvp, FALSE, &total_parsed_argc); +} + +static void +read_overflowids (void) +{ + cleanup_free char *uid_data = NULL; + cleanup_free char *gid_data = NULL; + + uid_data = load_file_at (AT_FDCWD, "/proc/sys/kernel/overflowuid"); + if (uid_data == NULL) + die_with_error ("Can't read /proc/sys/kernel/overflowuid"); + + overflow_uid = strtol (uid_data, NULL, 10); + if (overflow_uid == 0) + die ("Can't parse /proc/sys/kernel/overflowuid"); + + gid_data = load_file_at (AT_FDCWD, "/proc/sys/kernel/overflowgid"); + if (gid_data == NULL) + die_with_error ("Can't read /proc/sys/kernel/overflowgid"); + + overflow_gid = strtol (gid_data, NULL, 10); + if (overflow_gid == 0) + die ("Can't parse /proc/sys/kernel/overflowgid"); +} + +int +main (int argc, + char **argv) +{ + mode_t old_umask; + cleanup_free char *base_path = NULL; + int clone_flags; + char *old_cwd = NULL; + pid_t pid; + int event_fd = -1; + int child_wait_fd = -1; + const char *new_cwd; + uid_t ns_uid; + gid_t ns_gid; + struct stat sbuf; + uint64_t val; + int res UNUSED; + cleanup_free char *seccomp_data = NULL; + size_t seccomp_len; + struct sock_fprog seccomp_prog; + + /* Handle --version early on before we try to acquire/drop + * any capabilities so it works in a build environment; + * right now flatpak's build runs bubblewrap --version. + * https://github.com/projectatomic/bubblewrap/issues/185 + */ + if (argc == 2 && (strcmp (argv[1], "--version") == 0)) + print_version_and_exit (); + + real_uid = getuid (); + real_gid = getgid (); + + /* Get the (optional) privileges we need */ + acquire_privs (); + + /* Never gain any more privs during exec */ + if (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) + die_with_error ("prctl(PR_SET_NO_NEW_CAPS) failed"); + + /* The initial code is run with high permissions + (i.e. CAP_SYS_ADMIN), so take lots of care. */ + + read_overflowids (); + + argv0 = argv[0]; + + if (isatty (1)) + host_tty_dev = ttyname (1); + + argv++; + argc--; + + if (argc == 0) + usage (EXIT_FAILURE, stderr); + + parse_args (&argc, &argv); + + /* We have to do this if we weren't installed setuid (and we're not + * root), so let's just DWIM */ + if (!is_privileged && getuid () != 0) + opt_unshare_user = TRUE; + +#ifdef ENABLE_REQUIRE_USERNS + /* In this build option, we require userns. */ + if (is_privileged && getuid () != 0) + opt_unshare_user = TRUE; +#endif + + if (opt_unshare_user_try && + stat ("/proc/self/ns/user", &sbuf) == 0) + { + bool disabled = FALSE; + + /* RHEL7 has a kernel module parameter that lets you enable user namespaces */ + if (stat ("/sys/module/user_namespace/parameters/enable", &sbuf) == 0) + { + cleanup_free char *enable = NULL; + enable = load_file_at (AT_FDCWD, "/sys/module/user_namespace/parameters/enable"); + if (enable != NULL && enable[0] == 'N') + disabled = TRUE; + } + + /* Debian lets you disable *unprivileged* user namespaces. However this is not + a problem if we're privileged, and if we're not opt_unshare_user is TRUE + already, and there is not much we can do, its just a non-working setup. */ + + if (!disabled) + opt_unshare_user = TRUE; + } + + if (argc == 0) + usage (EXIT_FAILURE, stderr); + + __debug__ (("Creating root mount point\n")); + + if (opt_sandbox_uid == -1) + opt_sandbox_uid = real_uid; + if (opt_sandbox_gid == -1) + opt_sandbox_gid = real_gid; + + if (!opt_unshare_user && opt_sandbox_uid != real_uid) + die ("Specifying --uid requires --unshare-user"); + + if (!opt_unshare_user && opt_sandbox_gid != real_gid) + die ("Specifying --gid requires --unshare-user"); + + if (!opt_unshare_uts && opt_sandbox_hostname != NULL) + die ("Specifying --hostname requires --unshare-uts"); + + /* We need to read stuff from proc during the pivot_root dance, etc. + Lets keep a fd to it open */ + proc_fd = open ("/proc", O_RDONLY | O_PATH); + if (proc_fd == -1) + die_with_error ("Can't open /proc"); + + /* We need *some* mountpoint where we can mount the root tmpfs. + We first try in /run, and if that fails, try in /tmp. */ + base_path = xasprintf ("/run/user/%d/.bubblewrap", real_uid); + if (mkdir (base_path, 0755) && errno != EEXIST) + { + free (base_path); + base_path = xasprintf ("/tmp/.bubblewrap-%d", real_uid); + if (mkdir (base_path, 0755) && errno != EEXIST) + die_with_error ("Creating root mountpoint failed"); + } + + __debug__ (("creating new namespace\n")); + + if (opt_unshare_pid) + { + event_fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK); + if (event_fd == -1) + die_with_error ("eventfd()"); + } + + /* We block sigchild here so that we can use signalfd in the monitor. */ + block_sigchild (); + + clone_flags = SIGCHLD | CLONE_NEWNS; + if (opt_unshare_user) + clone_flags |= CLONE_NEWUSER; + if (opt_unshare_pid) + clone_flags |= CLONE_NEWPID; + if (opt_unshare_net) + clone_flags |= CLONE_NEWNET; + if (opt_unshare_ipc) + clone_flags |= CLONE_NEWIPC; + if (opt_unshare_uts) + clone_flags |= CLONE_NEWUTS; + if (opt_unshare_cgroup) + { + if (stat ("/proc/self/ns/cgroup", &sbuf)) + { + if (errno == ENOENT) + die ("Cannot create new cgroup namespace because the kernel does not support it"); + else + die_with_error ("stat on /proc/self/ns/cgroup failed"); + } + clone_flags |= CLONE_NEWCGROUP; + } + if (opt_unshare_cgroup_try) + if (!stat ("/proc/self/ns/cgroup", &sbuf)) + clone_flags |= CLONE_NEWCGROUP; + + child_wait_fd = eventfd (0, EFD_CLOEXEC); + if (child_wait_fd == -1) + die_with_error ("eventfd()"); + + pid = raw_clone (clone_flags, NULL); + if (pid == -1) + { + if (opt_unshare_user) + { + if (errno == EINVAL) + die ("Creating new namespace failed, likely because the kernel does not support user namespaces. bwrap must be installed setuid on such systems."); + else if (errno == EPERM && !is_privileged) + die ("No permissions to creating new namespace, likely because the kernel does not allow non-privileged user namespaces. On e.g. debian this can be enabled with 'sysctl kernel.unprivileged_userns_clone=1'."); + } + + die_with_error ("Creating new namespace failed"); + } + + ns_uid = opt_sandbox_uid; + ns_gid = opt_sandbox_gid; + + if (pid != 0) + { + /* Parent, outside sandbox, privileged (initially) */ + + if (is_privileged && opt_unshare_user) + { + /* We're running as euid 0, but the uid we want to map is + * not 0. This means we're not allowed to write this from + * the child user namespace, so we do it from the parent. + * + * Also, we map uid/gid 0 in the namespace (to overflowuid) + * if opt_needs_devpts is true, because otherwise the mount + * of devpts fails due to root not being mapped. + */ + write_uid_gid_map (ns_uid, real_uid, + ns_gid, real_gid, + pid, TRUE, opt_needs_devpts); + } + + /* Initial launched process, wait for exec:ed command to exit */ + + /* We don't need any privileges in the launcher, drop them immediately. */ + drop_privs (); + + /* Optionally bind our lifecycle to that of the parent */ + handle_die_with_parent (); + + /* Let child run now that the uid maps are set up */ + val = 1; + res = write (child_wait_fd, &val, 8); + /* Ignore res, if e.g. the child died and closed child_wait_fd we don't want to error out here */ + close (child_wait_fd); + + if (opt_info_fd != -1) + { + cleanup_free char *output = xasprintf ("{\n \"child-pid\": %i\n}\n", pid); + size_t len = strlen (output); + if (write (opt_info_fd, output, len) != len) + die_with_error ("Write to info_fd"); + close (opt_info_fd); + } + + monitor_child (event_fd, pid); + exit (0); /* Should not be reached, but better safe... */ + } + + /* Child, in sandbox, privileged in the parent or in the user namespace (if --unshare-user). + * + * Note that for user namespaces we run as euid 0 during clone(), so + * the child user namespace is owned by euid 0., This means that the + * regular user namespace parent (with uid != 0) doesn't have any + * capabilities in it, which is nice as we can't exploit those. In + * particular the parent user namespace doesn't have CAP_PTRACE + * which would otherwise allow the parent to hijack of the child + * after this point. + * + * Unfortunately this also means you can't ptrace the final + * sandboxed process from outside the sandbox either. + */ + + if (opt_info_fd != -1) + close (opt_info_fd); + + /* Wait for the parent to init uid/gid maps and drop caps */ + res = read (child_wait_fd, &val, 8); + close (child_wait_fd); + + /* At this point we can completely drop root uid, but retain the + * required permitted caps. This allow us to do full setup as + * the user uid, which makes e.g. fuse access work. + */ + switch_to_user_with_privs (); + + if (opt_unshare_net) + loopback_setup (); /* Will exit if unsuccessful */ + + ns_uid = opt_sandbox_uid; + ns_gid = opt_sandbox_gid; + if (!is_privileged && opt_unshare_user) + { + /* In the unprivileged case we have to write the uid/gid maps in + * the child, because we have no caps in the parent */ + + if (opt_needs_devpts) + { + /* This is a bit hacky, but we need to first map the real uid/gid to + 0, otherwise we can't mount the devpts filesystem because root is + not mapped. Later we will create another child user namespace and + map back to the real uid */ + ns_uid = 0; + ns_gid = 0; + } + + write_uid_gid_map (ns_uid, real_uid, + ns_gid, real_gid, + -1, TRUE, FALSE); + } + + old_umask = umask (0); + + /* Need to do this before the chroot, but after we're the real uid */ + resolve_symlinks_in_ops (); + + /* Mark everything as slave, so that we still + * receive mounts from the real root, but don't + * propagate mounts to the real root. */ + if (mount (NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) + die_with_error ("Failed to make / slave"); + + /* Create a tmpfs which we will use as / in the namespace */ + if (mount ("", base_path, "tmpfs", MS_NODEV | MS_NOSUID, NULL) != 0) + die_with_error ("Failed to mount tmpfs"); + + old_cwd = get_current_dir_name (); + + /* Chdir to the new root tmpfs mount. This will be the CWD during + the entire setup. Access old or new root via "oldroot" and "newroot". */ + if (chdir (base_path) != 0) + die_with_error ("chdir base_path"); + + /* We create a subdir "$base_path/newroot" for the new root, that + * way we can pivot_root to base_path, and put the old root at + * "$base_path/oldroot". This avoids problems accessing the oldroot + * dir if the user requested to bind mount something over / */ + + if (mkdir ("newroot", 0755)) + die_with_error ("Creating newroot failed"); + + if (mkdir ("oldroot", 0755)) + die_with_error ("Creating oldroot failed"); + + if (pivot_root (base_path, "oldroot")) + die_with_error ("pivot_root"); + + if (chdir ("/") != 0) + die_with_error ("chdir / (base path)"); + + if (is_privileged) + { + pid_t child; + int privsep_sockets[2]; + + if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, privsep_sockets) != 0) + die_with_error ("Can't create privsep socket"); + + child = fork (); + if (child == -1) + die_with_error ("Can't fork unprivileged helper"); + + if (child == 0) + { + /* Unprivileged setup process */ + drop_privs (); + close (privsep_sockets[0]); + setup_newroot (opt_unshare_pid, privsep_sockets[1]); + exit (0); + } + else + { + int status; + uint32_t buffer[2048]; /* 8k, but is int32 to guarantee nice alignment */ + uint32_t op, flags; + const char *arg1, *arg2; + cleanup_fd int unpriv_socket = -1; + + unpriv_socket = privsep_sockets[0]; + close (privsep_sockets[1]); + + do + { + op = read_priv_sec_op (unpriv_socket, buffer, sizeof (buffer), + &flags, &arg1, &arg2); + privileged_op (-1, op, flags, arg1, arg2); + if (write (unpriv_socket, buffer, 1) != 1) + die ("Can't write to op_socket"); + } + while (op != PRIV_SEP_OP_DONE); + + waitpid (child, &status, 0); + /* Continue post setup */ + } + } + else + { + setup_newroot (opt_unshare_pid, -1); + } + + /* The old root better be rprivate or we will send unmount events to the parent namespace */ + if (mount ("oldroot", "oldroot", NULL, MS_REC | MS_PRIVATE, NULL) != 0) + die_with_error ("Failed to make old root rprivate"); + + if (umount2 ("oldroot", MNT_DETACH)) + die_with_error ("unmount old root"); + + if (opt_unshare_user && + (ns_uid != opt_sandbox_uid || ns_gid != opt_sandbox_gid)) + { + /* Now that devpts is mounted and we've no need for mount + permissions we can create a new userspace and map our uid + 1:1 */ + + if (unshare (CLONE_NEWUSER)) + die_with_error ("unshare user ns"); + + write_uid_gid_map (opt_sandbox_uid, ns_uid, + opt_sandbox_gid, ns_gid, + -1, FALSE, FALSE); + } + + /* Now make /newroot the real root */ + if (chdir ("/newroot") != 0) + die_with_error ("chdir newroot"); + if (chroot ("/newroot") != 0) + die_with_error ("chroot /newroot"); + if (chdir ("/") != 0) + die_with_error ("chdir /"); + + /* All privileged ops are done now, so drop it */ + drop_privs (); + + if (opt_block_fd != -1) + { + char b[1]; + read (opt_block_fd, b, 1); + close (opt_block_fd); + } + + if (opt_seccomp_fd != -1) + { + seccomp_data = load_file_data (opt_seccomp_fd, &seccomp_len); + if (seccomp_data == NULL) + die_with_error ("Can't read seccomp data"); + + if (seccomp_len % 8 != 0) + die ("Invalid seccomp data, must be multiple of 8"); + + seccomp_prog.len = seccomp_len / 8; + seccomp_prog.filter = (struct sock_filter *) seccomp_data; + + close (opt_seccomp_fd); + } + + umask (old_umask); + + new_cwd = "/"; + if (opt_chdir_path) + { + if (chdir (opt_chdir_path)) + die_with_error ("Can't chdir to %s", opt_chdir_path); + new_cwd = opt_chdir_path; + } + else if (chdir (old_cwd) == 0) + { + /* If the old cwd is mapped in the sandbox, go there */ + new_cwd = old_cwd; + } + else + { + /* If the old cwd is not mapped, go to home */ + const char *home = getenv ("HOME"); + if (home != NULL && + chdir (home) == 0) + new_cwd = home; + } + xsetenv ("PWD", new_cwd, 1); + free (old_cwd); + + if (opt_new_session && + setsid () == (pid_t) -1) + die_with_error ("setsid"); + + if (label_exec (opt_exec_label) == -1) + die_with_error ("label_exec %s", argv[0]); + + __debug__ (("forking for child\n")); + + if (opt_unshare_pid || lock_files != NULL || opt_sync_fd != -1) + { + /* We have to have a pid 1 in the pid namespace, because + * otherwise we'll get a bunch of zombies as nothing reaps + * them. Alternatively if we're using sync_fd or lock_files we + * need some process to own these. + */ + + pid = fork (); + if (pid == -1) + die_with_error ("Can't fork for pid 1"); + + if (pid != 0) + { + /* Close fds in pid 1, except stdio and optionally event_fd + (for syncing pid 2 lifetime with monitor_child) and + opt_sync_fd (for syncing sandbox lifetime with outside + process). + Any other fds will been passed on to the child though. */ + { + int dont_close[3]; + int j = 0; + if (event_fd != -1) + dont_close[j++] = event_fd; + if (opt_sync_fd != -1) + dont_close[j++] = opt_sync_fd; + dont_close[j++] = -1; + fdwalk (proc_fd, close_extra_fds, dont_close); + } + + return do_init (event_fd, pid, seccomp_data != NULL ? &seccomp_prog : NULL); + } + } + + __debug__ (("launch executable %s\n", argv[0])); + + if (proc_fd != -1) + close (proc_fd); + + if (opt_sync_fd != -1) + close (opt_sync_fd); + + /* We want sigchild in the child */ + unblock_sigchild (); + + /* Optionally bind our lifecycle */ + handle_die_with_parent (); + + /* Should be the last thing before execve() so that filters don't + * need to handle anything above */ + if (seccomp_data != NULL && + prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &seccomp_prog) != 0) + die_with_error ("prctl(PR_SET_SECCOMP)"); + + if (execvp (argv[0], argv) == -1) + die_with_error ("execvp %s", argv[0]); + + return 0; +} diff -Nuar flatpak-1.0.0.orig/bubblewrap/bubblewrap.jpg flatpak-1.0.0/bubblewrap/bubblewrap.jpg --- flatpak-1.0.0.orig/bubblewrap/bubblewrap.jpg 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/bubblewrap.jpg 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,143 @@ +JFIFHHCC  + c6M5G?ory-=:I.l֯v+ܐjJN턐1%=U ɮP|5q6`: y/M=.q$ l_ӛg7} < +DoMs_Vsf5Djs2`w5^.vb'dIȯHmX3!e7a%QY: x)3rah_ױRZ*P)E ˦ۦ7.K6q'qoҋj9㱞˹N9SjRrUT/вa:Bie{.ޥ+[5DE<<ϋs0ye}F˥a|f,WA[HIžצu]RNd&)4+}i3W7W"Yf?7? +6h=Jyf;iBѩV9g٭bV`ѐ_l[36 `z,R5 `ga6D/aD2dg GRYWG1ák[rC:K"%[B~g|dMlIa tp!GnuX&!KۘGNh- :jp5R>{mGAvTazRe[xWO0!牮P-d,ww~Qu_vSdcB<T՞gb2vr>ߔoK !A +lF!f%hQd]~ϊOH 𰙐k;Sy[OEIOO>:3,aMTCEhʷ~%/p9qp: +vpi);y$C9!Xݲϲx1ˁVetLM,\04zԺ'y"dp A+ݑܵd/V'as;6>7+gq1VRk>oeTO5u/:vJ . فEԵ 105\88ۤO]7+.mŀʾy;)f G"?sjK<*˻8\I-ZΊ|l8A'1}>Qz\AnIK=ʙS;.T}6k  Ʉ 6!RQ 6H/r7|.V5o(!.[+ӕ[>zM48g&suM6}jpHe3C +5ҧq4ߖxk[ͺnFȮ=y}Q=}9$*jRO1b\7J 7*9ݟ| ت {9r3ѵs[jz]!VG2J! -T:EO?A0^k֭w!׻r\yއ5@'6GCBxϗ]4O!>5n#Ûnr:0D)2l(rit._ b`ԁsm3bƹ^+Y!&L% wE01v]XYw\ Yw,JfdrAm53Z",kNVk:4Y0Hѐ-,]QAvm>ja]dI5\$PdGD?%!"#$k +LXZV{6kRl@g.TrжnJgՍ2.dGt % k-ATA`LO^3LyDP9\orv Eޠ)"?W%ק}YOyu򯣜z:[78S;AwWB'[5')6P&IBTmO4HHg㺈(t1@o73sޫ^ZC;a3T,Г*sK@֭>hor ]{vz5Xz  -I0iC^]VM%4զz#?7 :!Yà8|U,HF1/5:^뛆k˜z֋f???*)][d3D2pؼiW)UJ#%9bs|XJYMquM1G B\gҗ>B_&jd'y~)׎}|īi1FmU95GFVzBO>Q/}NHTXk[bYT|! ԋ+-Q^ =GH? A^Ck5b.Q#8!syKN'tZo<@GOI1k;je;hh:gV0CMAo_] $)._r3#KİS|ڪk${/=?(Kl=U7ڇ>grFO;TW}=d8=hߺXvD1 -oɌ78l>_ <Ǣ /%/.1& g[Qnu{5Ύ˧|db)* 6ؤNP("(U;阫%d@{ +%[; /5&HҏU^M-S5>s,L͙_猉NѤV v5Aig10%α gnaZ]"Y +lPK"Dt*A|t;C0z6zg!^wJ"9濫|Kҧ=u1[3Σh"Z s4_ u -Yv$V#еcwvx`<[ie{.thlݤ_vgQyQUԖM_Ei)2ٺ$WGo +jKA0B `뚁>"AЍ +ޜ[ z}~;c{MozW2Df2AtǮO^ˇF~uiX,[׺J8Gb}AOIA፜.jInQk70ׯOT=l*\Y7ybkE]yo!, h /]LPzaX,Z}=kNkV8FEKMbvA'SQ70G¥3*{'G/ζd5vjOUfJQ26Dk$DXӆ+cyp;ziLd5E9,%ʠ9e6q,}}V*jXGO; Pxmtݎ9{ZmNcab{ $MPR(砈PĖr. si>(E")Gڣ(FQ̹j&0Go{ig [;Fߑ5<.n'͞[BgXz71>)g6xA\t֙2&&t)d/@|Of +yt%e+a WasYE}>Ǘ&b^R^3$z۶_m3g^fc~{3S31C2$#g2ǰxs|=l_^5r(wQKUXTK{H}`m\7%M3v{eNSW=C=q).~XU_Q_h1R_%VaS#}q[8 +jz5_~YtVl6w=s~wY+L~qt$& XXWϛO.^oV%""5%wfi,Mpv 2k4vg\Bt!+r\,+h1=%p:ͧFɮ+ٱmB +afO-s3d^:-krTuraFjk8dfl8 aL-}V%y/XfHo@ReO!?a*T{X.Ht+5h+}F(q]Gp^I#tXb cĒ2[+QBc)ZbJڔ.*qj\WfŦPKbr9+/;iXjGK8k4e2u?S zZ97Ɵ +|'6gF "2#3BC!1QRSabr$Aqs4TDcdt?V$X|bX9coKH++*ن[mITǍ£bUJ­v̘QjI$b=Zݔib-QˑZkTJs&獘fʬ$v4mJG2bHՒ,6'l2C%Ċ3 %#qm(ؑјe2-$y bEmCVbtq,r~5V5bLr!q#Y|] QcЭ ,UFcN}aY%5#L9rFekͷ YV&shIb8oHfUHdܱVR$mdp!DklF3Ut꫉7$j#1mb_߰еe +3*I{zgF-XqRMdK4m'Hj2\HٷHc$[Q|7ȷLZb9$cɍVjjTwL~=_ѫr %4nRሲ3q$WiIj{r6\F$լ4 aoXd7 ^B͸i U~ēPjLZ2?n2"U]xC2XcUⱛ2I[<T'YD:KGiY5SoiMDIiѲjN%ef\bH5MV nE˗e-Xok,GVG +.GU/L7en5V?LXxf+yXK=Y`M$qfۖG51ñ6(VOXFr-V#YlaWT5U-ZYXFȪªka~/{sVNUj"7/!ffZ4ؖ)kb{;%^?xKb5UYVŕxcf?/5,,a#[+an_q[8CbWO`͈!-cv7%t :q/G^x7oObF{GOO/AӜcrt|ggGG +"#23B!ACQRq$1DSabr4Tcdst?/<nwϯm (XLiJrL1ʆ F;RHuĻ jJbb)idpm>KqE.!ca2v&$u낻DQZfp7Ze>!j2NzelpLh V*ˉjs*%-[Ub5)j*VYPRŒV1%+"S׉J e/ s#B(78u ,=ue?$heQZA"".!hB,x-^ #43 K.\=}*U+& %rk .΂$\QcSdYo*ox!(0WibFBg؄Ql 8ШK r{ +SK +iG|Uʨ6v Ie*),odrJ=ݬI!ʬ xV)|aҡVU5ŝJSөlBc~Myu-{5ҕ /ʥ//yXVlؚT͉J]F»ʅ0i^̹P1YbJ4vź]>ᘄbA+em4MY!)hƌk!Yi}f,u>PJ)8+G\?§ "~!b,AWN\K sD]`tV *5;V7)1ԭ$*2"a§WB% \W ]8nl!^wJ]5lA+0PTR۲ +PfNF9c蠰n-+f`a $$u댧S*s G6..A#fQC>9wiLTpRZqtZ+F&Щ$Ä/͕UY{DDqf&ܫQvYc2"d_DH дۈsB,M>l(-r";]hHK[trҕHUONS\_OUW_IKZ_֠ ?",!k[K M|7EΉ JhXtnNPۧTU8P)8f.2إŬۚ"+_ieUa]MRAUSw^aG̬&e. )gYJ}a]nnviUN7ʔt#wc +ىu0L&QLK  l,/3x,%A%ȢO(r l$fȚqXv\>k:~z~|]fJW"m9BPK4q 4prT8[ҿZJ)m7,ŚiGNEUmO^pD01k;Ût,6[;)VKVhnpB֓'w(Œ)gxmWQnn|AUs7l% +/EolդV\MnKpPG{`}[_`{ +6˽$<0Yln +Q-8ˆ'(wn+1bJcb|&XKRJ,!+(+Y0h4KZ0t9B4 SXQU\KM1K,1uPKL˔0ktTR_:jqAUt5Z~?}ҎeJǕ5./z4~XR׎ZكUiQ+KQf;fNߞ#l,hx{-%xoOuK3^R-/a- !d3*u¸d7kk%Q(ULdD]I ^ F:J]Jj +^4Z9Ird, + 2g- ,gFi٦e kLeLʃpxIfNqpqjwSuIXqSڢoL+&c8Az9ꅸܪ:d^X+2; /cNw#(D=7/j]˗f믢3}+!Jv y?IkwГmökfhgVꗿrQkHyP-EŅ)u5[Z) " ,)7!!rͰm)m[./]o]z[K NǺ:\_%Oʂ{ʌUs֢|k*ew*]"e ECX*2UkWGBe֎i7,Z=Ym݄"CD0e{V^˚[0}aIKi>զb]zW&T"S!$ZRV`:USPV$61b̧>"{RaPFR!0Fу- +nf-MS38b0P{OKL/K-? m翰.PG,G ElY&%ݖB"3?)n豷1KRۡeW sB/fAL:vM/dfPMi^494:KGdzN,6c:;<=z4f|׫ 6@S׫L)4OO "#3!2BC1RSbc$Ars4DQaTqdt%5?b7DFLfD|)$ >1( L:WqKKQGSŢR+?suOM`F\Y}ίSi6IW(~uvY]:'ښ!tJlMba+tTT#mbئr;6 +QK^6+88etX+N2&$,̽}&hYe 2zEo}̞NJ-lͥUrh*ǵ*M5l Ǒ`dV?o5JG,' I]J~X57Ia5vw*J0T=t jM'/]f)n c* TdɕM?KasșqS~>yE0]UhH1]},䱪ҒV_Tl ,F[bق_U_ &5(fT0/<+92&*&nmv*cTTF msQ2:-K֨K*yE+JTkΓ~//P)19D|@xG,-štϊ)zi(JuY*#? \(vSy-9p5>Vmakp2MYM %ZbGޢ[5QZ 5ZA/%x|~V3JITUPHNe.%|pi4~u}Ujj%Pޚ@;M^pܫVխ5qXשl> ZDzzGSKLE5;/dp0?Kn(kdѴj lB<\Lö7OTDèUcN rJn^7HzAS2]@<Ұ꒒}cC2bZK}7 21Ҫ'L&k#oTE'(Y1r]D :aݡM:[ٛcW^]!+$3 R6J +ƓZgȥq|,=d嵔XR^/: N袞jUS1T +( 6(CG9|tΧ7 []d_!Z.VfOJM%ӛr+ԇңHYScP>ر3[ndwE+H u>PGWl +҂&.`&7V|P= ́Dt@2o@VA]$#lI7H x<r6ұI0 +ZiೖNw/ WbCR袨U]ߟR&ⵦ ?uOF&|SR@6g39sN@K>P/#)OX2{KHO߫t#U@ s1qx&]DBѲ~kC# Zj>S`^CQR;b5j-@6*w{ֹ X"ήJJt25${nBx1uYZ'aS*j>:vh.*9jRfiMIT ]kLf;IjcU[ŏr0jDe5^U꜕gK^hƻ) +" =&/rcW*7d&XtX]DNj*FMjjN.SP;6:6BWOOvdYV5)JƤvmu}5hʛNMz9MmMPgZ7[rj䢍5uk[bi|XnS6-%"5D=߲ VӸbƵVa:pR58X<B<.O6nrn#L +֊ê`UE"\;+h#!*d%],GUgQ/%?jU-(b58BلyzkS~nxԂDd*rPNX|JU.6vwVHb@m(/Kn4V yղڃ|̰'LN&YEe4rY$O""Z&d/Tc9YJΧ1~NlRHgp-ik>C1ɪq@YBÕh{`*in_Ueo>j.*o|g40j'o{U=QjR3}r=:o:٠tRH42D`bbXs2h14|!@~@!koGcצ]o6KBP3~RaI7/*զGkpeV.UcjeWII״VH$*~k1XT1_TJʪ,*WPќi˗$kG-,p"v6'Hy9]jvQSE)l[ }>$NOOf[lɎLu^vcΤpTm6RUi֮ML^R7T@)X8*͒\kg+Rꙁ؉ǕmV9R!U9*fU+v/gdK'_YijCbqb͗)@RkhBVTemZXm:su}AC*C jdo+')\ܩ0t.CUֿٻSZf7D4\4*q>i y*8'5(,8KlU+8]2l{'yYh;:\̸5YZ>ĿzQJR'1q#gǪQ6񼄘Ӧ8We ӘVE%Fzuj W +Vv4nv S UJD?ڪ++T$DYi th z[YNm2+]$WFttۉHl<_~\_V.Q7?%[`w'̗cѧ)R^(YܫLqe-} f0&wc&RRr3ʭ Q,5U) Tr5;9  BHo |.5c;h\hʿ*JH5Keu"D]?;T zn2J8L˾ߜ>jJU]9MuBJnMBCh6DV$YQN۔2*_R|ΓoWmmjHQW\"N-ғS +I=.rM'IkLشTʥ*:]+.`o*2 j^lʮf;&v=SPoj\U}3nEfOhpT$XDbF|WS%%fUOGN–ïh4?(&7uz\Ś-U-nj 6r8]%Edm|ίr&T  )Jw"?=4)ų$.TJxk HcwhjK~mEYL +f +Ze5MEML +T8MrB`z~\VJH1T\ >O!CJ X^RUx? ~$1p$FOio=(2b|]q<+S4"Mu> H/r,gZSjjGzcJ R`];yK45UD6G8@(i֤ggd jMS3g>01|K\(U*%ePp|'oĸx.9f,Y =U( d>f!/y~.S~⒁xNLd +Jl٪%ezQBTy)OPچsZĜ;*Rv0*2]m:r,Y9jjĠ3\#J OBg- f^ }%KhBi*-Wg3<űʞsp]iU,Օz[8N6^-WR;cTUJO,ٖ-BTKm#V7u*.N*n ZVr[;.Vw+TUk0p%~*81!|xW\%$k6LP1UOfZNY]g(nX̺].^>tCN0J%++;9>vϥw)XTtԽLD 1|^oï#ll܅QPt̫r')]I. cs51&SW|a=ͤTzDZ/8p94F6F"DL\9~RʊrrpɼrËKn E(>zS'G ;hm=Q62Z7i;Bہj~%-324`$Sg>."d25o_Tb*XU&ɻد:@.MY.=D#mÃ2Zi<Ó'~],l'tq wG fſ \E=΢#6f{͎ G~KzY9\n6gUt+ehdM`Y?pi{oiiSXMtec*[]E -;ȩ;|6ꎂ0(Vuvg9k+*iM( +mmZYz^ 6vhd}?g2;Q]O +w; vxGՃNYki$VAEV*H4 + ⷃ%u"-a~DTADENJ̻@ +; f~Q9"N/߿X+d WqR0~R*w +e 5 :Q 'E,$% @_*,_k?|>&cM27> +>M~ra5")Ak};8S]7A0[b-2e釧R)U-CVTmҕ`5hmV-Kg+jSCcѤ{-eQKlQ"<_?5JiY4 ¥]O⪨kT:􈏙btWXQ) ͒>MV)9ǕdPTʠ0S|5jc*P 16\ߟh{6V!凕fO3ԅ;%:Y/|z}S$sq_ǽ#PuwXljNkgfT%SEhNu_LVU PS. UY?o͞U˦eEΪeS{6%寕Ljh:E\4ƞGOKe.FȡB1?6_F)nDz1Cfqܣ-ARg()A IJOVQx`zW[iU-L0K#< V|Z2{M83.V~ncw&?K{3;OuKΘ+JFD̄s0 t==ԜTF콝Pڦo5o0luPyi<<8mbJޭ_Juu୕psWFbf45:]Xc)TUKO;6(sHPq}l Q@:٪Tx(2UUU#gHB R!­g]^<%f"xn)xbƷKRӂoL1>!cv + س \jldJińaԴXkWR"T^f] +I-Z۞ag3BVŜAH4/I92 R/P?/O{&bT 7G;mH&چj|xois2sl;IՃjZtNT>UijX8Dps XjW)˘USFZ >}si/eZ$$n#7?Ӝm l.g/q\3r#DX= Sa}Vy 2‹gӻ҄j(^:tF$g/#![{k+-pR23%MW&"0"Ux<i9z*jl,1jc9JWEMȬUkPLVgI'mlnШˋ*mlUӶ^T;S[=e>ApM&Z!Ƿ>;EB#Q/Ē'_Qmg%eAH3qF2zyC+R7lPb>e?zcIBfNѓUcЄӆ!+o9fЄBqŰY>=+4C-\( odUɿ^kJ,O.&h"'*ؑ~]mW)k*5" +J⬢ALFKgUSrrQRKKOKybl8"PxҿUti*'iRT$*d%P`v~]OjDT^KLml#is!'N&D10Ch [{{(w[k+ad[c/~./ҙ o]iE)ݫtD{g~(QiG|: BrLb.>;nytח5ZpSlB]íD.jT{Fkbl+Ni9$'\} Cj*YPR4g櫰PTMCL?ƭGEEe%9)խRH*ʹDy> +=wWj6{J[*sj Q!_ljv,GE^ë JIH@ddv:QokSA[ uH3LZ_cUlԃ( :DJؼv_gL_+.-ޭPfb[pd]pmqrLDkNIYu&@IδŒ`.+@,|Rj-agCk # 1,Y1eu8.;:HE9(!!!+j |Y~uKGNy_ש]CCn͎$cm!ԍhvk'̚dߪhNΧ\dM޶{\z +t9NjƭƩ 嚯J{,J33ĤO'g` Y4f-5rE;xSr}c>?#3n=!-Uq n\ď_1i7H -bR;Zs}^iUdřq6˙gro|FHvάvy$ 62#9uAENީQ n5,ScJf#YVjڝM@3o~RUJ2箍$am>U5 YmJ"4^=+wmjcyNt>dF><]Br-[k[tꦤJIP4CUccviA-blJdT4nj? \e=5+~fcJS%`?0z&a=>eG2-VFt +Z1*iI+["W*5Hfl߳ѭT軠tyI3bkWˠ> +hK^.WgKZkE7A}~SyzSf-Q$xDgZeP2[CmF;6vVШAUkzfwӕ:t҆֙h4)^/$iB`= $SH[ >+ٔV@\B7v!</詏/qH#p?NzFfxe@>[}KOKo~jm^]թ`>" ٤QSS:e,E CO&l[r-3ru7_ i3tBNxϫ[XvsN,MXa+WC=F(aՐ$uTgkU!uAsv-lݨM9TRH`͌żxގ%bVivXT"3U~3`|=RdrSN\EAȴw$3Euy';^@j, T`^d"^:Kn?I eH6RS>05\NmAs^@g U;(X_}m%^OWB<,[0\/> E6+gLlqsmg+5Jɹd~ߧ=zeReև,g9Oi6WNu?@MX$6E{KBa[J|nGRTHEVCE^W+G:"CVBZ![/hW_] Rs._sUl7I\k!FvՓjI.2Dcĩޣ@hXǾؙ<}>_Pphk^@FЫySR ,V@:@ '7riY%IӐs0TZ^mdŤ_žfL22l5jx5,GMϤt6E*Z62WM\n캴2'-ig;9xV'rXK?F;h,cj0$R\gT.c9Y@ʕڵ +TXe>%z>Pjl[g3G_Ze!Dq!+wg#LUGhJJ\:wuSM}.3N{9 [UNp̭ :mij$DbޫYgK[N!@IkǎjoU]GlBj=[LQՠwk훱۵iE_P;8hW,:J~&) 諗V{FP%*5jhAh%gS"֮o7+S06?lŷS6WQC]N`+ۃC?Y(6ص~+_%rEnͩ؛0nhDJ@V,<̐lJqZAj322\ŵYO ID͔XU16aR0V~=5 7wTAh-@G6%(:,K:@eeUަ/]1#(h 4V8# [w[siQ2h(1+ jNW:r8NJ尪- Ox>W[9<6Ɣ5*!1Ey>)=QQ(؉g;C |aW$ +ԲOǪg_TDwnC,#0lEhN\W)ehٔ p*@s9%jkm`!!HM-`qjg?ʳ.eYJBj+"U,X|-muZ_OXtnTjFn5|UiqT2观x磐dK(6xsZOn `7 qP=Aӵ=MK1 $EU 2ϋgK4Pw8xhrYL 2--X>41p? 4 +Bȝ-in 9J" 1B\(V3;:( %2)n`EP}Ў\nj˼0"7xDκ﷾.Fv}RV>g {e/=*]e[+e׭P4ʬ@1 gh^]\fp4wX rc^_fݢXMRvP"oUW&i?teN8e|]Rꎨ +:B-`Q?~g-SWm:q}]3qSuU_EF_j+eN6IJs0Oʼn##(TOS*(u@P;j9$_iƳmECRDlQ^iq3. +]к6Ų#&%^) 5SVB˄;| }&J&.SoXS3X0w> 0' s,hs=^-Ȏp"wpˍVgcn/2MVfIƜkp(*q+!1_K՗WTUXhM؏:m^EsloFU=] +StPdjŇ\KboJHOݸ he #S;hXa!Y۵3k>%ǻ H.i@LT58 ݿ> IEuշOtF }u5OgLf ;.%^xo+-~JkE%_@%h[yP5k魝]2Аe+qpsJíMWEf`ǐZ@Fߨ +S& JJoBީgiU5{bmIZs/ S&ux=]B"6ԅxT!&);k/eϪ+)NکtUe(Q@A\O;J}EkuFMh2%="PN?NjHR8|v.8̚|J<>XUhc`ýa|Z딁_mB<Dy꺞UlEN$NxΠ_5NSR :*TѪ ~LcMIYRQڐ rs!jV>ϏRrR2F ?5ҊyaFs?~FX Dǵݡ'o۾D%,kR6:wH2FfFw-M2dgͦ1POvC[_;c6[٧  Vx?%;~Lխ֕twŅ/!&t׍JB*Z^3zMj3X"&E![IZPv?ɏJ 6740hZ9 fqHɭFERŴq*MEՑ!"pҨǃ>fsۗWlT@*jy8Ôd}]T*Z,M=w0!gupr~:a)J;S1TT) tI?RmU 6YWAfFr4SR/` + *D'Ig쪓TZ'Ø88 ]ffG<uRD=3wC͡n7lGDqwD ZQE1Sb[CA'V$~(':l#Kw6ҙgpcI|(U'"#_jN^G @cd\gC".AfTMVnm$wMIe" x.W:ՊN` W=WΧňi %y o(peaGψPX~52hkE5T5 3{Dj7 +RvZ^_UkTJJQT-Hy4KeS#9V#bl儅*-p$  e&6in6;M6C7s _itM575W5p8,5i{> 211Son |ݠN f'C)9(&L[6m]U`i&,OE.)[bwBP31ltƃ#IMAxآn]-˶uZ )N('wGywoikKT3+/hjKfn1DcZMN:5frdVmY@LY*\fp|9?LӐw zfOXr |%m6x.t|O '; tϷ\th∈Z${mZ\$~_ +fd?- ̙wnrb&B7LuaL{5~ :wG^9ݿۡ3d2!ހΎ*SOrc,k’EE*_oL2}M>h$u;H%|fo;F5ZY`fђ-Zx:aV'wH_hG {:xf13x Cxd{Ťӂg;GZ̚d`N7n˦\;}N7GtVS=zݺCE],w=0ǻݭ7wcxw|wwnՍDnϟX. éaS埻Co;vۭxwV4LJjХn7ŷ !-*wL`f"8G5[t^TӁ;E132?G~6Gtjrb]w;Pݻ G~󭟴"K˜[^ YMaF-;bqf-oQ0P}ŐO߭ſX\,|^lF-D^ !6ZQ?x<#CΤv]$O߿O' !1Aa0qQ?!5yB> +F&tZ 8[x^MCj6HC/%Xqe߀3KuJ(<([Вa92R`qG(L4 :a_` }ݍH_o@8zGq #4AG Bᾇpwv,:pPO.q-$B #4 -:H | C,$&@'Ȅ᱀ON++B-#9CEi148G. +OG@(1 ·ݎCȀBD+^$g -eDbQnqfҔ#Fj@JfpgÏHIMI*NI,TI8~(@3\̔ !pIhGl x -Rϴ1;* RpwʉP?aiP'Tpzڎ{GV$Zkdӽh![ 6DxHfhH wZkT-VN* +m sBfQƠD-|BʜɍPL(zZ"i {qGF`<߾îs<$&ii(DXh">ī-4q,ֱdZIgt=l81L/C#` ^.PڣL2Fg I*ұ7b+6I$5ze\L{(3 ޣ'Kk=8qf!bs;@bGicWMv>(p7xɝ#4`\.hG2J)?#K+gEQm$L&RKp]n v$Cpa04g0@%W!0sPc;r;JU$O$Pԇ g ]2ˀze0"IOp"422pdaݫ!+X9wYcAM^ZiO&}m$-ْG'O 'L7 45`&1%\P3^Ӈcb[I&,J xKx9.jE3dmaRn_#9X >kH‡yݛKVG C05B3!!+ %2M D!B'1q)cqrAO[H9d0: j<6^H3Y'<DxeեCAzTIx* +FJ` qI-0>3;X F\S@RN@ᔌ8b&%szdI&.Ŝ 2 +D2ă0f Wz]K9Ӭ1qF@+LDB}H+ r h"IDUNٴa\@3e 帍Lp2-[!7P?I5i^jhpM%AjP U*\)}ؠ(G!މѥa +^ט + HSLO4G)@8i䕄;EvrJT:ؐga{ G"ExTÞ)˔(ab@Yn鴁ISA0:A$'tU +eE(FŽ$`Xne : H!d,fQBPDBã%UB&=F9{Rш{9D#0KK +8(1TsH"PF\ȈHK1qRKDet|= J1mp!ep nÀ2^Fu/J0&'pOF1}!@}Bn4_bT$1ƢqKF_J `3dk1 <9`@E6E 8} w@fahb>JTX\0ʓY q+1cQ ƋlXvZCܜPOJ۩S0 &ye*ڗ}+X8 #ziIH(dޠüoR%*LzreP1zy  ,qB :WrN49(=N#k8C0jM0 1Jx|c I:YԤwHHUI2ZUت3\For c .Dxe)h5ZRFM+`]Aw =e(5psBkXy%P1 qUdf71dG%n-cm#lך" QG ƽBHG~nqYaV!Mc,mS1n&G1%0C3 F:@6`*ݎnA>f⦿V2<^8*:]0P)wwER"% Ukmkt3v# 7δnI ^ tϑ{eov=;?+1kDq0Gڃٺ>]6kWwltoɗBK.%M\ C݃72~S}gӴ5<ӞG]}n  jwL^b65""wI"$hH7KZ㭨:s 5mNl gjo7Fṭv'& +DU2%%$9/ Ƀ{N3G!#%ҷ֏F4fuqB^! +MS0ϓ &U ȥ@{N<cՑ&!1AQaq?ښi 2/j |O**2*uC^r\wynن}F/ 퉙/O5& ](\0wS؏7d)nm7>؇ { bBk#cʸ<|7G xoSYwфMZ7+̩ťQArnIJ=lN{^<}al9)筋Ba:c~V:5$Lo\Ԗ\3QSH(wEF9q=yNmMUDގ]V`U2ܨrGGT6旀y8$>V\ۤÌJ#iNEo&jGȘpj4?d"?uz.i0rx"ǃ6_MaewdL192 >)Mc?FB_6+uxF09=HopgV4 e7vێŠsDc">Pڣ<_;t`;S33~٭cEXnCm'0~,ډ 룷FGC5>[s{4;'.K#|NQ5_TU$^{t7L?-3H'᥿!G IZe]NF2 +RhmsCFff)o? 踂co>}1ɐлtIDXΗ`s*ٚQ){kω{Fyad =V64/cxAi-v= +=r"""dAn`3s`͇n{\*Gd&[,vYI$v+30pԁ7*w~JU:"sxAvKn9WЉSzN;SMoû˖G!K Nsvv)aD+ɗE(vV?{V 'ƌ>́ tкKtne ~#&VdA@aբA{}pnc%\$z04 h_xH0$yÃ`a/ΜЍˆ.{ }~d6(5X7(08L5 w~1ܹLPּ I!қyg* {F5R 巫6-g㧼cþşDK=؉F^0> ʿ_:JXCT'0W ~V!n*}x͊:kdч'zF?r"ٍъ<V2/{0nVZO xnPWf sN4s"n;t]4բgUDWB1d|{ +~x@$Q4 3g.c:oaAc _"Ӱc:M7߲fp^O*Sː-B\8W+_&:Y1B~H\%4apjFyVKrN.' נrcM%8оZKj&yʈ5uUV"oja䬖Lv)zD5՘UrZ*+'+Lo &4">rAŷdiȔӶOVd }mep71% +Kٺ(]HFdBxQ%JEՏ$?lOI`{1ndJ&< ZT~I濍&2uFh;p"T?`_tl/>>j*I ++J7y]y]RWE~@:[YAAtG؞R@jrAͽ_g7JHJjDڶ6z6,S*ato*0Y z0ٮag8c$>>MR6]ca۰8vTLCNl'v+D9 +_BWln50?p (xcw9+x>F}0 j) 9Dj}}01vQaUW4?+&,wajqnLU\3yV)#j:DB߇}880Vuu@2 챧 y%{luQ7j&xE$ Lep_6'> 6hx-_{1O+cbMeڗ dȺռ_Q3혭k(S*tt|+\@BeK)`fƙP!ТAjo8:{  ݥA0f6 hɋvÛMT:=~jc3`mݖxhp?SLb+"!h`D#S~ qIY/(=2Og靶Z:~Ϻgd8xi;YӎX7+=Qd RЛMq^:>92XF(@LXOq`}k=jAH߻1߻/Jwq=-5.@f:/XL$LAabLh2 *K&gǠvBW5 /4kU7fػx\aݺ1࿮NF"=I(ƜިӅ+i _<.C35~dLdz~{Y(BᏢ#Vؤ9'|~e ^.j>ݲLFFZR{+l-BJ38gi:q?{k-l*ۻ,|\L8^E{޸`ŧj'cW#n>1rM5yioju7SSk/ < o7y*d}2fo˽.E +s> +z. ^d+?@ɠxؙα&qƙHIӕo"bOkvW36;n&GdžkK2 oWaD.eϯSݐXa΁uZ)&"i[#L E"fs0.CΛ6HR[ DǼyuv]B294Avٟϯs5Į!FD|KmDdt3Sء>UX5-h{>VÙ?:n2z B1W\3>= 1T^͏X2e[Xiq=tFߢ1PB4O8J0SƕUG_,̅B͈AAbJ R?_ pf%"Ӱ[MN쁲f 2OK=3H&!1AQaq?x:(T-%R87@ctD@49)PIP28E0ȁf  +IHEov|zo#D%tBf@$I8G2_@:(}ܤ0xd~G~ҁA%irW=lF|Ysa3_3D(yP.$#BEhnNa+S9/ܹ+7TY49Q)vMAyXEec"=U-d(!ם4Y'rsC% +>T=P.僫w3טƝI#8bn*z{_tULa+G8Bȝ1*Olzv0]>cN&f:"g T@X@UPԔAdRAD r05Е()]bH8S!U U&6<Swᣤ%*K>3y(՟ZBR08S%p$j^iBUc~['JPԱ"JP  ҳ\1lNYA$(p@\AV n, ylKۀ<ȦNDd\!fxזOS;u7ۍ3.[Q[Ծ0% +k7!73jj+_oT Ѐ*k$ HU&Ix@%I*Nb?ȒP^Jr8x2_kڑ_th-ݡC +8w/j=cJ ]xq6r]^*dPpS2ZJjċ}2[JFoYcšPD 9B_K~ǓP=N~ϊ[X#@*X ",Ą8K%d&W r鵳&6I wo+ܺMRt؊B::d t+aTx62Ki"\xir8#|pʾ$T 0dÖ2ѠrZ]0t+Fg"3SG{O&\}CWo ֺ \ VBH +R`%0 @Ht +Aq0P (ST +dr(G wH2R}-E{vX=)STe!8?(}U9.cI2Jm,XI>V)[%I%O\ _Y+^ѩp.k; |JA%_X,(یÂQNOK8WaY/Ŏ4yL9/WEwx{J \ء$h}z+4a,ZIIh쬼m&3 Eէԍ@*zK 4K/wOsN+p;3ƅFd~x4WUB )d}p4~D?{=JiSZ`r- ()$14A!Q@՗>'8<`6i_TUWRN4Q ޣj,H`f]Lӊ"ģ?8䴗gI9$I$.ï^/a#$[bKvM!k8~+[k}`zvp{OIQ})FϿ~-)a:M9xkgqH]7Y'T{Ȣ9̤e7Bҩxq!(Iyc)LB ,fiRxp!SKvU)N\}c-a_ +dvqro1V}F*M+{y`ht) Ǻ#؞$%ZG{F@F3N~vvh0*TA@]hpyX0+3b<ˤH奚&hVJ[ǫN3'ϊZW}6w$ +nT,J+^ c;lhEնOb~R:\gI_j +c9Q9]) "AGz#@BJP-_vpr7Gpvf!v/y3Y:yثG{rp9bt^Hly`/2-ˡgf\ ʅiӸG*ۃV'y}cYSB +/b(j @ .omfz}DVw (z[6Kf(5N.,9/a !y,/H-| jL㠺(2]0% r;Õ=0ZjۗqI?$uWctXJT'Sjʂ<ٖT;+Z*=="CͶeڝ$_B*~tf- +B @r9@ccGP?1_Nm*‰jj N7='|r\`'5/ciC|{FHz=POJ:%Z G ,f8;'쑱?F}Ӻm2S;gș>^FaRS02نȆ5~jZ4qz= +6-5 9G"cv|£گґPZnN<hdl;G;s!Lϋf;џwE۽F(oHښkGU +v:VW9uxUXRԭAGc5tY4]עC)ya }e$THK񲈼=#;c O:\-%Hc`)Ry8\gYo)/JQ1}4nnRx*I5]BrQGqjy/ăWt:-z[""OZrQItQ;a:cixYeMѠp4ZTM_.?Qhg N"b,C SQ=5ZNT%(FPssӒY%O;ӧ22m1(SN/&3t^H'k 3j=%H-*b4$h{P045]+@ +eZ` Ep|Ű>B3OV*R}4 ӧv܋1) N2`Lg Ux9ȏ&!1AQaq?`̞44/OܼW9$ rj+ +=I7Jus h 8D^a,)`@RF!PB ]B8QB+2C=.AP1 I#>҂XK>82Q"E,. ]ŧg/9A"Oa, JRIJHq}rL8FġWGl3qMmgƪu!aRe Pώ*,'oP`_ HP2!Y 0E]V%D2T)W8F* !LFy g:A g- jpX FD0U Ƒ"Jr +ZR7!RĪA@$Y +ӝܚ2 X *`zKAXeii`Ӂr5?|=xmjiDcJRu/"/.A=-sօAu%lx!*!+ p o|Q!dSi$`D.Ă  `](j +E\a @VCSК> A:hNPP&'89A-qT3DF8";6|@ t2D24$M5bK/2rTtBA)CjTdI6H$Pa($c @: !0AdSB+!,D8آ/l#BYgU +F it\K@* $D  3HhhIjr@7@L؞@Ɖ ː_Ab *B{)cMЛo!our`bǁڠ :Oa1myX']*}CmV_ߚ:1GTlHńjIc #fQEXP68y3X bkNa;6Q 3ŭGZXDЮ4 Xv%[_~Ri'r :w(T1XDېIhJ`" x#څQ(vROb%rҤ_~hrD*5=u(@/EK QNC*F V:P9ł8@~"OU@`wX :X/ Pi"ɮ"EL8B["LQWM0Y* R* S6 +lA}KR@^wAn+* \ih,PKZآl+o C($'h]z,+{d)RIO-B\w"M4.ZDhoy}x^IRgk(wi%\U䱤 .d$ !X +5C^R@ӂzY4)l'oxA`J,QRRoj>E+cha5"n& +a}XVJW(njE M:eJxp\PD=c%tR~uEI@oJRqALDx@+O1&J1?POX$KC:0 + JZpϠPQ@Yrh`;AG+2~ 4pPCg6j3:M@ LdK.Ԧ`/f6?# X]1=$y蛥X5i(;hLTZ\p&ȰS[vtI٭BZn6A78J +8_s"dN*,A +. WAVF%Hc#bP$RaAJ^ IP)XNX? 3,80hI;UћZ&je#_*t؛ ),S^@&ɁyHw0b=XBB9+C'EdÞ!X`{^YI'-ۉD|w;0&xlQlBsڈ$ {тAS#GLL3)m`DzdHIF28+M6b?ܸɖ`Q+pJnGb@_P +?ܧ%0QH zNjKIY'kYjN@,H5zQ1Sռ'/#!1UO/1~8I֨}M rND?@gR/Urj`!N7#( бBBL@0eCB5i؛$AoMa/*0F:JF|}ي^֤5UAEvf` +`Nsid[OX).MGv\w,,@i9L Q0ePbAdZD NJj@faul ]ʴF\j#OP<>ɯ= ]b$6"M(кjm(YEC0Yf b&TH3C)H3AbAUV` +;)_h*,6NeFt]N =T(ւ3878 DPJL 4I+ #@q9Be$;{ $:ؙ"$/D8ssqIz^ ׌V(`phQg΄dvjbUIZ!V B`#.w!㾠ưaM@48eBVe +I ϋTmAaH~'3- ZLGyXvCԠdpqYkH_b!8(lpAKj>h%@ +@L%r& +iq}.f9 cjy @gIp6"X& +zH5% - +XX(pXan+) aJB JPs0`XkA Z + JIv&KViZܦјBHNp?Rp: ߵNubiCJACP )Je`X;/eI$J +" +Ry=+XFlf^ yޤ۟ +E#X"oIr APCo +%! !V=Ad +ZXRRe5L:u- wg'/R2 Vp|DCL&(IFP'x +){2 g]}ZhT Exewjn^Q;Bb oAZ!"2I 3y"Ű8thK <נ6;W䄠%$hOE̠\ sqhhd?xhe$|1MQFۢC=7X X*I"CA Cu&i@NLEsқHRAlTH0/ULN]J Pb.$\og`!b=ښ +`- 1Ј!sP]BY kA5-v!ÐlĴx*:$ꑴ"KX +s]Hχ4)A2 n\ʨ +0^zBS^xM;MG,{Ѩ vX#fXԮO| Odc]TQۇ/TXiADS̀=<±!ˋ~]pCNB$Uc-g.C|KYd$_ "p9Pc݈0`a.HܗtAoz@/chiC^AÇ5l07ǚs^a9 lt&cP' GM/$Tv#Yp}4=nj 75PF z@U?XR@~BlO^K(\kdyC+INVB% +6Tk`)kj}Ҫ tu )Շ Tf,sB,fţy[6(#hMjkE MkE/\alu-X$_\ r_X 5u97sN=X;Y$1w(yB́lWV%@|xа2:Aˢo=—4^d1K 9I"5E6;f3.26 Yv|7B%ڀ꺾xhk3)iPd#,l6\C=RN#x9Ă :3leS`.“2 >4EdPt' +vɲ]0>g+ \ Dosya sonunda yenisatır yok. diff -Nuar flatpak-1.0.0.orig/bubblewrap/bwrap.xml flatpak-1.0.0/bubblewrap/bwrap.xml --- flatpak-1.0.0.orig/bubblewrap/bwrap.xml 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/bwrap.xml 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,320 @@ + + + + + + bwrap + Project Atomic + + + Developer + Alexander + Larsson + + + Developer + Colin + Walters + + + + + + bwrap + 1 + User Commands + + + + bwrap + container setup utility + + + + +bwrap +OPTION +COMMAND + + + +Description + + bwrap is a privileged helper for container setup. You + are unlikely to use it directly from the commandline, although that is possible. + + + It works by creating a new, completely empty, filesystem namespace where the root + is on a tmpfs that is invisible from the host, and which will be automatically + cleaned up when the last process exists. You can then use commandline options to + construct the root filesystem and process environment for the command to run in + the namespace. + + + By default, bwrap creates a new mount namespace for the sandbox. + Optionally it also sets up new user, ipc, pid, network and uts namespaces (but note the + user namespace is required if bwrap is not installed setuid root). + The application in the sandbox can be made to run with a different UID and GID. + + + If needed (e.g. when using a PID namespace) bwrap + is running a minimal pid 1 process in the sandbox that is + responsible for reaping zombies. It also detects when the initial + application process (pid 2) dies and reports its exit status back to + the original spawner. The pid 1 process exits to clean up the + sandbox when there are no other processes in the sandbox left. + + + +Options + + When options are used multiple times, the last option wins, unless otherwise + specified. + + General options: + + + + Print help and exit + + + + Print version + + + + + Parse nul-separated arguments from the given file descriptor. + This option can be used multiple times to parse options from + multiple sources. + + + + Options related to kernel namespaces: + + + + Create a new user namespace + + + + Create a new user namespace if possible else skip it + + + + Create a new ipc namespace + + + + Create a new pid namespace + + + + Create a new network namespace + + + + Create a new uts namespace + + + + Create a new cgroup namespace + + + + Create a new cgroup namespace if possible else skip it + + + + Unshare all possible namespaces. Currently equivalent with: + + + + Use a custom user id in the sandbox (requires ) + + + + Use a custom group id in the sandbox (requires ) + + + + Use a custom hostname in the sandbox (requires ) + + + Options about environment setup: + + + + Change directory to DIR + + + + Set an environment variable + + + + Unset an environment variable + + + Options for monitoring the sandbox from the outside: + + + + + Take a lock on DEST while the sandbox is running. + This option can be used multiple times to take locks on multiple files. + + + + + Keep this file descriptor open while the sandbox is running + + + + Filesystem related options. These are all operations that modify the filesystem directly, or + mounts stuff in the filesystem. These are applied in the order they are given as arguments. + Any missing parent directories that are required to create a specified destination are + automatically created as needed. + + + + + Bind mount the host path SRC on DEST + + + + Bind mount the host path SRC on DEST, allowing device access + + + + Bind mount the host path SRC readonly on DEST + + + + Remount the path DEST as readonly. It works only on the specified mount point, without changing any other mount point under the specified path + + + + Mount procfs on DEST + + + + Mount new devtmpfs on DEST + + + + Mount new tmpfs on DEST + + + + Mount new mqueue on DEST + + + + Create a directory at DEST + + + + Copy from the file descriptor FD to DEST + + + + Copy from the file descriptor FD to a file which is bind-mounted on DEST + + + + Copy from the file descriptor FD to a file which is bind-mounted readonly on DEST + + + + Create a symlink at DEST with target SRC + + + Lockdown options: + + + + + Load and use seccomp rules from FD. + The rules need to be in the form of a compiled eBPF program, + as generated by seccomp_export_bpf. + + + + + + Exec Label from the sandbox. On an SELinux system you can specify the SELinux + context for the sandbox process(s). + + + + + + File label for temporary sandbox content. On an SELinux system you can specify + the SELinux context for the sandbox content. + + + + + + Block the sandbox on reading from FD until some data is available. + + + + + + Write information in JSON format about the sandbox to FD. + + + + + + Create a new terminal session for the sandbox (calls setsid()). This + disconnects the sandbox from the controlling terminal which means + the sandbox can't for instance inject input into the terminal. + + Note: In a general sandbox, if you don't use --new-session, it is + recommended to use seccomp to disallow the TIOCSTI ioctl, otherwise + the application can feed keyboard input to the terminal. + + + + + + Ensures child process (COMMAND) dies when bwrap's parent dies. Kills (SIGKILL) + all bwrap sandbox processes in sequence from parent to child + including COMMAND process when bwrap or bwrap's parent dies. + See prctl, PR_SET_PDEATHSIG. + + + + + + + Environment + + + + HOME + + Used as the cwd in the sandbox if has not been + explicitly specified and the current cwd is not present inside the sandbox. + The option can be used to override the value + that is used here. + + + + + + + Exit status + + + The bwrap command returns the exit status of the + initial application process (pid 2 in the sandbox). + + + + diff -Nuar flatpak-1.0.0.orig/bubblewrap/ci/redhat-ci.sh flatpak-1.0.0/bubblewrap/ci/redhat-ci.sh --- flatpak-1.0.0.orig/bubblewrap/ci/redhat-ci.sh 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/ci/redhat-ci.sh 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -xeuo pipefail + +distro=$1 + +runcontainer() { + docker run --rm --env=container=true --env=BWRAP_SUID=${BWRAP_SUID:-} --env CFLAGS="${CFLAGS:-}" --net=host --privileged -v /usr:/host/usr -v $(pwd):/srv/code -w /srv/code $distro ./ci/redhat-ci.sh $distro +} + +buildinstall_to_host() { + + yum -y install git autoconf automake libtool make gcc redhat-rpm-config \ + libcap-devel 'pkgconfig(libselinux)' 'libxslt' 'docbook-style-xsl' \ + lib{a,ub,t}san /usr/bin/eu-readelf + + echo testing: $(git describe --tags --always --abbrev=42) + + env NOCONFIGURE=1 ./autogen.sh + ./configure --prefix=/usr --libdir=/usr/lib64 + make -j 8 + tmpd=$(mktemp -d) + make install DESTDIR=${tmpd} + for san in a t ub; do + if eu-readelf -d ${tmpd}/usr/bin/bwrap | grep -q "NEEDED.*lib${san}san"; then + for x in /usr/lib64/lib${san}san*.so.*; do + install -D $x ${tmpd}${x} + done + fi + done + rsync -rlv ${tmpd}/usr/ /host/usr/ + if ${BWRAP_SUID}; then + chmod u+s /host/usr/bin/bwrap + fi + rm ${tmpd} -rf +} + +if test -z "${container:-}"; then + ostree admin unlock + # Hack until the host tree is updated in rhci + rpm -Uvh https://kojipkgs.fedoraproject.org//packages/glibc/2.24/4.fc25/x86_64/{libcrypt-nss,glibc,glibc-common,glibc-all-langpacks}-2.24-4.fc25.x86_64.rpm + useradd bwrap-tester + runcontainer + runuser -u bwrap-tester env ASAN_OPTIONS=detect_leaks=false ./tests/test-run.sh +else + buildinstall_to_host +fi diff -Nuar flatpak-1.0.0.orig/bubblewrap/completions/bash/bwrap flatpak-1.0.0/bubblewrap/completions/bash/bwrap --- flatpak-1.0.0.orig/bubblewrap/completions/bash/bwrap 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/completions/bash/bwrap 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,60 @@ +#!/bin/bash +# +# bash completion file for bubblewrap commands +# + +_bwrap() { + local cur prev words cword + _init_completion || return + + local boolean_options=" + --help + --unshare-cgroup + --unshare-cgroup-try + --unshare-user + --unshare-user-try + --unshare-ipc + --unshare-net + --unshare-pid + --unshare-uts + --version + " + + local options_with_args=" + $boolean_optons + --args + --bind + --bind-data + --block-fd + --chdir + --dev + --dev-bind + --dir + --exec-label + --file + --file-label + --gid + --hostname + --info-fd + --lock-file + --proc + --ro-bind + --remount-ro + --seccomp + --setenv + --symlink + --sync-fd + --uid + --unsetenv + --seccomp + --symlink + --die-with-parent + " + + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + fi + + return 0 +} +complete -F _bwrap bwrap diff -Nuar flatpak-1.0.0.orig/bubblewrap/configure.ac flatpak-1.0.0/bubblewrap/configure.ac --- flatpak-1.0.0.orig/bubblewrap/configure.ac 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/configure.ac 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,127 @@ +AC_PREREQ([2.63]) +AC_INIT([bubblewrap], [0.1.8], [atomic-devel@projectatomic.io]) +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) + +AC_USE_SYSTEM_EXTENSIONS + +AM_INIT_AUTOMAKE([1.11 -Wno-portability foreign no-define tar-ustar no-dist-gzip dist-xz]) +AM_MAINTAINER_MODE([enable]) +AM_SILENT_RULES([yes]) + +AC_SYS_LARGEFILE + +AC_PROG_CC +AM_PROG_CC_C_O + +AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])]) + +AC_ARG_ENABLE(man, + [AS_HELP_STRING([--enable-man], + [generate man pages [default=auto]])],, + enable_man=maybe) + +AS_IF([test "$enable_man" != no], [ + AC_PATH_PROG([XSLTPROC], [xsltproc], []) + AS_IF([test -z "$XSLTPROC"], [ + AS_IF([test "$enable_man" = yes], [ + AC_MSG_ERROR([xsltproc is required for --enable-man]) + ]) + enable_man=no + ], [ + enable_man=yes + ]) +]) +AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no) + +AC_ARG_WITH([bash-completion-dir], + AS_HELP_STRING([--with-bash-completion-dir[=PATH]], + [Install the bash auto-completion script in this directory. @<:@default=yes@:>@]), + [], + [with_bash_completion_dir=yes]) + +if test "x$with_bash_completion_dir" = "xyes"; then + PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0], + [BASH_COMPLETION_DIR="`pkg-config --variable=completionsdir bash-completion`"], + [BASH_COMPLETION_DIR="$datadir/bash-completion/completions"]) +else + BASH_COMPLETION_DIR="$with_bash_completion_dir" +fi + +AC_SUBST([BASH_COMPLETION_DIR]) +AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"]) +# ------------------------------------------------------------------------------ +have_selinux=no +AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [Disable optional SELINUX support])) +if test "x$enable_selinux" != "xno"; then + PKG_CHECK_MODULES([SELINUX], [libselinux >= 2.1.9], + [AC_DEFINE(HAVE_SELINUX, 1, [Define if SELinux is available]) + have_selinux=yes + M4_DEFINES="$M4_DEFINES -DHAVE_SELINUX"], + [have_selinux=no]) + if test "x$have_selinux" = xno -a "x$enable_selinux" = xyes; then + AC_MSG_ERROR([*** SELinux support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"]) + +dnl Keep this in sync with ostree, except remove -Werror=declaration-after-statement +CC_CHECK_FLAGS_APPEND([WARN_CFLAGS], [CFLAGS], [\ + -pipe \ + -Wall \ + -Werror=empty-body \ + -Werror=strict-prototypes \ + -Werror=missing-prototypes \ + -Werror=implicit-function-declaration \ + "-Werror=format=2 -Werror=format-security -Werror=format-nonliteral" \ + -Werror=pointer-arith -Werror=init-self \ + -Werror=missing-declarations \ + -Werror=return-type \ + -Werror=overflow \ + -Werror=int-conversion \ + -Werror=parenthesis \ + -Werror=incompatible-pointer-types \ + -Werror=misleading-indentation \ + -Werror=missing-include-dirs -Werror=aggregate-return \ +]) +AC_SUBST(WARN_CFLAGS) + +AC_ARG_WITH(priv-mode, + AS_HELP_STRING([--with-priv-mode=setuid/none], + [How to set privilege-raising during make install]), + [], + [with_priv_mode="none"]) + +AM_CONDITIONAL(PRIV_MODE_SETUID, test "x$with_priv_mode" = "xsetuid") + +AC_ARG_ENABLE(sudo, + AS_HELP_STRING([--enable-sudo],[Use sudo to set privileged mode on binaries during install (only needed if --with-priv-mode used)]), + [SUDO_BIN="sudo"], [SUDO_BIN=""]) +AC_SUBST([SUDO_BIN]) + +AC_ARG_ENABLE(require-userns, + AS_HELP_STRING([--enable-require-userns=yes/no (default no)], + [Require user namespaces by default when installed suid]), + [], + [enable_require_userns="no"]) + +AS_IF([ test "x$enable_require_userns" = "xyes" ], [ + AC_DEFINE(ENABLE_REQUIRE_USERNS, 1, [Define if userns should be used by default in suid mode]) + ]) + +AC_CONFIG_FILES([ +Makefile +]) +AC_OUTPUT + +echo " + bubblewrap $VERSION + =================== + + man pages (xsltproc): $enable_man + SELinux: $have_selinux + setuid mode on make install: $with_priv_mode + require default userns: $enable_require_userns + mysteriously satisfying to pop: yes" +echo "" diff -Nuar flatpak-1.0.0.orig/bubblewrap/COPYING flatpak-1.0.0/bubblewrap/COPYING --- flatpak-1.0.0.orig/bubblewrap/COPYING 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/COPYING 2018-02-03 21:26:06.271233339 +0300 @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff -Nuar flatpak-1.0.0.orig/bubblewrap/demos/bubblewrap-shell.sh flatpak-1.0.0/bubblewrap/demos/bubblewrap-shell.sh --- flatpak-1.0.0.orig/bubblewrap/demos/bubblewrap-shell.sh 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/demos/bubblewrap-shell.sh 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Use bubblewrap to run /bin/sh reusing the host OS binaries (/usr), but with +# separate /tmp, /home, /var, /run, and /etc. For /etc we just inherit the +# host's resolv.conf, and set up "stub" passwd/group files. Not sharing +# /home for example is intentional. If you wanted to, you could design +# a bwrap-using program that shared individual parts of /home, perhaps +# public content. +# +# Another way to build on this example is to remove --share-net to disable +# networking. +set -euo pipefail +(exec bwrap --ro-bind /usr /usr \ + --dir /tmp \ + --dir /var \ + --symlink ../tmp var/tmp \ + --proc /proc \ + --dev /dev \ + --ro-bind /etc/resolv.conf /etc/resolv.conf \ + --symlink usr/lib /lib \ + --symlink usr/lib64 /lib64 \ + --symlink usr/bin /bin \ + --symlink usr/sbin /sbin \ + --chdir / \ + --unshare-all \ + --share-net \ + --dir /run/user/$(id -u) \ + --setenv XDG_RUNTIME_DIR "/run/user/`id -u`" \ + --setenv PS1 "bwrap-demo$ " \ + --file 11 /etc/passwd \ + --file 12 /etc/group \ + /bin/sh) \ + 11< <(getent passwd $UID 65534) \ + 12< <(getent group $(id -g) 65534) diff -Nuar flatpak-1.0.0.orig/bubblewrap/demos/flatpak.bpf flatpak-1.0.0/bubblewrap/demos/flatpak.bpf --- flatpak-1.0.0.orig/bubblewrap/demos/flatpak.bpf 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/demos/flatpak.bpf 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,2 @@ + >> WeVgUTSRQPONMLKJIH*Gg@F@E@D@C@B@A@@@?@>@=@<@;*@: @9@838@8 T/2)@ 5*) -) 5 5$ '      @ 3Vg{  & 6 += Pf ax T \ Dosya sonunda yenisatır yok. diff -Nuar flatpak-1.0.0.orig/bubblewrap/demos/flatpak-run.sh flatpak-1.0.0/bubblewrap/demos/flatpak-run.sh --- flatpak-1.0.0.orig/bubblewrap/demos/flatpak-run.sh 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/demos/flatpak-run.sh 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,65 @@ +#!/bin/bash +# For this to work you first have to run these commands: +# curl -O http://sdk.gnome.org/nightly/keys/nightly.gpg +# flatpak --user remote-add --gpg-key=nightly.gpg gnome-nightly http://sdk.gnome.org/nightly/repo/ +# flatpak --user install gnome-nightly org.gnome.Platform +# flatpak --user install gnome-nightly org.gnome.Weather + +mkdir -p ~/.var/app/org.gnome.Weather/cache ~/.var/app/org.gnome.Weather/config ~/.var/app/org.gnome.Weather/data + +( + exec bwrap \ + --ro-bind ~/.local/share/flatpak/runtime/org.gnome.Platform/x86_64/master/active/files /usr \ + --lock-file /usr/.ref \ + --ro-bind ~/.local/share/flatpak/app/org.gnome.Weather/x86_64/master/active/files/ /app \ + --lock-file /app/.ref \ + --dev /dev \ + --proc /proc \ + --dir /tmp \ + --symlink /tmp /var/tmp \ + --symlink /run /var/run \ + --symlink usr/lib /lib \ + --symlink usr/lib64 /lib64 \ + --symlink usr/bin /bin \ + --symlink usr/sbin /sbin \ + --symlink usr/etc /etc \ + --dir /run/user/`id -u` \ + --ro-bind /etc/machine-id /usr/etc/machine-id \ + --ro-bind /etc/resolv.conf /run/host/monitor/resolv.conf \ + --ro-bind /sys/block /sys/block \ + --ro-bind /sys/bus /sys/bus \ + --ro-bind /sys/class /sys/class \ + --ro-bind /sys/dev /sys/dev \ + --ro-bind /sys/devices /sys/devices \ + --dev-bind /dev/dri /dev/dri \ + --bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X99 \ + --bind ~/.var/app/org.gnome.Weather ~/.var/app/org.gnome.Weather \ + --bind ~/.config/dconf ~/.config/dconf \ + --bind /run/user/`id -u`/dconf /run/user/`id -u`/dconf \ + --unshare-pid \ + --setenv XDG_RUNTIME_DIR "/run/user/`id -u`" \ + --setenv DISPLAY :99 \ + --setenv GI_TYPELIB_PATH /app/lib/girepository-1.0 \ + --setenv GST_PLUGIN_PATH /app/lib/gstreamer-1.0 \ + --setenv LD_LIBRARY_PATH /app/lib:/usr/lib/GL \ + --setenv DCONF_USER_CONFIG_DIR .config/dconf \ + --setenv PATH /app/bin:/usr/bin \ + --setenv XDG_CONFIG_DIRS /app/etc/xdg:/etc/xdg \ + --setenv XDG_DATA_DIRS /app/share:/usr/share \ + --setenv SHELL /bin/sh \ + --setenv XDG_CACHE_HOME ~/.var/app/org.gnome.Weather/cache \ + --setenv XDG_CONFIG_HOME ~/.var/app/org.gnome.Weather/config \ + --setenv XDG_DATA_HOME ~/.var/app/org.gnome.Weather/data \ + --file 10 /run/user/`id -u`/flatpak-info \ + --bind-data 11 /usr/etc/passwd \ + --bind-data 12 /usr/etc/group \ + --seccomp 13 \ + /bin/sh) \ + 11< <(getent passwd $UID 65534 ) \ + 12< <(getent group $(id -g) 65534) \ + 13< `dirname $0`/flatpak.bpf \ + 10</dev/null; then \ + echo "$$x already includes git.mk"; \ + else \ + failed=; \ + echo "Updating $$x"; \ + { cat $$x; \ + echo ''; \ + echo '-include $$(top_srcdir)/git.mk'; \ + } > $$x.tmp || failed=1; \ + if test x$$failed = x; then \ + mv $$x.tmp $$x || failed=1; \ + fi; \ + if test x$$failed = x; then : else \ + echo "Failed updating $$x"; >&2 \ + any_failed=1; \ + fi; \ + fi; done; test -z "$$any_failed" + +git-mk-update: + wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk + +.PHONY: git-all git-mk-install git-mk-update + + + +############################################################################### +# Actual .gitignore generation: +############################################################################### + +$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk + @echo "git.mk: Generating $@" + @{ \ + if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \ + for x in \ + $(DOC_MODULE)-decl-list.txt \ + $(DOC_MODULE)-decl.txt \ + tmpl/$(DOC_MODULE)-unused.sgml \ + "tmpl/*.bak" \ + $(REPORT_FILES) \ + $(DOC_MODULE).pdf \ + xml html \ + ; do echo "/$$x"; done; \ + FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \ + case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \ + if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \ + echo "/$(DOC_MODULE).types"; \ + fi; \ + if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \ + echo "/$(DOC_MODULE)-sections.txt"; \ + fi; \ + if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + for x in \ + $(SETUP_FILES) \ + $(DOC_MODULE).types \ + ; do echo "/$$x"; done; \ + fi; \ + fi; \ + if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \ + for lc in $(DOC_LINGUAS); do \ + for x in \ + $(if $(DOC_MODULE),$(DOC_MODULE).xml) \ + $(DOC_PAGES) \ + $(DOC_INCLUDES) \ + ; do echo "/$$lc/$$x"; done; \ + done; \ + for x in \ + $(_DOC_OMF_ALL) \ + $(_DOC_DSK_ALL) \ + $(_DOC_HTML_ALL) \ + $(_DOC_MOFILES) \ + $(DOC_H_FILE) \ + "*/.xml2po.mo" \ + "*/*.omf.out" \ + ; do echo /$$x; done; \ + fi; \ + if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \ + for lc in $(HELP_LINGUAS); do \ + for x in \ + $(HELP_FILES) \ + "$$lc.stamp" \ + "$$lc.mo" \ + ; do echo "/$$lc/$$x"; done; \ + done; \ + fi; \ + if test "x$(gsettings_SCHEMAS)" = x; then :; else \ + for x in \ + $(gsettings_SCHEMAS:.xml=.valid) \ + $(gsettings__enum_file) \ + ; do echo "/$$x"; done; \ + fi; \ + if test "x$(appdata_XML)" = x; then :; else \ + for x in \ + $(appdata_XML:.xml=.valid) \ + ; do echo "/$$x"; done; \ + fi; \ + if test "x$(appstream_XML)" = x; then :; else \ + for x in \ + $(appstream_XML:.xml=.valid) \ + ; do echo "/$$x"; done; \ + fi; \ + if test -f $(srcdir)/po/Makefile.in.in; then \ + for x in \ + po/Makefile.in.in \ + po/Makefile.in.in~ \ + po/Makefile.in \ + po/Makefile \ + po/Makevars.template \ + po/POTFILES \ + po/Rules-quot \ + po/stamp-it \ + po/stamp-po \ + po/.intltool-merge-cache \ + "po/*.gmo" \ + "po/*.header" \ + "po/*.mo" \ + "po/*.sed" \ + "po/*.sin" \ + po/$(GETTEXT_PACKAGE).pot \ + intltool-extract.in \ + intltool-merge.in \ + intltool-update.in \ + ; do echo "/$$x"; done; \ + fi; \ + if test -f $(srcdir)/configure; then \ + for x in \ + autom4te.cache \ + configure \ + config.h \ + stamp-h1 \ + libtool \ + config.lt \ + ; do echo "/$$x"; done; \ + fi; \ + if test "x$(DEJATOOL)" = x; then :; else \ + for x in \ + $(DEJATOOL) \ + ; do echo "/$$x.sum"; echo "/$$x.log"; done; \ + echo /site.exp; \ + fi; \ + if test "x$(am__dirstamp)" = x; then :; else \ + echo "$(am__dirstamp)"; \ + fi; \ + if test "x$(LTCOMPILE)" = x -a "x$(LTCXXCOMPILE)" = x -a "x$(GTKDOC_RUN)" = x; then :; else \ + for x in \ + "*.lo" \ + ".libs" "_libs" \ + ; do echo "$$x"; done; \ + fi; \ + for x in \ + .gitignore \ + $(GITIGNOREFILES) \ + $(CLEANFILES) \ + $(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \ + $(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \ + $(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \ + so_locations \ + $(MOSTLYCLEANFILES) \ + $(TEST_LOGS) \ + $(TEST_LOGS:.log=.trs) \ + $(TEST_SUITE_LOG) \ + $(TESTS:=.test) \ + "*.gcda" \ + "*.gcno" \ + $(DISTCLEANFILES) \ + $(am__CONFIG_DISTCLEAN_FILES) \ + $(CONFIG_CLEAN_FILES) \ + TAGS ID GTAGS GRTAGS GSYMS GPATH tags \ + "*.tab.c" \ + $(MAINTAINERCLEANFILES) \ + $(BUILT_SOURCES) \ + $(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \ + $(filter %_vala.stamp,$(DIST_COMMON)) \ + $(filter %.vapi,$(DIST_COMMON)) \ + $(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \ + Makefile \ + Makefile.in \ + "*.orig" \ + "*.rej" \ + "*.bak" \ + "*~" \ + ".*.sw[nop]" \ + ".dirstamp" \ + ; do echo "/$$x"; done; \ + for x in \ + "*.$(OBJEXT)" \ + $(DEPDIR) \ + ; do echo "$$x"; done; \ + } | \ + sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \ + sed 's@/[.]/@/@g' | \ + LC_ALL=C sort | uniq > $@.tmp && \ + mv $@.tmp $@; + +all: $(srcdir)/.gitignore gitignore-recurse-maybe +gitignore: $(srcdir)/.gitignore gitignore-recurse + +gitignore-recurse-maybe: + @for subdir in $(DIST_SUBDIRS); do \ + case " $(SUBDIRS) " in \ + *" $$subdir "*) :;; \ + *) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \ + esac; \ + done +gitignore-recurse: + @for subdir in $(DIST_SUBDIRS); do \ + test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \ + done + +maintainer-clean: gitignore-clean +gitignore-clean: + -rm -f $(srcdir)/.gitignore + +.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe diff -Nuar flatpak-1.0.0.orig/bubblewrap/LICENSE flatpak-1.0.0/bubblewrap/LICENSE --- flatpak-1.0.0.orig/bubblewrap/LICENSE 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/LICENSE 2018-02-03 21:26:06.271233339 +0300 @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff -Nuar flatpak-1.0.0.orig/bubblewrap/m4/attributes.m4 flatpak-1.0.0/bubblewrap/m4/attributes.m4 --- flatpak-1.0.0.orig/bubblewrap/m4/attributes.m4 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/m4/attributes.m4 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,292 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2008 Diego Pettenò +dnl Copyright (c) 2006-2008 xine project +dnl Copyright (c) 2012 Lucas De Marchi +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if FLAG in ENV-VAR is supported by compiler and append it +dnl to WHERE-TO-APPEND variable. Note that we invert -Wno-* checks to +dnl -W* as gcc cannot test for negated warnings. If a C snippet is passed, +dnl use it, otherwise use a simple main() definition that just returns 0. +dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG], [C-SNIPPET]) + +AC_DEFUN([CC_CHECK_FLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], + AS_TR_SH([cc_cv_$2_$3]), + [eval "AS_TR_SH([cc_save_$2])='${$2}'" + eval "AS_TR_SH([$2])='${cc_save_$2} -Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" + AC_LINK_IFELSE([AC_LANG_SOURCE(ifelse([$4], [], + [int main(void) { return 0; } ], + [$4]))], + [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], + [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) + eval "AS_TR_SH([$2])='$cc_save_$2'"]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], + [eval "$1='${$1} $3'"]) +]) + +dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2], [C-SNIPPET]) +AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ + for flag in [$3]; do + CC_CHECK_FLAG_APPEND([$1], [$2], $flag, [$4]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([int main() { return 1; }], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd* | *-openbsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable command line, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }])], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) diff -Nuar flatpak-1.0.0.orig/bubblewrap/Makefile.am flatpak-1.0.0/bubblewrap/Makefile.am --- flatpak-1.0.0.orig/bubblewrap/Makefile.am 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/Makefile.am 2018-02-03 21:26:06.271233339 +0300 @@ -0,0 +1,46 @@ +AM_CFLAGS = $(WARN_CFLAGS) +CLEANFILES = +EXTRA_DIST = + +GITIGNOREFILES = build-aux/ gtk-doc.make config.h.in aclocal.m4 + +bin_PROGRAMS = bwrap + +bwrap_srcpath := $(srcdir) +include Makefile-bwrap.am + +install-exec-hook: +if PRIV_MODE_SETUID + $(SUDO_BIN) chown root $(DESTDIR)$(bindir)/bwrap + $(SUDO_BIN) chmod u+s $(DESTDIR)$(bindir)/bwrap +endif + +check_PROGRAMS = test-bwrap + +test-bwrap: bwrap + rm -rf test-bwrap + cp bwrap test-bwrap +if PRIV_MODE_SETUID + $(SUDO_BIN) chown root test-bwrap + $(SUDO_BIN) chmod u+s test-bwrap +endif + +test_bwrap_SOURCES= + +include Makefile-docs.am + +TESTS = tests/test-run.sh +TESTS_ENVIRONMENT = BWRAP=$(abs_top_builddir)/test-bwrap + +EXTRA_DIST += $(TESTS) + +if ENABLE_BASH_COMPLETION +bashcompletiondir = $(BASH_COMPLETION_DIR) +dist_bashcompletion_DATA = completions/bash/bwrap +endif + +-include $(top_srcdir)/git.mk + +AM_DISTCHECK_CONFIGURE_FLAGS = \ + --with-bash-completion-dir="\$(datadir)"/bash-completion/ \ + $(NULL) diff -Nuar flatpak-1.0.0.orig/bubblewrap/Makefile-bwrap.am flatpak-1.0.0/bubblewrap/Makefile-bwrap.am --- flatpak-1.0.0.orig/bubblewrap/Makefile-bwrap.am 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/Makefile-bwrap.am 2018-02-03 21:26:06.271233339 +0300 @@ -0,0 +1,13 @@ + +bwrap_SOURCES = \ + $(bwrap_srcpath)/bubblewrap.c \ + $(bwrap_srcpath)/bind-mount.h \ + $(bwrap_srcpath)/bind-mount.c \ + $(bwrap_srcpath)/network.h \ + $(bwrap_srcpath)/network.c \ + $(bwrap_srcpath)/utils.h \ + $(bwrap_srcpath)/utils.c \ + $(NULL) + +bwrap_CFLAGS = $(AM_CFLAGS) +bwrap_LDADD = $(SELINUX_LIBS) diff -Nuar flatpak-1.0.0.orig/bubblewrap/Makefile-docs.am flatpak-1.0.0/bubblewrap/Makefile-docs.am --- flatpak-1.0.0.orig/bubblewrap/Makefile-docs.am 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/Makefile-docs.am 2018-02-03 21:26:06.271233339 +0300 @@ -0,0 +1,18 @@ +XSLTPROC = xsltproc + +XSLTPROC_FLAGS = \ + --nonet \ + --stringparam man.output.quietly 1 \ + --stringparam funcsynopsis.style ansi \ + --stringparam man.th.extra1.suppress 1 \ + --stringparam man.authors.section.enabled 0 \ + --stringparam man.copyright.section.enabled 0 + +.xml.1: + $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< + +if ENABLE_MAN +man_MANS = bwrap.1 +CLEANFILES += $(man_MANS) +endif +EXTRA_DIST += bwrap.xml diff -Nuar flatpak-1.0.0.orig/bubblewrap/network.c flatpak-1.0.0/bubblewrap/network.c --- flatpak-1.0.0.orig/bubblewrap/network.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/network.c 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,198 @@ +/* bubblewrap + * Copyright (C) 2016 Alexander Larsson + * + * 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 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 . + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "network.h" + +static void * +add_rta (struct nlmsghdr *header, + int type, + size_t size) +{ + struct rtattr *rta; + size_t rta_size = RTA_LENGTH (size); + + rta = (struct rtattr *) ((char *) header + NLMSG_ALIGN (header->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = rta_size; + + header->nlmsg_len = NLMSG_ALIGN (header->nlmsg_len) + rta_size; + + return RTA_DATA (rta); +} + +static int +rtnl_send_request (int rtnl_fd, + struct nlmsghdr *header) +{ + struct sockaddr_nl dst_addr = { AF_NETLINK, 0 }; + ssize_t sent; + + sent = sendto (rtnl_fd, (void *) header, header->nlmsg_len, 0, + (struct sockaddr *) &dst_addr, sizeof (dst_addr)); + if (sent < 0) + return -1; + + return 0; +} + +static int +rtnl_read_reply (int rtnl_fd, + int seq_nr) +{ + char buffer[1024]; + ssize_t received; + struct nlmsghdr *rheader; + + while (1) + { + received = recv (rtnl_fd, buffer, sizeof (buffer), 0); + if (received < 0) + return -1; + + rheader = (struct nlmsghdr *) buffer; + while (received >= NLMSG_HDRLEN) + { + if (rheader->nlmsg_seq != seq_nr) + return -1; + if (rheader->nlmsg_pid != getpid ()) + return -1; + if (rheader->nlmsg_type == NLMSG_ERROR) + { + uint32_t *err = NLMSG_DATA (rheader); + if (*err == 0) + return 0; + + return -1; + } + if (rheader->nlmsg_type == NLMSG_DONE) + return 0; + + rheader = NLMSG_NEXT (rheader, received); + } + } +} + +static int +rtnl_do_request (int rtnl_fd, + struct nlmsghdr *header) +{ + if (rtnl_send_request (rtnl_fd, header) != 0) + return -1; + + if (rtnl_read_reply (rtnl_fd, header->nlmsg_seq) != 0) + return -1; + + return 0; +} + +static struct nlmsghdr * +rtnl_setup_request (char *buffer, + int type, + int flags, + size_t size) +{ + struct nlmsghdr *header; + size_t len = NLMSG_LENGTH (size); + static uint32_t counter = 0; + + memset (buffer, 0, len); + + header = (struct nlmsghdr *) buffer; + header->nlmsg_len = len; + header->nlmsg_type = type; + header->nlmsg_flags = flags | NLM_F_REQUEST; + header->nlmsg_seq = counter++; + header->nlmsg_pid = getpid (); + + return (struct nlmsghdr *) header; +} + +void +loopback_setup (void) +{ + int r, if_loopback; + cleanup_fd int rtnl_fd = -1; + char buffer[1024]; + struct sockaddr_nl src_addr = { AF_NETLINK, 0 }; + struct nlmsghdr *header; + struct ifaddrmsg *addmsg; + struct ifinfomsg *infomsg; + struct in_addr *ip_addr; + + src_addr.nl_pid = getpid (); + + if_loopback = (int) if_nametoindex ("lo"); + if (if_loopback <= 0) + die_with_error ("loopback: Failed to look up lo"); + + rtnl_fd = socket (PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); + if (rtnl_fd < 0) + die_with_error ("loopback: Failed to create NETLINK_ROUTE socket"); + + r = bind (rtnl_fd, (struct sockaddr *) &src_addr, sizeof (src_addr)); + if (r < 0) + die_with_error ("loopback: Failed to bind NETLINK_ROUTE socket"); + + header = rtnl_setup_request (buffer, RTM_NEWADDR, + NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, + sizeof (struct ifaddrmsg)); + addmsg = NLMSG_DATA (header); + + addmsg->ifa_family = AF_INET; + addmsg->ifa_prefixlen = 8; + addmsg->ifa_flags = IFA_F_PERMANENT; + addmsg->ifa_scope = RT_SCOPE_HOST; + addmsg->ifa_index = if_loopback; + + ip_addr = add_rta (header, IFA_LOCAL, sizeof (*ip_addr)); + ip_addr->s_addr = htonl (INADDR_LOOPBACK); + + ip_addr = add_rta (header, IFA_ADDRESS, sizeof (*ip_addr)); + ip_addr->s_addr = htonl (INADDR_LOOPBACK); + + assert (header->nlmsg_len < sizeof (buffer)); + + if (rtnl_do_request (rtnl_fd, header) != 0) + die_with_error ("loopback: Failed RTM_NEWADDR"); + + header = rtnl_setup_request (buffer, RTM_NEWLINK, + NLM_F_ACK, + sizeof (struct ifinfomsg)); + infomsg = NLMSG_DATA (header); + + infomsg->ifi_family = AF_UNSPEC; + infomsg->ifi_type = 0; + infomsg->ifi_index = if_loopback; + infomsg->ifi_flags = IFF_UP; + infomsg->ifi_change = IFF_UP; + + assert (header->nlmsg_len < sizeof (buffer)); + + if (rtnl_do_request (rtnl_fd, header) != 0) + die_with_error ("loopback: Failed RTM_NEWLINK"); +} diff -Nuar flatpak-1.0.0.orig/bubblewrap/network.h flatpak-1.0.0/bubblewrap/network.h --- flatpak-1.0.0.orig/bubblewrap/network.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/network.h 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,21 @@ +/* bubblewrap + * Copyright (C) 2016 Alexander Larsson + * + * 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 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 . + * + */ + +#pragma once + +void loopback_setup (void); diff -Nuar flatpak-1.0.0.orig/bubblewrap/packaging/bubblewrap.spec flatpak-1.0.0/bubblewrap/packaging/bubblewrap.spec --- flatpak-1.0.0.orig/bubblewrap/packaging/bubblewrap.spec 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/packaging/bubblewrap.spec 2018-02-03 21:26:06.273233339 +0300 @@ -0,0 +1,49 @@ +%global commit0 66d12bb23b04e201c5846e325f0b10930ed802f8 +%global shortcommit0 %(c=%{commit0}; echo ${c:0:7}) + +Summary: Core execution tool for unprivileged containers +Name: bubblewrap +Version: 0 +Release: 1%{?dist} +#VCS: git:https://github.com/projectatomic/bubblewrap +Source0: https://github.com/projectatomic/%{name}/archive/%{commit0}.tar.gz#/%{name}-%{shortcommit0}.tar.gz +License: LGPLv2+ +URL: https://github.com/projectatomic/bubblewrap + +BuildRequires: git +# We always run autogen.sh +BuildRequires: autoconf automake libtool +BuildRequires: libcap-devel +BuildRequires: pkgconfig(libselinux) +BuildRequires: libxslt +BuildRequires: docbook-style-xsl + +%description +Bubblewrap (/usr/bin/bwrap) is a core execution engine for unprivileged +containers that works as a setuid binary on kernels without +user namespaces. + +%prep +%autosetup -Sgit -n %{name}-%{version} + +%build +env NOCONFIGURE=1 ./autogen.sh +%configure --disable-silent-rules --with-priv-mode=none + +make %{?_smp_mflags} + +%install +make install DESTDIR=$RPM_BUILD_ROOT INSTALL="install -p -c" +find $RPM_BUILD_ROOT -name '*.la' -delete + +%files +%license COPYING +%doc README.md +%{_datadir}/bash-completion/completions/bwrap +%if (0%{?rhel} != 0 && 0%{?rhel} <= 7) +%attr(4755,root,root) %{_bindir}/bwrap +%else +%{_bindir}/bwrap +%endif +%{_mandir}/man1/* + diff -Nuar flatpak-1.0.0.orig/bubblewrap/README.md flatpak-1.0.0/bubblewrap/README.md --- flatpak-1.0.0.orig/bubblewrap/README.md 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/README.md 2018-02-03 21:26:06.272233339 +0300 @@ -0,0 +1,179 @@ +Bubblewrap +========== + +Many container runtime tools like `systemd-nspawn`, `docker`, +etc. focus on providing infrastructure for system administrators and +orchestration tools (e.g. Kubernetes) to run containers. + +These tools are not suitable to give to unprivileged users, because it +is trivial to turn such access into to a fully privileged root shell +on the host. + +User namespaces +--------------- + +There is an effort in the Linux kernel called +[user namespaces](https://www.google.com/search?q=user+namespaces+site%3Ahttps%3A%2F%2Flwn.net) +which attempts to allow unprivileged users to use container features. +While significant progress has been made, there are +[still concerns](https://lwn.net/Articles/673597/) about it, and +it is not available to unprivileged users in several production distributions +such as CentOS/Red Hat Enterprise Linux 7, Debian Jessie, etc. + +See for example +[CVE-2016-3135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3135) +which is a local root vulnerability introduced by userns. +[This March 2016 post](https://lkml.org/lkml/2016/3/9/555) has some +more discussion. + +Bubblewrap could be viewed as setuid implementation of a *subset* of +user namespaces. Emphasis on subset - specifically relevant to the +above CVE, bubblewrap does not allow control over iptables. + +The original bubblewrap code existed before user namespaces - it inherits code from +[xdg-app helper](https://cgit.freedesktop.org/xdg-app/xdg-app/tree/common/xdg-app-helper.c) +which in turn distantly derives from +[linux-user-chroot](https://git.gnome.org/browse/linux-user-chroot). + +Security +-------- + +The maintainers of this tool believe that it does not, even when used +in combination with typical software installed on that distribution, +allow privilege escalation. It may increase the ability of a logged +in user to perform denial of service attacks, however. + +In particular, bubblewrap uses `PR_SET_NO_NEW_PRIVS` to turn off +setuid binaries, which is the [traditional way](https://en.wikipedia.org/wiki/Chroot#Limitations) to get out of things +like chroots. + +Users +----- + +This program can be shared by all container tools which perform +non-root operation, such as: + + - [Flatpak](http://www.flatpak.org) + - [rpm-ostree unprivileged](https://github.com/projectatomic/rpm-ostree/pull/209) + +We would also like to see this be available in Kubernetes/OpenShift +clusters. Having the ability for unprivileged users to use container +features would make it significantly easier to do interactive +debugging scenarios and the like. + +Usage +----- + +bubblewrap works by creating a new, completely empty, mount +namespace where the root is on a tmpfs that is invisible from the +host, and will be automatically cleaned up when the last process +exits. You can then use commandline options to construct the root +filesystem and process environment and command to run in the +namespace. + +There's a larger [demo script](./demos/bubblewrap-shell.sh) in the +source code, but here's a trimmed down version which runs +a new shell reusing the host's `/usr`. + +``` +bwrap --ro-bind /usr /usr --symlink usr/lib64 /lib64 --proc /proc --dev /dev --unshare-pid bash +``` + +This is an incomplete example, but useful for purposes of +illustration. More often, rather than creating a container using the +host's filesystem tree, you want to target a chroot. There, rather +than creating the symlink `lib64 -> usr/lib64` in the tmpfs, you might +have already created it in the target rootfs. + +Sandboxing +---------- + +The goal of bubblewrap is to run an application in a sandbox, where it +has restricted access to parts of the operating system or user data +such as the home directory. + +bubblewrap always creates a new mount namespace, and the user can specify +exactly what parts of the filesystem should be visible in the sandbox. +Any such directories you specify mounted `nodev` by default, and can be made readonly. + +Additionally you can use these kernel features: + +User namespaces ([CLONE_NEWUSER](http://linux.die.net/man/2/clone)): This hides all but the current uid and gid from the +sandbox. You can also change what the value of uid/gid should be in the sandbox. + +IPC namespaces ([CLONE_NEWIPC](http://linux.die.net/man/2/clone)): The sandbox will get its own copy of all the +different forms of IPCs, like SysV shared memory and semaphores. + +PID namespaces ([CLONE_NEWPID](http://linux.die.net/man/2/clone)): The sandbox will not see any processes outside the sandbox. Additionally, bubblewrap will run a trivial pid1 inside your container to handle the requirements of reaping children in the sandbox. .This avoids what is known now as the [Docker pid 1 problem](https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/). + + +Network namespaces ([CLONE_NEWNET](http://linux.die.net/man/2/clone)): The sandbox will not see the network. Instead it will have its own network namespace with only a loopback device. + +UTS namespace ([CLONE_NEWUTS](http://linux.die.net/man/2/clone)): The sandbox will have its own hostname. + +Seccomp filters: You can pass in seccomp filters that limit which syscalls can be done in the sandbox. For more information, see [Seccomp](https://en.wikipedia.org/wiki/Seccomp). + +Related project comparison: Firejail +------------------------------------ + +[Firejail](https://github.com/netblue30/firejail/tree/master/src/firejail) +is similar to Flatpak before bubblewrap was split out in that it combines +a setuid tool with a lot of desktop-specific sandboxing features. For +example, Firejail knows about Pulseaudio, whereas bubblewrap does not. + +The bubblewrap authors believe it's much easier to audit a small +setuid program, and keep features such as Pulseaudio filtering as an +unprivileged process, as now occurs in Flatpak. + +Also, @cgwalters thinks trying to +[whitelist file paths](https://github.com/netblue30/firejail/blob/37a5a3545ef6d8d03dad8bbd888f53e13274c9e5/src/firejail/fs_whitelist.c#L176) +is a bad idea given the myriad ways users have to manipulate paths, +and the myriad ways in which system administrators may configure a +system. The bubblewrap approach is to only retain a few specific +Linux capabilities such as `CAP_SYS_ADMIN`, but to always access the +filesystem as the invoking uid. This entirely closes +[TOCTTOU attacks](https://cwe.mitre.org/data/definitions/367.html) and +such. + +Related project comparison: Sandstorm.io +---------------------------------------- + +[Sandstorm.io](https://sandstorm.io/) requries unprivileged user +namespaces to set up its sandbox, though it could easily be adapted +to operate in a setuid mode as well. @cgwalters believes their code is +fairly good, but it could still make sense to unify on bubblewrap. +However, @kentonv (of Sandstorm) feels that while this makes sense +in principle, the switching cost outweighs the practical benefits for +now. This decision could be re-evaluated in the future, but it is not +being actively pursued today. + +Related project comparison: runc/binctr +---------------------------------------- + +[runC](https://github.com/opencontainers/runc) is currently working on +supporting [rootless containers](https://github.com/opencontainers/runc/pull/774), +without needing `setuid` or any other privileges during installation of +runC (using unprivileged user namespaces rather than `setuid`), +creation, and management of containers. However, the standard mode of +using runC is similar to [systemd nspawn](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html) +in that it is tooling intended to be invoked by root. + +The bubblewrap authors believe that runc and systemd-nspawn are not +designed to be made setuid, and are distant from supporting such a mode. +However with rootless containers, runC will be able to fulfill certain usecases +that bubblewrap supports (with the added benefit of being a standardised and +complete OCI runtime). + +[binctr](https://github.com/jfrazelle/binctr) is just a wrapper for +runC, so inherits all of its design tradeoffs. + +Whats with the name ?! +---------------------- + +The name bubblewrap was chosen to convey that this +tool runs as the parent of the application (so wraps it in some sense) and creates +a protective layer (the sandbox) around it. + +![](bubblewrap.jpg) + +(Bubblewrap cat by [dancing_stupidity](https://www.flickr.com/photos/27549668@N03/)) diff -Nuar flatpak-1.0.0.orig/bubblewrap/.redhat-ci.yml flatpak-1.0.0/bubblewrap/.redhat-ci.yml --- flatpak-1.0.0.orig/bubblewrap/.redhat-ci.yml 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/.redhat-ci.yml 2018-02-03 21:26:06.271233339 +0300 @@ -0,0 +1,25 @@ +context: centos7 +required: true + +branches: + - master + - auto + - try + +host: + distro: centos/7/atomic + +tests: + - env BWRAP_SUID=true ./ci/redhat-ci.sh centos:7 + +timeout: 30m + +--- + +inherit: true + +context: f25-asan-ubsan +required: true + +tests: + - env CFLAGS='-g -Og -fsanitize=undefined -fsanitize=address' ./ci/redhat-ci.sh fedora:25 diff -Nuar flatpak-1.0.0.orig/bubblewrap/tests/test-run.sh flatpak-1.0.0/bubblewrap/tests/test-run.sh --- flatpak-1.0.0.orig/bubblewrap/tests/test-run.sh 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/tests/test-run.sh 2018-02-03 21:26:06.274233339 +0300 @@ -0,0 +1,132 @@ +#!/bin/bash + +set -xeuo pipefail + +srcd=$(cd $(dirname $0) && pwd) +bn=$(basename $0) +tempdir=$(mktemp -d /var/tmp/tap-test.XXXXXX) +touch ${tempdir}/.testtmp +function cleanup () { + if test -n "${TEST_SKIP_CLEANUP:-}"; then + echo "Skipping cleanup of ${test_tmpdir}" + else if test -f ${tempdir}/.test; then + rm "${tempdir}" -rf + fi + fi +} +trap cleanup EXIT +cd ${tempdir} + +: "${BWRAP:=bwrap}" + +skip () { + echo $@ 1>&2; exit 77 +} + +assert_not_reached () { + echo $@ 1>&2; exit 1 +} + +assert_file_has_content () { + if ! grep -q -e "$2" "$1"; then + echo 1>&2 "File '$1' doesn't match regexp '$2'"; exit 1 + fi +} + +FUSE_DIR= +for mp in $(cat /proc/self/mounts | grep " fuse[. ]" | grep user_id=$(id -u) | awk '{print $2}'); do + if test -d $mp; then + echo Using $mp as test fuse mount + FUSE_DIR=$mp + break + fi +done + +# This is supposed to be an otherwise readable file in an unreadable (by the user) dir +UNREADABLE=/root/.bashrc +if test -x `dirname $UNREADABLE`; then + UNREADABLE= +fi + +# Default arg, bind whole host fs to /, tmpfs on /tmp +RUN="${BWRAP} --bind / / --tmpfs /tmp" + +if ! $RUN true; then + skip Seems like bwrap is not working at all. Maybe setuid is not working +fi + +# Test help +${BWRAP} --help > help.txt +assert_file_has_content help.txt "usage: ${BWRAP}" + +for ALT in "" "--unshare-user-try" "--unshare-pid" "--unshare-user-try --unshare-pid"; do + # Test fuse fs as bind source + if [ x$FUSE_DIR != x ]; then + $RUN $ALT --proc /proc --dev /dev --bind $FUSE_DIR /tmp/foo true + fi + # no --dev => no devpts => no map_root workaround + $RUN $ALT --proc /proc true + # No network + $RUN $ALT --unshare-net --proc /proc --dev /dev true + # Unreadable file + echo -n "expect EPERM: " + if $RUN $ALT --unshare-net --proc /proc --bind /etc/shadow /tmp/foo cat /etc/shadow; then + assert_not_reached Could read /etc/shadow + fi + # Unreadable dir + if [ x$UNREADABLE != x ]; then + echo -n "expect EPERM: " + if $RUN $ALT --unshare-net --proc /proc --dev /dev --bind $UNREADABLE /tmp/foo cat /tmp/foo ; then + assert_not_reached Could read $UNREADABLE + fi + fi + + # bind dest in symlink (https://github.com/projectatomic/bubblewrap/pull/119) + $RUN $ALT --dir /tmp/dir --symlink dir /tmp/link --bind /etc /tmp/link true +done + +# Test --die-with-parent + +cat >lockf-n.py <. + * + */ +#include "config.h" + +#include "utils.h" +#include +#ifdef HAVE_SELINUX +#include +#endif + +void +die_with_error (const char *format, ...) +{ + va_list args; + int errsv; + + errsv = errno; + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + fprintf (stderr, ": %s\n", strerror (errsv)); + + exit (1); +} + +void +die (const char *format, ...) +{ + va_list args; + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + fprintf (stderr, "\n"); + + exit (1); +} + +void +die_unless_label_valid (const char *label) +{ +#ifdef HAVE_SELINUX + if (is_selinux_enabled () == 1) + { + if (security_check_context ((security_context_t) label) < 0) + die_with_error ("invalid label %s", label); + return; + } +#endif + die ("labeling not supported on this system"); +} + +void +die_oom (void) +{ + puts ("Out of memory"); + exit (1); +} + +void * +xmalloc (size_t size) +{ + void *res = malloc (size); + + if (res == NULL) + die_oom (); + return res; +} + +void * +xcalloc (size_t size) +{ + void *res = calloc (1, size); + + if (res == NULL) + die_oom (); + return res; +} + +void * +xrealloc (void *ptr, size_t size) +{ + void *res = realloc (ptr, size); + + if (size != 0 && res == NULL) + die_oom (); + return res; +} + +char * +xstrdup (const char *str) +{ + char *res; + + assert (str != NULL); + + res = strdup (str); + if (res == NULL) + die_oom (); + + return res; +} + +void +strfreev (char **str_array) +{ + if (str_array) + { + int i; + + for (i = 0; str_array[i] != NULL; i++) + free (str_array[i]); + + free (str_array); + } +} + +/* Compares if str has a specific path prefix. This differs + from a regular prefix in two ways. First of all there may + be multiple slashes separating the path elements, and + secondly, if a prefix is matched that has to be en entire + path element. For instance /a/prefix matches /a/prefix/foo/bar, + but not /a/prefixfoo/bar. */ +bool +has_path_prefix (const char *str, + const char *prefix) +{ + while (TRUE) + { + /* Skip consecutive slashes to reach next path + element */ + while (*str == '/') + str++; + while (*prefix == '/') + prefix++; + + /* No more prefix path elements? Done! */ + if (*prefix == 0) + return TRUE; + + /* Compare path element */ + while (*prefix != 0 && *prefix != '/') + { + if (*str != *prefix) + return FALSE; + str++; + prefix++; + } + + /* Matched prefix path element, + must be entire str path element */ + if (*str != '/' && *str != 0) + return FALSE; + } +} + +bool +path_equal (const char *path1, + const char *path2) +{ + while (TRUE) + { + /* Skip consecutive slashes to reach next path + element */ + while (*path1 == '/') + path1++; + while (*path2 == '/') + path2++; + + /* No more prefix path elements? Done! */ + if (*path1 == 0 || *path2 == 0) + return *path1 == 0 && *path2 == 0; + + /* Compare path element */ + while (*path1 != 0 && *path1 != '/') + { + if (*path1 != *path2) + return FALSE; + path1++; + path2++; + } + + /* Matched path1 path element, must be entire path element */ + if (*path2 != '/' && *path2 != 0) + return FALSE; + } +} + + +bool +has_prefix (const char *str, + const char *prefix) +{ + return strncmp (str, prefix, strlen (prefix)) == 0; +} + +void +xsetenv (const char *name, const char *value, int overwrite) +{ + if (setenv (name, value, overwrite)) + die ("setenv failed"); +} + +void +xunsetenv (const char *name) +{ + if (unsetenv (name)) + die ("unsetenv failed"); +} + +char * +strconcat (const char *s1, + const char *s2) +{ + size_t len = 0; + char *res; + + if (s1) + len += strlen (s1); + if (s2) + len += strlen (s2); + + res = xmalloc (len + 1); + *res = 0; + if (s1) + strcat (res, s1); + if (s2) + strcat (res, s2); + + return res; +} + +char * +strconcat3 (const char *s1, + const char *s2, + const char *s3) +{ + size_t len = 0; + char *res; + + if (s1) + len += strlen (s1); + if (s2) + len += strlen (s2); + if (s3) + len += strlen (s3); + + res = xmalloc (len + 1); + *res = 0; + if (s1) + strcat (res, s1); + if (s2) + strcat (res, s2); + if (s3) + strcat (res, s3); + + return res; +} + +char * +xasprintf (const char *format, + ...) +{ + char *buffer = NULL; + va_list args; + + va_start (args, format); + if (vasprintf (&buffer, format, args) == -1) + die_oom (); + va_end (args); + + return buffer; +} + +int +fdwalk (int proc_fd, int (*cb)(void *data, + int fd), void *data) +{ + int open_max; + int fd; + int dfd; + int res = 0; + DIR *d; + + dfd = openat (proc_fd, "self/fd", O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC | O_NOCTTY); + if (dfd == -1) + return res; + + if ((d = fdopendir (dfd))) + { + struct dirent *de; + + while ((de = readdir (d))) + { + long l; + char *e = NULL; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol (de->d_name, &e, 10); + if (errno != 0 || !e || *e) + continue; + + fd = (int) l; + + if ((long) fd != l) + continue; + + if (fd == dirfd (d)) + continue; + + if ((res = cb (data, fd)) != 0) + break; + } + + closedir (d); + return res; + } + + open_max = sysconf (_SC_OPEN_MAX); + + for (fd = 0; fd < open_max; fd++) + if ((res = cb (data, fd)) != 0) + break; + + return res; +} + +/* Sets errno on error (!= 0), ENOSPC on short write */ +int +write_to_fd (int fd, + const char *content, + ssize_t len) +{ + ssize_t res; + + while (len > 0) + { + res = write (fd, content, len); + if (res < 0 && errno == EINTR) + continue; + if (res <= 0) + { + if (res == 0) /* Unexpected short write, should not happen when writing to a file */ + errno = ENOSPC; + return -1; + } + len -= res; + content += res; + } + + return 0; +} + +/* Sets errno on error (!= 0), ENOSPC on short write */ +int +write_file_at (int dirfd, + const char *path, + const char *content) +{ + int fd; + bool res; + int errsv; + + fd = openat (dirfd, path, O_RDWR | O_CLOEXEC, 0); + if (fd == -1) + return -1; + + res = 0; + if (content) + res = write_to_fd (fd, content, strlen (content)); + + errsv = errno; + close (fd); + errno = errsv; + + return res; +} + +/* Sets errno on error (!= 0), ENOSPC on short write */ +int +create_file (const char *path, + mode_t mode, + const char *content) +{ + int fd; + int res; + int errsv; + + fd = creat (path, mode); + if (fd == -1) + return -1; + + res = 0; + if (content) + res = write_to_fd (fd, content, strlen (content)); + + errsv = errno; + close (fd); + errno = errsv; + + return res; +} + +int +ensure_file (const char *path, + mode_t mode) +{ + struct stat buf; + + /* We check this ahead of time, otherwise + the create file will fail in the read-only + case with EROFD instead of EEXIST */ + if (stat (path, &buf) == 0 && + S_ISREG (buf.st_mode)) + return 0; + + if (create_file (path, mode, NULL) != 0 && errno != EEXIST) + return -1; + + return 0; +} + + +#define BUFSIZE 8192 +/* Sets errno on error (!= 0), ENOSPC on short write */ +int +copy_file_data (int sfd, + int dfd) +{ + char buffer[BUFSIZE]; + ssize_t bytes_read; + + while (TRUE) + { + bytes_read = read (sfd, buffer, BUFSIZE); + if (bytes_read == -1) + { + if (errno == EINTR) + continue; + + return -1; + } + + if (bytes_read == 0) + break; + + if (write_to_fd (dfd, buffer, bytes_read) != 0) + return -1; + } + + return 0; +} + +/* Sets errno on error (!= 0), ENOSPC on short write */ +int +copy_file (const char *src_path, + const char *dst_path, + mode_t mode) +{ + int sfd; + int dfd; + int res; + int errsv; + + sfd = open (src_path, O_CLOEXEC | O_RDONLY); + if (sfd == -1) + return -1; + + dfd = creat (dst_path, mode); + if (dfd == -1) + { + errsv = errno; + close (sfd); + errno = errsv; + return -1; + } + + res = copy_file_data (sfd, dfd); + + errsv = errno; + close (sfd); + close (dfd); + errno = errsv; + + return res; +} + +/* Sets errno on error (== NULL), + * Always ensures terminating zero */ +char * +load_file_data (int fd, + size_t *size) +{ + cleanup_free char *data = NULL; + ssize_t data_read; + ssize_t data_len; + ssize_t res; + int errsv; + + data_read = 0; + data_len = 4080; + data = xmalloc (data_len); + + do + { + if (data_len == data_read + 1) + { + data_len *= 2; + data = xrealloc (data, data_len); + } + + do + res = read (fd, data + data_read, data_len - data_read - 1); + while (res < 0 && errno == EINTR); + + if (res < 0) + { + errsv = errno; + close (fd); + errno = errsv; + return NULL; + } + + data_read += res; + } + while (res > 0); + + data[data_read] = 0; + + if (size) + *size = (size_t) data_read; + + return steal_pointer (&data); +} + +/* Sets errno on error (== NULL), + * Always ensures terminating zero */ +char * +load_file_at (int dirfd, + const char *path) +{ + int fd; + char *data; + int errsv; + + fd = openat (dirfd, path, O_CLOEXEC | O_RDONLY); + if (fd == -1) + return NULL; + + data = load_file_data (fd, NULL); + + errsv = errno; + close (fd); + errno = errsv; + + return data; +} + +/* Sets errno on error (< 0) */ +int +get_file_mode (const char *pathname) +{ + struct stat buf; + + if (stat (pathname, &buf) != 0) + return -1; + + return buf.st_mode & S_IFMT; +} + +/* Sets errno on error (!= 0) */ +int +mkdir_with_parents (const char *pathname, + int mode, + bool create_last) +{ + cleanup_free char *fn = NULL; + char *p; + struct stat buf; + + if (pathname == NULL || *pathname == '\0') + { + errno = EINVAL; + return -1; + } + + fn = xstrdup (pathname); + + p = fn; + while (*p == '/') + p++; + + do + { + while (*p && *p != '/') + p++; + + if (!*p) + p = NULL; + else + *p = '\0'; + + if (!create_last && p == NULL) + break; + + if (stat (fn, &buf) != 0) + { + if (mkdir (fn, mode) == -1 && errno != EEXIST) + return -1; + } + else if (!S_ISDIR (buf.st_mode)) + { + errno = ENOTDIR; + return -1; + } + + if (p) + { + *p++ = '/'; + while (*p && *p == '/') + p++; + } + } + while (p); + + return 0; +} + +int +raw_clone (unsigned long flags, + void *child_stack) +{ +#if defined(__s390__) || defined(__CRIS__) + /* On s390 and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + return (int) syscall (__NR_clone, child_stack, flags); +#else + return (int) syscall (__NR_clone, flags, child_stack); +#endif +} + +int +pivot_root (const char * new_root, const char * put_old) +{ +#ifdef __NR_pivot_root + return syscall (__NR_pivot_root, new_root, put_old); +#else + errno = ENOSYS; + return -1; +#endif +} + +char * +label_mount (const char *opt, const char *mount_label) +{ +#ifdef HAVE_SELINUX + if (mount_label) + { + if (opt) + return xasprintf ("%s,context=\"%s\"", opt, mount_label); + else + return xasprintf ("context=\"%s\"", mount_label); + } +#endif + if (opt) + return xstrdup (opt); + return NULL; +} + +int +label_create_file (const char *file_label) +{ +#ifdef HAVE_SELINUX + if (is_selinux_enabled () > 0 && file_label) + return setfscreatecon ((security_context_t) file_label); +#endif + return 0; +} + +int +label_exec (const char *exec_label) +{ +#ifdef HAVE_SELINUX + if (is_selinux_enabled () > 0 && exec_label) + return setexeccon ((security_context_t) exec_label); +#endif + return 0; +} diff -Nuar flatpak-1.0.0.orig/bubblewrap/utils.h flatpak-1.0.0/bubblewrap/utils.h --- flatpak-1.0.0.orig/bubblewrap/utils.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/bubblewrap/utils.h 2018-02-03 21:26:06.274233339 +0300 @@ -0,0 +1,166 @@ +/* bubblewrap + * Copyright (C) 2016 Alexander Larsson + * + * 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 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 . + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define __debug__(x) printf x +#else +#define __debug__(x) +#endif + +#define UNUSED __attribute__((__unused__)) + +#define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) + +#define TRUE 1 +#define FALSE 0 +typedef int bool; + +#define PIPE_READ_END 0 +#define PIPE_WRITE_END 1 + +void die_with_error (const char *format, + ...) __attribute__((__noreturn__)) __attribute__((format (printf, 1, 2))); +void die (const char *format, + ...) __attribute__((__noreturn__)) __attribute__((format (printf, 1, 2))); +void die_oom (void) __attribute__((__noreturn__)); +void die_unless_label_valid (const char *label); + +void *xmalloc (size_t size); +void *xcalloc (size_t size); +void *xrealloc (void *ptr, + size_t size); +char *xstrdup (const char *str); +void strfreev (char **str_array); +void xsetenv (const char *name, + const char *value, + int overwrite); +void xunsetenv (const char *name); +char *strconcat (const char *s1, + const char *s2); +char *strconcat3 (const char *s1, + const char *s2, + const char *s3); +char * xasprintf (const char *format, + ...) __attribute__((format (printf, 1, 2))); +bool has_prefix (const char *str, + const char *prefix); +bool has_path_prefix (const char *str, + const char *prefix); +bool path_equal (const char *path1, + const char *path2); +int fdwalk (int proc_fd, + int (*cb)(void *data, + int fd), + void *data); +char *load_file_data (int fd, + size_t *size); +char *load_file_at (int dirfd, + const char *path); +int write_file_at (int dirfd, + const char *path, + const char *content); +int write_to_fd (int fd, + const char *content, + ssize_t len); +int copy_file_data (int sfd, + int dfd); +int copy_file (const char *src_path, + const char *dst_path, + mode_t mode); +int create_file (const char *path, + mode_t mode, + const char *content); +int ensure_file (const char *path, + mode_t mode); +int get_file_mode (const char *pathname); +int mkdir_with_parents (const char *pathname, + int mode, + bool create_last); + +/* syscall wrappers */ +int raw_clone (unsigned long flags, + void *child_stack); +int pivot_root (const char *new_root, + const char *put_old); +char *label_mount (const char *opt, + const char *mount_label); +int label_exec (const char *exec_label); +int label_create_file (const char *file_label); + +static inline void +cleanup_freep (void *p) +{ + void **pp = (void **) p; + + if (*pp) + free (*pp); +} + +static inline void +cleanup_strvp (void *p) +{ + void **pp = (void **) p; + + strfreev (*pp); +} + +static inline void +cleanup_fdp (int *fdp) +{ + int fd; + + assert (fdp); + + fd = *fdp; + if (fd != -1) + (void) close (fd); +} + +#define cleanup_free __attribute__((cleanup (cleanup_freep))) +#define cleanup_fd __attribute__((cleanup (cleanup_fdp))) +#define cleanup_strv __attribute__((cleanup (cleanup_strvp))) + +static inline void * +steal_pointer (void *pp) +{ + void **ptr = (void **) pp; + void *ref; + + ref = *ptr; + *ptr = NULL; + + return ref; +} + +/* type safety */ +#define steal_pointer(pp) \ + (0 ? (*(pp)) : (steal_pointer) (pp)) diff -Nuar flatpak-1.0.0.orig/libglnx/COPYING flatpak-1.0.0/libglnx/COPYING --- flatpak-1.0.0.orig/libglnx/COPYING 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/COPYING 2018-02-03 21:26:06.307233341 +0300 @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff -Nuar flatpak-1.0.0.orig/libglnx/.git flatpak-1.0.0/libglnx/.git --- flatpak-1.0.0.orig/libglnx/.git 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/.git 2018-02-03 21:26:06.241233337 +0300 @@ -0,0 +1 @@ +gitdir: ../.git/modules/libglnx diff -Nuar flatpak-1.0.0.orig/libglnx/.gitignore flatpak-1.0.0/libglnx/.gitignore --- flatpak-1.0.0.orig/libglnx/.gitignore 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/.gitignore 2018-02-03 21:26:06.307233341 +0300 @@ -0,0 +1,16 @@ +# A path ostree writes to work around automake bug with +# subdir-objects +Makefile-libglnx.am.inc + +# Some standard bits +.deps +.libs +.dirstamp +*.typelib +*.la +*.lo +*.o +*.pyc +*.stamp +*~ + diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-backport-autocleanups.h flatpak-1.0.0/libglnx/glnx-backport-autocleanups.h --- flatpak-1.0.0.orig/libglnx/glnx-backport-autocleanups.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-backport-autocleanups.h 2018-02-03 21:26:06.307233341 +0300 @@ -0,0 +1,124 @@ +/* + * Copyright © 2015 Canonical Limited + * + * This library 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 of the licence, 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 . + * + * Author: Ryan Lortie + */ + +#pragma once + +#include + +#if !GLIB_CHECK_VERSION(2, 43, 4) + +static inline void +g_autoptr_cleanup_generic_gfree (void *p) +{ + void **pp = (void**)p; + if (*pp) + g_free (*pp); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAsyncQueue, g_async_queue_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBookmarkFile, g_bookmark_file_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBytes, g_bytes_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GChecksum, g_checksum_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDateTime, g_date_time_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDir, g_dir_close) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GError, g_error_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GHashTable, g_hash_table_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GHmac, g_hmac_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GIOChannel, g_io_channel_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GKeyFile, g_key_file_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GList, g_list_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GArray, g_array_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPtrArray, g_ptr_array_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContext, g_main_context_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainLoop, g_main_loop_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSource, g_source_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMappedFile, g_mapped_file_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMarkupParseContext, g_markup_parse_context_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gchar, g_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GNode, g_node_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionContext, g_option_context_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionGroup, g_option_group_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPatternSpec, g_pattern_spec_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GQueue, g_queue_free) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRand, g_rand_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRegex, g_regex_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMatchInfo, g_match_info_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GScanner, g_scanner_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSequence, g_sequence_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSList, g_slist_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStringChunk, g_string_chunk_free) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GThread, g_thread_unref) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GMutex, g_mutex_clear) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GCond, g_cond_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimer, g_timer_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimeZone, g_time_zone_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTree, g_tree_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariant, g_variant_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantBuilder, g_variant_builder_unref) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantBuilder, g_variant_builder_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantIter, g_variant_iter_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantDict, g_variant_dict_unref) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantDict, g_variant_dict_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantType, g_variant_type_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSubprocess, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSubprocessLauncher, g_object_unref) + +/* Add GObject-based types as needed. */ +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCancellable, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverter, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverterOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDataInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFile, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileEnumerator, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileIOStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileInfo, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileMonitor, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMemoryInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMemoryOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSocket, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSocketAddress, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTask, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsCertificate, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsDatabase, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsInteraction, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDBusConnection, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDBusMessage, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GZlibCompressor, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GZlibDecompressor, g_object_unref) + +#endif + +#if !GLIB_CHECK_VERSION(2, 45, 8) + +static inline void +g_autoptr_cleanup_gstring_free (GString *string) +{ + if (string) + g_string_free (string, TRUE); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GString, g_autoptr_cleanup_gstring_free) + +#endif diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-backport-autoptr.h flatpak-1.0.0/libglnx/glnx-backport-autoptr.h --- flatpak-1.0.0.orig/libglnx/glnx-backport-autoptr.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-backport-autoptr.h 2018-02-03 21:26:06.308233341 +0300 @@ -0,0 +1,133 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Colin Walters + * + * GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#if !GLIB_CHECK_VERSION(2, 43, 4) + +#define _GLIB_AUTOPTR_FUNC_NAME(TypeName) glib_autoptr_cleanup_##TypeName +#define _GLIB_AUTOPTR_TYPENAME(TypeName) TypeName##_autoptr +#define _GLIB_AUTO_FUNC_NAME(TypeName) glib_auto_cleanup_##TypeName +#define _GLIB_CLEANUP(func) __attribute__((cleanup(func))) +#define _GLIB_DEFINE_AUTOPTR_CHAINUP(ModuleObjName, ParentName) \ + typedef ModuleObjName *_GLIB_AUTOPTR_TYPENAME(ModuleObjName); \ + static inline void _GLIB_AUTOPTR_FUNC_NAME(ModuleObjName) (ModuleObjName **_ptr) { \ + _GLIB_AUTOPTR_FUNC_NAME(ParentName) ((ParentName **) _ptr); } \ + + +/* these macros are API */ +#define G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func) \ + typedef TypeName *_GLIB_AUTOPTR_TYPENAME(TypeName); \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + static inline void _GLIB_AUTOPTR_FUNC_NAME(TypeName) (TypeName **_ptr) { if (*_ptr) (func) (*_ptr); } \ + G_GNUC_END_IGNORE_DEPRECATIONS +#define G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func) \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + static inline void _GLIB_AUTO_FUNC_NAME(TypeName) (TypeName *_ptr) { (func) (_ptr); } \ + G_GNUC_END_IGNORE_DEPRECATIONS +#define G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func, none) \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + static inline void _GLIB_AUTO_FUNC_NAME(TypeName) (TypeName *_ptr) { if (*_ptr != none) (func) (*_ptr); } \ + G_GNUC_END_IGNORE_DEPRECATIONS +#define g_autoptr(TypeName) _GLIB_CLEANUP(_GLIB_AUTOPTR_FUNC_NAME(TypeName)) _GLIB_AUTOPTR_TYPENAME(TypeName) +#define g_auto(TypeName) _GLIB_CLEANUP(_GLIB_AUTO_FUNC_NAME(TypeName)) TypeName +#define g_autofree _GLIB_CLEANUP(g_autoptr_cleanup_generic_gfree) + +/** + * g_steal_pointer: + * @pp: a pointer to a pointer + * + * Sets @pp to %NULL, returning the value that was there before. + * + * Conceptually, this transfers the ownership of the pointer from the + * referenced variable to the "caller" of the macro (ie: "steals" the + * reference). + * + * The return value will be properly typed, according to the type of + * @pp. + * + * This can be very useful when combined with g_autoptr() to prevent the + * return value of a function from being automatically freed. Consider + * the following example (which only works on GCC and clang): + * + * |[ + * GObject * + * create_object (void) + * { + * g_autoptr(GObject) obj = g_object_new (G_TYPE_OBJECT, NULL); + * + * if (early_error_case) + * return NULL; + * + * return g_steal_pointer (&obj); + * } + * ]| + * + * It can also be used in similar ways for 'out' parameters and is + * particularly useful for dealing with optional out parameters: + * + * |[ + * gboolean + * get_object (GObject **obj_out) + * { + * g_autoptr(GObject) obj = g_object_new (G_TYPE_OBJECT, NULL); + * + * if (early_error_case) + * return FALSE; + * + * if (obj_out) + * *obj_out = g_steal_pointer (&obj); + * + * return TRUE; + * } + * ]| + * + * In the above example, the object will be automatically freed in the + * early error case and also in the case that %NULL was given for + * @obj_out. + * + * Since: 2.44 + */ +static inline gpointer +(g_steal_pointer) (gpointer pp) +{ + gpointer *ptr = (gpointer *) pp; + gpointer ref; + + ref = *ptr; + *ptr = NULL; + + return ref; +} + +/* type safety */ +#define g_steal_pointer(pp) \ + (0 ? (*(pp)) : (g_steal_pointer) (pp)) + +#endif /* !GLIB_CHECK_VERSION(2, 43, 3) */ + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-backports.c flatpak-1.0.0/libglnx/glnx-backports.c --- flatpak-1.0.0.orig/libglnx/glnx-backports.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-backports.c 2018-02-03 21:26:06.308233341 +0300 @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Colin Walters + * + * 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 of the licence 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-backports.h" + +#if !GLIB_CHECK_VERSION(2, 44, 0) +gboolean +glnx_strv_contains (const gchar * const *strv, + const gchar *str) +{ + g_return_val_if_fail (strv != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + for (; *strv != NULL; strv++) + { + if (g_str_equal (str, *strv)) + return TRUE; + } + + return FALSE; +} + +gboolean +glnx_set_object (GObject **object_ptr, + GObject *new_object) +{ + GObject *old_object = *object_ptr; + + if (old_object == new_object) + return FALSE; + + if (new_object != NULL) + g_object_ref (new_object); + + *object_ptr = new_object; + + if (old_object != NULL) + g_object_unref (old_object); + + return TRUE; +} +#endif diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-backports.h flatpak-1.0.0/libglnx/glnx-backports.h --- flatpak-1.0.0.orig/libglnx/glnx-backports.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-backports.h 2018-02-03 21:26:06.308233341 +0300 @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Colin Walters + * + * GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#if !GLIB_CHECK_VERSION(2, 44, 0) + +#define g_strv_contains glnx_strv_contains +gboolean glnx_strv_contains (const gchar * const *strv, + const gchar *str); + +#define g_set_object(object_ptr, new_object) \ + (/* Check types match. */ \ + 0 ? *(object_ptr) = (new_object), FALSE : \ + glnx_set_object ((GObject **) (object_ptr), (GObject *) (new_object)) \ + ) +gboolean glnx_set_object (GObject **object_ptr, + GObject *new_object); + +#endif /* !GLIB_CHECK_VERSION(2, 44, 0) */ + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-console.c flatpak-1.0.0/libglnx/glnx-console.c --- flatpak-1.0.0.orig/libglnx/glnx-console.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-console.c 2018-05-26 00:50:25.433037228 +0300 @@ -0,0 +1,359 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2015 Colin Walters + * + * 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 of the licence 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-console.h" + +#include +#include +#include +#include +#include +#include + +/* For people with widescreen monitors and maximized terminals, it looks pretty + * bad to have an enormous progress bar. For much the same reason as web pages + * tend to have a maximum width; + * https://ux.stackexchange.com/questions/48982/suggest-good-max-width-for-fluid-width-design + */ +#define MAX_PROGRESSBAR_COLUMNS 20 + +/* Max updates output per second. On a tty there's no point to rendering + * extremely fast; and for a non-tty we're probably in a Jenkins job + * or whatever and having percentages spam multiple lines there is annoying. + */ +#define MAX_TTY_UPDATE_HZ (5) +#define MAX_NONTTY_UPDATE_HZ (1) + +static gboolean locked; +static guint64 last_update_ms; /* monotonic time in millis we last updated */ + +gboolean +glnx_stdout_is_tty (void) +{ + static gsize initialized = 0; + static gboolean stdout_is_tty_v; + + if (g_once_init_enter (&initialized)) + { + stdout_is_tty_v = isatty (1); + g_once_init_leave (&initialized, 1); + } + + return stdout_is_tty_v; +} + +static volatile guint cached_columns = 0; +static volatile guint cached_lines = 0; + +static int +fd_columns (int fd) +{ + struct winsize ws = {}; + + if (ioctl (fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_col <= 0) + return -EIO; + + return ws.ws_col; +} + +/** + * glnx_console_columns: + * + * Returns: The number of columns for terminal output + */ +guint +glnx_console_columns (void) +{ + if (G_UNLIKELY (cached_columns == 0)) + { + int c; + + c = fd_columns (STDOUT_FILENO); + + if (c <= 0) + c = 80; + + if (c > 256) + c = 256; + + cached_columns = c; + } + + return cached_columns; +} + +static int +fd_lines (int fd) +{ + struct winsize ws = {}; + + if (ioctl (fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_row <= 0) + return -EIO; + + return ws.ws_row; +} + +/** + * glnx_console_lines: + * + * Returns: The number of lines for terminal output + */ +guint +glnx_console_lines (void) +{ + if (G_UNLIKELY (cached_lines == 0)) + { + int l; + + l = fd_lines (STDOUT_FILENO); + + if (l <= 0) + l = 24; + + cached_lines = l; + } + + return cached_lines; +} + +static void +on_sigwinch (int signum) +{ + cached_columns = 0; + cached_lines = 0; +} + +void +glnx_console_lock (GLnxConsoleRef *console) +{ + static gsize sigwinch_initialized = 0; + + g_return_if_fail (!locked); + g_return_if_fail (!console->locked); + + console->is_tty = glnx_stdout_is_tty (); + + locked = console->locked = TRUE; + + if (console->is_tty) + { + if (g_once_init_enter (&sigwinch_initialized)) + { + signal (SIGWINCH, on_sigwinch); + g_once_init_leave (&sigwinch_initialized, 1); + } + + { static const char initbuf[] = { '\n', 0x1B, 0x37 }; + (void) fwrite (initbuf, 1, sizeof (initbuf), stdout); + } + } +} + +static void +printpad (const char *padbuf, + guint padbuf_len, + guint n) +{ + const guint d = n / padbuf_len; + const guint r = n % padbuf_len; + guint i; + + for (i = 0; i < d; i++) + fwrite (padbuf, 1, padbuf_len, stdout); + fwrite (padbuf, 1, r, stdout); +} + +static void +text_percent_internal (const char *text, + int percentage) +{ + /* Check whether we're trying to render too fast; unless percentage is 100, in + * which case we assume this is the last call, so we always render it. + */ + const guint64 current_ms = g_get_monotonic_time () / 1000; + if (percentage != 100) + { + const guint64 diff_ms = current_ms - last_update_ms; + if (glnx_stdout_is_tty ()) + { + if (diff_ms < (1000/MAX_TTY_UPDATE_HZ)) + return; + } + else + { + if (diff_ms < (1000/MAX_NONTTY_UPDATE_HZ)) + return; + } + } + last_update_ms = current_ms; + + static const char equals[] = "===================="; + const guint n_equals = sizeof (equals) - 1; + static const char spaces[] = " "; + const guint n_spaces = sizeof (spaces) - 1; + const guint ncolumns = glnx_console_columns (); + const guint bar_min = 10; + + if (text && !*text) + text = NULL; + + const guint input_textlen = text ? strlen (text) : 0; + + if (!glnx_stdout_is_tty ()) + { + if (text) + fprintf (stdout, "%s", text); + if (percentage != -1) + { + if (text) + fputc (' ', stdout); + fprintf (stdout, "%u%%", percentage); + } + fputc ('\n', stdout); + fflush (stdout); + return; + } + + if (ncolumns < bar_min) + return; /* TODO: spinner */ + + /* Restore cursor */ + { const char beginbuf[2] = { 0x1B, 0x38 }; + (void) fwrite (beginbuf, 1, sizeof (beginbuf), stdout); + } + + if (percentage == -1) + { + if (text != NULL) + fwrite (text, 1, input_textlen, stdout); + + /* Overwrite remaining space, if any */ + if (ncolumns > input_textlen) + printpad (spaces, n_spaces, ncolumns - input_textlen); + } + else + { + const guint textlen = MIN (input_textlen, ncolumns - bar_min); + const guint barlen = MIN (MAX_PROGRESSBAR_COLUMNS, ncolumns - (textlen + 1)); + + if (textlen > 0) + { + fwrite (text, 1, textlen, stdout); + fputc (' ', stdout); + } + + { + const guint nbraces = 2; + const guint textpercent_len = 5; + const guint bar_internal_len = barlen - nbraces - textpercent_len; + const guint eqlen = bar_internal_len * (percentage / 100.0); + const guint spacelen = bar_internal_len - eqlen; + + fputc ('[', stdout); + printpad (equals, n_equals, eqlen); + printpad (spaces, n_spaces, spacelen); + fputc (']', stdout); + fprintf (stdout, " %3d%%", percentage); + } + } + + fflush (stdout); +} + +/** + * glnx_console_progress_text_percent: + * @text: Show this text before the progress bar + * @percentage: An integer in the range of 0 to 100 + * + * On a tty, print to the console @text followed by an ASCII art + * progress bar whose percentage is @percentage. If stdout is not a + * tty, a more basic line by line change will be printed. + * + * You must have called glnx_console_lock() before invoking this + * function. + * + */ +void +glnx_console_progress_text_percent (const char *text, + guint percentage) +{ + g_return_if_fail (percentage <= 100); + + text_percent_internal (text, percentage); +} + +/** + * glnx_console_progress_n_items: + * @text: Show this text before the progress bar + * @current: An integer for how many items have been processed + * @total: An integer for how many items there are total + * + * On a tty, print to the console @text followed by [@current/@total], + * then an ASCII art progress bar, like glnx_console_progress_text_percent(). + * + * You must have called glnx_console_lock() before invoking this + * function. + */ +void +glnx_console_progress_n_items (const char *text, + guint current, + guint total) +{ + g_return_if_fail (current <= total); + g_return_if_fail (total > 0); + + g_autofree char *newtext = g_strdup_printf ("%s (%u/%u)", text, current, total); + /* Special case current == total to ensure we end at 100% */ + int percentage = (current == total) ? 100 : (((double)current) / total * 100); + glnx_console_progress_text_percent (newtext, percentage); +} + +void +glnx_console_text (const char *text) +{ + text_percent_internal (text, -1); +} + +/** + * glnx_console_unlock: + * + * Print a newline, and reset all cached console progress state. + * + * This function does nothing if stdout is not a tty. + */ +void +glnx_console_unlock (GLnxConsoleRef *console) +{ + g_return_if_fail (locked); + g_return_if_fail (console->locked); + + if (console->is_tty) + fputc ('\n', stdout); + + locked = console->locked = FALSE; +} diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-console.h flatpak-1.0.0/libglnx/glnx-console.h --- flatpak-1.0.0.orig/libglnx/glnx-console.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-console.h 2018-05-26 00:50:25.433037228 +0300 @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2015 Colin Walters + * + * 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 of the licence 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +struct GLnxConsoleRef { + gboolean locked; + gboolean is_tty; +}; + +typedef struct GLnxConsoleRef GLnxConsoleRef; + +gboolean glnx_stdout_is_tty (void); + +void glnx_console_lock (GLnxConsoleRef *ref); + +void glnx_console_text (const char *text); + +void glnx_console_progress_text_percent (const char *text, + guint percentage); + +void glnx_console_progress_n_items (const char *text, + guint current, + guint total); + +void glnx_console_unlock (GLnxConsoleRef *ref); + +guint glnx_console_lines (void); + +guint glnx_console_columns (void); + +static inline void +glnx_console_ref_cleanup (GLnxConsoleRef *p) +{ + if (p->locked) + glnx_console_unlock (p); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxConsoleRef, glnx_console_ref_cleanup) + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-dirfd.c flatpak-1.0.0/libglnx/glnx-dirfd.c --- flatpak-1.0.0.orig/libglnx/glnx-dirfd.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-dirfd.c 2018-05-26 00:50:25.433037228 +0300 @@ -0,0 +1,425 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +/** + * glnx_opendirat_with_errno: + * @dfd: File descriptor for origin directory + * @name: Pathname, relative to @dfd + * @follow: Whether or not to follow symbolic links + * + * Use openat() to open a directory, using a standard set of flags. + * This function sets errno. + */ +int +glnx_opendirat_with_errno (int dfd, + const char *path, + gboolean follow) +{ + int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY; + if (!follow) + flags |= O_NOFOLLOW; + + dfd = glnx_dirfd_canonicalize (dfd); + + return openat (dfd, path, flags); +} + +/** + * glnx_opendirat: + * @dfd: File descriptor for origin directory + * @path: Pathname, relative to @dfd + * @follow: Whether or not to follow symbolic links + * @error: Error + * + * Use openat() to open a directory, using a standard set of flags. + */ +gboolean +glnx_opendirat (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error) +{ + int ret = glnx_opendirat_with_errno (dfd, path, follow); + if (ret == -1) + return glnx_throw_errno_prefix (error, "opendir(%s)", path); + *out_fd = ret; + return TRUE; +} + +struct GLnxRealDirfdIterator +{ + gboolean initialized; + int fd; + DIR *d; +}; +typedef struct GLnxRealDirfdIterator GLnxRealDirfdIterator; + +/** + * glnx_dirfd_iterator_init_at: + * @dfd: File descriptor, may be AT_FDCWD or -1 + * @path: Path, may be relative to @dfd + * @follow: If %TRUE and the last component of @path is a symlink, follow it + * @out_dfd_iter: (out caller-allocates): A directory iterator, will be initialized + * @error: Error + * + * Initialize @out_dfd_iter from @dfd and @path. + */ +gboolean +glnx_dirfd_iterator_init_at (int dfd, + const char *path, + gboolean follow, + GLnxDirFdIterator *out_dfd_iter, + GError **error) +{ + glnx_autofd int fd = -1; + if (!glnx_opendirat (dfd, path, follow, &fd, error)) + return FALSE; + + if (!glnx_dirfd_iterator_init_take_fd (&fd, out_dfd_iter, error)) + return FALSE; + + return TRUE; +} + +/** + * glnx_dirfd_iterator_init_take_fd: + * @dfd: File descriptor - ownership is taken, and the value is set to -1 + * @dfd_iter: A directory iterator + * @error: Error + * + * Steal ownership of @dfd, using it to initialize @dfd_iter for + * iteration. + */ +gboolean +glnx_dirfd_iterator_init_take_fd (int *dfd, + GLnxDirFdIterator *dfd_iter, + GError **error) +{ + GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + DIR *d = fdopendir (*dfd); + if (!d) + return glnx_throw_errno_prefix (error, "fdopendir"); + + real_dfd_iter->fd = glnx_steal_fd (dfd); + real_dfd_iter->d = d; + real_dfd_iter->initialized = TRUE; + + return TRUE; +} + +/** + * glnx_dirfd_iterator_next_dent: + * @dfd_iter: A directory iterator + * @out_dent: (out) (transfer none): Pointer to dirent; do not free + * @cancellable: Cancellable + * @error: Error + * + * Read the next value from @dfd_iter, causing @out_dent to be + * updated. If end of stream is reached, @out_dent will be set + * to %NULL, and %TRUE will be returned. + */ +gboolean +glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error) +{ + GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + + g_return_val_if_fail (out_dent, FALSE); + g_return_val_if_fail (dfd_iter->initialized, FALSE); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + do + { + errno = 0; + *out_dent = readdir (real_dfd_iter->d); + if (*out_dent == NULL && errno != 0) + return glnx_throw_errno_prefix (error, "readdir"); + } while (*out_dent && + (strcmp ((*out_dent)->d_name, ".") == 0 || + strcmp ((*out_dent)->d_name, "..") == 0)); + + return TRUE; +} + +/** + * glnx_dirfd_iterator_next_dent_ensure_dtype: + * @dfd_iter: A directory iterator + * @out_dent: (out) (transfer none): Pointer to dirent; do not free + * @cancellable: Cancellable + * @error: Error + * + * A variant of @glnx_dirfd_iterator_next_dent, which will ensure the + * `dent->d_type` member is filled in by calling `fstatat` + * automatically if the underlying filesystem type sets `DT_UNKNOWN`. + */ +gboolean +glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (out_dent, FALSE); + + if (!glnx_dirfd_iterator_next_dent (dfd_iter, out_dent, cancellable, error)) + return FALSE; + + struct dirent *ret_dent = *out_dent; + if (ret_dent) + { + + if (ret_dent->d_type == DT_UNKNOWN) + { + struct stat stbuf; + if (!glnx_fstatat (dfd_iter->fd, ret_dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + ret_dent->d_type = IFTODT (stbuf.st_mode); + } + } + + return TRUE; +} + +/** + * glnx_dirfd_iterator_clear: + * @dfd_iter: Iterator, will be de-initialized + * + * Unset @dfd_iter, freeing any resources. If @dfd_iter is not + * initialized, do nothing. + */ +void +glnx_dirfd_iterator_clear (GLnxDirFdIterator *dfd_iter) +{ + GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + /* fd is owned by dfd_iter */ + if (!real_dfd_iter->initialized) + return; + (void) closedir (real_dfd_iter->d); + real_dfd_iter->initialized = FALSE; +} + +/** + * glnx_fdrel_abspath: + * @dfd: Directory fd + * @path: Path + * + * Turn a fd-relative pair into something that can be used for legacy + * APIs expecting absolute paths. + * + * This is Linux specific, and only valid inside this process (unless + * you set up the child process to have the exact same fd number, but + * don't try that). + */ +char * +glnx_fdrel_abspath (int dfd, + const char *path) +{ + dfd = glnx_dirfd_canonicalize (dfd); + if (dfd == AT_FDCWD) + return g_strdup (path); + return g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path); +} + +/** + * glnx_gen_temp_name: + * @tmpl: (type filename): template directory name, the last 6 characters will be replaced + * + * Replace the last 6 characters of @tmpl with random ASCII. You must + * use this in combination with a mechanism to ensure race-free file + * creation such as `O_EXCL`. + */ +void +glnx_gen_temp_name (gchar *tmpl) +{ + g_return_if_fail (tmpl != NULL); + const size_t len = strlen (tmpl); + g_return_if_fail (len >= 6); + + static const char letters[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + static const int NLETTERS = sizeof (letters) - 1; + + char *XXXXXX = tmpl + (len - 6); + for (int i = 0; i < 6; i++) + XXXXXX[i] = letters[g_random_int_range(0, NLETTERS)]; +} + +/** + * glnx_mkdtempat: + * @dfd: Directory fd + * @tmpl: (type filename): Initial template directory name, last 6 characters will be replaced + * @mode: permissions with which to create the temporary directory + * @out_tmpdir: (out caller-allocates): Initialized tempdir structure + * @error: Error + * + * Somewhat similar to g_mkdtemp_full(), but fd-relative, and returns a + * structure that uses autocleanups. Note that the supplied @dfd lifetime + * must match or exceed that of @out_tmpdir in order to remove the directory. + */ +gboolean +glnx_mkdtempat (int dfd, const char *tmpl, int mode, + GLnxTmpDir *out_tmpdir, GError **error) +{ + g_return_val_if_fail (tmpl != NULL, FALSE); + g_return_val_if_fail (out_tmpdir != NULL, FALSE); + g_return_val_if_fail (!out_tmpdir->initialized, FALSE); + + dfd = glnx_dirfd_canonicalize (dfd); + + g_autofree char *path = g_strdup (tmpl); + for (int count = 0; count < 100; count++) + { + glnx_gen_temp_name (path); + + /* Ideally we could use openat(O_DIRECTORY | O_CREAT | O_EXCL) here + * to create and open the directory atomically, but that’s not supported by + * current kernel versions: http://www.openwall.com/lists/oss-security/2014/11/26/14 + * (Tested on kernel 4.10.10-200.fc25.x86_64). For the moment, accept a + * TOCTTOU race here. */ + if (mkdirat (dfd, path, mode) == -1) + { + if (errno == EEXIST) + continue; + + /* Any other error will apply also to other names we might + * try, and there are 2^32 or so of them, so give up now. + */ + return glnx_throw_errno_prefix (error, "mkdirat"); + } + + /* And open it */ + glnx_autofd int ret_dfd = -1; + if (!glnx_opendirat (dfd, path, FALSE, &ret_dfd, error)) + { + /* If we fail to open, let's try to clean up */ + (void)unlinkat (dfd, path, AT_REMOVEDIR); + return FALSE; + } + + /* Return the initialized directory struct */ + out_tmpdir->initialized = TRUE; + out_tmpdir->src_dfd = dfd; /* referenced; see above docs */ + out_tmpdir->fd = glnx_steal_fd (&ret_dfd); + out_tmpdir->path = g_steal_pointer (&path); + return TRUE; + } + + /* Failure */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "glnx_mkdtempat ran out of combinations to try"); + return FALSE; +} + +/** + * glnx_mkdtemp: + * @tmpl: (type filename): Source template directory name, last 6 characters will be replaced + * @mode: permissions to create the temporary directory with + * @out_tmpdir: (out caller-allocates): Return location for tmpdir data + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_mkdtempat(), but will use g_get_tmp_dir() as the parent + * directory to @tmpl. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_mkdtemp (const gchar *tmpl, + int mode, + GLnxTmpDir *out_tmpdir, + GError **error) +{ + g_autofree char *path = g_build_filename (g_get_tmp_dir (), tmpl, NULL); + return glnx_mkdtempat (AT_FDCWD, path, mode, + out_tmpdir, error); +} + +static gboolean +_glnx_tmpdir_free (GLnxTmpDir *tmpd, + gboolean delete_dir, + GCancellable *cancellable, + GError **error) +{ + /* Support being passed NULL so we work nicely in a GPtrArray */ + if (!(tmpd && tmpd->initialized)) + return TRUE; + g_assert_cmpint (tmpd->fd, !=, -1); + glnx_close_fd (&tmpd->fd); + g_assert (tmpd->path); + g_assert_cmpint (tmpd->src_dfd, !=, -1); + g_autofree char *path = tmpd->path; /* Take ownership */ + tmpd->initialized = FALSE; + if (delete_dir) + { + if (!glnx_shutil_rm_rf_at (tmpd->src_dfd, path, cancellable, error)) + return FALSE; + } + return TRUE; +} + +/** + * glnx_tmpdir_delete: + * @tmpf: Temporary dir + * @cancellable: Cancellable + * @error: Error + * + * Deallocate a tmpdir, closing the fd and recursively deleting the path. This + * is normally called indirectly via glnx_tmpdir_cleanup() by the autocleanup + * attribute, but you can also invoke this directly. + * + * If an error occurs while deleting the filesystem path, @tmpf will still have + * been deallocated and should not be reused. + * + * See also `glnx_tmpdir_unset` to avoid deleting the path. + */ +gboolean +glnx_tmpdir_delete (GLnxTmpDir *tmpf, GCancellable *cancellable, GError **error) +{ + return _glnx_tmpdir_free (tmpf, TRUE, cancellable, error); +} + +/** + * glnx_tmpdir_unset: + * @tmpf: Temporary dir + * @cancellable: Cancellable + * @error: Error + * + * Deallocate a tmpdir, but do not delete the filesystem path. See also + * `glnx_tmpdir_delete()`. + */ +void +glnx_tmpdir_unset (GLnxTmpDir *tmpf) +{ + (void) _glnx_tmpdir_free (tmpf, FALSE, NULL, NULL); +} diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-dirfd.h flatpak-1.0.0/libglnx/glnx-dirfd.h --- flatpak-1.0.0.orig/libglnx/glnx-dirfd.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-dirfd.h 2018-02-03 21:26:06.308233341 +0300 @@ -0,0 +1,137 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * glnx_dirfd_canonicalize: + * @fd: A directory file descriptor + * + * It's often convenient in programs to use `-1` for "unassigned fd", + * and also because gobject-introspection doesn't support `AT_FDCWD`, + * libglnx honors `-1` to mean `AT_FDCWD`. This small inline function + * canonicalizes `-1 -> AT_FDCWD`. + */ +static inline int +glnx_dirfd_canonicalize (int fd) +{ + if (fd == -1) + return AT_FDCWD; + return fd; +} + +struct GLnxDirFdIterator { + gboolean initialized; + int fd; + gpointer padding_data[4]; +}; + +typedef struct GLnxDirFdIterator GLnxDirFdIterator; +gboolean glnx_dirfd_iterator_init_at (int dfd, const char *path, + gboolean follow, + GLnxDirFdIterator *dfd_iter, GError **error); +gboolean glnx_dirfd_iterator_init_take_fd (int *dfd, GLnxDirFdIterator *dfd_iter, GError **error); +gboolean glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error); +gboolean glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error); +void glnx_dirfd_iterator_clear (GLnxDirFdIterator *dfd_iter); + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxDirFdIterator, glnx_dirfd_iterator_clear) + +int glnx_opendirat_with_errno (int dfd, + const char *path, + gboolean follow); + +gboolean glnx_opendirat (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error); + +char *glnx_fdrel_abspath (int dfd, + const char *path); + +void glnx_gen_temp_name (gchar *tmpl); + +/** + * glnx_ensure_dir: + * @dfd: directory fd + * @path: Directory path + * @mode: Mode + * @error: Return location for a #GError, or %NULL + * + * Wrapper around mkdirat() which adds #GError support, ensures that + * it retries on %EINTR, and also ignores `EEXIST`. + * + * See also `glnx_shutil_mkdir_p_at()` for recursive handling. + * + * Returns: %TRUE on success, %FALSE otherwise + */ +static inline gboolean +glnx_ensure_dir (int dfd, + const char *path, + mode_t mode, + GError **error) +{ + if (TEMP_FAILURE_RETRY (mkdirat (dfd, path, mode)) != 0) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdirat(%s)", path); + } + return TRUE; +} + +typedef struct { + gboolean initialized; + int src_dfd; + int fd; + char *path; +} GLnxTmpDir; +gboolean glnx_tmpdir_delete (GLnxTmpDir *tmpf, GCancellable *cancellable, GError **error); +void glnx_tmpdir_unset (GLnxTmpDir *tmpf); +static inline void +glnx_tmpdir_cleanup (GLnxTmpDir *tmpf) +{ + (void)glnx_tmpdir_delete (tmpf, NULL, NULL); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxTmpDir, glnx_tmpdir_cleanup) + +gboolean glnx_mkdtempat (int dfd, const char *tmpl, int mode, + GLnxTmpDir *out_tmpdir, GError **error); + +gboolean glnx_mkdtemp (const char *tmpl, int mode, + GLnxTmpDir *out_tmpdir, GError **error); + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-errors.c flatpak-1.0.0/libglnx/glnx-errors.c --- flatpak-1.0.0.orig/libglnx/glnx-errors.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-errors.c 2018-05-26 00:50:25.433037228 +0300 @@ -0,0 +1,131 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +/* Set @error with G_IO_ERROR/G_IO_ERROR_FAILED. + * + * This function returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (strcmp (foo, "somevalue") != 0) + * return glnx_throw (error, "key must be somevalue, not '%s'", foo); + * ``` + */ +gboolean +glnx_throw (GError **error, + const char *fmt, + ...) +{ + if (error == NULL) + return FALSE; + + va_list args; + va_start (args, fmt); + GError *new = g_error_new_valist (G_IO_ERROR, G_IO_ERROR_FAILED, fmt, args); + va_end (args); + g_propagate_error (error, g_steal_pointer (&new)); + return FALSE; +} + +void +glnx_real_set_prefix_error_va (GError *error, + const char *format, + va_list args) +{ + if (error == NULL) + return; + + g_autofree char *old_msg = g_steal_pointer (&error->message); + g_autoptr(GString) buf = g_string_new (""); + g_string_append_vprintf (buf, format, args); + g_string_append (buf, ": "); + g_string_append (buf, old_msg); + error->message = g_string_free (g_steal_pointer (&buf), FALSE); +} + +/* Prepend to @error's message by `$prefix: ` where `$prefix` is computed via + * printf @fmt. Returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (!function_that_fails (s, error)) + * return glnx_throw_prefix (error, "while handling '%s'", s); + * ``` + * */ +gboolean +glnx_prefix_error (GError **error, + const char *fmt, + ...) +{ + if (error == NULL) + return FALSE; + + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_va (*error, fmt, args); + va_end (args); + return FALSE; +} + +void +glnx_real_set_prefix_error_from_errno_va (GError **error, + gint errsv, + const char *format, + va_list args) +{ + if (!error) + return; + + g_set_error_literal (error, + G_IO_ERROR, + g_io_error_from_errno (errsv), + g_strerror (errsv)); + glnx_real_set_prefix_error_va (*error, format, args); +} + +/* Set @error using the value of `$prefix: g_strerror (errno)` where `$prefix` + * is computed via printf @fmt. + * + * This function returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * return glnx_throw_errno_prefix (error, "unlinking %s", pathname); + * ``` + */ +gboolean +glnx_throw_errno_prefix (GError **error, + const char *fmt, + ...) +{ + int errsv = errno; + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_from_errno_va (error, errsv, fmt, args); + va_end (args); + /* See comment in glnx_throw_errno() about preserving errno */ + errno = errsv; + return FALSE; +} diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-errors.h flatpak-1.0.0/libglnx/glnx-errors.h --- flatpak-1.0.0.orig/libglnx/glnx-errors.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-errors.h 2018-05-26 00:50:25.433037228 +0300 @@ -0,0 +1,134 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +gboolean glnx_throw (GError **error, const char *fmt, ...) G_GNUC_PRINTF (2,3); + +/* Like `glnx_throw ()`, but returns %NULL. */ +#define glnx_null_throw(error, args...) \ + ({glnx_throw (error, args); NULL;}) + +/* Implementation detail of glnx_throw_prefix() */ +void glnx_real_set_prefix_error_va (GError *error, + const char *format, + va_list args) G_GNUC_PRINTF (2,0); + +gboolean glnx_prefix_error (GError **error, const char *fmt, ...) G_GNUC_PRINTF (2,3); + +/* Like `glnx_prefix_error ()`, but returns %NULL. */ +#define glnx_prefix_error_null(error, args...) \ + ({glnx_prefix_error (error, args); NULL;}) + +/** + * GLNX_AUTO_PREFIX_ERROR: + * + * An autocleanup-based macro to automatically call `g_prefix_error()` (also with a colon+space `: `) + * when it goes out of scope. This is useful when one wants error strings built up by the callee + * function, not all callers. + * + * ``` + * gboolean start_http_request (..., GError **error) + * { + * GLNX_AUTO_PREFIX_ERROR ("HTTP request", error) + * + * if (!libhttp_request_start (..., error)) + * return FALSE; + * ... + * return TRUE; + * ``` + */ +typedef struct { + const char *prefix; + GError **error; +} GLnxAutoErrorPrefix; +static inline void +glnx_cleanup_auto_prefix_error (GLnxAutoErrorPrefix *prefix) +{ + if (prefix->error && *(prefix->error)) + g_prefix_error (prefix->error, "%s: ", prefix->prefix); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxAutoErrorPrefix, glnx_cleanup_auto_prefix_error) +#define GLNX_AUTO_PREFIX_ERROR(text, error) \ + G_GNUC_UNUSED g_auto(GLnxAutoErrorPrefix) _GLNX_MAKE_ANONYMOUS(_glnxautoprefixerror_) = { text, error } + +/* Set @error using the value of `g_strerror (errno)`. + * + * This function returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (unlinkat (fd, somepathname) < 0) + * return glnx_throw_errno (error); + * ``` + */ +static inline gboolean +glnx_throw_errno (GError **error) +{ + /* Save the value of errno, in case one of the + * intermediate function calls happens to set it. + */ + int errsv = errno; + g_set_error_literal (error, G_IO_ERROR, + g_io_error_from_errno (errsv), + g_strerror (errsv)); + /* We also restore the value of errno, since that's + * what was done in a long-ago libgsystem commit + * https://git.gnome.org/browse/libgsystem/commit/?id=ed106741f7a0596dc8b960b31fdae671d31d666d + * but I certainly can't remember now why I did that. + */ + errno = errsv; + return FALSE; +} + +/* Like glnx_throw_errno(), but yields a NULL pointer. */ +#define glnx_null_throw_errno(error) \ + ({glnx_throw_errno (error); NULL;}) + +/* Implementation detail of glnx_throw_errno_prefix() */ +void glnx_real_set_prefix_error_from_errno_va (GError **error, + gint errsv, + const char *format, + va_list args) G_GNUC_PRINTF (3,0); + +gboolean glnx_throw_errno_prefix (GError **error, const char *fmt, ...) G_GNUC_PRINTF (2,3); + +/* Like glnx_throw_errno_prefix(), but yields a NULL pointer. */ +#define glnx_null_throw_errno_prefix(error, args...) \ + ({glnx_throw_errno_prefix (error, args); NULL;}) + +/* BEGIN LEGACY APIS */ + +#define glnx_set_error_from_errno(error) \ + do { \ + glnx_throw_errno (error); \ + } while (0); + +#define glnx_set_prefix_error_from_errno(error, format, args...) \ + do { \ + glnx_throw_errno_prefix (error, format, args); \ + } while (0); + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-fdio.c flatpak-1.0.0/libglnx/glnx-fdio.c --- flatpak-1.0.0.orig/libglnx/glnx-fdio.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-fdio.c 2018-05-26 00:50:25.434037228 +0300 @@ -0,0 +1,1106 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * Portions derived from systemd: + * Copyright 2010 Lennart Poettering + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* The standardized version of BTRFS_IOC_CLONE */ +#ifndef FICLONE +#define FICLONE _IOW(0x94, 9, int) +#endif + +/* Returns the number of chars needed to format variables of the + * specified type as a decimal string. Adds in extra space for a + * negative '-' prefix (hence works correctly on signed + * types). Includes space for the trailing NUL. */ +#define DECIMAL_STR_MAX(type) \ + (2+(sizeof(type) <= 1 ? 3 : \ + sizeof(type) <= 2 ? 5 : \ + sizeof(type) <= 4 ? 10 : \ + sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) + +gboolean +glnx_stdio_file_flush (FILE *f, GError **error) +{ + if (fflush (f) != 0) + return glnx_throw_errno_prefix (error, "fflush"); + if (ferror (f) != 0) + return glnx_throw_errno_prefix (error, "ferror"); + return TRUE; +} + +/* An implementation of renameat2(..., RENAME_NOREPLACE) + * with fallback to a non-atomic version. + */ +int +glnx_renameat2_noreplace (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) +{ +#ifndef ENABLE_WRPSEUDO_COMPAT + if (renameat2 (olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) < 0) + { + if (G_IN_SET(errno, EINVAL, ENOSYS)) + { + /* Fall through */ + } + else + { + return -1; + } + } + else + return TRUE; +#endif + + if (linkat (olddirfd, oldpath, newdirfd, newpath, 0) < 0) + return -1; + + if (unlinkat (olddirfd, oldpath, 0) < 0) + return -1; + + return 0; +} + +static gboolean +rename_file_noreplace_at (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, + gboolean ignore_eexist, + GError **error) +{ + if (glnx_renameat2_noreplace (olddirfd, oldpath, + newdirfd, newpath) < 0) + { + if (errno == EEXIST && ignore_eexist) + { + (void) unlinkat (olddirfd, oldpath, 0); + return TRUE; + } + else + return glnx_throw_errno_prefix (error, "renameat"); + } + return TRUE; +} + +/* An implementation of renameat2(..., RENAME_EXCHANGE) + * with fallback to a non-atomic version. + */ +int +glnx_renameat2_exchange (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) +{ +#ifndef ENABLE_WRPSEUDO_COMPAT + if (renameat2 (olddirfd, oldpath, newdirfd, newpath, RENAME_EXCHANGE) == 0) + return 0; + else + { + if (G_IN_SET(errno, ENOSYS, EINVAL)) + { + /* Fall through */ + } + else + { + return -1; + } + } +#endif + + /* Fallback */ + { char *old_tmp_name_buf = glnx_strjoina (oldpath, ".XXXXXX"); + /* This obviously isn't race-free, but doing better gets tricky, since if + * we're here the kernel isn't likely to support RENAME_NOREPLACE either. + * Anyways, upgrade the kernel. Failing that, avoid use of this function in + * shared subdirectories like /tmp. + */ + glnx_gen_temp_name (old_tmp_name_buf); + const char *old_tmp_name = old_tmp_name_buf; + + /* Move old out of the way */ + if (renameat (olddirfd, oldpath, olddirfd, old_tmp_name) < 0) + return -1; + /* Now move new into its place */ + if (renameat (newdirfd, newpath, olddirfd, oldpath) < 0) + return -1; + /* And finally old(tmp) into new */ + if (renameat (olddirfd, old_tmp_name, newdirfd, newpath) < 0) + return -1; + } + return 0; +} + +/* Deallocate a tmpfile, closing the fd and deleting the path, if any. This is + * normally called by default by the autocleanup attribute, but you can also + * invoke this directly. + */ +void +glnx_tmpfile_clear (GLnxTmpfile *tmpf) +{ + /* Support being passed NULL so we work nicely in a GPtrArray */ + if (!tmpf) + return; + if (!tmpf->initialized) + return; + glnx_close_fd (&tmpf->fd); + /* If ->path is set, we're likely aborting due to an error. Clean it up */ + if (tmpf->path) + { + (void) unlinkat (tmpf->src_dfd, tmpf->path, 0); + g_free (tmpf->path); + } + tmpf->initialized = FALSE; +} + +static gboolean +open_tmpfile_core (int dfd, const char *subpath, + int flags, + GLnxTmpfile *out_tmpf, + GError **error) +{ + /* Picked this to match mkstemp() */ + const guint mode = 0600; + + dfd = glnx_dirfd_canonicalize (dfd); + + /* Creates a temporary file, that shall be renamed to "target" + * later. If possible, this uses O_TMPFILE – in which case + * "ret_path" will be returned as NULL. If not possible a the + * tempoary path name used is returned in "ret_path". Use + * link_tmpfile() below to rename the result after writing the file + * in full. */ +#if defined(O_TMPFILE) && !defined(DISABLE_OTMPFILE) && !defined(ENABLE_WRPSEUDO_COMPAT) + { + glnx_autofd int fd = openat (dfd, subpath, O_TMPFILE|flags, mode); + if (fd == -1 && !(G_IN_SET(errno, ENOSYS, EISDIR, EOPNOTSUPP))) + return glnx_throw_errno_prefix (error, "open(O_TMPFILE)"); + if (fd != -1) + { + /* Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17523 + * See also https://github.com/ostreedev/ostree/issues/991 + */ + if (fchmod (fd, mode) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + out_tmpf->initialized = TRUE; + out_tmpf->src_dfd = dfd; /* Copied; caller must keep open */ + out_tmpf->fd = glnx_steal_fd (&fd); + out_tmpf->path = NULL; + return TRUE; + } + } + /* Fallthrough */ +#endif + + const guint count_max = 100; + { g_autofree char *tmp = g_strconcat (subpath, "/tmp.XXXXXX", NULL); + + for (int count = 0; count < count_max; count++) + { + glnx_gen_temp_name (tmp); + + glnx_autofd int fd = openat (dfd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, mode); + if (fd < 0) + { + if (errno == EEXIST) + continue; + else + return glnx_throw_errno_prefix (error, "Creating temp file"); + } + else + { + out_tmpf->initialized = TRUE; + out_tmpf->src_dfd = dfd; /* Copied; caller must keep open */ + out_tmpf->fd = glnx_steal_fd (&fd); + out_tmpf->path = g_steal_pointer (&tmp); + return TRUE; + } + } + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Exhausted %u attempts to create temporary file", count_max); + return FALSE; +} + +/* Allocate a temporary file, using Linux O_TMPFILE if available. The file mode + * will be 0600. + * + * The result will be stored in @out_tmpf, which is caller allocated + * so you can store it on the stack in common scenarios. + * + * The directory fd @dfd must live at least as long as the output @out_tmpf. + */ +gboolean +glnx_open_tmpfile_linkable_at (int dfd, + const char *subpath, + int flags, + GLnxTmpfile *out_tmpf, + GError **error) +{ + /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE; + * it's used for glnx_open_anonymous_tmpfile(). + */ + g_return_val_if_fail ((flags & O_EXCL) == 0, FALSE); + + return open_tmpfile_core (dfd, subpath, flags, out_tmpf, error); +} + +/* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking. + * Useful for true temporary storage. The fd will be allocated in /var/tmp to + * ensure maximum storage space. + */ +gboolean +glnx_open_anonymous_tmpfile (int flags, + GLnxTmpfile *out_tmpf, + GError **error) +{ + /* Add in O_EXCL */ + if (!open_tmpfile_core (AT_FDCWD, "/var/tmp", flags | O_EXCL, out_tmpf, error)) + return FALSE; + if (out_tmpf->path) + { + (void) unlinkat (out_tmpf->src_dfd, out_tmpf->path, 0); + g_clear_pointer (&out_tmpf->path, g_free); + } + out_tmpf->anonymous = TRUE; + out_tmpf->src_dfd = -1; + return TRUE; +} + +/* Use this after calling glnx_open_tmpfile_linkable_at() to give + * the file its final name (link into place). + */ +gboolean +glnx_link_tmpfile_at (GLnxTmpfile *tmpf, + GLnxLinkTmpfileReplaceMode mode, + int target_dfd, + const char *target, + GError **error) +{ + const gboolean replace = (mode == GLNX_LINK_TMPFILE_REPLACE); + const gboolean ignore_eexist = (mode == GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST); + + g_return_val_if_fail (!tmpf->anonymous, FALSE); + g_return_val_if_fail (tmpf->fd >= 0, FALSE); + g_return_val_if_fail (tmpf->src_dfd == AT_FDCWD || tmpf->src_dfd >= 0, FALSE); + + /* Unlike the original systemd code, this function also supports + * replacing existing files. + */ + + /* We have `tmpfile_path` for old systems without O_TMPFILE. */ + if (tmpf->path) + { + if (replace) + { + /* We have a regular tempfile, we're overwriting - this is a + * simple renameat(). + */ + if (renameat (tmpf->src_dfd, tmpf->path, target_dfd, target) < 0) + return glnx_throw_errno_prefix (error, "renameat"); + } + else + { + /* We need to use renameat2(..., NOREPLACE) or emulate it */ + if (!rename_file_noreplace_at (tmpf->src_dfd, tmpf->path, target_dfd, target, + ignore_eexist, + error)) + return FALSE; + } + /* Now, clear the pointer so we don't try to unlink it */ + g_clear_pointer (&tmpf->path, g_free); + } + else + { + /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */ + char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1]; + + sprintf (proc_fd_path, "/proc/self/fd/%i", tmpf->fd); + + if (replace) + { + /* In this case, we had our temp file atomically hidden, but now + * we need to make it visible in the FS so we can do a rename. + * Ideally, linkat() would gain AT_REPLACE or so. + */ + /* TODO - avoid double alloca, we can just alloca a copy of + * the pathname plus space for tmp.XXXXX */ + char *dnbuf = strdupa (target); + const char *dn = dirname (dnbuf); + char *tmpname_buf = glnx_strjoina (dn, "/tmp.XXXXXX"); + + const guint count_max = 100; + guint count; + for (count = 0; count < count_max; count++) + { + glnx_gen_temp_name (tmpname_buf); + + if (linkat (AT_FDCWD, proc_fd_path, target_dfd, tmpname_buf, AT_SYMLINK_FOLLOW) < 0) + { + if (errno == EEXIST) + continue; + else + return glnx_throw_errno_prefix (error, "linkat"); + } + else + break; + } + if (count == count_max) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Exhausted %u attempts to create temporary file", count); + return FALSE; + } + if (!glnx_renameat (target_dfd, tmpname_buf, target_dfd, target, error)) + { + /* This is currently the only case where we need to have + * a cleanup unlinkat() still with O_TMPFILE. + */ + (void) unlinkat (target_dfd, tmpname_buf, 0); + return FALSE; + } + } + else + { + if (linkat (AT_FDCWD, proc_fd_path, target_dfd, target, AT_SYMLINK_FOLLOW) < 0) + { + if (errno == EEXIST && mode == GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST) + ; + else + return glnx_throw_errno_prefix (error, "linkat"); + } + } + + } + return TRUE; +} + +/** + * glnx_openat_rdonly: + * @dfd: File descriptor for origin directory + * @path: Pathname, relative to @dfd + * @follow: Whether or not to follow symbolic links in the final component + * @out_fd: (out): File descriptor + * @error: Error + * + * Use openat() to open a file, with flags `O_RDONLY | O_CLOEXEC | O_NOCTTY`. + * Like the other libglnx wrappers, will use `TEMP_FAILURE_RETRY` and + * also includes @path in @error in case of failure. + */ +gboolean +glnx_openat_rdonly (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error) +{ + int flags = O_RDONLY | O_CLOEXEC | O_NOCTTY; + if (!follow) + flags |= O_NOFOLLOW; + int fd = TEMP_FAILURE_RETRY (openat (dfd, path, flags)); + if (fd == -1) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + *out_fd = fd; + return TRUE; +} + +static guint8* +glnx_fd_readall_malloc (int fd, + gsize *out_len, + gboolean nul_terminate, + GCancellable *cancellable, + GError **error) +{ + const guint maxreadlen = 4096; + + struct stat stbuf; + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; + + gsize buf_allocated; + if (S_ISREG (stbuf.st_mode) && stbuf.st_size > 0) + buf_allocated = stbuf.st_size; + else + buf_allocated = 16; + + g_autofree guint8* buf = g_malloc (buf_allocated); + + gsize buf_size = 0; + while (TRUE) + { + gsize readlen = MIN (buf_allocated - buf_size, maxreadlen); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + gssize bytes_read; + do + bytes_read = read (fd, buf + buf_size, readlen); + while (G_UNLIKELY (bytes_read == -1 && errno == EINTR)); + if (G_UNLIKELY (bytes_read == -1)) + return glnx_null_throw_errno (error); + if (bytes_read == 0) + break; + + buf_size += bytes_read; + if (buf_allocated - buf_size < maxreadlen) + buf = g_realloc (buf, buf_allocated *= 2); + } + + if (nul_terminate) + { + if (buf_allocated - buf_size == 0) + buf = g_realloc (buf, buf_allocated + 1); + buf[buf_size] = '\0'; + } + + *out_len = buf_size; + return g_steal_pointer (&buf); +} + +/** + * glnx_fd_readall_bytes: + * @fd: A file descriptor + * @cancellable: Cancellable: + * @error: Error + * + * Read all data from file descriptor @fd into a #GBytes. It's + * recommended to only use this for small files. + * + * Returns: (transfer full): A newly allocated #GBytes + */ +GBytes * +glnx_fd_readall_bytes (int fd, + GCancellable *cancellable, + GError **error) +{ + gsize len; + guint8 *buf = glnx_fd_readall_malloc (fd, &len, FALSE, cancellable, error); + if (!buf) + return NULL; + return g_bytes_new_take (buf, len); +} + +/** + * glnx_fd_readall_utf8: + * @fd: A file descriptor + * @out_len: (out): Returned length + * @cancellable: Cancellable: + * @error: Error + * + * Read all data from file descriptor @fd, validating + * the result as UTF-8. + * + * Returns: (transfer full): A string validated as UTF-8, or %NULL on error. + */ +char * +glnx_fd_readall_utf8 (int fd, + gsize *out_len, + GCancellable *cancellable, + GError **error) +{ + gsize len; + g_autofree guint8 *buf = glnx_fd_readall_malloc (fd, &len, TRUE, cancellable, error); + if (!buf) + return FALSE; + + if (!g_utf8_validate ((char*)buf, len, NULL)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Invalid UTF-8"); + return FALSE; + } + + if (out_len) + *out_len = len; + return (char*)g_steal_pointer (&buf); +} + +/** + * glnx_file_get_contents_utf8_at: + * @dfd: Directory file descriptor + * @subpath: Path relative to @dfd + * @out_len: (out) (allow-none): Optional length + * @cancellable: Cancellable + * @error: Error + * + * Read the entire contents of the file referred + * to by @dfd and @subpath, validate the result as UTF-8. + * The length is optionally stored in @out_len. + * + * Returns: (transfer full): UTF-8 validated text, or %NULL on error + */ +char * +glnx_file_get_contents_utf8_at (int dfd, + const char *subpath, + gsize *out_len, + GCancellable *cancellable, + GError **error) +{ + dfd = glnx_dirfd_canonicalize (dfd); + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd, subpath, TRUE, &fd, error)) + return NULL; + + gsize len; + g_autofree char *buf = glnx_fd_readall_utf8 (fd, &len, cancellable, error); + if (G_UNLIKELY(!buf)) + return FALSE; + + if (out_len) + *out_len = len; + return g_steal_pointer (&buf); +} + +/** + * glnx_readlinkat_malloc: + * @dfd: Directory file descriptor + * @subpath: Subpath + * @cancellable: Cancellable + * @error: Error + * + * Read the value of a symlink into a dynamically + * allocated buffer. + */ +char * +glnx_readlinkat_malloc (int dfd, + const char *subpath, + GCancellable *cancellable, + GError **error) +{ + dfd = glnx_dirfd_canonicalize (dfd); + + size_t l = 100; + for (;;) + { + g_autofree char *c = g_malloc (l); + ssize_t n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1)); + if (n < 0) + return glnx_null_throw_errno_prefix (error, "readlinkat"); + + if ((size_t) n < l-1) + { + c[n] = 0; + return g_steal_pointer (&c); + } + + l *= 2; + } + + g_assert_not_reached (); +} + +static gboolean +copy_symlink_at (int src_dfd, + const char *src_subpath, + const struct stat *src_stbuf, + int dest_dfd, + const char *dest_subpath, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *buf = glnx_readlinkat_malloc (src_dfd, src_subpath, cancellable, error); + if (!buf) + return FALSE; + + if (TEMP_FAILURE_RETRY (symlinkat (buf, dest_dfd, dest_subpath)) != 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + + if (!(copyflags & GLNX_FILE_COPY_NOXATTRS)) + { + g_autoptr(GVariant) xattrs = NULL; + + if (!glnx_dfd_name_get_all_xattrs (src_dfd, src_subpath, &xattrs, + cancellable, error)) + return FALSE; + + if (!glnx_dfd_name_set_all_xattrs (dest_dfd, dest_subpath, xattrs, + cancellable, error)) + return FALSE; + } + + if (TEMP_FAILURE_RETRY (fchownat (dest_dfd, dest_subpath, + src_stbuf->st_uid, src_stbuf->st_gid, + AT_SYMLINK_NOFOLLOW)) != 0) + return glnx_throw_errno_prefix (error, "fchownat"); + + return TRUE; +} + +#define COPY_BUFFER_SIZE (16*1024) + +/* Most of the code below is from systemd, but has been reindented to GNU style, + * and changed to use POSIX error conventions (return -1, set errno) to more + * conveniently fit in with the rest of libglnx. + */ + +/* Like write(), but loop until @nbytes are written, or an error + * occurs. + * + * On error, -1 is returned an @errno is set. NOTE: This is an + * API change from previous versions of this function. + */ +int +glnx_loop_write(int fd, const void *buf, size_t nbytes) +{ + g_return_val_if_fail (fd >= 0, -1); + g_return_val_if_fail (buf, -1); + + errno = 0; + + const uint8_t *p = buf; + while (nbytes > 0) + { + ssize_t k = write(fd, p, nbytes); + if (k < 0) + { + if (errno == EINTR) + continue; + + return -1; + } + + if (k == 0) /* Can't really happen */ + { + errno = EIO; + return -1; + } + + p += k; + nbytes -= k; + } + + return 0; +} + +/* Read from @fdf until EOF, writing to @fdt. If max_bytes is -1, a full-file + * clone will be attempted. Otherwise Linux copy_file_range(), sendfile() + * syscall will be attempted. If none of those work, this function will do a + * plain read()/write() loop. + * + * The file descriptor @fdf must refer to a regular file. + * + * If provided, @max_bytes specifies the maximum number of bytes to read from @fdf. + * On error, this function returns `-1` and @errno will be set. + */ +int +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes) +{ + /* Last updates from systemd as of commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca */ + static int have_cfr = -1; /* -1 means unknown */ + bool try_cfr = have_cfr != 0; + static int have_sendfile = -1; /* -1 means unknown */ + bool try_sendfile = have_sendfile != 0; + + g_return_val_if_fail (fdf >= 0, -1); + g_return_val_if_fail (fdt >= 0, -1); + g_return_val_if_fail (max_bytes >= -1, -1); + + /* If we've requested to copy the whole range, try a full-file clone first. + */ + if (max_bytes == (off_t) -1) + { + if (ioctl (fdt, FICLONE, fdf) == 0) + return 0; + /* Fall through */ + struct stat stbuf; + + /* Gather the size so we can provide the whole thing at once to + * copy_file_range() or sendfile(). + */ + if (fstat (fdf, &stbuf) < 0) + return -1; + max_bytes = stbuf.st_size; + } + + while (TRUE) + { + ssize_t n; + + /* First, try copy_file_range(). Note this is an inlined version of + * try_copy_file_range() from systemd upstream, which works better since + * we use POSIX errno style. + */ + if (try_cfr) + { + n = copy_file_range (fdf, NULL, fdt, NULL, max_bytes, 0u); + if (n < 0) + { + if (errno == ENOSYS) + { + /* No cfr in kernel, mark as permanently unavailable + * and fall through to sendfile(). + */ + have_cfr = 0; + try_cfr = false; + } + else if (errno == EXDEV) + /* We won't try cfr again for this run, but let's be + * conservative and not mark it as available/unavailable until + * we know for sure. + */ + try_cfr = false; + else + return -1; + } + else + { + /* cfr worked, mark it as available */ + if (have_cfr == -1) + have_cfr = 1; + + if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + } + + /* Next try sendfile(); this version is also changed from systemd upstream + * to match the same logic we have for copy_file_range(). + */ + if (try_sendfile) + { + n = sendfile (fdt, fdf, NULL, max_bytes); + if (n < 0) + { + if (G_IN_SET (errno, EINVAL, ENOSYS)) + { + /* No sendfile(), or it doesn't work on regular files. + * Mark it as permanently unavailable, and fall through + * to plain read()/write(). + */ + have_sendfile = 0; + try_sendfile = false; + } + else + return -1; + } + else + { + /* sendfile() worked, mark it as available */ + if (have_sendfile == -1) + have_sendfile = 1; + + if (n == 0) /* EOF */ + break; + else if (n > 0) + /* Succcess! */ + goto next; + } + } + + /* As a fallback just copy bits by hand */ + { size_t m = COPY_BUFFER_SIZE; + if (max_bytes != (off_t) -1) + { + if ((off_t) m > max_bytes) + m = (size_t) max_bytes; + } + char buf[m]; + + n = TEMP_FAILURE_RETRY (read (fdf, buf, m)); + if (n < 0) + return -1; + if (n == 0) /* EOF */ + break; + + if (glnx_loop_write (fdt, buf, (size_t) n) < 0) + return -1; + } + + next: + if (max_bytes != (off_t) -1) + { + g_assert_cmpint (max_bytes, >=, n); + max_bytes -= n; + if (max_bytes == 0) + break; + } + } + + return 0; +} + +/** + * glnx_file_copy_at: + * @src_dfd: Source directory fd + * @src_subpath: Subpath relative to @src_dfd + * @src_stbuf: (allow-none): Optional stat buffer for source; if a stat() has already been done + * @dest_dfd: Target directory fd + * @dest_subpath: Destination name + * @copyflags: Flags + * @cancellable: cancellable + * @error: Error + * + * Perform a full copy of the regular file or symbolic link from @src_subpath to + * @dest_subpath; if @src_subpath is anything other than a regular file or + * symbolic link, an error will be returned. + * + * If the source is a regular file and the destination exists as a symbolic + * link, the symbolic link will not be followed; rather the link itself will be + * replaced. Related to this: for regular files, when `GLNX_FILE_COPY_OVERWRITE` + * is specified, this function always uses `O_TMPFILE` (if available) and does a + * rename-into-place rather than `open(O_TRUNC)`. + */ +gboolean +glnx_file_copy_at (int src_dfd, + const char *src_subpath, + struct stat *src_stbuf, + int dest_dfd, + const char *dest_subpath, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error) +{ + /* Canonicalize dfds */ + src_dfd = glnx_dirfd_canonicalize (src_dfd); + dest_dfd = glnx_dirfd_canonicalize (dest_dfd); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + /* Automatically do stat() if no stat buffer was supplied */ + struct stat local_stbuf; + if (!src_stbuf) + { + if (!glnx_fstatat (src_dfd, src_subpath, &local_stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + src_stbuf = &local_stbuf; + } + + /* For symlinks, defer entirely to copy_symlink_at() */ + if (S_ISLNK (src_stbuf->st_mode)) + { + return copy_symlink_at (src_dfd, src_subpath, src_stbuf, + dest_dfd, dest_subpath, + copyflags, + cancellable, error); + } + else if (!S_ISREG (src_stbuf->st_mode)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Cannot copy non-regular/non-symlink file: %s", src_subpath); + return FALSE; + } + + /* Regular file path below here */ + + glnx_autofd int src_fd = -1; + if (!glnx_openat_rdonly (src_dfd, src_subpath, FALSE, &src_fd, error)) + return FALSE; + + /* Open a tmpfile for dest. Particularly for AT_FDCWD calls, we really want to + * open in the target directory, otherwise we may not be able to link. + */ + g_auto(GLnxTmpfile) tmp_dest = { 0, }; + { char *dnbuf = strdupa (dest_subpath); + const char *dn = dirname (dnbuf); + if (!glnx_open_tmpfile_linkable_at (dest_dfd, dn, O_WRONLY | O_CLOEXEC, + &tmp_dest, error)) + return FALSE; + } + + if (glnx_regfile_copy_bytes (src_fd, tmp_dest.fd, (off_t) -1) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + + if (fchown (tmp_dest.fd, src_stbuf->st_uid, src_stbuf->st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + + if (!(copyflags & GLNX_FILE_COPY_NOXATTRS)) + { + g_autoptr(GVariant) xattrs = NULL; + + if (!glnx_fd_get_all_xattrs (src_fd, &xattrs, + cancellable, error)) + return FALSE; + + if (!glnx_fd_set_all_xattrs (tmp_dest.fd, xattrs, + cancellable, error)) + return FALSE; + } + + /* Always chmod after setting xattrs, in case the file has mode 0400 or less, + * like /etc/shadow. Linux currently allows write() on non-writable open files + * but not fsetxattr(). + */ + if (fchmod (tmp_dest.fd, src_stbuf->st_mode & 07777) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + struct timespec ts[2]; + ts[0] = src_stbuf->st_atim; + ts[1] = src_stbuf->st_mtim; + (void) futimens (tmp_dest.fd, ts); + + if (copyflags & GLNX_FILE_COPY_DATASYNC) + { + if (fdatasync (tmp_dest.fd) < 0) + return glnx_throw_errno_prefix (error, "fdatasync"); + } + + const GLnxLinkTmpfileReplaceMode replacemode = + (copyflags & GLNX_FILE_COPY_OVERWRITE) ? + GLNX_LINK_TMPFILE_REPLACE : + GLNX_LINK_TMPFILE_NOREPLACE; + + if (!glnx_link_tmpfile_at (&tmp_dest, replacemode, dest_dfd, dest_subpath, error)) + return FALSE; + + return TRUE; +} + +/** + * glnx_file_replace_contents_at: + * @dfd: Directory fd + * @subpath: Subpath + * @buf: (array len=len) (element-type guint8): File contents + * @len: Length (if `-1`, assume @buf is `NUL` terminated) + * @flags: Flags + * @cancellable: Cancellable + * @error: Error + * + * Create a new file, atomically replacing the contents of @subpath + * (relative to @dfd) with @buf. By default, if the file already + * existed, fdatasync() will be used before rename() to ensure stable + * contents. This and other behavior can be controlled via @flags. + * + * Note that no metadata from the existing file is preserved, such as + * uid/gid or extended attributes. The default mode will be `0666`, + * modified by umask. + */ +gboolean +glnx_file_replace_contents_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error) +{ + return glnx_file_replace_contents_with_perms_at (dfd, subpath, buf, len, + (mode_t) -1, (uid_t) -1, (gid_t) -1, + flags, cancellable, error); +} + +/** + * glnx_file_replace_contents_with_perms_at: + * @dfd: Directory fd + * @subpath: Subpath + * @buf: (array len=len) (element-type guint8): File contents + * @len: Length (if `-1`, assume @buf is `NUL` terminated) + * @mode: File mode; if `-1`, use `0666 - umask` + * @flags: Flags + * @cancellable: Cancellable + * @error: Error + * + * Like glnx_file_replace_contents_at(), but also supports + * setting mode, and uid/gid. + */ +gboolean +glnx_file_replace_contents_with_perms_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + mode_t mode, + uid_t uid, + gid_t gid, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error) +{ + char *dnbuf = strdupa (subpath); + const char *dn = dirname (dnbuf); + + dfd = glnx_dirfd_canonicalize (dfd); + + /* With O_TMPFILE we can't use umask, and we can't sanely query the + * umask...let's assume something relatively standard. + */ + if (mode == (mode_t) -1) + mode = 0644; + + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (dfd, dn, O_WRONLY | O_CLOEXEC, + &tmpf, error)) + return FALSE; + + if (len == -1) + len = strlen ((char*)buf); + + if (!glnx_try_fallocate (tmpf.fd, 0, len, error)) + return FALSE; + + if (glnx_loop_write (tmpf.fd, buf, len) < 0) + return glnx_throw_errno_prefix (error, "write"); + + if (!(flags & GLNX_FILE_REPLACE_NODATASYNC)) + { + struct stat stbuf; + gboolean do_sync; + + if (!glnx_fstatat_allow_noent (dfd, subpath, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + do_sync = (flags & GLNX_FILE_REPLACE_DATASYNC_NEW) > 0; + else + do_sync = TRUE; + + if (do_sync) + { + if (fdatasync (tmpf.fd) != 0) + return glnx_throw_errno_prefix (error, "fdatasync"); + } + } + + if (uid != (uid_t) -1) + { + if (fchown (tmpf.fd, uid, gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + } + + if (fchmod (tmpf.fd, mode) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, + dfd, subpath, error)) + return FALSE; + + return TRUE; +} diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-fdio.h flatpak-1.0.0/libglnx/glnx-fdio.h --- flatpak-1.0.0.orig/libglnx/glnx-fdio.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-fdio.h 2018-05-26 00:50:25.434037228 +0300 @@ -0,0 +1,369 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// For dirname(), and previously basename() +#include + +#include +#include + +G_BEGIN_DECLS + +/* Irritatingly, g_basename() which is what we want + * is deprecated. + */ +static inline +const char *glnx_basename (const char *path) +{ + gchar *base = strrchr (path, G_DIR_SEPARATOR); + + if (base) + return base + 1; + + return path; +} + +/* Utilities for standard FILE* */ +static inline void +glnx_stdio_file_cleanup (void *filep) +{ + FILE *f = filep; + if (f) + fclose (f); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FILE, glnx_stdio_file_cleanup) + +/** + * glnx_stdio_file_flush: + * Call fflush() and check ferror(). + */ +gboolean +glnx_stdio_file_flush (FILE *f, GError **error); + +typedef struct { + gboolean initialized; + gboolean anonymous; + int src_dfd; + int fd; + char *path; +} GLnxTmpfile; +void glnx_tmpfile_clear (GLnxTmpfile *tmpf); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxTmpfile, glnx_tmpfile_clear) + +gboolean +glnx_open_anonymous_tmpfile (int flags, + GLnxTmpfile *out_tmpf, + GError **error); + +gboolean +glnx_open_tmpfile_linkable_at (int dfd, + const char *subpath, + int flags, + GLnxTmpfile *out_tmpf, + GError **error); + +typedef enum { + GLNX_LINK_TMPFILE_REPLACE, + GLNX_LINK_TMPFILE_NOREPLACE, + GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST +} GLnxLinkTmpfileReplaceMode; + +gboolean +glnx_link_tmpfile_at (GLnxTmpfile *tmpf, + GLnxLinkTmpfileReplaceMode flags, + int target_dfd, + const char *target, + GError **error); + +gboolean +glnx_openat_rdonly (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error); + +GBytes * +glnx_fd_readall_bytes (int fd, + GCancellable *cancellable, + GError **error); + +char * +glnx_fd_readall_utf8 (int fd, + gsize *out_len, + GCancellable *cancellable, + GError **error); + +char * +glnx_file_get_contents_utf8_at (int dfd, + const char *subpath, + gsize *out_len, + GCancellable *cancellable, + GError **error); + +/** + * GLnxFileReplaceFlags: + * @GLNX_FILE_REPLACE_DATASYNC_NEW: Call fdatasync() even if the file did not exist + * @GLNX_FILE_REPLACE_NODATASYNC: Never call fdatasync() + * + * Flags controlling file replacement. + */ +typedef enum { + GLNX_FILE_REPLACE_DATASYNC_NEW = (1 << 0), + GLNX_FILE_REPLACE_NODATASYNC = (1 << 1), +} GLnxFileReplaceFlags; + +gboolean +glnx_file_replace_contents_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_file_replace_contents_with_perms_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + mode_t mode, + uid_t uid, + gid_t gid, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error); + +char * +glnx_readlinkat_malloc (int dfd, + const char *subpath, + GCancellable *cancellable, + GError **error); + +int +glnx_loop_write (int fd, const void *buf, size_t nbytes); + +int +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes); + +typedef enum { + GLNX_FILE_COPY_OVERWRITE = (1 << 0), + GLNX_FILE_COPY_NOXATTRS = (1 << 1), + GLNX_FILE_COPY_DATASYNC = (1 << 2) +} GLnxFileCopyFlags; + +gboolean +glnx_file_copy_at (int src_dfd, + const char *src_subpath, + struct stat *src_stbuf, + int dest_dfd, + const char *dest_subpath, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error); + +int glnx_renameat2_noreplace (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath); +int glnx_renameat2_exchange (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath); + +/** + * glnx_try_fallocate: + * @fd: File descriptor + * @size: Size + * @error: Error + * + * Wrapper for Linux fallocate(). Explicitly ignores a @size of zero. + * Also, will silently do nothing if the underlying filesystem doesn't + * support it. Use this instead of posix_fallocate(), since the glibc fallback + * is bad: https://sourceware.org/bugzilla/show_bug.cgi?id=18515 + */ +static inline gboolean +glnx_try_fallocate (int fd, + off_t offset, + off_t size, + GError **error) +{ + /* This is just nicer than throwing an error */ + if (size == 0) + return TRUE; + + if (fallocate (fd, 0, offset, size) < 0) + { + if (G_IN_SET(errno, ENOSYS, EOPNOTSUPP)) + ; /* Ignore */ + else + return glnx_throw_errno_prefix (error, "fallocate"); + } + + return TRUE; +} + +/** + * glnx_fstat: + * @fd: FD to stat + * @buf: (out caller-allocates): Return location for stat details + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fstat() which adds #GError support and ensures that it retries + * on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstat (int fd, + struct stat *buf, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstat (fd, buf)) != 0) + return glnx_throw_errno_prefix (error, "fstat"); + return TRUE; +} + +/** + * glnx_fchmod: + * @fd: FD + * @mode: Mode + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fchmod() which adds #GError support and ensures that it + * retries on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fchmod (int fd, + mode_t mode, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fchmod (fd, mode)) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + return TRUE; +} + +/** + * glnx_fstatat: + * @dfd: Directory FD to stat beneath + * @path: Path to stat beneath @dfd + * @buf: (out caller-allocates): Return location for stat details + * @flags: Flags to pass to fstatat() + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fstatat() which adds #GError support and ensures that it + * retries on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstatat (int dfd, + const gchar *path, + struct stat *buf, + int flags, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstatat (dfd, path, buf, flags)) != 0) + return glnx_throw_errno_prefix (error, "fstatat(%s)", path); + return TRUE; +} + +/** + * glnx_fstatat_allow_noent: + * @dfd: Directory FD to stat beneath + * @path: Path to stat beneath @dfd + * @buf: (out caller-allocates) (allow-none): Return location for stat details + * @flags: Flags to pass to fstatat() + * @error: Return location for a #GError, or %NULL + * + * Like glnx_fstatat(), but handles `ENOENT` in a non-error way. Instead, + * on success `errno` will be zero, otherwise it will be preserved. Hence + * you can test `if (errno == 0)` to conditionalize on the file existing, + * or `if (errno == ENOENT)` for non-existence. + * + * Returns: %TRUE on success, %FALSE otherwise (errno is preserved) + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstatat_allow_noent (int dfd, + const char *path, + struct stat *out_buf, + int flags, + GError **error) +{ + G_GNUC_UNUSED struct stat unused_stbuf; + if (TEMP_FAILURE_RETRY (fstatat (dfd, path, out_buf ? out_buf : &unused_stbuf, flags)) != 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat(%s)", path); + /* Note we preserve errno as ENOENT */ + } + else + errno = 0; + return TRUE; +} + +/** + * glnx_renameat: + * + * Wrapper around renameat() which adds #GError support and ensures that it + * retries on %EINTR. + */ +static inline gboolean +glnx_renameat (int src_dfd, + const gchar *src_path, + int dest_dfd, + const gchar *dest_path, + GError **error) +{ + if (TEMP_FAILURE_RETRY (renameat (src_dfd, src_path, dest_dfd, dest_path)) != 0) + return glnx_throw_errno_prefix (error, "renameat(%s, %s)", src_path, dest_path); + return TRUE; +} + +/** + * glnx_unlinkat: + * + * Wrapper around unlinkat() which adds #GError support and ensures that it + * retries on %EINTR. + */ +static inline gboolean +glnx_unlinkat (int dfd, + const gchar *path, + int flags, + GError **error) +{ + if (TEMP_FAILURE_RETRY (unlinkat (dfd, path, flags)) != 0) + return glnx_throw_errno_prefix (error, "unlinkat(%s)", path); + return TRUE; +} + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-local-alloc.c flatpak-1.0.0/libglnx/glnx-local-alloc.c --- flatpak-1.0.0.orig/libglnx/glnx-local-alloc.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-local-alloc.c 2018-02-03 21:26:06.308233341 +0300 @@ -0,0 +1,72 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012,2015 Colin Walters + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-local-alloc.h" + +/** + * SECTION:glnxlocalalloc + * @title: GLnx local allocation + * @short_description: Release local variables automatically when they go out of scope + * + * These macros leverage the GCC extension __attribute__ ((cleanup)) + * to allow calling a cleanup function such as g_free() when a + * variable goes out of scope. See + * for more information on the attribute. + * + * The provided macros make it easy to use the cleanup attribute for + * types that come with GLib. The primary two are #glnx_free and + * #glnx_unref_object, which correspond to g_free() and + * g_object_unref(), respectively. + * + * The rationale behind this is that particularly when handling error + * paths, it can be very tricky to ensure the right variables are + * freed. With this, one simply applies glnx_unref_object to a + * locally-allocated #GFile for example, and it will be automatically + * unreferenced when it goes out of scope. + * + * Note - you should only use these macros for stack + * allocated variables. They don't provide garbage + * collection or let you avoid freeing things. They're simply a + * compiler assisted deterministic mechanism for calling a cleanup + * function when a stack frame ends. + * + * Calling g_free automatically + * + * + * GFile * + * create_file (GError **error) + * { + * glnx_free char *random_id = NULL; + * + * if (!prepare_file (error)) + * return NULL; + * + * random_id = alloc_random_id (); + * + * return create_file_real (error); + * // Note that random_id is freed here automatically + * } + * + * + * + */ diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-local-alloc.h flatpak-1.0.0/libglnx/glnx-local-alloc.h --- flatpak-1.0.0.orig/libglnx/glnx-local-alloc.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-local-alloc.h 2018-02-03 21:26:06.308233341 +0300 @@ -0,0 +1,91 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +/** + * glnx_unref_object: + * + * Call g_object_unref() on a variable location when it goes out of + * scope. Note that unlike g_object_unref(), the variable may be + * %NULL. + */ +#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) +static inline void +glnx_local_obj_unref (void *v) +{ + GObject *o = *(GObject **)v; + if (o) + g_object_unref (o); +} +#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) + +static inline int +glnx_steal_fd (int *fdp) +{ + int fd = *fdp; + *fdp = -1; + return fd; +} + +/** + * glnx_close_fd: + * @fdp: Pointer to fd + * + * Effectively `close (glnx_steal_fd (&fd))`. Also + * asserts that `close()` did not raise `EBADF` - encountering + * that error is usually a critical bug in the program. + */ +static inline void +glnx_close_fd (int *fdp) +{ + int errsv; + + g_assert (fdp); + + int fd = glnx_steal_fd (fdp); + if (fd >= 0) + { + errsv = errno; + if (close (fd) < 0) + g_assert (errno != EBADF); + errno = errsv; + } +} + +/** + * glnx_fd_close: + * + * Deprecated in favor of `glnx_autofd`. + */ +#define glnx_fd_close __attribute__((cleanup(glnx_close_fd))) +/** + * glnx_autofd: + * + * Call close() on a variable location when it goes out of scope. + */ +#define glnx_autofd __attribute__((cleanup(glnx_close_fd))) + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-lockfile.c flatpak-1.0.0/libglnx/glnx-lockfile.c --- flatpak-1.0.0.orig/libglnx/glnx-lockfile.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-lockfile.c 2018-05-26 00:50:25.434037228 +0300 @@ -0,0 +1,179 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + Now copied into libglnx: + - Use GError + + Copyright 2010 Lennart Poettering + Copyright 2015 Colin Walters + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glnx-lockfile.h" +#include "glnx-errors.h" +#include "glnx-fdio.h" +#include "glnx-backport-autocleanups.h" +#include "glnx-local-alloc.h" + +#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) + +/** + * glnx_make_lock_file: + * @dfd: Directory file descriptor (if not `AT_FDCWD`, must have lifetime `>=` @out_lock) + * @p: Path + * @operation: one of `LOCK_SH`, `LOCK_EX`, `LOCK_UN`, as passed to flock() + * @out_lock: (out) (caller allocates): Return location for lock + * @error: Error + * + * Block until a lock file named @p (relative to @dfd) can be created, + * using the flags in @operation, returning the lock data in the + * caller-allocated location @out_lock. + * + * This API wraps new-style process locking if available, otherwise + * falls back to BSD locks. + */ +gboolean +glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_lock, GError **error) { + glnx_autofd int fd = -1; + g_autofree char *t = NULL; + int r; + + /* + * We use UNPOSIX locks if they are available. They have nice + * semantics, and are mostly compatible with NFS. However, + * they are only available on new kernels. When we detect we + * are running on an older kernel, then we fall back to good + * old BSD locks. They also have nice semantics, but are + * slightly problematic on NFS, where they are upgraded to + * POSIX locks, even though locally they are orthogonal to + * POSIX locks. + */ + + t = g_strdup(p); + + for (;;) { +#ifdef F_OFD_SETLK + struct flock fl = { + .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK, + .l_whence = SEEK_SET, + }; +#endif + struct stat st; + + fd = openat(dfd, p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600); + if (fd < 0) + return glnx_throw_errno(error); + + /* Unfortunately, new locks are not in RHEL 7.1 glibc */ +#ifdef F_OFD_SETLK + r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl); +#else + r = -1; + errno = EINVAL; +#endif + if (r < 0) { + + /* If the kernel is too old, use good old BSD locks */ + if (errno == EINVAL) + r = flock(fd, operation); + + if (r < 0) + return glnx_throw_errno_prefix (error, "flock"); + } + + /* If we acquired the lock, let's check if the file + * still exists in the file system. If not, then the + * previous exclusive owner removed it and then closed + * it. In such a case our acquired lock is worthless, + * hence try again. */ + + if (!glnx_fstat (fd, &st, error)) + return FALSE; + if (st.st_nlink > 0) + break; + + glnx_close_fd (&fd); + } + + /* Note that if this is not AT_FDCWD, the caller takes responsibility + * for the fd's lifetime being >= that of the lock. + */ + out_lock->initialized = TRUE; + out_lock->dfd = dfd; + out_lock->path = g_steal_pointer (&t); + out_lock->fd = glnx_steal_fd (&fd); + out_lock->operation = operation; + return TRUE; +} + +void glnx_release_lock_file(GLnxLockFile *f) { + int r; + + if (!(f && f->initialized)) + return; + + if (f->path) { + + /* If we are the exclusive owner we can safely delete + * the lock file itself. If we are not the exclusive + * owner, we can try becoming it. */ + + if (f->fd >= 0 && + (f->operation & ~LOCK_NB) == LOCK_SH) { +#ifdef F_OFD_SETLK + static const struct flock fl = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + }; + + r = fcntl(f->fd, F_OFD_SETLK, &fl); +#else + r = -1; + errno = EINVAL; +#endif + if (r < 0 && errno == EINVAL) + r = flock(f->fd, LOCK_EX|LOCK_NB); + + if (r >= 0) + f->operation = LOCK_EX|LOCK_NB; + } + + if ((f->operation & ~LOCK_NB) == LOCK_EX) { + (void) unlinkat(f->dfd, f->path, 0); + } + + g_free(f->path); + f->path = NULL; + } + + glnx_close_fd (&f->fd); + f->operation = 0; + f->initialized = FALSE; +} diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-lockfile.h flatpak-1.0.0/libglnx/glnx-lockfile.h --- flatpak-1.0.0.orig/libglnx/glnx-lockfile.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-lockfile.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,40 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2015 Colin Walters + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +#include "config.h" + +#include "glnx-backport-autoptr.h" + +typedef struct GLnxLockFile { + gboolean initialized; + int dfd; + char *path; + int fd; + int operation; +} GLnxLockFile; + +gboolean glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *ret, GError **error); +void glnx_release_lock_file(GLnxLockFile *f); + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxLockFile, glnx_release_lock_file) diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-macros.h flatpak-1.0.0/libglnx/glnx-macros.h --- flatpak-1.0.0.orig/libglnx/glnx-macros.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-macros.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,189 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Colin Walters + * With original source from systemd: + * Copyright 2010 Lennart Poettering + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +/* All of these are for C only. */ +#ifndef __GI_SCANNER__ + +/* Taken from https://github.com/systemd/systemd/src/basic/string-util.h + * at revision v228-666-gcf6c8c4 + */ +#define glnx_strjoina(a, ...) \ + ({ \ + const char *_appendees_[] = { a, __VA_ARGS__ }; \ + char *_d_, *_p_; \ + size_t _len_ = 0; \ + unsigned _i_; \ + for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \ + _len_ += strlen(_appendees_[_i_]); \ + _p_ = _d_ = alloca(_len_ + 1); \ + for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \ + _p_ = stpcpy(_p_, _appendees_[_i_]); \ + *_p_ = 0; \ + _d_; \ + }) + +#ifndef G_IN_SET + +/* Infrastructure for `G_IN_SET`; this code is copied from + * systemd's macro.h - please treat that version as canonical + * and submit patches first to systemd. + */ +#define _G_INSET_CASE_F(X) case X: +#define _G_INSET_CASE_F_1(CASE, X) _G_INSET_CASE_F(X) +#define _G_INSET_CASE_F_2(CASE, X, ...) CASE(X) _G_INSET_CASE_F_1(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_3(CASE, X, ...) CASE(X) _G_INSET_CASE_F_2(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_4(CASE, X, ...) CASE(X) _G_INSET_CASE_F_3(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_5(CASE, X, ...) CASE(X) _G_INSET_CASE_F_4(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_6(CASE, X, ...) CASE(X) _G_INSET_CASE_F_5(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_7(CASE, X, ...) CASE(X) _G_INSET_CASE_F_6(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_8(CASE, X, ...) CASE(X) _G_INSET_CASE_F_7(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_9(CASE, X, ...) CASE(X) _G_INSET_CASE_F_8(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_10(CASE, X, ...) CASE(X) _G_INSET_CASE_F_9(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_11(CASE, X, ...) CASE(X) _G_INSET_CASE_F_10(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_12(CASE, X, ...) CASE(X) _G_INSET_CASE_F_11(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_13(CASE, X, ...) CASE(X) _G_INSET_CASE_F_12(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_14(CASE, X, ...) CASE(X) _G_INSET_CASE_F_13(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_15(CASE, X, ...) CASE(X) _G_INSET_CASE_F_14(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_16(CASE, X, ...) CASE(X) _G_INSET_CASE_F_15(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_17(CASE, X, ...) CASE(X) _G_INSET_CASE_F_16(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_18(CASE, X, ...) CASE(X) _G_INSET_CASE_F_17(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_19(CASE, X, ...) CASE(X) _G_INSET_CASE_F_18(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_20(CASE, X, ...) CASE(X) _G_INSET_CASE_F_19(CASE, __VA_ARGS__) + +#define _G_INSET_GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME +#define _G_INSET_FOR_EACH_MAKE_CASE(...) \ + _G_INSET_GET_CASE_F(__VA_ARGS__,_G_INSET_CASE_F_20,_G_INSET_CASE_F_19,_G_INSET_CASE_F_18,_G_INSET_CASE_F_17,_G_INSET_CASE_F_16,_G_INSET_CASE_F_15,_G_INSET_CASE_F_14,_G_INSET_CASE_F_13,_G_INSET_CASE_F_12,_G_INSET_CASE_F_11, \ + _G_INSET_CASE_F_10,_G_INSET_CASE_F_9,_G_INSET_CASE_F_8,_G_INSET_CASE_F_7,_G_INSET_CASE_F_6,_G_INSET_CASE_F_5,_G_INSET_CASE_F_4,_G_INSET_CASE_F_3,_G_INSET_CASE_F_2,_G_INSET_CASE_F_1) \ + (_G_INSET_CASE_F,__VA_ARGS__) + +/* Note: claiming the name here even though it isn't upstream yet + * https://bugzilla.gnome.org/show_bug.cgi?id=783751 + */ +/** + * G_IN_SET: + * @x: Integer (or smaller) sized value + * @...: Elements to compare + * + * It's quite common to test whether or not `char` values or Unix @errno (among) others + * are members of a small set. Normally one has to choose to either use `if (x == val || x == otherval ...)` + * or a `switch` statement. This macro is useful to reduce duplication in the first case, + * where one can write simply `if (G_IN_SET (x, val, otherval))`, and avoid the verbosity + * that the `switch` statement requires. + */ +#define G_IN_SET(x, ...) \ + ({ \ + gboolean _g_inset_found = FALSE; \ + /* If the build breaks in the line below, you need to extend the case macros */ \ + static G_GNUC_UNUSED char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \ + switch(x) { \ + _G_INSET_FOR_EACH_MAKE_CASE(__VA_ARGS__) \ + _g_inset_found = TRUE; \ + break; \ + default: \ + break; \ + } \ + _g_inset_found; \ + }) + +#endif /* ifndef G_IN_SET */ + +#define _GLNX_CONCAT(a, b) a##b +#define _GLNX_CONCAT_INDIRECT(a, b) _GLNX_CONCAT(a, b) +#define _GLNX_MAKE_ANONYMOUS(a) _GLNX_CONCAT_INDIRECT(a, __COUNTER__) + +#define _GLNX_HASH_TABLE_FOREACH_IMPL_KV(guard, ht, it, kt, k, vt, v) \ + gboolean guard = TRUE; \ + G_STATIC_ASSERT (sizeof (kt) == sizeof (void*)); \ + G_STATIC_ASSERT (sizeof (vt) == sizeof (void*)); \ + for (GHashTableIter it; \ + guard && ({ g_hash_table_iter_init (&it, ht), TRUE; }); \ + guard = FALSE) \ + for (kt k; guard; guard = FALSE) \ + for (vt v; g_hash_table_iter_next (&it, (gpointer)&k, (gpointer)&v);) + + +/* Cleaner method to iterate over a GHashTable. I.e. rather than + * + * gpointer k, v; + * GHashTableIter it; + * g_hash_table_iter_init (&it, table); + * while (g_hash_table_iter_next (&it, &k, &v)) + * { + * const char *str = k; + * GPtrArray *arr = v; + * ... + * } + * + * you can simply do + * + * GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, str, GPtrArray*, arr) + * { + * ... + * } + * + * All variables are scoped within the loop. You may use the `it` variable as + * usual, e.g. to remove an element using g_hash_table_iter_remove(&it). There + * are shorter variants for the more common cases where you do not need access + * to the iterator or to keys/values: + * + * GLNX_HASH_TABLE_FOREACH (table, const char*, str) { ... } + * GLNX_HASH_TABLE_FOREACH_V (table, MyData*, data) { ... } + * GLNX_HASH_TABLE_FOREACH_KV (table, const char*, str, MyData*, data) { ... } + * + */ +#define GLNX_HASH_TABLE_FOREACH_IT(ht, it, kt, k, vt, v) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, it, kt, k, vt, v) + +/* Variant of GLNX_HASH_TABLE_FOREACH without having to specify an iterator. An + * anonymous iterator will be created. */ +#define GLNX_HASH_TABLE_FOREACH_KV(ht, kt, k, vt, v) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, vt, v) + +/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking keys. */ +#define GLNX_HASH_TABLE_FOREACH_V(ht, vt, v) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), \ + gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_), \ + vt, v) + +/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking vals. */ +#define GLNX_HASH_TABLE_FOREACH(ht, kt, k) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, \ + gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_)) + +#endif /* GI_SCANNER */ + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-missing.h flatpak-1.0.0/libglnx/glnx-missing.h --- flatpak-1.0.0.orig/libglnx/glnx-missing.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-missing.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,95 @@ +#pragma once + +/*** + This file was originally part of systemd. + + Copyright 2010 Lennart Poettering + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +/* Missing glibc definitions to access certain kernel APIs. + This file is last updated from systemd git: + + commit 71e5200f94b22589922704aa4abdf95d4fe2e528 + Author: Daniel Mack + AuthorDate: Tue Oct 18 17:57:10 2016 +0200 + Commit: Lennart Poettering + CommitDate: Fri Sep 22 15:24:54 2017 +0200 + + Add abstraction model for BPF programs +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* The precise definition of __O_TMPFILE is arch specific; use the + * values defined by the kernel (note: some are hexa, some are octal, + * duplicated as-is from the kernel definitions): + * - alpha, parisc, sparc: each has a specific value; + * - others: they use the "generic" value. + */ + +#ifndef __O_TMPFILE +#if defined(__alpha__) +#define __O_TMPFILE 0100000000 +#elif defined(__parisc__) || defined(__hppa__) +#define __O_TMPFILE 0400000000 +#elif defined(__sparc__) || defined(__sparc64__) +#define __O_TMPFILE 0x2000000 +#else +#define __O_TMPFILE 020000000 +#endif +#endif + +/* a horrid kludge trying to make sure that this will fail on old kernels */ +#ifndef O_TMPFILE +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +#endif + +#ifndef RENAME_NOREPLACE +#define RENAME_NOREPLACE (1 << 0) +#endif +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) +#endif + +#ifndef F_LINUX_SPECIFIC_BASE +#define F_LINUX_SPECIFIC_BASE 1024 +#endif + +#ifndef F_ADD_SEALS +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) + +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#define F_SEAL_WRITE 0x0008 /* prevent writes */ +#endif + +#ifndef MFD_ALLOW_SEALING +#define MFD_ALLOW_SEALING 0x0002U +#endif + +#ifndef MFD_CLOEXEC +#define MFD_CLOEXEC 0x0001U +#endif + +#include "glnx-missing-syscall.h" diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-missing-syscall.h flatpak-1.0.0/libglnx/glnx-missing-syscall.h --- flatpak-1.0.0.orig/libglnx/glnx-missing-syscall.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-missing-syscall.h 2018-05-26 00:50:25.434037228 +0300 @@ -0,0 +1,154 @@ +/*** + This file was originally part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +/* Missing glibc definitions to access certain kernel APIs. + This file is last updated from systemd git: + + commit 71e5200f94b22589922704aa4abdf95d4fe2e528 + Author: Daniel Mack + AuthorDate: Tue Oct 18 17:57:10 2016 +0200 + Commit: Lennart Poettering + CommitDate: Fri Sep 22 15:24:54 2017 +0200 + + Add abstraction model for BPF programs +*/ + +#include "config.h" + +#if !HAVE_DECL_RENAMEAT2 +# ifndef __NR_renameat2 +# if defined __x86_64__ +# define __NR_renameat2 316 +# elif defined __arm__ +# define __NR_renameat2 382 +# elif defined __aarch64__ +# define __NR_renameat2 276 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_renameat2 5311 +# endif +# elif defined __i386__ +# define __NR_renameat2 353 +# elif defined __powerpc64__ +# define __NR_renameat2 357 +# elif defined __s390__ || defined __s390x__ +# define __NR_renameat2 347 +# elif defined __arc__ +# define __NR_renameat2 276 +# else +# warning "__NR_renameat2 unknown for your architecture" +# endif +# endif + +static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { +# ifdef __NR_renameat2 + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +#if !HAVE_DECL_MEMFD_CREATE +# ifndef __NR_memfd_create +# if defined __x86_64__ +# define __NR_memfd_create 319 +# elif defined __arm__ +# define __NR_memfd_create 385 +# elif defined __aarch64__ +# define __NR_memfd_create 279 +# elif defined __s390__ +# define __NR_memfd_create 350 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_memfd_create 4354 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_memfd_create 5314 +# endif +# elif defined __i386__ +# define __NR_memfd_create 356 +# elif defined __arc__ +# define __NR_memfd_create 279 +# else +# warning "__NR_memfd_create unknown for your architecture" +# endif +# endif + +static inline int memfd_create(const char *name, unsigned int flags) { +# ifdef __NR_memfd_create + return syscall(__NR_memfd_create, name, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* Copied from systemd git: + commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca + Author: Yu Watanabe + AuthorDate: Thu Jul 27 20:22:54 2017 +0900 + Commit: Zbigniew Jędrzejewski-Szmek + CommitDate: Thu Jul 27 07:22:54 2017 -0400 +*/ +#if !HAVE_DECL_COPY_FILE_RANGE +# ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# elif defined __powerpc__ +# define __NR_copy_file_range 379 +# elif defined __arc__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-shutil.c flatpak-1.0.0/libglnx/glnx-shutil.c --- flatpak-1.0.0.orig/libglnx/glnx-shutil.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-shutil.c 2018-05-26 00:50:25.434037228 +0300 @@ -0,0 +1,260 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include + +static gboolean +glnx_shutil_rm_rf_children (GLnxDirFdIterator *dfd_iter, + GCancellable *cancellable, + GError **error) +{ + struct dirent *dent; + + while (TRUE) + { + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type == DT_DIR) + { + g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (dfd_iter->fd, dent->d_name, FALSE, + &child_dfd_iter, error)) + return FALSE; + + if (!glnx_shutil_rm_rf_children (&child_dfd_iter, cancellable, error)) + return FALSE; + + if (unlinkat (dfd_iter->fd, dent->d_name, AT_REMOVEDIR) == -1) + return glnx_throw_errno_prefix (error, "unlinkat"); + } + else + { + if (unlinkat (dfd_iter->fd, dent->d_name, 0) == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "unlinkat"); + } + } + } + + return TRUE; +} + +/** + * glnx_shutil_rm_rf_at: + * @dfd: A directory file descriptor, or `AT_FDCWD` or `-1` for current + * @path: Path + * @cancellable: Cancellable + * @error: Error + * + * Recursively delete the filename referenced by the combination of + * the directory fd @dfd and @path; it may be a file or directory. No + * error is thrown if @path does not exist. + */ +gboolean +glnx_shutil_rm_rf_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + dfd = glnx_dirfd_canonicalize (dfd); + + + /* With O_NOFOLLOW first */ + glnx_autofd int target_dfd = + openat (dfd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); + + if (target_dfd == -1) + { + int errsv = errno; + if (errsv == ENOENT) + { + ; + } + else if (errsv == ENOTDIR || errsv == ELOOP) + { + if (unlinkat (dfd, path, 0) != 0) + return glnx_throw_errno_prefix (error, "unlinkat"); + } + else + return glnx_throw_errno_prefix (error, "open(%s)", path); + } + else + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_take_fd (&target_dfd, &dfd_iter, error)) + return FALSE; + + if (!glnx_shutil_rm_rf_children (&dfd_iter, cancellable, error)) + return FALSE; + + if (unlinkat (dfd, path, AT_REMOVEDIR) == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "unlinkat"); + } + } + + return TRUE; +} + +static gboolean +mkdir_p_at_internal (int dfd, + char *path, + int mode, + GCancellable *cancellable, + GError **error) +{ + gboolean did_recurse = FALSE; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + again: + if (mkdirat (dfd, path, mode) == -1) + { + if (errno == ENOENT) + { + char *lastslash; + + g_assert (!did_recurse); + + lastslash = strrchr (path, '/'); + if (lastslash == NULL) + { + /* This can happen if @dfd was deleted between being opened and + * passed to mkdir_p_at_internal(). */ + return glnx_throw_errno_prefix (error, "mkdir(%s)", path); + } + + /* Note we can mutate the buffer as we dup'd it */ + *lastslash = '\0'; + + if (!glnx_shutil_mkdir_p_at (dfd, path, mode, + cancellable, error)) + return FALSE; + + /* Now restore it for another mkdir attempt */ + *lastslash = '/'; + + did_recurse = TRUE; + goto again; + } + else if (errno == EEXIST) + { + /* Fall through; it may not have been a directory, + * but we'll find that out on the next call up. + */ + } + else + return glnx_throw_errno_prefix (error, "mkdir(%s)", path); + } + + return TRUE; +} + +/** + * glnx_shutil_mkdir_p_at: + * @dfd: Directory fd + * @path: Directory path to be created + * @mode: Mode for newly created directories + * @cancellable: Cancellable + * @error: Error + * + * Similar to g_mkdir_with_parents(), except operates relative to the + * directory fd @dfd. + * + * See also glnx_ensure_dir() for a non-recursive version. + * + * This will return %G_IO_ERROR_NOT_FOUND if @dfd has been deleted since being + * opened. It may return other errors from mkdirat() in other situations. + */ +gboolean +glnx_shutil_mkdir_p_at (int dfd, + const char *path, + int mode, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + char *buf; + + /* Fast path stat to see whether it already exists */ + if (fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == 0) + { + /* Note early return */ + if (S_ISDIR (stbuf.st_mode)) + return TRUE; + } + + buf = strdupa (path); + + if (!mkdir_p_at_internal (dfd, buf, mode, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * glnx_shutil_mkdir_p_at_open: + * @dfd: Directory fd + * @path: Directory path to be created + * @mode: Mode for newly created directories + * @out_dfd: (out caller-allocates): Return location for an FD to @dfd/@path, + * or `-1` on error + * @cancellable: (nullable): Cancellable, or %NULL + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_shutil_mkdir_p_at(), except it opens the resulting directory + * and returns a directory FD to it. Currently, this is not guaranteed to be + * race-free. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_shutil_mkdir_p_at_open (int dfd, + const char *path, + int mode, + int *out_dfd, + GCancellable *cancellable, + GError **error) +{ + /* FIXME: It’s not possible to eliminate the race here until + * openat(O_DIRECTORY | O_CREAT) works (and returns a directory rather than a + * file). It appears to be not supported in current kernels. (Tested with + * 4.10.10-200.fc25.x86_64.) */ + *out_dfd = -1; + + if (!glnx_shutil_mkdir_p_at (dfd, path, mode, cancellable, error)) + return FALSE; + + return glnx_opendirat (dfd, path, TRUE, out_dfd, error); +} diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-shutil.h flatpak-1.0.0/libglnx/glnx-shutil.h --- flatpak-1.0.0.orig/libglnx/glnx-shutil.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-shutil.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean +glnx_shutil_rm_rf_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_shutil_mkdir_p_at (int dfd, + const char *path, + int mode, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_shutil_mkdir_p_at_open (int dfd, + const char *path, + int mode, + int *out_dfd, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-xattrs.c flatpak-1.0.0/libglnx/glnx-xattrs.c --- flatpak-1.0.0.orig/libglnx/glnx-xattrs.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-xattrs.c 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,444 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +static GVariant * +variant_new_ay_bytes (GBytes *bytes) +{ + gsize size; + gconstpointer data; + data = g_bytes_get_data (bytes, &size); + g_bytes_ref (bytes); + return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size, + TRUE, (GDestroyNotify)g_bytes_unref, bytes); +} + +static char * +canonicalize_xattrs (char *xattr_string, + size_t len) +{ + char *p; + GSList *xattrs = NULL; + GSList *iter; + GString *result; + + result = g_string_new (0); + + p = xattr_string; + while (p < xattr_string+len) + { + xattrs = g_slist_prepend (xattrs, p); + p += strlen (p) + 1; + } + + xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp); + for (iter = xattrs; iter; iter = iter->next) { + g_string_append (result, iter->data); + g_string_append_c (result, '\0'); + } + + g_slist_free (xattrs); + return g_string_free (result, FALSE); +} + +static gboolean +read_xattr_name_array (const char *path, + int fd, + const char *xattrs, + size_t len, + GVariantBuilder *builder, + GError **error) +{ + gboolean ret = FALSE; + const char *p; + int r; + const char *funcstr; + + g_assert (path != NULL || fd != -1); + + funcstr = fd != -1 ? "fgetxattr" : "lgetxattr"; + + for (p = xattrs; p < xattrs+len; p = p + strlen (p) + 1) + { + ssize_t bytes_read; + g_autofree char *buf = NULL; + g_autoptr(GBytes) bytes = NULL; + + again: + if (fd != -1) + bytes_read = fgetxattr (fd, p, NULL, 0); + else + bytes_read = lgetxattr (path, p, NULL, 0); + if (bytes_read < 0) + { + if (errno == ENODATA) + continue; + + glnx_set_prefix_error_from_errno (error, "%s", funcstr); + goto out; + } + if (bytes_read == 0) + continue; + + buf = g_malloc (bytes_read); + if (fd != -1) + r = fgetxattr (fd, p, buf, bytes_read); + else + r = lgetxattr (path, p, buf, bytes_read); + if (r < 0) + { + if (errno == ERANGE) + { + g_free (g_steal_pointer (&buf)); + goto again; + } + else if (errno == ENODATA) + continue; + + glnx_set_prefix_error_from_errno (error, "%s", funcstr); + goto out; + } + + bytes = g_bytes_new_take (g_steal_pointer (&buf), bytes_read); + g_variant_builder_add (builder, "(@ay@ay)", + g_variant_new_bytestring (p), + variant_new_ay_bytes (bytes)); + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +get_xattrs_impl (const char *path, + int fd, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + ssize_t bytes_read, real_size; + g_autofree char *xattr_names = NULL; + g_autofree char *xattr_names_canonical = NULL; + GVariantBuilder builder; + gboolean builder_initialized = FALSE; + g_autoptr(GVariant) ret_xattrs = NULL; + + g_assert (path != NULL || fd != -1); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + builder_initialized = TRUE; + + again: + if (path) + bytes_read = llistxattr (path, NULL, 0); + else + bytes_read = flistxattr (fd, NULL, 0); + + if (bytes_read < 0) + { + if (errno != ENOTSUP) + { + glnx_set_prefix_error_from_errno (error, "%s", "llistxattr"); + goto out; + } + } + else if (bytes_read > 0) + { + xattr_names = g_malloc (bytes_read); + if (path) + real_size = llistxattr (path, xattr_names, bytes_read); + else + real_size = flistxattr (fd, xattr_names, bytes_read); + if (real_size < 0) + { + if (errno == ERANGE) + { + g_free (xattr_names); + goto again; + } + glnx_set_prefix_error_from_errno (error, "%s", "llistxattr"); + goto out; + } + else if (real_size > 0) + { + xattr_names_canonical = canonicalize_xattrs (xattr_names, real_size); + + if (!read_xattr_name_array (path, fd, xattr_names_canonical, real_size, &builder, error)) + goto out; + } + } + + ret_xattrs = g_variant_builder_end (&builder); + builder_initialized = FALSE; + g_variant_ref_sink (ret_xattrs); + + ret = TRUE; + if (out_xattrs) + *out_xattrs = g_steal_pointer (&ret_xattrs); + out: + if (!builder_initialized) + g_variant_builder_clear (&builder); + return ret; +} + +/** + * glnx_fd_get_all_xattrs: + * @fd: a file descriptor + * @out_xattrs: (out): A new #GVariant containing the extended attributes + * @cancellable: Cancellable + * @error: Error + * + * Read all extended attributes from @fd in a canonical sorted order, and + * set @out_xattrs with the result. + * + * If the filesystem does not support extended attributes, @out_xattrs + * will have 0 elements, and this function will return successfully. + */ +gboolean +glnx_fd_get_all_xattrs (int fd, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + return get_xattrs_impl (NULL, fd, out_xattrs, + cancellable, error); +} + +/** + * glnx_dfd_name_get_all_xattrs: + * @dfd: Parent directory file descriptor + * @name: File name + * @out_xattrs: (out): Extended attribute set + * @cancellable: Cancellable + * @error: Error + * + * Load all extended attributes for the file named @name residing in + * directory @dfd. + */ +gboolean +glnx_dfd_name_get_all_xattrs (int dfd, + const char *name, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + if (G_IN_SET(dfd, AT_FDCWD, -1)) + { + return get_xattrs_impl (name, -1, out_xattrs, cancellable, error); + } + else + { + char buf[PATH_MAX]; + /* A workaround for the lack of lgetxattrat(), thanks to Florian Weimer: + * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html + */ + snprintf (buf, sizeof (buf), "/proc/self/fd/%d/%s", dfd, name); + return get_xattrs_impl (buf, -1, out_xattrs, cancellable, error); + } +} + +static gboolean +set_all_xattrs_for_path (const char *path, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + const guint n = g_variant_n_children (xattrs); + for (guint i = 0; i < n; i++) + { + const guint8* name; + g_autoptr(GVariant) value = NULL; + g_variant_get_child (xattrs, i, "(^&ay@ay)", + &name, &value); + + gsize value_len; + const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1); + + if (lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) < 0) + return glnx_throw_errno_prefix (error, "lsetxattr"); + } + + return TRUE; +} + +/** + * glnx_dfd_name_set_all_xattrs: + * @dfd: Parent directory file descriptor + * @name: File name + * @xattrs: Extended attribute set + * @cancellable: Cancellable + * @error: Error + * + * Set all extended attributes for the file named @name residing in + * directory @dfd. + */ +gboolean +glnx_dfd_name_set_all_xattrs (int dfd, + const char *name, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + if (G_IN_SET(dfd, AT_FDCWD, -1)) + { + return set_all_xattrs_for_path (name, xattrs, cancellable, error); + } + else + { + char buf[PATH_MAX]; + /* A workaround for the lack of lsetxattrat(), thanks to Florian Weimer: + * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html + */ + snprintf (buf, sizeof (buf), "/proc/self/fd/%d/%s", dfd, name); + return set_all_xattrs_for_path (buf, xattrs, cancellable, error); + } +} + +/** + * glnx_fd_set_all_xattrs: + * @fd: File descriptor + * @xattrs: Extended attributes + * @cancellable: Cancellable + * @error: Error + * + * For each attribute in @xattrs, set its value on the file or + * directory referred to by @fd. This function does not remove any + * attributes not in @xattrs. + */ +gboolean +glnx_fd_set_all_xattrs (int fd, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + const guint n = g_variant_n_children (xattrs); + for (guint i = 0; i < n; i++) + { + const guint8* name; + g_autoptr(GVariant) value = NULL; + g_variant_get_child (xattrs, i, "(^&ay@ay)", + &name, &value); + + gsize value_len; + const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1); + + if (TEMP_FAILURE_RETRY (fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0)) < 0) + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + + return TRUE; +} + +/** + * glnx_lgetxattrat: + * @dfd: Directory file descriptor + * @subpath: Subpath + * @attribute: Extended attribute to retrieve + * @error: Error + * + * Retrieve an extended attribute value, relative to a directory file + * descriptor. + */ +GBytes * +glnx_lgetxattrat (int dfd, + const char *subpath, + const char *attribute, + GError **error) +{ + char pathbuf[PATH_MAX]; + snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath); + + ssize_t bytes_read, real_size; + if (TEMP_FAILURE_RETRY (bytes_read = lgetxattr (pathbuf, attribute, NULL, 0)) < 0) + return glnx_null_throw_errno_prefix (error, "lgetxattr"); + + g_autofree guint8 *buf = g_malloc (bytes_read); + if (TEMP_FAILURE_RETRY (real_size = lgetxattr (pathbuf, attribute, buf, bytes_read)) < 0) + return glnx_null_throw_errno_prefix (error, "lgetxattr"); + + return g_bytes_new_take (g_steal_pointer (&buf), real_size); +} + +/** + * glnx_fgetxattr_bytes: + * @fd: Directory file descriptor + * @attribute: Extended attribute to retrieve + * @error: Error + * + * Returns: (transfer full): An extended attribute value, or %NULL on error + */ +GBytes * +glnx_fgetxattr_bytes (int fd, + const char *attribute, + GError **error) +{ + ssize_t bytes_read, real_size; + + if (TEMP_FAILURE_RETRY (bytes_read = fgetxattr (fd, attribute, NULL, 0)) < 0) + return glnx_null_throw_errno_prefix (error, "fgetxattr"); + + g_autofree guint8 *buf = g_malloc (bytes_read); + if (TEMP_FAILURE_RETRY (real_size = fgetxattr (fd, attribute, buf, bytes_read)) < 0) + return glnx_null_throw_errno_prefix (error, "fgetxattr"); + + return g_bytes_new_take (g_steal_pointer (&buf), real_size); +} + +/** + * glnx_lsetxattrat: + * @dfd: Directory file descriptor + * @subpath: Path + * @attribute: An attribute name + * @value: (array length=len) (element-type guint8): Attribute value + * @len: Length of @value + * @flags: Flags, containing either XATTR_CREATE or XATTR_REPLACE + * @error: Error + * + * Set an extended attribute, relative to a directory file descriptor. + */ +gboolean +glnx_lsetxattrat (int dfd, + const char *subpath, + const char *attribute, + const guint8 *value, + gsize len, + int flags, + GError **error) +{ + char pathbuf[PATH_MAX]; + snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath); + + if (TEMP_FAILURE_RETRY (lsetxattr (subpath, attribute, value, len, flags)) < 0) + return glnx_throw_errno_prefix (error, "lsetxattr"); + + return TRUE; +} + diff -Nuar flatpak-1.0.0.orig/libglnx/glnx-xattrs.h flatpak-1.0.0/libglnx/glnx-xattrs.h --- flatpak-1.0.0.orig/libglnx/glnx-xattrs.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/glnx-xattrs.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,78 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +gboolean +glnx_dfd_name_get_all_xattrs (int dfd, + const char *name, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_fd_get_all_xattrs (int fd, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_dfd_name_set_all_xattrs (int dfd, + const char *name, + GVariant *xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_fd_set_all_xattrs (int fd, + GVariant *xattrs, + GCancellable *cancellable, + GError **error); + +GBytes * +glnx_lgetxattrat (int dfd, + const char *subpath, + const char *attribute, + GError **error); + +GBytes * +glnx_fgetxattr_bytes (int fd, + const char *attribute, + GError **error); + +gboolean +glnx_lsetxattrat (int dfd, + const char *subpath, + const char *attribute, + const guint8 *value, + gsize len, + int flags, + GError **error); + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/libglnx.doap flatpak-1.0.0/libglnx/libglnx.doap --- flatpak-1.0.0.orig/libglnx/libglnx.doap 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/libglnx.doap 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,31 @@ + + + + libglnx + libglnx + + "Copylib" for system service modules using GLib with Linux + + This module is intended for use by + infrastructure code using GLib that is also Linux specific, such as + ostree, NetworkManager, and others. + + + + + + C + + + + Colin Walters + + walters + + + + diff -Nuar flatpak-1.0.0.orig/libglnx/libglnx.h flatpak-1.0.0/libglnx/libglnx.h --- flatpak-1.0.0.orig/libglnx/libglnx.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/libglnx.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012,2013,2015 Colin Walters . + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_END_DECLS diff -Nuar flatpak-1.0.0.orig/libglnx/libglnx.m4 flatpak-1.0.0/libglnx/libglnx.m4 --- flatpak-1.0.0.orig/libglnx/libglnx.m4 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/libglnx.m4 2018-05-26 00:50:25.434037228 +0300 @@ -0,0 +1,33 @@ +AC_DEFUN([LIBGLNX_CONFIGURE], +[ +AC_CHECK_DECLS([ + renameat2, + memfd_create, + copy_file_range], + [], [], [[ +#include +#include +#include +#include +#include +#include +#include +#include +]]) + +AC_ARG_ENABLE(otmpfile, + [AS_HELP_STRING([--disable-otmpfile], + [Disable use of O_TMPFILE [default=no]])],, + [enable_otmpfile=yes]) +AS_IF([test $enable_otmpfile = yes], [], [ + AC_DEFINE([DISABLE_OTMPFILE], 1, [Define if we should avoid using O_TMPFILE])]) + +AC_ARG_ENABLE(wrpseudo-compat, + [AS_HELP_STRING([--enable-wrpseudo-compat], + [Disable use syscall() and filesystem calls to for compatibility with wrpseudo [default=no]])],, + [enable_wrpseudo_compat=no]) +AS_IF([test $enable_wrpseudo_compat = no], [], [ + AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with wrpseudo])]) + +dnl end LIBGLNX_CONFIGURE +]) diff -Nuar flatpak-1.0.0.orig/libglnx/Makefile-libglnx.am flatpak-1.0.0/libglnx/Makefile-libglnx.am --- flatpak-1.0.0.orig/libglnx/Makefile-libglnx.am 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/Makefile-libglnx.am 2018-02-03 21:26:06.307233341 +0300 @@ -0,0 +1,78 @@ +# Copyright (C) 2015 Colin Walters +# +# This library 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 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, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +EXTRA_DIST += \ + $(libglnx_srcpath)/README.md \ + $(libglnx_srcpath)/COPYING \ + $(libglnx_srcpath)/libglnx.m4 \ + $(NULL) + +libglnx_la_SOURCES = \ + $(libglnx_srcpath)/glnx-macros.h \ + $(libglnx_srcpath)/glnx-backport-autocleanups.h \ + $(libglnx_srcpath)/glnx-backport-autoptr.h \ + $(libglnx_srcpath)/glnx-backports.h \ + $(libglnx_srcpath)/glnx-backports.c \ + $(libglnx_srcpath)/glnx-local-alloc.h \ + $(libglnx_srcpath)/glnx-local-alloc.c \ + $(libglnx_srcpath)/glnx-errors.h \ + $(libglnx_srcpath)/glnx-errors.c \ + $(libglnx_srcpath)/glnx-console.h \ + $(libglnx_srcpath)/glnx-console.c \ + $(libglnx_srcpath)/glnx-dirfd.h \ + $(libglnx_srcpath)/glnx-dirfd.c \ + $(libglnx_srcpath)/glnx-fdio.h \ + $(libglnx_srcpath)/glnx-fdio.c \ + $(libglnx_srcpath)/glnx-lockfile.h \ + $(libglnx_srcpath)/glnx-lockfile.c \ + $(libglnx_srcpath)/glnx-missing-syscall.h \ + $(libglnx_srcpath)/glnx-missing.h \ + $(libglnx_srcpath)/glnx-xattrs.h \ + $(libglnx_srcpath)/glnx-xattrs.c \ + $(libglnx_srcpath)/glnx-shutil.h \ + $(libglnx_srcpath)/glnx-shutil.c \ + $(libglnx_srcpath)/libglnx.h \ + $(libglnx_srcpath)/tests/libglnx-testlib.h \ + $(NULL) + +libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic +libglnx_la_LIBADD = $(libglnx_libs) + +libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil +TESTS += $(libglnx_tests) + +check_PROGRAMS += $(libglnx_tests) +test_libglnx_xattrs_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-xattrs.c +test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_fdio_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-fdio.c +test_libglnx_fdio_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_errors_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-errors.c +test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_macros_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-macros.c +test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_shutil_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-shutil.c +test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la diff -Nuar flatpak-1.0.0.orig/libglnx/README.md flatpak-1.0.0/libglnx/README.md --- flatpak-1.0.0.orig/libglnx/README.md 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/README.md 2018-05-26 00:50:25.433037228 +0300 @@ -0,0 +1,52 @@ +libglnx is the successor to libgsystem: https://git.gnome.org/browse/libgsystem + +It is for modules which depend on both GLib and Linux, intended to be +used as a git submodule. + +Features: + + - File APIs which use `openat()` like APIs, but also take a `GCancellable` + to support dynamic cancellation + - APIs also have a `GError` parameter + - High level "shutil", somewhat inspired by Python's + - A "console" API for tty output + - A backport of the GLib cleanup macros for projects which can't yet take + a dependency on 2.40. + +Why? +---- + +There are multiple projects which have a hard dependency on Linux and +GLib, such as NetworkManager, ostree, flatpak, etc. It makes sense +for them to be able to share Linux-specific APIs. + +This module also contains some code taken from systemd, which has very +high quality LGPLv2+ shared library code, but most of the internal +shared library is private, and not namespaced. + +One could also compare this project to gnulib; the salient differences +there are that at least some of this module is eventually destined for +inclusion in GLib. + +Porting from libgsystem +----------------------- + +For all of the filesystem access code, libglnx exposes only +fd-relative API, not `GFile*`. It does use `GCancellable` where +applicable. + +For local allocation macros, you should start using the `g_auto` +macros from GLib. A backport is included in libglnx. There are a few +APIs not defined in GLib yet, such as `glnx_autofd`. + +`gs_transfer_out_value` is replaced by `g_steal_pointer`. + +Contributing +------------ + +Currently there is not a Bugzilla product - one may be created +in the future. You can submit PRs against the Github mirror: + +https://github.com/GNOME/libglnx/pulls + +Or alternatively, email one of the maintainers directly. diff -Nuar flatpak-1.0.0.orig/libglnx/tests/libglnx-testlib.h flatpak-1.0.0/libglnx/tests/libglnx-testlib.h --- flatpak-1.0.0.orig/libglnx/tests/libglnx-testlib.h 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/tests/libglnx-testlib.h 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,34 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +typedef GError _GLnxTestAutoError; +static inline void +_glnx_test_auto_error_cleanup (_GLnxTestAutoError *autoerror) +{ + g_assert_no_error (autoerror); + /* We could add a clear call here, but no point...we'll have aborted */ +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(_GLnxTestAutoError, _glnx_test_auto_error_cleanup); + +#define _GLNX_TEST_DECLARE_ERROR(local_error, error) \ + g_autoptr(_GLnxTestAutoError) local_error = NULL; \ + GError **error = &local_error diff -Nuar flatpak-1.0.0.orig/libglnx/tests/test-libglnx-errors.c flatpak-1.0.0/libglnx/tests/test-libglnx-errors.c --- flatpak-1.0.0.orig/libglnx/tests/test-libglnx-errors.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/tests/test-libglnx-errors.c 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,183 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +static void +test_error_throw (void) +{ + g_autoptr(GError) error = NULL; + + g_assert (!glnx_throw (&error, "foo: %s %d", "hello", 42)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "foo: hello 42"); + g_clear_error (&error); + + gpointer dummy = glnx_null_throw (&error, "literal foo"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "literal foo"); + g_clear_error (&error); + + gpointer dummy2 = glnx_null_throw (&error, "foo: %s %d", "hola", 24); + g_assert (dummy2 == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "foo: hola 24"); + g_clear_error (&error); +} + +static void +test_error_errno (void) +{ + g_autoptr(GError) error = NULL; + const char noent_path[] = "/enoent-this-should-not-exist"; + int fd; + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + g_assert (!glnx_throw_errno (&error)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (!glnx_prefix_error (&error, "myprefix")); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "myprefix: ")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno (&error); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + dummy = glnx_prefix_error_null (&error, "myprefix"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "myprefix: ")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + g_autofree char *expected_prefix = g_strdup_printf ("Failed to open %s", noent_path); + g_assert (!glnx_throw_errno_prefix (&error, "Failed to open %s", noent_path)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, expected_prefix)); + g_clear_error (&error); + /* And test the legacy wrapper */ + glnx_set_prefix_error_from_errno (&error, "Failed to open %s", noent_path); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, expected_prefix)); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open file"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "Failed to open file")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open %s", noent_path); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, glnx_strjoina ("Failed to open ", noent_path))); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); +} + +static void +test_error_auto_nothrow (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + /* Side effect to avoid otherwise empty function */ + g_assert_no_error (*error); +} + +static void +test_error_auto_throw (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + (void) glnx_throw (error, "oops"); +} + +static void +test_error_auto_throw_recurse (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + + if (TRUE) + { + GLNX_AUTO_PREFIX_ERROR("bar", error); + (void) glnx_throw (error, "oops"); + } +} + +static void +test_error_auto (void) +{ + g_autoptr(GError) error = NULL; + test_error_auto_nothrow (&error); + g_assert_no_error (error); + test_error_auto_throw (&error); + g_assert_nonnull (error); + g_assert_cmpstr (error->message, ==, "foo: oops"); + g_clear_error (&error); + test_error_auto_throw_recurse (&error); + g_assert_nonnull (error); + g_assert_cmpstr (error->message, ==, "foo: bar: oops"); +} + +int main (int argc, char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/error-throw", test_error_throw); + g_test_add_func ("/error-errno", test_error_errno); + g_test_add_func ("/error-auto", test_error_auto); + + ret = g_test_run(); + + return ret; +} diff -Nuar flatpak-1.0.0.orig/libglnx/tests/test-libglnx-fdio.c flatpak-1.0.0/libglnx/tests/test-libglnx-fdio.c --- flatpak-1.0.0.orig/libglnx/tests/test-libglnx-fdio.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/tests/test-libglnx-fdio.c 2018-05-26 00:50:25.435037228 +0300 @@ -0,0 +1,254 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include +#include + +#include "libglnx-testlib.h" + +static gboolean +renameat_test_setup (int *out_srcfd, int *out_destfd, + GError **error) +{ + glnx_autofd int srcfd = -1; + glnx_autofd int destfd = -1; + + (void) glnx_shutil_rm_rf_at (AT_FDCWD, "srcdir", NULL, NULL); + if (mkdir ("srcdir", 0755) < 0) + err (1, "mkdir"); + if (!glnx_opendirat (AT_FDCWD, "srcdir", TRUE, &srcfd, error)) + return FALSE; + (void) glnx_shutil_rm_rf_at (AT_FDCWD, "destdir", NULL, NULL); + if (mkdir ("destdir", 0755) < 0) + err (1, "mkdir"); + if (!glnx_opendirat (AT_FDCWD, "destdir", TRUE, &destfd, error)) + return FALSE; + + if (!glnx_file_replace_contents_at (srcfd, "foo", (guint8*)"foo contents", strlen ("foo contents"), + GLNX_FILE_REPLACE_NODATASYNC, NULL, error)) + return FALSE; + if (!glnx_file_replace_contents_at (destfd, "bar", (guint8*)"bar contents", strlen ("bar contents"), + GLNX_FILE_REPLACE_NODATASYNC, NULL, error)) + return FALSE; + + *out_srcfd = srcfd; srcfd = -1; + *out_destfd = destfd; destfd = -1; + return TRUE; +} + +static void +test_renameat2_noreplace (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + glnx_autofd int srcfd = -1; + glnx_autofd int destfd = -1; + struct stat stbuf; + + if (!renameat_test_setup (&srcfd, &destfd, error)) + return; + + if (glnx_renameat2_noreplace (srcfd, "foo", destfd, "bar") == 0) + g_assert_not_reached (); + else + { + g_assert_cmpint (errno, ==, EEXIST); + } + + if (glnx_renameat2_noreplace (srcfd, "foo", destfd, "baz") < 0) + return (void)glnx_throw_errno_prefix (error, "renameat"); + if (!glnx_fstatat (destfd, "bar", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + + if (fstatat (srcfd, "foo", &stbuf, AT_SYMLINK_NOFOLLOW) == 0) + g_assert_not_reached (); + else + g_assert_cmpint (errno, ==, ENOENT); +} + +static void +test_renameat2_exchange (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + + glnx_autofd int srcfd = -1; + glnx_autofd int destfd = -1; + if (!renameat_test_setup (&srcfd, &destfd, error)) + return; + + if (glnx_renameat2_exchange (AT_FDCWD, "srcdir", AT_FDCWD, "destdir") < 0) + return (void)glnx_throw_errno_prefix (error, "renameat"); + + /* Ensure the dir fds are the same */ + struct stat stbuf; + if (!glnx_fstatat (srcfd, "foo", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + if (!glnx_fstatat (destfd, "bar", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + /* But the dirs should be swapped */ + if (!glnx_fstatat (AT_FDCWD, "destdir/foo", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + if (!glnx_fstatat (AT_FDCWD, "srcdir/bar", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; +} + +static void +test_tmpfile (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, ".", O_WRONLY|O_CLOEXEC, &tmpf, error)) + return; + if (glnx_loop_write (tmpf.fd, "foo", strlen ("foo")) < 0) + return (void)glnx_throw_errno_prefix (error, "write"); + if (glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE, AT_FDCWD, "foo", error)) + return; +} + +static void +test_stdio_file (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + g_auto(GLnxTmpfile) tmpf = { 0, }; + g_autoptr(FILE) f = NULL; + + if (!glnx_open_anonymous_tmpfile (O_RDWR|O_CLOEXEC, &tmpf, error)) + return; + f = fdopen (tmpf.fd, "w"); + tmpf.fd = -1; /* Ownership was transferred via fdopen() */ + if (!f) + return (void)glnx_throw_errno_prefix (error, "fdopen"); + if (fwrite ("hello", 1, strlen ("hello"), f) != strlen ("hello")) + return (void)glnx_throw_errno_prefix (error, "fwrite"); + if (!glnx_stdio_file_flush (f, error)) + return; +} + +static void +test_fstatat (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + struct stat stbuf = { 0, }; + + if (!glnx_fstatat_allow_noent (AT_FDCWD, ".", &stbuf, 0, error)) + return; + g_assert_cmpint (errno, ==, 0); + g_assert_no_error (local_error); + g_assert (S_ISDIR (stbuf.st_mode)); + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchfile", &stbuf, 0, error)) + return; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); + + /* test NULL parameter for stat */ + if (!glnx_fstatat_allow_noent (AT_FDCWD, ".", NULL, 0, error)) + return; + g_assert_cmpint (errno, ==, 0); + g_assert_no_error (local_error); + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchfile", NULL, 0, error)) + return; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); +} + +static void +test_filecopy (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + const char foo[] = "foo"; + struct stat stbuf; + + if (!glnx_ensure_dir (AT_FDCWD, "subdir", 0755, error)) + return; + + if (!glnx_file_replace_contents_at (AT_FDCWD, foo, (guint8*)foo, sizeof (foo), + GLNX_FILE_REPLACE_NODATASYNC, NULL, error)) + return; + + /* Copy it into both the same dir and a subdir */ + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "bar", + GLNX_FILE_COPY_NOXATTRS, NULL, error)) + return; + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "subdir/bar", + GLNX_FILE_COPY_NOXATTRS, NULL, error)) + return; + if (!glnx_fstatat (AT_FDCWD, "subdir/bar", &stbuf, 0, error)) + return; + + if (glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "bar", + GLNX_FILE_COPY_NOXATTRS, NULL, error)) + g_assert_not_reached (); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS); + g_clear_error (&local_error); + + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "bar", + GLNX_FILE_COPY_NOXATTRS | GLNX_FILE_COPY_OVERWRITE, + NULL, error)) + return; + + if (symlinkat ("nosuchtarget", AT_FDCWD, "link") < 0) + return (void) glnx_throw_errno_prefix (error, "symlinkat"); + + /* Shouldn't be able to overwrite a symlink without GLNX_FILE_COPY_OVERWRITE */ + if (glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "link", + GLNX_FILE_COPY_NOXATTRS, + NULL, error)) + g_assert_not_reached (); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS); + g_clear_error (&local_error); + + /* Test overwriting symlink */ + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "link", + GLNX_FILE_COPY_NOXATTRS | GLNX_FILE_COPY_OVERWRITE, + NULL, error)) + return; + + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchtarget", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); + + if (!glnx_fstatat (AT_FDCWD, "link", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + g_assert (S_ISREG (stbuf.st_mode)); +} + +int main (int argc, char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/tmpfile", test_tmpfile); + g_test_add_func ("/stdio-file", test_stdio_file); + g_test_add_func ("/filecopy", test_filecopy); + g_test_add_func ("/renameat2-noreplace", test_renameat2_noreplace); + g_test_add_func ("/renameat2-exchange", test_renameat2_exchange); + g_test_add_func ("/fstat", test_fstatat); + + ret = g_test_run(); + + return ret; +} diff -Nuar flatpak-1.0.0.orig/libglnx/tests/test-libglnx-macros.c flatpak-1.0.0/libglnx/tests/test-libglnx-macros.c --- flatpak-1.0.0.orig/libglnx/tests/test-libglnx-macros.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/tests/test-libglnx-macros.c 2018-02-03 21:26:06.309233341 +0300 @@ -0,0 +1,109 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +static void +test_inset (void) +{ + g_assert (G_IN_SET (7, 7)); + g_assert (G_IN_SET (7, 42, 7)); + g_assert (G_IN_SET (7, 7,42,3,9)); + g_assert (G_IN_SET (42, 7,42,3,9)); + g_assert (G_IN_SET (3, 7,42,3,9)); + g_assert (G_IN_SET (9, 7,42,3,9)); + g_assert (!G_IN_SET (8, 7,42,3,9)); + g_assert (!G_IN_SET (-1, 7,42,3,9)); + g_assert (G_IN_SET ('x', 'a', 'x', 'c')); + g_assert (!G_IN_SET ('y', 'a', 'x', 'c')); +} + +static void +test_hash_table_foreach (void) +{ + /* use var names all different from the macro metavars to ensure proper + * substitution */ + g_autoptr(GHashTable) table = g_hash_table_new (g_str_hash, g_str_equal); + const char *keys[] = {"key1", "key2"}; + const char *vals[] = {"val1", "val2"}; + g_hash_table_insert (table, (gpointer)keys[0], (gpointer)vals[0]); + g_hash_table_insert (table, (gpointer)keys[1], (gpointer)vals[1]); + + guint i = 0; + GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, key, const char*, val) + { + g_assert_cmpstr (key, ==, keys[i]); + g_assert_cmpstr (val, ==, vals[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, key, const char*, val) + { + g_hash_table_iter_remove (&it); + break; + } + g_assert_cmpuint (g_hash_table_size (table), ==, 1); + + g_hash_table_insert (table, (gpointer)keys[1], (gpointer)vals[1]); + g_assert_cmpuint (g_hash_table_size (table), ==, 1); + + g_hash_table_insert (table, (gpointer)keys[0], (gpointer)vals[0]); + g_assert_cmpuint (g_hash_table_size (table), ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH_KV (table, const char*, key, const char*, val) + { + g_assert_cmpstr (key, ==, keys[i]); + g_assert_cmpstr (val, ==, vals[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH (table, const char*, key) + { + g_assert_cmpstr (key, ==, keys[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH_V (table, const char*, val) + { + g_assert_cmpstr (val, ==, vals[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/inset", test_inset); + g_test_add_func ("/hash_table_foreach", test_hash_table_foreach); + return g_test_run(); +} diff -Nuar flatpak-1.0.0.orig/libglnx/tests/test-libglnx-shutil.c flatpak-1.0.0/libglnx/tests/test-libglnx-shutil.c --- flatpak-1.0.0.orig/libglnx/tests/test-libglnx-shutil.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/tests/test-libglnx-shutil.c 2018-05-26 00:50:25.435037228 +0300 @@ -0,0 +1,63 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2017 Endless Mobile, Inc. + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include +#include + +#include "libglnx-testlib.h" + +static void +test_mkdir_p_enoent (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + glnx_autofd int dfd = -1; + + if (!glnx_ensure_dir (AT_FDCWD, "test", 0755, error)) + return; + if (!glnx_opendirat (AT_FDCWD, "test", FALSE, &dfd, error)) + return; + if (rmdir ("test") < 0) + return (void) glnx_throw_errno_prefix (error, "rmdir(%s)", "test"); + + /* This should fail with ENOENT. */ + glnx_shutil_mkdir_p_at (dfd, "blah/baz", 0755, NULL, error); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_clear_error (&local_error); +} + +int +main (int argc, + char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/mkdir-p/enoent", test_mkdir_p_enoent); + + ret = g_test_run(); + + return ret; +} diff -Nuar flatpak-1.0.0.orig/libglnx/tests/test-libglnx-xattrs.c flatpak-1.0.0/libglnx/tests/test-libglnx-xattrs.c --- flatpak-1.0.0.orig/libglnx/tests/test-libglnx-xattrs.c 1970-01-01 02:00:00.000000000 +0200 +++ flatpak-1.0.0/libglnx/tests/test-libglnx-xattrs.c 2018-05-26 00:50:25.435037228 +0300 @@ -0,0 +1,283 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +#define XATTR_THREAD_RUN_TIME_USECS (5 * G_USEC_PER_SEC) + +struct XattrWorker { + int dfd; + gboolean is_writer; + guint n_attrs_read; +}; + +typedef enum { + WRITE_RUN_MUTATE, + WRITE_RUN_CREATE, +} WriteType; + +static gboolean +set_random_xattr_value (int fd, const char *name, GError **error) +{ + const guint8 randxattrbyte = g_random_int_range (0, 256); + const guint32 randxattrvalue_len = (g_random_int () % 256) + 1; /* Picked to be not too small or large */ + g_autofree char *randxattrvalue = g_malloc (randxattrvalue_len); + + memset (randxattrvalue, randxattrbyte, randxattrvalue_len); + + if (fsetxattr (fd, name, randxattrvalue, randxattrvalue_len, 0) < 0) + { + glnx_set_error_from_errno (error); + return FALSE; + } + + return TRUE; +} + +static gboolean +add_random_xattrs (int fd, GError **error) +{ + const guint nattrs = MIN (2, g_random_int () % 16); + + for (guint i = 0; i < nattrs; i++) + { + guint32 randxattrname_v = g_random_int (); + g_autofree char *randxattrname = g_strdup_printf ("user.test%u", randxattrname_v); + + if (!set_random_xattr_value (fd, randxattrname, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +do_write_run (GLnxDirFdIterator *dfd_iter, GError **error) +{ + WriteType wtype = g_random_int () % 2; + + if (wtype == WRITE_RUN_CREATE) + { + guint32 randname_v = g_random_int (); + g_autofree char *randname = g_strdup_printf ("file%u", randname_v); + glnx_autofd int fd = -1; + + again: + fd = openat (dfd_iter->fd, randname, O_CREAT | O_EXCL, 0644); + if (fd < 0) + { + if (errno == EEXIST) + { + g_printerr ("Congratulations! I suggest purchasing a lottery ticket today!\n"); + goto again; + } + else + { + glnx_set_error_from_errno (error); + return FALSE; + } + } + + if (!add_random_xattrs (fd, error)) + return FALSE; + } + else if (wtype == WRITE_RUN_MUTATE) + { + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent (dfd_iter, &dent, NULL, error)) + return FALSE; + if (!dent) + break; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error)) + return FALSE; + + g_autoptr(GVariant) current_xattrs = NULL; + if (!glnx_fd_get_all_xattrs (fd, ¤t_xattrs, NULL, error)) + return FALSE; + + for (int i = 0; i < g_variant_n_children (current_xattrs); i++) + { + const char *name, *value; + g_variant_get_child (current_xattrs, i, "(^&ay^&ay)", &name, &value); + + /* We don't want to potentially test/change xattrs like security.selinux + * that were injected by the system. + */ + if (!g_str_has_prefix (name, "user.test")) + continue; + + if (!set_random_xattr_value (fd, name, error)) + return FALSE; + } + } + } + else + g_assert_not_reached (); + + return TRUE; +} + +static gboolean +do_read_run (GLnxDirFdIterator *dfd_iter, + guint *out_n_read, + GError **error) +{ + guint nattrs = 0; + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent (dfd_iter, &dent, NULL, error)) + return FALSE; + if (!dent) + break; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error)) + return FALSE; + + g_autoptr(GVariant) current_xattrs = NULL; + if (!glnx_fd_get_all_xattrs (fd, ¤t_xattrs, NULL, error)) + return FALSE; + + /* We don't actually care about the values, just use the variable + * to avoid compiler warnings. + */ + nattrs += g_variant_n_children (current_xattrs); + } + + *out_n_read = nattrs; + return TRUE; +} + +static gpointer +xattr_thread (gpointer data) +{ + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + struct XattrWorker *worker = data; + guint64 end_time = g_get_monotonic_time () + XATTR_THREAD_RUN_TIME_USECS; + guint n_read = 0; + + while (g_get_monotonic_time () < end_time) + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (worker->dfd, ".", TRUE, &dfd_iter, error)) + goto out; + + if (worker->is_writer) + { + if (!do_write_run (&dfd_iter, error)) + goto out; + } + else + { + if (!do_read_run (&dfd_iter, &n_read, error)) + goto out; + } + } + + out: + g_assert_no_error (local_error); + + return GINT_TO_POINTER (n_read); +} + +static void +test_xattr_races (void) +{ + /* If for some reason we're built in a VM which only has one vcpu, let's still + * at least make the test do something. + */ + /* FIXME - this deadlocks for me on 4.9.4-201.fc25.x86_64, whether + * using overlayfs or xfs as source/dest. + */ + const guint nprocs = MAX (4, g_get_num_processors ()); + struct XattrWorker wdata[nprocs]; + GThread *threads[nprocs]; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + g_auto(GLnxTmpDir) tmpdir = { 0, }; + g_autofree char *tmpdir_path = g_strdup_printf ("%s/libglnx-xattrs-XXXXXX", + getenv ("TMPDIR") ?: "/var/tmp"); + guint nread = 0; + + if (!glnx_mkdtempat (AT_FDCWD, tmpdir_path, 0700, + &tmpdir, error)) + goto out; + + /* Support people building/testing on tmpfs https://github.com/flatpak/flatpak/issues/686 */ + if (fsetxattr (tmpdir.fd, "user.test", "novalue", strlen ("novalue"), 0) < 0) + { + if (errno == EOPNOTSUPP) + { + g_test_skip ("no xattr support"); + return; + } + else + { + glnx_set_error_from_errno (error); + goto out; + } + } + + for (guint i = 0; i < nprocs; i++) + { + struct XattrWorker *worker = &wdata[i]; + worker->dfd = tmpdir.fd; + worker->is_writer = i % 2 == 0; + threads[i] = g_thread_new (NULL, xattr_thread, worker); + } + + for (guint i = 0; i < nprocs; i++) + { + if (wdata[i].is_writer) + (void) g_thread_join (threads[i]); + else + nread += GPOINTER_TO_UINT (g_thread_join (threads[i])); + } + + g_print ("Read %u xattrs race free!\n", nread); + + out: + g_assert_no_error (local_error); +} + +int main (int argc, char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/xattr-races", test_xattr_races); + + ret = g_test_run(); + + return ret; +}