All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: andrew.cooper3@citrix.com, mattjd@gmail.com,
	Ian Jackson <ian.jackson@eu.citrix.com>,
	security@xen.org
Subject: [PATCH 10/22] libelf: check nul-terminated strings properly
Date: Tue, 11 Jun 2013 19:22:28 +0100	[thread overview]
Message-ID: <1370974960-19824-11-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1370974960-19824-1-git-send-email-ian.jackson@eu.citrix.com>

It is not safe to simply take pointers into the ELF and use them as C
pointers.  They might not be properly nul-terminated (and the pointers
might be wild).

So we are going to introduce a new function elf_strval for safely
getting strings.  This will check that the addresses are in range and
that there is a proper nul-terminated string.  Of course it might
discover that there isn't.  In that case, it will be made to fail.
This means that elf_note_name might fail, too.

For the benefit of call sites which are just going to pass the value
to a printf-like function, we provide elf_strfmt which returns
"(invalid)" on failure rather than NULL.

In this patch we introduce dummy definitions of these functions.  We
introduce calls to elf_strval and elf_strfmt everywhere, and update
all the call sites with appropriate error checking.

There is not yet any semantic change, since before this patch all the
places where we introduce elf_strval dereferenced the value anyway, so
it mustn't have been NULL.

In future patches, when elf_strval is made able return NULL, when it
does so it will mark the elf "broken" so that an appropriate
diagnostic can be printed.

This is part of the fix to a security issue, XSA-55.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 tools/xcutils/readnotes.c          |   11 ++++++++---
 xen/common/libelf/libelf-dominfo.c |   13 ++++++++++---
 xen/common/libelf/libelf-tools.c   |   10 +++++++---
 xen/include/xen/libelf.h           |    7 +++++--
 4 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/tools/xcutils/readnotes.c b/tools/xcutils/readnotes.c
