diff --git a/common/flatpak-context-private.h b/common/flatpak-context-private.h index 6e07eefd..8a565377 100644 --- a/common/flatpak-context-private.h +++ b/common/flatpak-context-private.h @@ -84,6 +84,7 @@ extern const char *flatpak_context_features[]; extern const char *flatpak_context_shares[]; gboolean flatpak_context_parse_filesystem (const char *filesystem_and_mode, + gboolean negated, char **filesystem_out, FlatpakFilesystemMode *mode_out, GError **error); diff --git a/common/flatpak-context.c b/common/flatpak-context.c index dd230d26..34510c15 100644 --- a/common/flatpak-context.c +++ b/common/flatpak-context.c @@ -87,6 +87,7 @@ const char *flatpak_context_special_filesystems[] = { "host", "host-etc", "host-os", + "host-reset", NULL }; @@ -704,6 +705,12 @@ unparse_filesystem_flags (const char *path, case FLATPAK_FILESYSTEM_MODE_NONE: g_string_insert_c (s, 0, '!'); + + if (g_str_has_suffix (s->str, "-reset")) + { + g_string_truncate (s, s->len - 6); + g_string_append (s, ":reset"); + } break; default: @@ -716,11 +723,14 @@ unparse_filesystem_flags (const char *path, static char * parse_filesystem_flags (const char *filesystem, - FlatpakFilesystemMode *mode_out) + gboolean negated, + FlatpakFilesystemMode *mode_out, + GError **error) { g_autoptr(GString) s = g_string_new (""); const char *p, *suffix; FlatpakFilesystemMode mode; + gboolean reset = FALSE; p = filesystem; while (*p != 0 && *p != ':') @@ -735,7 +745,31 @@ parse_filesystem_flags (const char *filesystem, g_string_append_c (s, *p++); } - mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE; + if (negated) + mode = FLATPAK_FILESYSTEM_MODE_NONE; + else + mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE; + + if (g_str_equal (s->str, "host-reset")) + { + reset = TRUE; + + if (!negated) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Filesystem token \"%s\" is only applicable for --nofilesystem", + s->str); + return NULL; + } + + if (*p != '\0') + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Filesystem token \"%s\" cannot be used with a suffix", + s->str); + return NULL; + } + } if (*p == ':') { @@ -747,10 +781,63 @@ parse_filesystem_flags (const char *filesystem, mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE; else if (strcmp (suffix, "create") == 0) mode = FLATPAK_FILESYSTEM_MODE_CREATE; + else if (strcmp (suffix, "reset") == 0) + reset = TRUE; else if (*suffix != 0) g_warning ("Unexpected filesystem suffix %s, ignoring", suffix); + + if (negated && mode != FLATPAK_FILESYSTEM_MODE_NONE) + { + g_warning ("Filesystem suffix \"%s\" is not applicable for --nofilesystem", + suffix); + mode = FLATPAK_FILESYSTEM_MODE_NONE; + } + + if (reset) + { + if (!negated) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Filesystem suffix \"%s\" only applies to --nofilesystem", + suffix); + return NULL; + } + + if (!g_str_equal (s->str, "host")) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Filesystem suffix \"%s\" can only be applied to " + "--nofilesystem=host", + suffix); + return NULL; + } + + /* We internally handle host:reset (etc) as host-reset, only exposing it as a flag in the public + part to allow it to be ignored (with a warning) for old flatpak versions */ + g_string_append (s, "-reset"); + } } + /* Postcondition check: the code above should make some results + * impossible */ + if (negated) + { + g_assert (mode == FLATPAK_FILESYSTEM_MODE_NONE); + } + else + { + g_assert (mode > FLATPAK_FILESYSTEM_MODE_NONE); + /* This flag is only applicable to --nofilesystem */ + g_assert (!reset); + } + + /* Postcondition check: filesystem token is host-reset iff reset flag + * was found */ + if (reset) + g_assert (g_str_equal (s->str, "host-reset")); + else + g_assert (!g_str_equal (s->str, "host-reset")); + if (mode_out) *mode_out = mode; @@ -759,13 +846,18 @@ parse_filesystem_flags (const char *filesystem, gboolean flatpak_context_parse_filesystem (const char *filesystem_and_mode, + gboolean negated, char **filesystem_out, FlatpakFilesystemMode *mode_out, GError **error) { - g_autofree char *filesystem = parse_filesystem_flags (filesystem_and_mode, mode_out); + g_autofree char *filesystem = NULL; char *slash; + filesystem = parse_filesystem_flags (filesystem_and_mode, negated, mode_out, error); + if (filesystem == NULL) + return FALSE; + slash = strchr (filesystem, '/'); /* Forbid /../ in paths */ @@ -857,6 +949,14 @@ flatpak_context_take_filesystem (FlatpakContext *context, char *fs, FlatpakFilesystemMode mode) { + /* Special case: --nofilesystem=host-reset implies --nofilesystem=host. + * --filesystem=host-reset (or host:reset) is not allowed. */ + if (g_str_equal (fs, "host-reset")) + { + g_return_if_fail (mode == FLATPAK_FILESYSTEM_MODE_NONE); + g_hash_table_insert (context->filesystems, g_strdup ("host"), GINT_TO_POINTER (mode)); + } + g_hash_table_insert (context->filesystems, fs, GINT_TO_POINTER (mode)); } @@ -888,6 +988,14 @@ flatpak_context_merge (FlatpakContext *context, while (g_hash_table_iter_next (&iter, &key, &value)) g_hash_table_insert (context->persistent, g_strdup (key), value); + /* We first handle host:reset, as it overrides all other keys from the parent */ + if (g_hash_table_lookup_extended (other->filesystems, "host-reset", NULL, &value)) + { + g_warn_if_fail (GPOINTER_TO_INT (value) == FLATPAK_FILESYSTEM_MODE_NONE); + g_hash_table_remove_all (context->filesystems); + } + + /* Then set the new ones, which includes propagating host:reset. */ g_hash_table_iter_init (&iter, other->filesystems); while (g_hash_table_iter_next (&iter, &key, &value)) g_hash_table_insert (context->filesystems, g_strdup (key), value); @@ -1075,7 +1183,7 @@ option_filesystem_cb (const gchar *option_name, g_autofree char *fs = NULL; FlatpakFilesystemMode mode; - if (!flatpak_context_parse_filesystem (value, &fs, &mode, error)) + if (!flatpak_context_parse_filesystem (value, FALSE, &fs, &mode, error)) return FALSE; flatpak_context_take_filesystem (context, g_steal_pointer (&fs), mode); @@ -1092,7 +1200,7 @@ option_nofilesystem_cb (const gchar *option_name, g_autofree char *fs = NULL; FlatpakFilesystemMode mode; - if (!flatpak_context_parse_filesystem (value, &fs, &mode, error)) + if (!flatpak_context_parse_filesystem (value, TRUE, &fs, &mode, error)) return FALSE; flatpak_context_take_filesystem (context, g_steal_pointer (&fs), @@ -1597,15 +1705,13 @@ flatpak_context_load_metadata (FlatpakContext *context, g_autofree char *filesystem = NULL; FlatpakFilesystemMode mode; - if (!flatpak_context_parse_filesystem (fs, &filesystem, &mode, NULL)) + if (!flatpak_context_parse_filesystem (fs, remove, + &filesystem, &mode, NULL)) g_debug ("Unknown filesystem type %s", filesystems[i]); else { - if (remove) - flatpak_context_take_filesystem (context, g_steal_pointer (&filesystem), - FLATPAK_FILESYSTEM_MODE_NONE); - else - flatpak_context_take_filesystem (context, g_steal_pointer (&filesystem), mode); + g_assert (mode == FLATPAK_FILESYSTEM_MODE_NONE || !remove); + flatpak_context_take_filesystem (context, g_steal_pointer (&filesystem), mode); } } } @@ -1851,11 +1957,24 @@ flatpak_context_save_metadata (FlatpakContext *context, { g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + /* Serialize host-reset first, because order can matter in + * corner cases. */ + if (g_hash_table_lookup_extended (context->filesystems, "host-reset", + NULL, &value)) + { + g_warn_if_fail (GPOINTER_TO_INT (value) == FLATPAK_FILESYSTEM_MODE_NONE); + g_ptr_array_add (array, g_strdup ("!host:reset")); + } + g_hash_table_iter_init (&iter, context->filesystems); while (g_hash_table_iter_next (&iter, &key, &value)) { FlatpakFilesystemMode mode = GPOINTER_TO_INT (value); + /* We already did this */ + if (g_str_equal (key, "host-reset")) + continue; + g_ptr_array_add (array, unparse_filesystem_flags (key, mode)); } @@ -1994,7 +2113,8 @@ flatpak_context_save_metadata (FlatpakContext *context, void flatpak_context_allow_host_fs (FlatpakContext *context) { - flatpak_context_take_filesystem (context, g_strdup ("host"), FLATPAK_FILESYSTEM_MODE_READ_WRITE); + flatpak_context_take_filesystem (context, g_strdup ("host"), + FLATPAK_FILESYSTEM_MODE_READ_WRITE); } gboolean @@ -2185,18 +2305,36 @@ flatpak_context_to_args (FlatpakContext *context, g_ptr_array_add (args, g_strdup_printf ("--system-%s-name=%s", flatpak_policy_to_string (policy), name)); } + /* Serialize host-reset first, because order can matter in + * corner cases. */ + if (g_hash_table_lookup_extended (context->filesystems, "host-reset", + NULL, &value)) + { + g_warn_if_fail (GPOINTER_TO_INT (value) == FLATPAK_FILESYSTEM_MODE_NONE); + g_ptr_array_add (args, g_strdup ("--nofilesystem=host:reset")); + } + g_hash_table_iter_init (&iter, context->filesystems); while (g_hash_table_iter_next (&iter, &key, &value)) { + g_autofree char *fs = NULL; FlatpakFilesystemMode mode = GPOINTER_TO_INT (value); + /* We already did this */ + if (g_str_equal (key, "host-reset")) + continue; + + fs = unparse_filesystem_flags (key, mode); + if (mode != FLATPAK_FILESYSTEM_MODE_NONE) { - g_autofree char *fs = unparse_filesystem_flags (key, mode); g_ptr_array_add (args, g_strdup_printf ("--filesystem=%s", fs)); } else - g_ptr_array_add (args, g_strdup_printf ("--nofilesystem=%s", (char *) key)); + { + g_assert (fs[0] == '!'); + g_ptr_array_add (args, g_strdup_printf ("--nofilesystem=%s", &fs[1])); + } } } diff --git a/doc/flatpak-override.xml b/doc/flatpak-override.xml index 05c4a800..ed1ba52b 100644 --- a/doc/flatpak-override.xml +++ b/doc/flatpak-override.xml @@ -248,6 +248,14 @@ accessing most of the home directory, but it will still be allowed to access $XDG_CONFIG_HOME/MyApp. + + As a special case, + + will ignore all + permissions inherited from the app manifest or a + lower-precedence layer of overrides, in addition to + having the behaviour of + . diff --git a/doc/flatpak-run.xml b/doc/flatpak-run.xml index 69df02c9..90df07e4 100644 --- a/doc/flatpak-run.xml +++ b/doc/flatpak-run.xml @@ -389,6 +389,14 @@ accessing most of the home directory, but it will still be allowed to access $XDG_CONFIG_HOME/MyApp. + + As a special case, + + will ignore all + permissions inherited from the app manifest or + flatpak-override1, + in addition to having the behaviour of + . diff --git a/tests/test-exports.c b/tests/test-exports.c index c0af5689..d12042a1 100644 --- a/tests/test-exports.c +++ b/tests/test-exports.c @@ -607,8 +607,8 @@ test_filesystems (void) gboolean ret; g_test_message ("%s", fs->input); - ret = flatpak_context_parse_filesystem (fs->input, &normalized, &mode, - &error); + ret = flatpak_context_parse_filesystem (fs->input, FALSE, + &normalized, &mode, &error); g_assert_no_error (error); g_assert_true (ret); @@ -629,8 +629,8 @@ test_filesystems (void) gboolean ret; g_test_message ("%s", not->input); - ret = flatpak_context_parse_filesystem (not->input, &normalized, &mode, - &error); + ret = flatpak_context_parse_filesystem (not->input, FALSE, + &normalized, &mode, &error); g_test_message ("-> %s", error ? error->message : "(no error)"); g_assert_error (error, G_OPTION_ERROR, not->code); g_assert_false (ret);