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