diff options
author | Alex Henrie <alexhenrie24@gmail.com> | 2023-11-19 15:54:27 -0700 |
---|---|---|
committer | Alex Henrie <alexhenrie24@gmail.com> | 2023-11-19 15:54:27 -0700 |
commit | e624bc318fda9660e6a5e91f4b32e4a8a8947ea4 (patch) | |
tree | 8a0cce4f12990c634268871338c614af56af6217 | |
parent | 179296748e92bd91bf531656632a1056307fb7b7 (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.c | 43 | ||||
-rw-r--r-- | src/xdgmime.h | 3 | ||||
-rw-r--r-- | src/xdgmimecache.c | 47 | ||||
-rw-r--r-- | src/xdgmimecache.h | 3 |
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); |