mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-08-05 21:50:21 +08:00
libctf, ld: diagnose corrupted CTF header cth_strlen
The last section in a CTF dict is the string table, at an offset represented by the cth_stroff header field. Its length is recorded in the next field, cth_strlen, and the two added together are taken as the size of the CTF dict. Upon opening a dict, we check that none of the header offsets exceed this size, and we check when uncompressing a compressed dict that the result of the uncompression is the same length: but CTF dicts need not be compressed, and short ones are not. Uncompressed dicts just use the ctf_size without checking it. This field is thankfully almost unused: it is mostly used when reserializing a dict, which can't be done to dicts read off disk since they're read-only. However, when opening an uncompressed foreign-endian dict we have to copy it out of the mmaped region it is stored in so we can endian- swap it, and we use ctf_size when doing that. When the cth_strlen is corrupt, this can overrun. Fix this by checking the ctf_size in all uncompressed cases, just as we already do in the compressed case. Add a new test. This came to light because various corrupted-CTF raw-asm tests had an incorrect cth_strlen: fix all of them so they produce the expected error again. libctf/ PR libctf/28933 * ctf-open.c (ctf_bufopen_internal): Always check uncompressed CTF dict sizes against the section size in case the cth_strlen is corrupt. ld/ PR libctf/28933 * testsuite/ld-ctf/diag-strlen-invalid.*: New test, derived from diag-cttname-invalid.s. * testsuite/ld-ctf/diag-cttname-invalid.s: Fix incorrect cth_strlen. * testsuite/ld-ctf/diag-cttname-null.s: Likewise. * testsuite/ld-ctf/diag-cuname.s: Likewise. * testsuite/ld-ctf/diag-parlabel.s: Likewise. * testsuite/ld-ctf/diag-parname.s: Likewise.
This commit is contained in:
@ -15,7 +15,7 @@
|
|||||||
.long 0x8
|
.long 0x8
|
||||||
.long 0x10
|
.long 0x10
|
||||||
.long 0x40
|
.long 0x40
|
||||||
.long 0x42
|
.long 0x37
|
||||||
.long 0x1
|
.long 0x1
|
||||||
.long 0x7
|
.long 0x7
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
.long 0x8
|
.long 0x8
|
||||||
.long 0x10
|
.long 0x10
|
||||||
.long 0x40
|
.long 0x40
|
||||||
.long 0x42
|
.long 0x37
|
||||||
.long 0x1
|
.long 0x1
|
||||||
.long 0x7
|
.long 0x7
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
.long 0x8
|
.long 0x8
|
||||||
.long 0x10
|
.long 0x10
|
||||||
.long 0x40
|
.long 0x40
|
||||||
.long 0x42
|
.long 0x37
|
||||||
.long 0x1
|
.long 0x1
|
||||||
.long 0x7
|
.long 0x7
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
.long 0x8
|
.long 0x8
|
||||||
.long 0x10
|
.long 0x10
|
||||||
.long 0x40
|
.long 0x40
|
||||||
.long 0x42
|
.long 0x37
|
||||||
.long 0x1
|
.long 0x1
|
||||||
.long 0x7
|
.long 0x7
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
.long 0x8
|
.long 0x8
|
||||||
.long 0x10
|
.long 0x10
|
||||||
.long 0x40
|
.long 0x40
|
||||||
.long 0x42
|
.long 0x37
|
||||||
.long 0x1
|
.long 0x1
|
||||||
.long 0x7
|
.long 0x7
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
5
ld/testsuite/ld-ctf/diag-strlen-invalid.d
Normal file
5
ld/testsuite/ld-ctf/diag-strlen-invalid.d
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#as:
|
||||||
|
#source: diag-strlen-invalid.s
|
||||||
|
#ld: -shared
|
||||||
|
#name: Diagnostics - String offset invalid.
|
||||||
|
#warning: .* byte long CTF dictionary overruns .* byte long CTF section
|
44
ld/testsuite/ld-ctf/diag-strlen-invalid.s
Normal file
44
ld/testsuite/ld-ctf/diag-strlen-invalid.s
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.file "A.c"
|
||||||
|
.section .ctf,"",@progbits
|
||||||
|
.Lctf0:
|
||||||
|
.2byte 0xdff2
|
||||||
|
.byte 0x4
|
||||||
|
.byte 0
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
.long 0x9
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
.long 0x4
|
||||||
|
.long 0x4
|
||||||
|
.long 0x8
|
||||||
|
.long 0x8
|
||||||
|
.long 0x10
|
||||||
|
.long 0x40
|
||||||
|
.long 0x42
|
||||||
|
.long 0x1
|
||||||
|
.long 0x7
|
||||||
|
.long 0x7
|
||||||
|
.long 0x1
|
||||||
|
.long 0xff00
|
||||||
|
.long 0x1a000001
|
||||||
|
.long 0x8
|
||||||
|
.long 0x5
|
||||||
|
.long 0
|
||||||
|
.long 0x3
|
||||||
|
.long 0x3
|
||||||
|
.long 0x26000000
|
||||||
|
.long 0x6
|
||||||
|
.long 0
|
||||||
|
.long 0xe000000
|
||||||
|
.long 0x2
|
||||||
|
.ascii "\0"
|
||||||
|
.ascii "A\0"
|
||||||
|
.ascii "B\0"
|
||||||
|
.ascii "b\0"
|
||||||
|
.ascii "a\0"
|
||||||
|
.ascii "/usr/src/binutils-gdb/ld/testsuite/ld-ctf/A.c\0"
|
||||||
|
.text
|
||||||
|
.comm a,8,8
|
||||||
|
.ident "GCC: (GNU) 8.3.1 20191121 (Red Hat 8.3.1-5.0.1)"
|
||||||
|
.section .note.GNU-stack,"",@progbits
|
@ -1517,26 +1517,39 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (foreign_endian)
|
|
||||||
{
|
|
||||||
if ((fp->ctf_base = malloc (fp->ctf_size)) == NULL)
|
|
||||||
{
|
|
||||||
err = ECTF_ZALLOC;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
fp->ctf_dynbase = fp->ctf_base;
|
|
||||||
memcpy (fp->ctf_base, ((unsigned char *) ctfsect->cts_data) + hdrsz,
|
|
||||||
fp->ctf_size);
|
|
||||||
fp->ctf_buf = fp->ctf_base;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We are just using the section passed in -- but its header may be an old
|
if (_libctf_unlikely_ (ctfsect->cts_size < hdrsz + fp->ctf_size))
|
||||||
version. Point ctf_buf past the old header, and never touch it
|
{
|
||||||
again. */
|
ctf_err_warn (NULL, 0, ECTF_CORRUPT,
|
||||||
fp->ctf_base = (unsigned char *) ctfsect->cts_data;
|
_("%lu byte long CTF dictionary overruns %lu byte long CTF section"),
|
||||||
fp->ctf_dynbase = NULL;
|
(unsigned long) ctfsect->cts_size,
|
||||||
fp->ctf_buf = fp->ctf_base + hdrsz;
|
(unsigned long) (hdrsz + fp->ctf_size));
|
||||||
|
err = ECTF_CORRUPT;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign_endian)
|
||||||
|
{
|
||||||
|
if ((fp->ctf_base = malloc (fp->ctf_size)) == NULL)
|
||||||
|
{
|
||||||
|
err = ECTF_ZALLOC;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
fp->ctf_dynbase = fp->ctf_base;
|
||||||
|
memcpy (fp->ctf_base, ((unsigned char *) ctfsect->cts_data) + hdrsz,
|
||||||
|
fp->ctf_size);
|
||||||
|
fp->ctf_buf = fp->ctf_base;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We are just using the section passed in -- but its header may
|
||||||
|
be an old version. Point ctf_buf past the old header, and
|
||||||
|
never touch it again. */
|
||||||
|
fp->ctf_base = (unsigned char *) ctfsect->cts_data;
|
||||||
|
fp->ctf_dynbase = NULL;
|
||||||
|
fp->ctf_buf = fp->ctf_base + hdrsz;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Once we have uncompressed and validated the CTF data buffer, we can
|
/* Once we have uncompressed and validated the CTF data buffer, we can
|
||||||
|
Reference in New Issue
Block a user