From 93ebd35fa24871ad51914892733ba8cb626feed2 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 7 Nov 2024 12:37:59 +0000 Subject: [PATCH] Fix illegal memory accesses when parsing corrupt a.out format files. Resolves: RHEL-64927 --- binutils-CVE-2018-12699-part6-PR28862.patch | 11 ++ binutils-CVE-2018-12699-part7-PR28718.patch | 131 ++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/binutils-CVE-2018-12699-part6-PR28862.patch b/binutils-CVE-2018-12699-part6-PR28862.patch index 22c341b..1f49770 100644 --- a/binutils-CVE-2018-12699-part6-PR28862.patch +++ b/binutils-CVE-2018-12699-part6-PR28862.patch @@ -1,3 +1,14 @@ +# Commit 481153777e278b71e694fd2db6b897f7a9e3dcb8 fixing PR 28862 +# +# From: Alan Modra +# +# I have no info on the format of a "SUNPRO C++ Namespace" stab, so am +# relying on the previous code being correct in parsing these stabs. +# Just don't allow NULs anywhere in the stab. +# +# PR 28862 +# * stabs.c (parse_stab_string): Don't overrun buffer when parsing +# 'Y' stab. --- binutils.orig/binutils/stabs.c 2024-11-06 17:39:57.460250962 +0000 +++ binutils-2.30/binutils/stabs.c 2024-11-06 17:41:32.293848603 +0000 @@ -1138,15 +1138,13 @@ parse_stab_string (void *dhandle, struct diff --git a/binutils-CVE-2018-12699-part7-PR28718.patch b/binutils-CVE-2018-12699-part7-PR28718.patch index e938f15..0c1f735 100644 --- a/binutils-CVE-2018-12699-part7-PR28718.patch +++ b/binutils-CVE-2018-12699-part7-PR28718.patch @@ -1,3 +1,50 @@ +# This is a merge of four commits to fix a stack overflow bug: +# +# From af4004d1da135610ab931e04a3ba2c9124defbd7 Mon Sep 17 00:00:00 2001 +# From: Nick Clifton +# Date: Thu, 6 Jan 2022 16:37:26 +0000 +# Subject: [PATCH] Fix a stack exhaustion bug parsing malicious STABS format +# debug information. +# +# PR 28718 +# * debug.c (debug_write_type): Allow for malicious recursion via +# indirect debug types. +# +# From 0e9f1c04b9572920c7f940203a67d5af3f6c19f6 Mon Sep 17 00:00:00 2001 +# From: Pavel Mayorov +# Date: Fri, 7 Jan 2022 12:34:37 +0000 +# Subject: [PATCH] Revert previous delta to debug.c. Replace with patch to +# reject indirect types that point to indirect types. +# +# PR 28718 +# * dwarf.c: Revert previous delta. +# (debug_get_real_type): Reject indirect types that point to +# indirect types. +# (debug_get_type_name, debug_get_type_size, debug_write_type): +# Likewise. +# +# From 55a75aae9d971d3d0f49884e3954ac4794559542 Mon Sep 17 00:00:00 2001 +# From: Alan Modra +# Date: Tue, 9 May 2023 17:11:46 +0930 +# Subject: [PATCH] stack overflow in debug_write_type +# +# Another fuzzer attack. This one was a "set" with elements using an +# indirect type pointing back at the set. The existing recursion check +# only prevented simple recursion. +# +# * debug.c (struct debug_type_s): Add mark. +# (debug_write_type): Set mark and check before recursing into +# indirect types. +# +# From 6109320673fe30163b5d00d9e3a7f4e77befb22a Mon Sep 17 00:00:00 2001 +# From: Alan Modra +# Date: Wed, 10 May 2023 23:05:00 +0930 +# Subject: [PATCH] Re: stack overflow in debug_write_type +# +# Apparently u.kindirect->slot can point at a NULL. +# +# * debug.c (debug_write_type): Don't segfault on NULL indirect. + --- binutils.orig/binutils/debug.c 2024-11-06 17:39:57.452250912 +0000 +++ binutils-2.30/binutils/debug.c 2024-11-06 17:44:37.951018606 +0000 @@ -2483,8 +2483,22 @@ debug_write_type (struct debug_handle *i @@ -25,3 +72,87 @@ case DEBUG_KIND_VOID: return (*fns->void_type) (fhandle); case DEBUG_KIND_INT: +--- binutils.orig/binutils/debug.c 2024-11-07 12:05:27.049161875 +0000 ++++ binutils-2.30/binutils/debug.c 2024-11-07 12:25:03.616783102 +0000 +@@ -102,6 +102,8 @@ struct debug_type_s + enum debug_type_kind kind; + /* Size of type (0 if not known). */ + unsigned int size; ++ /* Used by debug_write to stop DEBUG_KIND_INDIRECT infinite recursion. */ ++ unsigned int mark; + /* Type which is a pointer to this type. */ + debug_type pointer; + /* Tagged union with additional information about the type. */ +@@ -2065,7 +2067,9 @@ debug_get_real_type (void *handle, debug + /* The default case is just here to avoid warnings. */ + default: + case DEBUG_KIND_INDIRECT: +- if (*type->u.kindirect->slot != NULL) ++ /* A valid non-self-referencing indirect type. */ ++ if (*type->u.kindirect->slot != NULL ++ && *type->u.kindirect->slot != type) + return debug_get_real_type (handle, *type->u.kindirect->slot, &rl); + return type; + case DEBUG_KIND_NAMED: +@@ -2095,7 +2099,9 @@ debug_get_type_name (void *handle, debug + { + if (type->kind == DEBUG_KIND_INDIRECT) + { +- if (*type->u.kindirect->slot != NULL) ++ /* A valid non-self-referencing indirect type. */ ++ if (*type->u.kindirect->slot != NULL ++ && *type->u.kindirect->slot != type) + return debug_get_type_name (handle, *type->u.kindirect->slot); + return type->u.kindirect->tag; + } +@@ -2124,7 +2130,9 @@ debug_get_type_size (void *handle, debug + default: + return 0; + case DEBUG_KIND_INDIRECT: +- if (*type->u.kindirect->slot != NULL) ++ /* A valid non-self-referencing indirect type. */ ++ if (*type->u.kindirect->slot != NULL ++ && *type->u.kindirect->slot != type) + return debug_get_type_size (handle, *type->u.kindirect->slot); + return 0; + case DEBUG_KIND_NAMED: +@@ -2419,6 +2427,9 @@ debug_write_type (struct debug_handle *i + int is; + const char *tag = NULL; + ++ /* Mark the type so that we don't define a type in terms of itself. */ ++ type->mark = info->mark; ++ + /* If we have a name for this type, just output it. We only output + typedef names after they have been defined. We output type tags + whenever we are not actually defining them. */ +@@ -2481,24 +2492,12 @@ debug_write_type (struct debug_handle *i + debug_error (_("debug_write_type: illegal type encountered")); + return FALSE; + case DEBUG_KIND_INDIRECT: +- if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) ++ /* Prevent infinite recursion. */ ++ if (*type->u.kindirect->slot != DEBUG_TYPE_NULL ++ && (*type->u.kindirect->slot)->mark == info->mark) + return (*fns->empty_type) (fhandle); +- /* PR 28718: Allow for malicious recursion. */ +- { +- static int recursion_depth = 0; +- bfd_boolean result; +- +- if (recursion_depth > 256) +- { +- debug_error (_("debug_write_type: too many levels of nested indirection")); +- return FALSE; +- } +- ++ recursion_depth; +- result = debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, +- name); +- -- recursion_depth; +- return result; +- } ++ return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, ++ name); + case DEBUG_KIND_VOID: + return (*fns->void_type) (fhandle); + case DEBUG_KIND_INT: