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 <m...@klomp.org>
---
 libelf/ChangeLog       |  7 ++++++
 libelf/version_xlate.h | 56 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 55 insertions(+), 8 deletions(-)

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  <m...@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  <m...@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);
 }
-- 
2.30.2

Reply via email to