[PATCH] libctf: bounds-check forward ctt_type before indexing pop[]

Naveed Khan <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
init_static_types_internal() walks the CTF type section that comes
directly from an object file's .ctf section.  During the first counting
pass it treats a CTF_K_FORWARD record's ctt_type as the CTF_K_* kind of
the forwarded tag and bumps the corresponding population count:

	if (kind == CTF_K_FORWARD)
	  pop[tp->ctt_type]++;

pop[] is a fixed-size stack array with CTF_K_MAX + 1 (64) entries, but
ctt_type is a 32-bit value read straight from the file and is never
validated.  A crafted dict whose forward record carries a ctt_type
greater than CTF_K_MAX therefore causes an out-of-bounds write to the
stack at an attacker-controlled index.

The type walk is reachable from ctf_bufopen()/ctf_open(), i.e. whenever
libctf opens a dict: ld while linking CTF, and objdump/nm --ctf.  The
second pass already tolerates an out-of-range ctt_type (ctf_name_table()
has a default case), so only this first-pass index was unguarded.

Reject a ctt_type outside the valid kind range as ECTF_CORRUPT, matching
the existing corruption handling in the same loop.

Reproduced with a 65-byte in-memory dict (one CTF_K_FORWARD record whose
ctt_type is 64) passed to ctf_bufopen().  Before the fix, AddressSanitizer
reports a stack-buffer-overflow at ctf-open.c:759 overflowing pop[64];
after the fix ctf_bufopen() returns ECTF_CORRUPT.  Valid forwards
(ctt_type of CTF_K_STRUCT/UNION/ENUM) and the boundary value CTF_K_MAX
still open successfully.

Signed-off-by: Naveed Khan <[email protected]>
---
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 584d502a..73ff1ab7 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -754,9 +754,15 @@ init_static_types_internal (ctf_dict_t *fp, ctf_header_t *cth,
 	return ECTF_CORRUPT;
 
       /* For forward declarations, ctt_type is the CTF_K_* kind for the tag,
-	 so bump that population count too.  */
+	 so bump that population count too.  A corrupt dict may store an
+	 out-of-range kind here, so guard against indexing pop[] out of
+	 bounds.  */
       if (kind == CTF_K_FORWARD)
-	pop[tp->ctt_type]++;
+	{
+	  if (tp->ctt_type > CTF_K_MAX)
+	    return ECTF_CORRUPT;
+	  pop[tp->ctt_type]++;
+	}
 
       tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes);
       pop[kind]++;
-- 
2.52.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.