libelf: Don't overflow offsets in elf_cvt_Verneed and elf_cvt_Verdef

Message ID 20220320212940.155193-1-mark@klomp.org
State Committed
Headers
Series libelf: Don't overflow offsets in elf_cvt_Verneed and elf_cvt_Verdef |

Commit Message

Mark Wielaard March 20, 2022, 9:29 p.m. UTC
  The conversion functions for Verdef and Verneed keep offsets to the next
structure. Make sure that following vd_aux, vda_next, vd_next, vn_aux,
vna_next and vn_next don't overflow (and wrap around) the offsets.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libelf/ChangeLog       |  7 ++++++
 libelf/version_xlate.h | 56 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 55 insertions(+), 8 deletions(-)
  

Patch

diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index f6b47c68..ea204e2b 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,10 @@ 
+2022-03-20  Mark Wielaard  <mark@klomp.org>
+
+	* version_xlate.h (elf_cvt_Verdef): Make sure aux_offset and
+	def_offset don't overflow.
+	(elf_cvt_Verneed): Make sure aux_offset and need_offset don't
+	overflow.
+
 2022-03-18  Mark Wielaard  <mark@klomp.org>
 
 	* version_xlate.h (elf_cvt_Verdef): Check alignment of def_offset
diff --git a/libelf/version_xlate.h b/libelf/version_xlate.h
index b7bd301d..97f3b730 100644
--- a/libelf/version_xlate.h
+++ b/libelf/version_xlate.h
@@ -87,10 +87,16 @@  elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode)
 	  ddest->vd_aux = bswap_32 (dsrc->vd_aux);
 	  ddest->vd_next = bswap_32 (dsrc->vd_next);
 
+	  if (ddest->vd_aux > len - def_offset)
+	    return;
 	  aux_offset = def_offset + ddest->vd_aux;
 	}
       else
-	aux_offset = def_offset + dsrc->vd_aux;
+	{
+	  if (dsrc->vd_aux > len - def_offset)
+	    return;
+	  aux_offset = def_offset + dsrc->vd_aux;
+	}
 
       /* Handle all the auxiliary records belonging to this definition.  */
       do
@@ -107,19 +113,29 @@  elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode)
 	  asrc = (GElf_Verdaux *) ((char *) src + aux_offset);
 
 	  if (encode)
-	    aux_offset += asrc->vda_next;
+	    {
+	      if (asrc->vda_next > len - aux_offset)
+		return;
+	      aux_offset += asrc->vda_next;
+	    }
 
 	  adest->vda_name = bswap_32 (asrc->vda_name);
 	  adest->vda_next = bswap_32 (asrc->vda_next);
 
 	  if (! encode)
-	    aux_offset += adest->vda_next;
+	    {
+	      if (adest->vda_next > len - aux_offset)
+		return;
+	      aux_offset += adest->vda_next;
+	    }
 	}
       while (asrc->vda_next != 0);
 
       /* Encode now if necessary.  */
       if (encode)
 	{
+	  if (dsrc->vd_next > len - def_offset)
+	    return;
 	  def_offset += dsrc->vd_next;
 
 	  ddest->vd_version = bswap_16 (dsrc->vd_version);
@@ -131,7 +147,11 @@  elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode)
 	  ddest->vd_next = bswap_32 (dsrc->vd_next);
 	}
       else
-	def_offset += ddest->vd_next;
+	{
+	  if (ddest->vd_next > len - def_offset)
+	    return;
+	  def_offset += ddest->vd_next;
+	}
     }
   while (dsrc->vd_next != 0);
 }
@@ -188,10 +208,16 @@  elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode)
 	  ndest->vn_aux = bswap_32 (nsrc->vn_aux);
 	  ndest->vn_next = bswap_32 (nsrc->vn_next);
 
+	  if (ndest->vn_aux > len - need_offset)
+	    return;
 	  aux_offset = need_offset + ndest->vn_aux;
 	}
       else
-	aux_offset = need_offset + nsrc->vn_aux;
+	{
+	  if (nsrc->vn_aux > len - need_offset)
+	    return;
+	  aux_offset = need_offset + nsrc->vn_aux;
+	}
 
       /* Handle all the auxiliary records belonging to this requirement.  */
       do
@@ -208,7 +234,11 @@  elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode)
 	  asrc = (GElf_Vernaux *) ((char *) src + aux_offset);
 
 	  if (encode)
-	    aux_offset += asrc->vna_next;
+	    {
+	      if (asrc->vna_next > len - aux_offset)
+		return;
+	      aux_offset += asrc->vna_next;
+	    }
 
 	  adest->vna_hash = bswap_32 (asrc->vna_hash);
 	  adest->vna_flags = bswap_16 (asrc->vna_flags);
@@ -217,13 +247,19 @@  elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode)
 	  adest->vna_next = bswap_32 (asrc->vna_next);
 
 	  if (! encode)
-	    aux_offset += adest->vna_next;
+	    {
+	      if (adest->vna_next > len - aux_offset)
+		return;
+	      aux_offset += adest->vna_next;
+	    }
 	}
       while (asrc->vna_next != 0);
 
       /* Encode now if necessary.  */
       if (encode)
 	{
+	  if (nsrc->vn_next > len - need_offset)
+	    return;
 	  need_offset += nsrc->vn_next;
 
 	  ndest->vn_version = bswap_16 (nsrc->vn_version);
@@ -233,7 +269,11 @@  elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode)
 	  ndest->vn_next = bswap_32 (nsrc->vn_next);
 	}
       else
-	need_offset += ndest->vn_next;
+	{
+	  if (ndest->vn_next > len - need_offset)
+	    return;
+	  need_offset += ndest->vn_next;
+	}
     }
   while (nsrc->vn_next != 0);
 }