summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Henrie <alexhenrie24@gmail.com>2023-11-19 15:54:27 -0700
committerAlex Henrie <alexhenrie24@gmail.com>2023-11-19 15:54:27 -0700
commite624bc318fda9660e6a5e91f4b32e4a8a8947ea4 (patch)
tree8a0cce4f12990c634268871338c614af56af6217
parent179296748e92bd91bf531656632a1056307fb7b7 (diff)
xdgmime: Handle buggy type definitions with circular inheritance
This fixes a stack overflow reported by a user who had both the definition of text/javascript from shared-mime-info 2.3 and the definition of text/javascript from shared-mime-info 2.4 installed at the same time. In 2.3, text/javascript is a subtype of application/ecmascript, but in 2.4 application/ecmascript is a subtype of text/javascript. Having both at the same time resulted in circular inheritance. The new logic keeps a list of all parents that have already been checked, which is more comprehensive than the old workaround that was implemented in commit 38869ece2 ("xdgmime: Prevent infinite loops from badly-formed MIME registrations"). https://bugs.archlinux.org/task/80279
-rw-r--r--src/xdgmime.c43
-rw-r--r--src/xdgmime.h3
-rw-r--r--src/xdgmimecache.c47
-rw-r--r--src/xdgmimecache.h3
4 files changed, 74 insertions, 22 deletions
diff --git a/src/xdgmime.c b/src/xdgmime.c
index b640651..e6372a0 100644
--- a/src/xdgmime.c
+++ b/src/xdgmime.c
@@ -819,13 +819,16 @@ xdg_mime_is_super_type (const char *mime)
int
_xdg_mime_mime_type_subclass (const char *mime,
- const char *base)
+ const char *base,
+ const char **seen)
{
- const char *umime, *ubase;
+ const char *umime, *ubase, *parent;
const char **parents;
+ int first_seen = 0, i, ret = 0;
+
if (_caches)
- return _xdg_mime_cache_mime_type_subclass (mime, base);
+ return _xdg_mime_cache_mime_type_subclass (mime, base, NULL);
umime = _xdg_mime_unalias_mime_type (mime);
ubase = _xdg_mime_unalias_mime_type (base);
@@ -848,15 +851,39 @@ _xdg_mime_mime_type_subclass (const char *mime,
if (strcmp (ubase, "application/octet-stream") == 0 &&
strncmp (umime, "inode/", 6) != 0)
return 1;
-
+
+ if (!seen)
+ {
+ seen = calloc (1, sizeof (char *));
+ first_seen = 1;
+ }
+
parents = _xdg_mime_parent_list_lookup (parent_list, umime);
for (; parents && *parents; parents++)
{
- if (_xdg_mime_mime_type_subclass (*parents, ubase))
- return 1;
+ parent = *parents;
+
+ /* Detect and avoid buggy circular relationships */
+ for (i = 0; seen[i] != NULL; i++)
+ if (parent == seen[i])
+ goto next_parent;
+ seen = realloc (seen, (i + 2) * sizeof (char *));
+ seen[i] = parent;
+ seen[i + 1] = NULL;
+
+ if (_xdg_mime_mime_type_subclass (parent, ubase, seen))
+ {
+ ret = 1;
+ goto done;
+ }
+
+ next_parent:
}
- return 0;
+done:
+ if (first_seen)
+ free (seen);
+ return ret;
}
int
@@ -865,7 +892,7 @@ xdg_mime_mime_type_subclass (const char *mime,
{
xdg_mime_init ();
- return _xdg_mime_mime_type_subclass (mime, base);
+ return _xdg_mime_mime_type_subclass (mime, base, NULL);
}
char **
diff --git a/src/xdgmime.h b/src/xdgmime.h
index abba067..897683d 100644
--- a/src/xdgmime.h
+++ b/src/xdgmime.h
@@ -109,7 +109,8 @@ void xdg_mime_set_dirs (const char * const *dirs);
int _xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b);
int _xdg_mime_mime_type_subclass (const char *mime,
- const char *base);
+ const char *base,
+ const char **seen);
const char *_xdg_mime_unalias_mime_type (const char *mime);
diff --git a/src/xdgmimecache.c b/src/xdgmimecache.c
index 05378fc..e700089 100644
--- a/src/xdgmimecache.c
+++ b/src/xdgmimecache.c
@@ -704,8 +704,8 @@ cache_get_mime_type_for_data (const void *data,
/* Pick glob-result R where mime_type inherits from R */
for (n = 0; n < n_mime_types; n++)
{
- if (mime_types[n] && _xdg_mime_cache_mime_type_subclass(mime_types[n], mime_type))
- return mime_types[n];
+ if (mime_types[n] && _xdg_mime_cache_mime_type_subclass (mime_types[n], mime_type, NULL))
+ return mime_types[n];
}
if (n == 0)
{
@@ -854,13 +854,14 @@ is_super_type (const char *mime)
int
_xdg_mime_cache_mime_type_subclass (const char *mime,
- const char *base)
+ const char *base,
+ const char **seen)
{
- const char *umime, *ubase;
+ const char *umime, *ubase, *parent;
xdg_uint32_t j;
- int i, min, max, med, cmp;
-
+ int i, k, min, max, med, cmp, first_seen = 0, ret = 0;
+
umime = _xdg_mime_cache_unalias_mime_type (mime);
ubase = _xdg_mime_cache_unalias_mime_type (base);
@@ -885,7 +886,13 @@ _xdg_mime_cache_mime_type_subclass (const char *mime,
if (strcmp (ubase, "application/octet-stream") == 0 &&
strncmp (umime, "inode/", 6) != 0)
return 1;
-
+
+ if (!seen)
+ {
+ seen = calloc (1, sizeof (char *));
+ first_seen = 1;
+ }
+
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
@@ -919,10 +926,23 @@ _xdg_mime_cache_mime_type_subclass (const char *mime,
for (j = 0; j < n_parents; j++)
{
parent_offset = GET_UINT32 (cache->buffer, offset + 4 + 4 * j);
- if (strcmp (cache->buffer + parent_offset, mime) != 0 &&
- strcmp (cache->buffer + parent_offset, umime) != 0 &&
- _xdg_mime_cache_mime_type_subclass (cache->buffer + parent_offset, ubase))
- return 1;
+ parent = cache->buffer + parent_offset;
+
+ /* Detect and avoid buggy circular relationships */
+ for (k = 0; seen[k] != NULL; k++)
+ if (parent == seen[k])
+ goto next_parent;
+ seen = realloc (seen, (k + 2) * sizeof (char *));
+ seen[k] = parent;
+ seen[k + 1] = NULL;
+
+ if (_xdg_mime_cache_mime_type_subclass (parent, ubase, seen))
+ {
+ ret = 1;
+ goto done;
+ }
+
+ next_parent:
}
break;
@@ -930,7 +950,10 @@ _xdg_mime_cache_mime_type_subclass (const char *mime,
}
}
- return 0;
+done:
+ if (first_seen)
+ free (seen);
+ return ret;
}
const char *
diff --git a/src/xdgmimecache.h b/src/xdgmimecache.h
index 48aa752..5e6f274 100644
--- a/src/xdgmimecache.h
+++ b/src/xdgmimecache.h
@@ -54,7 +54,8 @@ int _xdg_mime_cache_mime_type_equal (const char *mime_a,
int _xdg_mime_cache_media_type_equal (const char *mime_a,
const char *mime_b);
int _xdg_mime_cache_mime_type_subclass (const char *mime_a,
- const char *mime_b);
+ const char *mime_b,
+ const char **seen);
char **_xdg_mime_cache_list_mime_parents (const char *mime);
const char *_xdg_mime_cache_unalias_mime_type (const char *mime);
int _xdg_mime_cache_get_max_buffer_extents (void);