From ad2a37157d3476dffb3baf93ca5001c9f6c44bda Mon Sep 17 00:00:00 2001
From: Nick Clifton <nickc@redhat.com>
Date: Wed, 9 Sep 2020 15:54:20 +0100
Subject: [PATCH] If the lto plugin encounters a file with multiple symbol
 sections, each of which also has a v1 symbol extension section[1] then it
 will attempt to read the extension data for *every* symbol from each of the
 extension sections.  This results in reading off the end of a buffer with the
 associated memory corruption that that entails.  This patch fixes that
 problem.

2020-09-09  Nick Clifton  <nickc@redhat.com>

	* lto-plugin.c (struct plugin_symtab): Add last_sym field.
	(parse_symtab_extension): Only read as many entries as are
	available in the buffer.  Store the data read into the symbol
	table indexed from last_sym.  Increment last_sym.
---
 lto-plugin/lto-plugin.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
index a65c2801b9b5..6f67552d0758 100644
--- a/lto-plugin/lto-plugin.c
+++ b/lto-plugin/lto-plugin.c
@@ -115,6 +115,7 @@ struct sym_aux
 struct plugin_symtab
 {
   int nsyms;
+  int last_sym;
   struct sym_aux *aux;
   struct ld_plugin_symbol *syms;
   unsigned long long id;
@@ -382,19 +383,30 @@ translate (char *data, char *end, struct plugin_symtab *out)
 static void
 parse_symtab_extension (char *data, char *end, struct plugin_symtab *out)
 {
-  unsigned i;
+  unsigned long i;
+  unsigned char version;
+
+  if (data >= end)
+    /* FIXME: Issue an error ?  */
+    return;
 
-  unsigned char version = *data;
+  version = *data;
   data++;
 
+  if (version != 1)
+    return;
+
   /* Version 1 contains the following data per entry:
      - symbol_type
      - section_kind
      .  */
 
-  if (version == 1)
-    for (i = 0; i < out->nsyms; i++)
-      data = parse_table_entry_extension (data, &out->syms[i]);
+  unsigned long nsyms = (end - data) / 2;
+
+  for (i = 0; i < nsyms; i++)
+    data = parse_table_entry_extension (data, out->syms + i + out->last_sym);
+
+  out->last_sym += nsyms;
 }
 
 /* Free all memory that is no longer needed after writing the symbol
@@ -1172,9 +1184,12 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
       /*  Parsing symtab extension should be done only for add_symbols_v2 and
 	  later versions.  */
       if (!errmsg && add_symbols_v2 != NULL)
-	errmsg = simple_object_find_sections (obj.objfile,
-					      process_symtab_extension,
-					      &obj, &err);
+	{
+	  obj.out->last_sym = 0;
+	  errmsg = simple_object_find_sections (obj.objfile,
+						process_symtab_extension,
+						&obj, &err);
+	}
     }
 
   if (!obj.objfile || errmsg)
-- 
GitLab