From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: mattjd@gmail.com, Ian Jackson <ian.jackson@eu.citrix.com>
Subject: [PATCH 15/16] libelf: check loops for running away
Date: Mon, 3 Jun 2013 16:41:50 +0100 [thread overview]
Message-ID: <1370274111-18377-16-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1370274111-18377-1-git-send-email-ian.jackson@eu.citrix.com>
Ensure that libelf does not have any loops which can run away
indefinitely even if the input is bogus. (Grepped for \bfor, \bwhile
and \bgoto in libelf and xc_dom_*loader*.c.)
Changes needed:
* elf_note_next uses the note's unchecked alleged length, which might
wrap round. If it does, return ELF_MAX_PTRVAL (0xfff..fff) instead,
which will be beyond the end of the section and so terminate the
caller's loop.
* In various loops over section and program headers, check that the
calculated header pointer is still within the image, and quit the
loop if it isn't.
We have not changed loops which might, in principle, iterate over the
whole image - even if they might do so one byte at a time with a
nontrivial access check function in the middle.
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
v3: Fix a whitespace error.
v2: BUGFIX: elf_shdr_by_name, elf_note_next: Reject new <= old, not just <.
elf_shdr_by_name: Change order of checks to be a bit clearer.
elf_load_bsdsyms: shdr loop check, improve chance of brokenness detection.
Style fixes.
---
tools/libxc/xc_dom_elfloader.c | 3 +++
xen/common/libelf/libelf-dominfo.c | 14 ++++++++++++++
xen/common/libelf/libelf-loader.c | 27 +++++++++++++++++++++++++--
xen/common/libelf/libelf-tools.c | 11 ++++++++++-
4 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c
index 83e16ef..b6671a1 100644
--- a/tools/libxc/xc_dom_elfloader.c
+++ b/tools/libxc/xc_dom_elfloader.c
@@ -222,6 +222,9 @@ static elf_errorstatus xc_dom_load_elf_symtab(struct xc_dom_image *dom,
for ( h = 0; h < count; h++ )
{
shdr = ELF_OBSOLETE_VOIDP_CAST elf_shdr_by_index(&syms, h);
+ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
+ /* input has an insane section header count field */
+ break;
type = elf_uval(&syms, shdr, sh_type);
if ( type == SHT_STRTAB )
{
diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c
index a9a5f41..289132e 100644
--- a/xen/common/libelf/libelf-dominfo.c
+++ b/xen/common/libelf/libelf-dominfo.c
@@ -485,6 +485,13 @@ elf_errorstatus elf_xen_parse(struct elf_binary *elf,
for ( i = 0; i < count; i++ )
{
phdr = elf_phdr_by_index(elf, i);
+ /*
+ * This test also arranges for the loop to terminate if the
+ * input file has a ridiculous value for the header count: The
+ * first putative header outside the input image will appear
+ * to have type 0 (since out-of-range accesses read as 0) and
+ * PT_NOTE != 0.
+ */
if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
continue;
@@ -515,6 +522,10 @@ elf_errorstatus elf_xen_parse(struct elf_binary *elf,
{
shdr = elf_shdr_by_index(elf, i);
+ /*
+ * See above re guarantee of loop termination.
+ * SHT_NOTE != 0.
+ */
if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
continue;
@@ -552,6 +563,9 @@ elf_errorstatus elf_xen_parse(struct elf_binary *elf,
elf_xen_parse_guest_info(elf, parms);
break;
}
+ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
+ /* input has an insane section header count field */
+ break;
}
}
diff --git a/xen/common/libelf/libelf-loader.c b/xen/common/libelf/libelf-loader.c
index bcdd3d2..26ca839 100644
--- a/xen/common/libelf/libelf-loader.c
+++ b/xen/common/libelf/libelf-loader.c
@@ -75,6 +75,9 @@ elf_errorstatus elf_init(struct elf_binary *elf, const char *image_input, size_t
for ( i = 0; i < count; i++ )
{
shdr = elf_shdr_by_index(elf, i);
+ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
+ /* input has an insane section header count field */
+ break;
if ( elf_uval(elf, shdr, sh_type) != SHT_SYMTAB )
continue;
elf->sym_tab = shdr;
@@ -170,6 +173,9 @@ void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart)
for ( i = 0; i < elf_shdr_count(elf); i++ )
{
shdr = elf_shdr_by_index(elf, i);
+ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
+ /* input has an insane section header count field */
+ break;
type = elf_uval(elf, shdr, sh_type);
if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
sz = elf_round_up(elf, sz + elf_uval(elf, shdr, sh_size));
@@ -224,6 +230,9 @@ do { \
for ( i = 0; i < elf_shdr_count(elf); i++ )
{
+ elf_ptrval old_shdr_p;
+ elf_ptrval new_shdr_p;
+
type = elf_uval(elf, shdr, sh_type);
if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
{
@@ -235,8 +244,16 @@ do { \
elf_hdr_elm(elf, shdr, sh_offset, maxva - symtab_addr);
maxva = ELF_OBSOLETE_VOIDP_CAST elf_round_up(elf, (unsigned long)maxva + sz);
}
- shdr = ELF_MAKE_HANDLE(elf_shdr, ELF_HANDLE_PTRVAL(shdr) +
- (unsigned long)elf_uval(elf, elf->ehdr, e_shentsize));
+ old_shdr_p = ELF_HANDLE_PTRVAL(shdr);
+ new_shdr_p = old_shdr_p + elf_uval(elf, elf->ehdr, e_shentsize);
+ if ( new_shdr_p <= old_shdr_p ) /* wrapped or stuck */
+ {
+ elf_mark_broken(elf, "bad section header length");
+ break;
+ }
+ if ( !elf_access_ok(elf, new_shdr_p, 1) ) /* outside image */
+ break;
+ shdr = ELF_MAKE_HANDLE(elf_shdr, new_shdr_p);
}
/* Write down the actual sym size. */
@@ -256,6 +273,9 @@ void elf_parse_binary(struct elf_binary *elf)
for ( i = 0; i < count; i++ )
{
phdr = elf_phdr_by_index(elf, i);
+ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
+ /* input has an insane program header count field */
+ break;
if ( !elf_phdr_is_loadable(elf, phdr) )
continue;
paddr = elf_uval(elf, phdr, p_paddr);
@@ -283,6 +303,9 @@ elf_errorstatus elf_load_binary(struct elf_binary *elf)
for ( i = 0; i < count; i++ )
{
phdr = elf_phdr_by_index(elf, i);
+ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
+ /* input has an insane program header count field */
+ break;
if ( !elf_phdr_is_loadable(elf, phdr) )
continue;
paddr = elf_uval(elf, phdr, p_paddr);
diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c
index b47a9ca..309a134 100644
--- a/xen/common/libelf/libelf-tools.c
+++ b/xen/common/libelf/libelf-tools.c
@@ -145,6 +145,9 @@ ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *n
for ( i = 0; i < count; i++ )
{
+ if (!elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1))
+ /* input has an insane section header count field */
+ break;
shdr = elf_shdr_by_index(elf, i);
sname = elf_section_name(elf, shdr);
if ( sname && !strcmp(sname, name) )
@@ -324,7 +327,13 @@ ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(
unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
unsigned descsz = (elf_uval(elf, note, descsz) + 3) & ~3;
- return ELF_MAKE_HANDLE(elf_note, ELF_HANDLE_PTRVAL(note) + elf_size(elf, note) + namesz + descsz);
+ elf_ptrval ptrval = ELF_HANDLE_PTRVAL(note)
+ + elf_size(elf, note) + namesz + descsz;
+
+ if (ptrval <= ELF_HANDLE_PTRVAL(note))
+ ptrval = ELF_MAX_PTRVAL; /* terminate caller's loop */
+
+ return ELF_MAKE_HANDLE(elf_note, ptrval);
}
/* ------------------------------------------------------------------------ */
--
1.7.2.5
next prev parent reply other threads:[~2013-06-03 15:41 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-03 15:41 [PATCH v3.1 00/16] XSA55 libelf fixes for unstable Ian Jackson
2013-06-03 15:41 ` [PATCH 01/16] libelf: abolish libelf-relocate.c Ian Jackson
2013-06-03 15:41 ` [PATCH 02/16] libxc: introduce xc_dom_seg_to_ptr_pages Ian Jackson
2013-06-03 15:41 ` [PATCH 03/16] libelf: add `struct elf_binary*' parameter to elf_load_image Ian Jackson
2013-06-03 15:41 ` [PATCH 04/16] libelf: abolish elf_sval and elf_access_signed Ian Jackson
2013-06-03 15:41 ` [PATCH 05/16] libelf: move include of <asm/guest_access.h> to top of file Ian Jackson
2013-06-03 15:41 ` [PATCH 06/16] libelf/xc_dom_load_elf_symtab: Do not use "syms" uninitialised Ian Jackson
2013-06-03 15:41 ` [PATCH 07/16] libelf: introduce macros for memory access and pointer handling Ian Jackson
2013-06-03 15:41 ` [PATCH 08/16] tools/xcutils/readnotes: adjust print_l1_mfn_valid_note Ian Jackson
2013-06-03 15:41 ` [PATCH 09/16] libelf: check nul-terminated strings properly Ian Jackson
2013-06-04 14:49 ` Matthew Daley
2013-06-04 15:15 ` Ian Jackson
2013-06-04 15:27 ` Matthew Daley
2013-06-04 17:13 ` Ian Jackson
2013-06-05 2:08 ` Matthew Daley
2013-06-05 7:24 ` Ian Campbell
2013-06-03 15:41 ` [PATCH 10/16] libelf: check all pointer accesses Ian Jackson
2013-06-04 14:55 ` Matthew Daley
2013-06-04 15:11 ` Ian Jackson
2013-06-03 15:41 ` [PATCH 11/16] libelf: Check pointer references in elf_is_elfbinary Ian Jackson
2013-06-03 15:41 ` [PATCH 12/16] libelf: Make all callers call elf_check_broken Ian Jackson
2013-06-03 15:41 ` [PATCH 13/16] libelf: use C99 bool for booleans Ian Jackson
2013-06-03 15:41 ` [PATCH 14/16] libelf: use only unsigned integers Ian Jackson
2013-06-04 10:50 ` Ian Jackson
2013-06-03 15:41 ` Ian Jackson [this message]
2013-06-03 15:41 ` [PATCH 16/16] libelf: abolish obsolete macros Ian Jackson
2013-06-03 16:08 ` [PATCH v3.1 00/16] XSA55 libelf fixes for unstable Ian Jackson
-- strict thread matches above, loose matches on Subject: below --
2013-06-04 17:59 [PATCH 4 " Ian Jackson
2013-06-04 18:00 ` [PATCH 15/16] libelf: check loops for running away Ian Jackson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1370274111-18377-16-git-send-email-ian.jackson@eu.citrix.com \
--to=ian.jackson@eu.citrix.com \
--cc=mattjd@gmail.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).