Rewrite exported mimetype files

We only allow globs, not magic matches, and we drop the glob
priority to a very low level (weight=5) which means that its
hard for app-installed mimetypes to override the system installed
ones. That should make exporting mimetypes pretty safe.
This commit is contained in:
Alexander Larsson
2017-05-11 16:55:46 +02:00
parent 050fe4e795
commit 3e9bc8ba7a
2 changed files with 127 additions and 1 deletions

View File

@@ -30,6 +30,9 @@
#include <glib/gi18n.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <gio/gio.h>
#include <gio/gunixsocketaddress.h>
#include "libglnx/libglnx.h"
@@ -3366,6 +3369,121 @@ export_ini_file (int parent_fd,
return TRUE;
}
static inline void
xml_autoptr_cleanup_generic_free (void *p)
{
void **pp = (void**)p;
if (*pp)
xmlFree (*pp);
}
#define xml_autofree _GLIB_CLEANUP(xml_autoptr_cleanup_generic_free)
/* This verifies the basic layout of the files, then it removes
* any magic matches, and makes all glob matches have a very low
* priority (weight = 5). This should make it pretty safe to
* export mime types, because the should not override the system
* ones in any weird ways. */
static gboolean
rewrite_mime_xml (xmlDoc *doc)
{
xmlNode *root_element = xmlDocGetRootElement (doc);
xmlNode *top_node = NULL;
for (top_node = root_element; top_node; top_node = top_node->next)
{
xmlNode *mime_node = NULL;
if (top_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp ((char *)top_node->name, "mime-info") != 0)
return FALSE;
for (mime_node = top_node->children; mime_node; mime_node = mime_node->next)
{
xmlNode *sub_node = NULL;
xmlNode *next_sub_node = NULL;
xml_autofree xmlChar *mimetype = NULL;
if (mime_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp ((char *)mime_node->name, "mime-type") != 0)
return FALSE;
mimetype = xmlGetProp (mime_node, (xmlChar *)"type");
for (sub_node = mime_node->children; sub_node; sub_node = next_sub_node)
{
next_sub_node = sub_node->next;
if (sub_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp ((char *)sub_node->name, "magic") == 0)
{
g_warning ("Removing magic mime rule from exports");
xmlUnlinkNode (sub_node);
xmlFreeNode(sub_node);
}
else if (strcmp ((char *)sub_node->name, "glob") == 0)
{
xmlSetProp (sub_node,
(const xmlChar *)"weight",
(const xmlChar *)"5");
}
}
}
}
return TRUE;
}
static gboolean
export_mime_file (int parent_fd,
const char *name,
struct stat *stat_buf,
char **target,
GCancellable *cancellable,
GError **error)
{
glnx_fd_close int desktop_fd = -1;
g_autofree char *tmpfile_name = g_strdup_printf ("export-mime-XXXXXX");
g_autoptr(GOutputStream) out_stream = NULL;
g_autofree gchar *data = NULL;
gsize data_len;
g_autoptr(GKeyFile) keyfile = NULL;
xmlDoc *doc = NULL;
xml_autofree xmlChar *xmlbuff = NULL;
int buffersize;
if (!flatpak_openat_noatime (parent_fd, name, &desktop_fd, cancellable, error) ||
!read_fd (desktop_fd, stat_buf, &data, &data_len, error))
return FALSE;
doc = xmlReadMemory (data, data_len, NULL, NULL, 0);
if (doc == NULL)
return flatpak_fail (error, _("Error reading mimetype xml file"));
if (!rewrite_mime_xml (doc))
{
xmlFreeDoc (doc);
return flatpak_fail (error, _("Invalid mimetype xml file"));
}
xmlDocDumpFormatMemory (doc, &xmlbuff, &buffersize, 1);
xmlFreeDoc (doc);
if (!flatpak_open_in_tmpdir_at (parent_fd, 0755, tmpfile_name, &out_stream, cancellable, error) ||
!g_output_stream_write_all (out_stream, xmlbuff, buffersize, NULL, cancellable, error) ||
!g_output_stream_close (out_stream, cancellable, error))
return FALSE;
if (target)
*target = g_steal_pointer (&tmpfile_name);
return TRUE;
}
static gboolean
export_desktop_file (const char *app,
@@ -3608,6 +3726,14 @@ rewrite_export_dir (const char *app,
goto out;
}
if (strcmp (source_name, "packages") == 0 &&
g_str_has_suffix (dent->d_name, ".xml"))
{
if (!export_mime_file (source_iter.fd, dent->d_name,
&stbuf, &new_name, cancellable, error))
goto out;
}
if (new_name)
{
g_hash_table_insert (visited_children, g_strdup (new_name), GINT_TO_POINTER (1));

View File

@@ -161,7 +161,7 @@ AC_SUBST([GDBUS_CODEGEN], [`$PKG_CONFIG --variable gdbus_codegen gio-2.0`])
POLKIT_GOBJECT_REQUIRED=0.98
PKG_CHECK_MODULES(BASE, [glib-2.0 >= $GLIB_REQS gio-2.0 gio-unix-2.0 libarchive >= 2.8.0])
PKG_CHECK_MODULES(BASE, [glib-2.0 >= $GLIB_REQS gio-2.0 gio-unix-2.0 libarchive >= 2.8.0 libxml-2.0 >= 2.4 ])
PKG_CHECK_MODULES(SOUP, [libsoup-2.4])
save_LIBS=$LIBS