diff options
author | Simon McVittie <smcv@debian.org> | 2019-01-25 19:13:33 +0000 |
---|---|---|
committer | Simon McVittie <smcv@debian.org> | 2022-01-19 23:16:36 +0000 |
commit | 749f58ce4cb42c5a0cf4220e920666e960b3932a (patch) | |
tree | f7e169ed411e33d840e6dc8c1f973a81c5544b62 | |
parent | 8bf37ae3243aa65f4015aa004c462c65e80ca703 (diff) |
Replace the icon validator with the one from Flatpak 1.10.1archive/debian/1.12.1-1_bpo11+1
We avoid relying on Flatpak here, since that dependency would be quite
circular.
Signed-off-by: Simon McVittie <smcv@debian.org>
Gbp-Pq: Name Replace-the-icon-validator-with-the-one-from-Flatpak-1.10.patch
-rw-r--r-- | src/Makefile.am.inc | 2 | ||||
-rw-r--r-- | src/notification.c | 14 | ||||
-rw-r--r-- | src/validate-icon.c | 212 |
3 files changed, 208 insertions, 20 deletions
diff --git a/src/Makefile.am.inc b/src/Makefile.am.inc index db4ac7b..d9c202b 100644 --- a/src/Makefile.am.inc +++ b/src/Makefile.am.inc @@ -220,4 +220,4 @@ xdg_desktop_portal_CPPFLAGS = \ xdg_desktop_portal_validate_icon_SOURCES = src/validate-icon.c xdg_desktop_portal_validate_icon_LDADD = $(GDK_PIXBUF_LIBS) -xdg_desktop_portal_validate_icon_CFLAGS = $(GDK_PIXBUF_CFLAGS) -DHELPER=\"$(BWRAP)\" +xdg_desktop_portal_validate_icon_CFLAGS = $(GDK_PIXBUF_CFLAGS) -DHELPER=\"$(BWRAP)\" -D_GNU_SOURCE=1 diff --git a/src/notification.c b/src/notification.c index 5412609..35c779c 100644 --- a/src/notification.c +++ b/src/notification.c @@ -366,7 +366,7 @@ validate_icon_more (GVariant *v) int status; g_autofree char *err = NULL; g_autoptr(GError) error = NULL; - const char *icon_validator = LIBEXECDIR "/flatpak-validate-icon"; + const char *icon_validator = LIBEXECDIR "/xdg-desktop-portal-validate-icon"; const char *args[6]; if (G_IS_THEMED_ICON (icon)) @@ -382,12 +382,6 @@ validate_icon_more (GVariant *v) return FALSE; } - if (!g_file_test (icon_validator, G_FILE_TEST_EXISTS)) - { - g_debug ("Icon validation: %s not found, accepting icon without further validation.", icon_validator); - return TRUE; - } - bytes = g_bytes_icon_get_bytes (G_BYTES_ICON (icon)); fd = g_file_open_tmp ("iconXXXXXX", &name, &error); if (fd == -1) @@ -420,14 +414,12 @@ validate_icon_more (GVariant *v) if (!g_spawn_sync (NULL, (char **)args, NULL, 0, NULL, NULL, NULL, &err, &status, &error)) { g_debug ("Icon validation: %s", error->message); - return FALSE; } - if (!g_spawn_check_exit_status (status, &error)) + if (!g_spawn_check_exit_status (status, NULL)) { - g_debug ("Icon validation: %s", error->message); - + g_debug ("Icon validation: %s", err); return FALSE; } diff --git a/src/validate-icon.c b/src/validate-icon.c index 2bab74f..2c28527 100644 --- a/src/validate-icon.c +++ b/src/validate-icon.c @@ -1,9 +1,35 @@ +/* + * Copyright © 2018 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Matthias Clasen <mclasen@redhat.com> + */ + #include <gdk-pixbuf/gdk-pixbuf.h> +#include <glib/gstdio.h> +#include <errno.h> +#include <unistd.h> static int -validate_icon (const char *filename) +validate_icon (const char *arg_width, + const char *arg_height, + const char *filename) { GdkPixbufFormat *format; + int max_width, max_height; int width, height; const char *name; const char *allowed_formats[] = { "png", "jpeg", "svg", NULL }; @@ -11,7 +37,7 @@ validate_icon (const char *filename) g_autoptr(GError) error = NULL; format = gdk_pixbuf_get_file_info (filename, &width, &height); - if (format == NULL) + if (format == NULL) { g_printerr ("Format not recognized\n"); return 1; @@ -20,13 +46,35 @@ validate_icon (const char *filename) name = gdk_pixbuf_format_get_name (format); if (!g_strv_contains (allowed_formats, name)) { - g_printerr ("Format %s not allowed\n", name); + g_printerr ("Format %s not accepted\n", name); return 1; } - if (width > 256 || height > 256) + if (!g_str_equal (name, "svg")) + { + max_width = g_ascii_strtoll (arg_width, NULL, 10); + if (max_width < 16 || max_width > 4096) + { + g_printerr ("Bad width limit: %s\n", arg_width); + return 1; + } + + max_height = g_ascii_strtoll (arg_height, NULL, 10); + if (max_height < 16 || max_height > 4096) + { + g_printerr ("Bad height limit: %s\n", arg_height); + return 1; + } + } + else + { + /* Sanity check for vector files */ + max_height = max_width = 4096; + } + + if (width > max_width || height > max_height) { - g_printerr ("Image too large (%dx%d)\n", width, height); + g_printerr ("Image too large (%dx%d). Max. size %dx%d\n", width, height, max_width, max_height); return 1; } @@ -40,14 +88,162 @@ validate_icon (const char *filename) return 0; } +G_GNUC_NULL_TERMINATED +static void +add_args (GPtrArray *argv_array, ...) +{ + va_list args; + const char *arg; + + va_start (args, argv_array); + while ((arg = va_arg (args, const gchar *))) + g_ptr_array_add (argv_array, g_strdup (arg)); + va_end (args); +} + +const char * +flatpak_get_bwrap (void) +{ + const char *e = g_getenv ("FLATPAK_BWRAP"); + + if (e != NULL) + return e; + return HELPER; +} + + +static gboolean +path_is_usrmerged (const char *dir) +{ + /* does /dir point to /usr/dir? */ + g_autofree char *target = NULL; + GStatBuf stat_buf_src, stat_buf_target; + + if (g_stat (dir, &stat_buf_src) < 0) + return FALSE; + + target = g_strdup_printf ("/usr/%s", dir); + + if (g_stat (target, &stat_buf_target) < 0) + return FALSE; + + return (stat_buf_src.st_dev == stat_buf_target.st_dev) && + (stat_buf_src.st_ino == stat_buf_target.st_ino); +} + +static int +rerun_in_sandbox (const char *arg_width, + const char *arg_height, + const char *filename) +{ + const char * const usrmerged_dirs[] = { "bin", "lib32", "lib64", "lib", "sbin" }; + int i; + g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free); + char validate_icon[PATH_MAX + 1]; + ssize_t symlink_size; + + symlink_size = readlink ("/proc/self/exe", validate_icon, sizeof (validate_icon) - 1); + if (symlink_size < 0 || (size_t) symlink_size >= sizeof (validate_icon)) + { + g_printerr ("Error: failed to read /proc/self/exe\n"); + return 1; + } + + validate_icon[symlink_size] = 0; + + add_args (args, + flatpak_get_bwrap (), + "--unshare-ipc", + "--unshare-net", + "--unshare-pid", + "--ro-bind", "/usr", "/usr", + "--ro-bind", "/etc/ld.so.cache", "/etc/ld.so.cache", + "--ro-bind", validate_icon, validate_icon, + NULL); + + /* These directories might be symlinks into /usr/... */ + for (i = 0; i < G_N_ELEMENTS (usrmerged_dirs); i++) + { + g_autofree char *absolute_dir = g_strdup_printf ("/%s", usrmerged_dirs[i]); + + if (!g_file_test (absolute_dir, G_FILE_TEST_EXISTS)) + continue; + + if (path_is_usrmerged (absolute_dir)) + { + g_autofree char *symlink_target = g_strdup_printf ("/usr/%s", absolute_dir); + + add_args (args, + "--symlink", symlink_target, absolute_dir, + NULL); + } + else + { + add_args (args, + "--ro-bind", absolute_dir, absolute_dir, + NULL); + } + } + + add_args (args, + "--tmpfs", "/tmp", + "--proc", "/proc", + "--dev", "/dev", + "--chdir", "/", + "--setenv", "GIO_USE_VFS", "local", + "--unsetenv", "TMPDIR", + "--die-with-parent", + "--ro-bind", filename, filename, + NULL); + + if (g_getenv ("G_MESSAGES_DEBUG")) + add_args (args, "--setenv", "G_MESSAGES_DEBUG", g_getenv ("G_MESSAGES_DEBUG"), NULL); + if (g_getenv ("G_MESSAGES_PREFIXED")) + add_args (args, "--setenv", "G_MESSAGES_PREFIXED", g_getenv ("G_MESSAGES_PREFIXED"), NULL); + + add_args (args, validate_icon, arg_width, arg_height, filename, NULL); + g_ptr_array_add (args, NULL); + + { + g_autofree char *cmdline = g_strjoinv (" ", (char **) args->pdata); + g_debug ("Icon validation: Spawning %s", cmdline); + } + + execvpe (flatpak_get_bwrap (), (char **) args->pdata, NULL); + /* If we get here, then execvpe() failed. */ + g_printerr ("Icon validation: execvpe %s: %s\n", flatpak_get_bwrap (), g_strerror (errno)); + return 1; +} + +static gboolean opt_sandbox; + +static GOptionEntry entries[] = { + { "sandbox", 0, 0, G_OPTION_ARG_NONE, &opt_sandbox, "Run in a sandbox", NULL }, + { NULL } +}; + int main (int argc, char *argv[]) { - if (argc != 2) + GOptionContext *context; + GError *error = NULL; + + context = g_option_context_new ("WIDTH HEIGHT PATH"); + g_option_context_add_main_entries (context, entries, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_printerr ("Error: %s\n", error->message); + return 1; + } + + if (argc != 4) { - g_error ("Expect a single path"); + g_printerr ("Usage: %s [OPTION…] WIDTH HEIGHT PATH\n", argv[0]); return 1; } - return validate_icon (argv[1]); + if (opt_sandbox) + return rerun_in_sandbox (argv[1], argv[2], argv[3]); + else + return validate_icon (argv[1], argv[2], argv[3]); } |