diff options
author | Alexander Larsson <alexl@redhat.com> | 2018-05-02 13:53:39 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2018-05-02 13:53:39 +0200 |
commit | b4484aa97eb62948d59cbd8413fc08e08b16dd3e (patch) | |
tree | 4354c159a4eeb8772857778af1166edaedfb648e | |
parent | 2c22aa17e0aacd1dc1c8cb1b87a8bd5e908b4c56 (diff) | |
download | flatpak-b4484aa97eb62948d59cbd8413fc08e08b16dd3e.tar.gz |
Re-fix export filename checks, this time also for build-finishre-fix-exports
The fix in 5122766284295c460320153c1213bccc7c8e3609 was not right.
First of all it didn't changethe regressing behaviour for
build-finish, just install.
Secondly, it changed the prefix matches to always use
flatpak_name_matches_one_wildcard_prefix() which had slight
differences in behaviour that the previously used
flatpak_name_matches_one_prefix. For example, it always removed
the extension, no matter what it was.
This has all been replaced with a shared (between install and
build-finish) version that is more strict with extensions, and with
what names can be exported as service files (these have to match
exactly, with the wildcard and cannot have suffixes).
To test this i tried to install these apps from flathub that has
some more complex exports:
org.sparkleshare.SparkleShare:
org.sparkleshare.SparkleShare.Invites.desktop
org.sparkleshare.SparkleShare-symbolic.svg
org.libreoffice.LibreOffice:
org.libreoffice.LibreOffice.desktop
org.libreoffice.LibreOffice-impress.desktop
org.libreoffice.LibreOffice-writer.png
org.libreoffice.LibreOffice-calc.png
com.github.bajoja.indicator-kdeconnect:
com.github.bajoja.indicator-kdeconnect.desktop
com.github.bajoja.indicator-kdeconnect.settings.desktop
com.github.bajoja.indicator-kdeconnect.tablettrusted.svg
com.github.philip_scott.spice-up:
com.github.philip_scott.spice-up.svg
com.github.philip_scott.spice-up-mime.svg
com.github.philip_scott.spice-up.mime.xml
org.gnome.Recipes:
org.gnome.Recipes.desktop
org.gnome.Recipes.service
org.gnome.Recipes-search-provider.ini
org.gnome.Recipes.png
org.gnome.Recipes-symbolic.symbolic.png
org.gnome.Recipes-mime.xml
org.gnome.Characters:
org.gnome.Characters.desktop
org.gnome.Characters.BackgroundService.service
org.gnome.Characters.service
org.gnome.Characters.search-provider.ini
org.gnome.Characters.png
org.gnome.Characters-symbolic.svg
org.gnome.Weather
org.gnome.Weather.Application.desktop
org.gnome.Weather.Application.service
org.gnome.Weather.BackgroundService.service
org.gnome.Weather.Application.search-provider.ini
org.gpodder.gpodder:
org.gpodder.gpodder.desktop
org.gpodder.gpodder.gpodder-url-handler.desktop
-rw-r--r-- | app/flatpak-builtins-build-finish.c | 152 | ||||
-rw-r--r-- | common/flatpak-dir.c | 70 | ||||
-rw-r--r-- | common/flatpak-utils.c | 146 | ||||
-rw-r--r-- | common/flatpak-utils.h | 15 |
4 files changed, 197 insertions, 186 deletions
diff --git a/app/flatpak-builtins-build-finish.c b/app/flatpak-builtins-build-finish.c index e0b23270..0a93728b 100644 --- a/app/flatpak-builtins-build-finish.c +++ b/app/flatpak-builtins-build-finish.c @@ -60,57 +60,15 @@ static GOptionEntry options[] = { { NULL } }; -typedef gboolean (*DirectoryExportFileFilterFunc) (char *path, gpointer user_data); - -typedef struct _BuiltinExportedDirectoryInfo { - char *path; - DirectoryExportFileFilterFunc filter_func; - gpointer user_data; - GDestroyNotify user_data_destroy; -} BuiltinExportedDirectoryInfo; - -static BuiltinExportedDirectoryInfo * -builtin_exported_directory_info_new (const char *path, - DirectoryExportFileFilterFunc filter_func, - gpointer user_data, - GDestroyNotify user_data_destroy) -{ - BuiltinExportedDirectoryInfo *info = g_new0 (BuiltinExportedDirectoryInfo, 1); - - info->path = g_strdup (path); - info->filter_func = filter_func; - info->user_data = user_data; - info->user_data_destroy = user_data_destroy; - - return info; -} - -static BuiltinExportedDirectoryInfo * -builtin_exported_directory_info_new_simple (const char *path, - const char *permissible_prefix) -{ - return builtin_exported_directory_info_new (path, - (DirectoryExportFileFilterFunc) flatpak_has_name_prefix, - g_strdup (permissible_prefix), - g_free); -} - -static void -builtin_exported_directory_info_free (BuiltinExportedDirectoryInfo *info) -{ - g_clear_pointer (&info->path, g_free); - - if (info->user_data_destroy != NULL) - g_clear_pointer (&info->user_data, info->user_data_destroy); -} - static gboolean export_dir (int source_parent_fd, const char *source_name, const char *source_relpath, int destination_parent_fd, const char *destination_name, - BuiltinExportedDirectoryInfo *exported_directory_info, + char **allowed_prefixes, + char **allowed_extensions, + gboolean require_exact_match, GCancellable *cancellable, GError **error) { @@ -173,17 +131,34 @@ export_dir (int source_parent_fd, g_autofree gchar *child_relpath = g_build_filename (source_relpath, dent->d_name, NULL); if (!export_dir (source_iter.fd, dent->d_name, child_relpath, destination_dfd, dent->d_name, - exported_directory_info, cancellable, error)) + allowed_prefixes, allowed_extensions, require_exact_match, + cancellable, error)) return FALSE; } else if (S_ISREG (stbuf.st_mode)) { + g_autofree gchar *name_without_extension = NULL; + int i; + source_printable = g_build_filename (source_relpath, dent->d_name, NULL); - if (!exported_directory_info->filter_func (dent->d_name, - exported_directory_info->user_data)) + for (i = 0; allowed_extensions[i] != NULL; i++) { - g_print (_("Not exporting %s, wrong prefix\n"), source_printable); + if (g_str_has_suffix (dent->d_name, allowed_extensions[i])) + break; + } + + if (allowed_extensions[i] == NULL) + { + g_print (_("Not exporting %s, wrong extension\n"), source_printable); + continue; + } + + name_without_extension = g_strndup (dent->d_name, strlen (dent->d_name) - strlen (allowed_extensions[i])); + + if (!flatpak_name_matches_one_wildcard_prefix (name_without_extension, (const char * const *) allowed_prefixes, require_exact_match)) + { + g_print (_("Not exporting %s, non-allowed export filename\n"), source_printable); continue; } @@ -224,7 +199,9 @@ static gboolean copy_exports (GFile *source, GFile *destination, const char *source_prefix, - BuiltinExportedDirectoryInfo *exported_directory_info, + char **allowed_prefixes, + char **allowed_extensions, + gboolean require_exact_match, GCancellable *cancellable, GError **error) { @@ -234,30 +211,13 @@ copy_exports (GFile *source, /* The fds are closed by this call */ if (!export_dir (AT_FDCWD, flatpak_file_get_path_cached (source), source_prefix, AT_FDCWD, flatpak_file_get_path_cached (destination), - exported_directory_info, cancellable, error)) + allowed_prefixes, allowed_extensions, require_exact_match, + cancellable, error)) return FALSE; return TRUE; } -static GStrv -lookup_permitted_dbus_service_file_prefixes (FlatpakContext *arg_context, - const char *app_id) -{ - g_auto(GStrv) dbus_own_name_prefixes = - flatpak_context_get_session_bus_policy_allowed_own_names (arg_context); - g_autoptr(GPtrArray) permitted_prefixes = g_ptr_array_new_with_free_func (g_free); - GStrv iter = dbus_own_name_prefixes; - - g_ptr_array_add (permitted_prefixes, g_strdup (app_id)); - - for (; *iter != NULL; ++iter) - g_ptr_array_add (permitted_prefixes, g_strdup (*iter)); - - g_ptr_array_add (permitted_prefixes, NULL); - return (GStrv) g_ptr_array_free (g_steal_pointer (&permitted_prefixes), FALSE); -} - static gboolean collect_exports (GFile *base, const char *app_id, @@ -267,34 +227,16 @@ collect_exports (GFile *base, { g_autoptr(GFile) files = NULL; g_autoptr(GFile) export = NULL; - g_autoptr(GPtrArray) exported_directory_infos = - g_ptr_array_new_with_free_func ((GDestroyNotify) builtin_exported_directory_info_free); - g_auto(GStrv) permitted_dbus_service_file_prefixes = - lookup_permitted_dbus_service_file_prefixes (arg_context, app_id); int i; + const char *paths[] = { + "share/applications", /* Copy desktop files */ + "share/mime/packages", /* Copy MIME Type files */ + "share/icons", /* Icons */ + "share/dbus-1/services", /* D-Bus service files */ + "share/gnome-shell/search-providers", /* Search providers */ + NULL, + }; - /* Copy desktop files */ - g_ptr_array_add (exported_directory_infos, - builtin_exported_directory_info_new_simple ("share/applications", app_id)); - - /* Copy MIME type files */ - g_ptr_array_add (exported_directory_infos, - builtin_exported_directory_info_new_simple ("share/mime/packages", app_id)); - - /* Copy icons */ - g_ptr_array_add (exported_directory_infos, - builtin_exported_directory_info_new_simple ("share/icons", app_id)); - - /* Copy D-Bus service files */ - g_ptr_array_add (exported_directory_infos, - builtin_exported_directory_info_new ("share/dbus-1/services", - (DirectoryExportFileFilterFunc) flatpak_name_matches_one_wildcard_prefix, - g_steal_pointer (&permitted_dbus_service_file_prefixes), - (GDestroyNotify) g_strfreev)); - - /* Copy Search Providers */ - g_ptr_array_add (exported_directory_infos, - builtin_exported_directory_info_new_simple ("share/gnome-shell/search-providers", app_id)); files = g_file_get_child (base, "files"); @@ -306,12 +248,18 @@ collect_exports (GFile *base, if (opt_no_exports) return TRUE; - for (i = 0; i < exported_directory_infos->len; i++) + for (i = 0; paths[i]; i++) { - g_autoptr(GFile) src = NULL; - BuiltinExportedDirectoryInfo *info = g_ptr_array_index (exported_directory_infos, i); - const char * path = info->path; - src = g_file_resolve_relative_path (files, path); + const char * path = paths[i]; + g_autoptr(GFile) src = g_file_resolve_relative_path (files, path); + g_auto(GStrv) allowed_prefixes = NULL; + g_auto(GStrv) allowed_extensions = NULL; + gboolean require_exact_match = FALSE; + + if (!flatpak_get_allowed_exports (path, app_id, arg_context, + &allowed_extensions, &allowed_prefixes, &require_exact_match)) + return flatpak_fail (error, "Unexpectedly not allowed to export %s", path); + if (g_file_query_exists (src, cancellable)) { g_debug ("Exporting from %s", path); @@ -326,7 +274,9 @@ collect_exports (GFile *base, if (!copy_exports (src, dest, path, - info, + allowed_prefixes, + allowed_extensions, + require_exact_match, cancellable, error)) return FALSE; diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 36877090..d7831e7c 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -4954,39 +4954,6 @@ out: return ret; } -typedef gboolean (*MultiplePrefixesComparisonFunc) (const char *path, - const char * const *prefixes); - -static GStrv -get_permissible_prefixes (FlatpakContext *context, - const char *source_path, - const char *app_id, - GError **error) -{ - g_autoptr(GPtrArray) prefixes = NULL; - - prefixes = g_ptr_array_new_with_free_func (g_free); - - /* Create a new pointer array with prefixes including the app - * ID and in the case of d-bus service files, the allowed own - * names. */ - g_ptr_array_add (prefixes, g_strdup_printf ("%s.*", app_id)); - - if (flatpak_has_path_prefix (source_path, "share/dbus-1/services")) - { - g_auto(GStrv) owned_dbus_names = - flatpak_context_get_session_bus_policy_allowed_own_names (context); - GStrv iter = owned_dbus_names; - - for (; *iter != NULL; ++iter) - g_ptr_array_add (prefixes, g_strdup (*iter)); - } - - g_ptr_array_add (prefixes, NULL); - - return (GStrv) g_ptr_array_free (g_steal_pointer (&prefixes), FALSE); -} - static gboolean rewrite_export_dir (const char *app, const char *branch, @@ -5004,10 +4971,17 @@ rewrite_export_dir (const char *app, g_auto(GLnxDirFdIterator) source_iter = {0}; g_autoptr(GHashTable) visited_children = NULL; struct dirent *dent; + gboolean exports_allowed = FALSE; + g_auto(GStrv) allowed_prefixes = NULL; + g_auto(GStrv) allowed_extensions = NULL; + gboolean require_exact_match = FALSE; if (!glnx_dirfd_iterator_init_at (source_parent_fd, source_name, FALSE, &source_iter, error)) goto out; + exports_allowed = flatpak_get_allowed_exports (source_path, app, context, + &allowed_extensions, &allowed_prefixes, &require_exact_match); + visited_children = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); while (TRUE) @@ -5048,18 +5022,32 @@ rewrite_export_dir (const char *app, path, cancellable, error)) goto out; } - else if (S_ISREG (stbuf.st_mode)) + else if (S_ISREG (stbuf.st_mode) && exports_allowed) { - g_auto(GStrv) permissible_prefixes = get_permissible_prefixes (context, - source_path, - app, - error); + g_autofree gchar *name_without_extension = NULL; g_autofree gchar *new_name = NULL; + int i; - if (permissible_prefixes == NULL) - return FALSE; + for (i = 0; allowed_extensions[i] != NULL; i++) + { + if (g_str_has_suffix (dent->d_name, allowed_extensions[i])) + break; + } + + if (allowed_extensions[i] == NULL) + { + g_warning ("Invalid extension for %s in app %s, removing.", dent->d_name, app); + if (unlinkat (source_iter.fd, dent->d_name, 0) != 0 && errno != ENOENT) + { + glnx_set_error_from_errno (error); + goto out; + } + continue; + } + + name_without_extension = g_strndup (dent->d_name, strlen (dent->d_name) - strlen (allowed_extensions[i])); - if (!flatpak_name_matches_one_wildcard_prefix (dent->d_name, (const char * const *) permissible_prefixes)) + if (!flatpak_name_matches_one_wildcard_prefix (name_without_extension, (const char * const *) allowed_prefixes, require_exact_match)) { g_warning ("Non-prefixed filename %s in app %s, removing.", dent->d_name, app); if (unlinkat (source_iter.fd, dent->d_name, 0) != 0 && errno != ENOENT) diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c index 2a93a19f..a370691b 100644 --- a/common/flatpak-utils.c +++ b/common/flatpak-utils.c @@ -761,63 +761,131 @@ out: } gboolean -flatpak_has_name_prefix (const char *string, - const char *name) +flatpak_name_matches_one_wildcard_prefix (const char *name, + const char * const *wildcarded_prefixes, + gboolean require_exact_match) { - const char *rest; + const char * const *iter = wildcarded_prefixes; + const char *remainder; + gsize longest_match_len = 0; + + /* Find longest valid match */ + for (; *iter != NULL; ++iter) + { + const char *prefix = *iter; + gsize prefix_len = strlen (prefix); + gsize match_len = strlen (prefix); + gboolean has_wildcard = FALSE; + const char *end_of_match; + + if (g_str_has_suffix (prefix, ".*")) + { + has_wildcard = TRUE; + prefix_len -= 2; + } + + if (strncmp (name, prefix, prefix_len) != 0) + continue; + + end_of_match = name + prefix_len; + + if (has_wildcard && + end_of_match[0] == '.' && + is_valid_initial_name_character (end_of_match[1], TRUE)) + { + end_of_match += 2; + while (*end_of_match != 0 && + is_valid_name_character (*end_of_match, TRUE)) + end_of_match++; + } - if (!g_str_has_prefix (string, name)) + match_len = end_of_match - name; + + if (match_len > longest_match_len) + longest_match_len = match_len; + } + + if (longest_match_len == 0) return FALSE; - rest = string + strlen (name); + if (require_exact_match) + return name[longest_match_len] == 0; + + /* non-exact matches can be exact, or can be followed by characters that would make + * not be part of the last element in the matched prefix, due to being invalid or + * a new element. As a special case we explicitly disallow dash here, even though + * it iss typically allowed in the final element of a name, this allows you too sloppily + * match org.the.App with org.the.App-symbolic[.png] or org.the.App-settings[.desktop]. + */ + remainder = name + longest_match_len; return - *rest == 0 || - *rest == '.' || - !is_valid_name_character (*rest, FALSE); + *remainder == 0 || + *remainder == '.' || + !is_valid_name_character (*remainder, FALSE); } gboolean -flatpak_name_matches_one_prefix (const char *name, - const char * const *prefixes) +flatpak_get_allowed_exports (const char *source_path, + const char *app_id, + FlatpakContext *context, + char ***allowed_extensions_out, + char ***allowed_prefixes_out, + gboolean *require_exact_match_out) { - const char * const *iter = prefixes; + g_autoptr(GPtrArray) allowed_extensions = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) allowed_prefixes = g_ptr_array_new_with_free_func (g_free); + gboolean require_exact_match = FALSE; - for (; *iter != NULL; ++iter) - if (flatpak_has_name_prefix (name, *iter)) - return TRUE; + g_ptr_array_add (allowed_prefixes, g_strdup_printf ("%s.*", app_id)); - return FALSE; -} + if (flatpak_has_path_prefix (source_path, "share/applications")) + { + g_ptr_array_add (allowed_extensions, g_strdup (".desktop")); + } + else if (flatpak_has_path_prefix (source_path, "share/icons")) + { + g_ptr_array_add (allowed_extensions, g_strdup (".svgz")); + g_ptr_array_add (allowed_extensions, g_strdup (".png")); + g_ptr_array_add (allowed_extensions, g_strdup (".svg")); + g_ptr_array_add (allowed_extensions, g_strdup (".ico")); + } + else if (flatpak_has_path_prefix (source_path, "share/dbus-1/services")) + { + g_auto(GStrv) owned_dbus_names = flatpak_context_get_session_bus_policy_allowed_own_names (context); -gboolean -flatpak_name_matches_one_wildcard_prefix (const char *name, - const char * const *wildcarded_prefixes) -{ - const char * const *iter = wildcarded_prefixes; - g_autofree char *name_without_suffix = g_strdup (name); + g_ptr_array_add (allowed_extensions, g_strdup (".service")); - char *first_dot = strrchr (name_without_suffix, '.'); - *first_dot = '\0'; + for (GStrv iter = owned_dbus_names; *iter != NULL; ++iter) + g_ptr_array_add (allowed_prefixes, g_strdup (*iter)); - for (; *iter != NULL; ++iter) + /* We need an exact match with no extra garbage, because the filename refers to busnames + * and we can *only* match exactly these */ + require_exact_match = TRUE; + } + else if (flatpak_has_path_prefix (source_path, "share/gnome-shell/search-providers")) + { + g_ptr_array_add (allowed_extensions, g_strdup (".ini")); + } + else if (flatpak_has_path_prefix (source_path, "share/mime/packages")) { - const char *maybe_wildcarded_prefix = *iter; + g_ptr_array_add (allowed_extensions, g_strdup (".xml")); + } + else + return FALSE; - if (g_str_has_suffix (maybe_wildcarded_prefix, ".*")) - { - g_autofree char *truncated_wildcarded_prefix = g_strndup (maybe_wildcarded_prefix, - strlen (maybe_wildcarded_prefix) - 2); + g_ptr_array_add (allowed_extensions, NULL); + g_ptr_array_add (allowed_prefixes, NULL); - if (flatpak_has_name_prefix (name_without_suffix, truncated_wildcarded_prefix)) - return TRUE; - } - else if (g_strcmp0 (name_without_suffix, maybe_wildcarded_prefix) == 0) - { - return TRUE; - } - } + if (allowed_extensions_out) + *allowed_extensions_out = (char **)g_ptr_array_free (g_steal_pointer (&allowed_extensions), FALSE); - return FALSE; + if (allowed_prefixes_out) + *allowed_prefixes_out = (char **)g_ptr_array_free (g_steal_pointer (&allowed_prefixes), FALSE); + + if (require_exact_match_out) + *require_exact_match_out = require_exact_match; + + return TRUE; } static gboolean diff --git a/common/flatpak-utils.h b/common/flatpak-utils.h index fcd19bb8..535932e6 100644 --- a/common/flatpak-utils.h +++ b/common/flatpak-utils.h @@ -141,12 +141,17 @@ gboolean flatpak_summary_lookup_ref (GVariant *summary, char **out_checksum, GVariant **out_variant); -gboolean flatpak_has_name_prefix (const char *string, - const char *name); -gboolean flatpak_name_matches_one_prefix (const char *string, - const char * const *prefixes); gboolean flatpak_name_matches_one_wildcard_prefix (const char *string, - const char * const *maybe_wildcard_prefixes); + const char * const *maybe_wildcard_prefixes, + gboolean require_exact_match); + +gboolean flatpak_get_allowed_exports (const char *source_path, + const char *app_id, + FlatpakContext *context, + char ***allowed_extensions_out, + char ***allowed_prefixes_out, + gboolean *require_exact_match_out); + gboolean flatpak_is_valid_name (const char *string, GError **error); gboolean flatpak_is_valid_branch (const char *string, |