index 7ff2530..cfae994 100644
--- a/tools/xcutils/readnotes.c
+++ b/tools/xcutils/readnotes.c
@@ -63,7 +63,7 @@ struct setup_header {
 static void print_string_note(const char *prefix, struct elf_binary *elf,
 			      ELF_HANDLE_DECL(elf_note) note)
 {
-	printf("%s: %s\n", prefix, (char*)elf_note_desc(elf, note));
+	printf("%s: %s\n", prefix, elf_strfmt(elf, elf_note_desc(elf, note)));
 }
 
 static void print_numeric_note(const char *prefix, struct elf_binary *elf,
@@ -103,10 +103,14 @@ static int print_notes(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) start,
 {
 	ELF_HANDLE_DECL(elf_note) note;
 	int notes_found = 0;
+	const char *this_note_name;
 
 	for ( note = start; ELF_HANDLE_PTRVAL(note) < ELF_HANDLE_PTRVAL(end); note = elf_note_next(elf, note) )
 	{
-		if (0 != strcmp(elf_note_name(elf, note), "Xen"))
+		this_note_name = elf_note_name(elf, note);
+		if (NULL == this_note_name)
+			continue;
+		if (0 != strcmp(this_note_name, "Xen"))
 			continue;
 
 		notes_found++;
@@ -294,7 +298,8 @@ int main(int argc, char **argv)
 
 	shdr = elf_shdr_by_name(&elf, "__xen_guest");
 	if (ELF_HANDLE_VALID(shdr))
-		printf("__xen_guest: %s\n", (char*)elf_section_start(&elf, shdr));
+		printf("__xen_guest: %s\n",
+                       elf_strfmt(&elf, elf_section_start(&elf, shdr)));
 
 	return 0;
 }
diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c
index 7140d59..b217f8f 100644
--- a/xen/common/libelf/libelf-dominfo.c
+++ b/xen/common/libelf/libelf-dominfo.c
@@ -137,7 +137,10 @@ int elf_xen_parse_note(struct elf_binary *elf,
 
     if ( note_desc[type].str )
     {
-        str = elf_note_desc(elf, note);
+        str = elf_strval(elf, elf_note_desc(elf, note));
+        if (str == NULL)
+            /* elf_strval will mark elf broken if it fails so no need to log */
+            return 0;
         elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
                 note_desc[type].name, str);
         parms->elf_notes[type].type = XEN_ENT_STR;
@@ -220,6 +223,7 @@ static int elf_xen_parse_notes(struct elf_binary *elf,
 {
     int xen_elfnotes = 0;
     ELF_HANDLE_DECL(elf_note) note;
+    const char *note_name;
 
     parms->elf_note_start = start;
     parms->elf_note_end   = end;
@@ -227,7 +231,10 @@ static int elf_xen_parse_notes(struct elf_binary *elf,
           ELF_HANDLE_PTRVAL(note) < parms->elf_note_end;
           note = elf_note_next(elf, note) )
     {
-        if ( strcmp(elf_note_name(elf, note), "Xen") )
+        note_name = elf_note_name(elf, note);
+        if ( note_name == NULL )
+            continue;
+        if ( strcmp(note_name, "Xen") )
             continue;
         if ( elf_xen_parse_note(elf, parms, note) )
             return -1;
@@ -541,7 +548,7 @@ int elf_xen_parse(struct elf_binary *elf,
                 parms->elf_note_start = ELF_INVALID_PTRVAL;
                 parms->elf_note_end   = ELF_INVALID_PTRVAL;
                 elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
-                        parms->guest_info);
+                        elf_strfmt(elf, parms->guest_info));
                 elf_xen_parse_guest_info(elf, parms);
                 break;
             }
diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c
index f1fd886..3a0cde1 100644
--- a/xen/common/libelf/libelf-tools.c
+++ b/xen/common/libelf/libelf-tools.c
@@ -119,7 +119,7 @@ const char *elf_section_name(struct elf_binary *elf,
     if ( ELF_PTRVAL_INVALID(elf->sec_strtab) )
         return "unknown";
 
-    return elf->sec_strtab + elf_uval(elf, shdr, sh_name);
+    return elf_strval(elf, elf->sec_strtab + elf_uval(elf, shdr, sh_name));
 }
 
 ELF_PTRVAL_CONST_VOID elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
@@ -151,6 +151,7 @@ ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *sym
     ELF_PTRVAL_CONST_VOID end = elf_section_end(elf, elf->sym_tab);
     ELF_HANDLE_DECL(elf_sym) sym;
     uint64_t info, name;
+    const char *sym_name;
 
     for ( ; ptr < end; ptr += elf_size(elf, sym) )
     {
@@ -159,7 +160,10 @@ ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *sym
         name = elf_uval(elf, sym, st_name);
         if ( ELF32_ST_BIND(info) != STB_GLOBAL )
             continue;
-        if ( strcmp(elf->sym_strtab + name, symbol) )
+        sym_name = elf_strval(elf, elf->sym_strtab + name);
+        if ( sym_name == NULL ) /* out of range, oops */
+            return ELF_INVALID_HANDLE(elf_sym);
+        if ( strcmp(sym_name, symbol) )
             continue;
         return sym;
     }
@@ -177,7 +181,7 @@ ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, int index)
 
 const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
 {
-    return ELF_HANDLE_PTRVAL(note) + elf_size(elf, note);
+    return elf_strval(elf, ELF_HANDLE_PTRVAL(note) + elf_size(elf, note));
 }
 
 ELF_PTRVAL_CONST_VOID elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
diff --git a/xen/include/xen/libelf.h b/xen/include/xen/libelf.h
index cefd3d3..af5b5c5 100644
--- a/xen/include/xen/libelf.h
+++ b/xen/include/xen/libelf.h
@@ -252,6 +252,9 @@ uint64_t elf_access_unsigned(struct elf_binary *elf, ELF_PTRVAL_CONST_VOID ptr,
 uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr);
 
 
+#define elf_strval(elf,x) ((const char*)(x)) /* may return NULL in the future */
+#define elf_strfmt(elf,x) ((const char*)(x)) /* will return (invalid) instead */
+
 #define elf_memcpy_safe(elf, dst, src, sz) memcpy((dst),(src),(sz))
 #define elf_memset_safe(elf, dst, c, sz)   memset((dst),(c),(sz))
   /*
@@ -279,7 +282,7 @@ ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *n
 ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_index(struct elf_binary *elf, int index);
 ELF_HANDLE_DECL(elf_phdr) elf_phdr_by_index(struct elf_binary *elf, int index);
 
-const char *elf_section_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr);
+const char *elf_section_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr); /* might return NULL if inputs are invalid */
 ELF_PTRVAL_CONST_VOID elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr);
 ELF_PTRVAL_CONST_VOID elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr);
 
@@ -289,7 +292,7 @@ ELF_PTRVAL_CONST_VOID elf_segment_end(struct elf_binary *elf, ELF_HANDLE_DECL(el
 ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *symbol);
 ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, int index);
 
-const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
+const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note); /* may return NULL */
 ELF_PTRVAL_CONST_VOID elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
 uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
 uint64_t elf_note_numeric_array(struct elf_binary *, ELF_HANDLE_DECL(elf_note),
-- 
1.7.2.5

  parent reply	other threads:[~2013-06-11 18:22 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-11 18:22 [PATCH v7 00/22] XSA55 libelf fixes for Xen 4.2 Ian Jackson
2013-06-11 18:22 ` [PATCH 01/22] libelf: abolish libelf-relocate.c Ian Jackson
2013-06-11 18:22 ` [PATCH 02/22] libxc: introduce xc_dom_seg_to_ptr_pages Ian Jackson
2013-06-11 18:22 ` [PATCH 03/22] libxc: Fix range checking in xc_dom_pfn_to_ptr etc Ian Jackson
2013-06-11 18:22 ` [PATCH 04/22] libelf: add `struct elf_binary*' parameter to elf_load_image Ian Jackson
2013-06-11 18:22 ` [PATCH 05/22] libelf: abolish elf_sval and elf_access_signed Ian Jackson
2013-06-11 18:22 ` [PATCH 06/22] libelf: move include of <asm/guest_access.h> to top of file Ian Jackson
2013-06-11 18:22 ` [PATCH 07/22] libelf/xc_dom_load_elf_symtab: Do not use "syms" uninitialised Ian Jackson
2013-06-11 18:22 ` [PATCH 08/22] libelf: introduce macros for memory access and pointer handling Ian Jackson
2013-06-11 18:22 ` [PATCH 09/22] tools/xcutils/readnotes: adjust print_l1_mfn_valid_note Ian Jackson
2013-06-11 18:22 ` Ian Jackson [this message]
2013-06-11 18:22 ` [PATCH 11/22] libelf: check all pointer accesses Ian Jackson
2013-06-11 18:22 ` [PATCH 12/22] libelf: Check pointer references in elf_is_elfbinary Ian Jackson
2013-06-11 18:22 ` [PATCH 13/22] libelf: Make all callers call elf_check_broken Ian Jackson
2013-06-11 18:22 ` [PATCH 14/22] libelf: use C99 bool for booleans Ian Jackson
2013-06-11 18:22 ` [PATCH 15/22] libelf: use only unsigned integers Ian Jackson
2013-06-11 18:22 ` [PATCH 16/22] libelf: check loops for running away Ian Jackson
2013-06-11 18:22 ` [PATCH 17/22] libelf: abolish obsolete macros Ian Jackson
2013-06-11 18:22 ` [PATCH 18/22] libxc: Add range checking to xc_dom_binloader Ian Jackson
2013-06-11 18:22 ` [PATCH 19/22] libxc: check failure of xc_dom_*_to_ptr, xc_map_foreign_range Ian Jackson
2013-06-13 15:22   ` Ian Jackson
2013-06-13 15:41     ` Andrew Cooper
2013-06-11 18:22 ` [PATCH 20/22] libxc: check return values from malloc Ian Jackson
2013-06-11 18:22 ` [PATCH 21/22] libxc: range checks in xc_dom_p2m_host and _guest Ian Jackson
2013-06-11 18:22 ` [PATCH 22/22] libxc: check blob size before proceeding in xc_dom_check_gzip Ian Jackson
  -- strict thread matches above, loose matches on Subject: below --
2013-06-11 18:20 [PATCH v7 00/22] XSA55 libelf fixes for unstable Ian Jackson
2013-06-11 18:20 ` [PATCH 10/22] libelf: check nul-terminated strings properly Ian Jackson
2013-06-11 19:14   ` Andrew Cooper
2013-06-07 18:35 [PATCH v6 00/22] XSA55 libelf fixes for Xen 4.2 Ian Jackson
2013-06-07 18:35 ` [PATCH 10/22] libelf: check nul-terminated strings properly Ian Jackson
2013-06-07 18:27 [PATCH v6 00/22] XSA55 libelf fixes for unstable Ian Jackson
2013-06-07 18:27 ` [PATCH 10/22] libelf: check nul-terminated strings properly Ian Jackson
2013-06-10 23:17   ` Andrew Cooper
2013-06-11 15:17     ` 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=1370974960-19824-11-git-send-email-ian.jackson@eu.citrix.com \
    --to=ian.jackson@eu.citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=mattjd@gmail.com \
    --cc=security@xen.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.