Similar to commit c460e2088, gelf_update_move does not distinguish between ELFCLASS32 and ELFCLASS64 binaries.
The code assumes that Elf32_Move and Elf64_Move structs are the same size but they are not. The m_info and m_poffset fields have type uint32_t for Elf32_Move but uint64_t for Elf64_Move. Fix this by handling ELFCLASS32 and ELFCLASS64 cases separately. Signed-off-by: Aaron Merey <[email protected]> --- libelf/gelf_update_move.c | 70 +++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/libelf/gelf_update_move.c b/libelf/gelf_update_move.c index 4190ee30..2b12c7eb 100644 --- a/libelf/gelf_update_move.c +++ b/libelf/gelf_update_move.c @@ -41,37 +41,73 @@ int gelf_update_move (Elf_Data *data, int ndx, GElf_Move *src) { + int result = 0; Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf *elf; if (data == NULL) - return 0; + return result; - /* The types for 32 and 64 bit are the same. Lucky us. */ - assert (sizeof (GElf_Move) == sizeof (Elf32_Move)); - assert (sizeof (GElf_Move) == sizeof (Elf64_Move)); - - /* Check whether we have to resize the data buffer. */ - if (INVALID_NDX (ndx, GElf_Move, &data_scn->d)) + if (unlikely (data->d_type != ELF_T_MOVE)) { - __libelf_seterrno (ELF_E_INVALID_INDEX); - return 0; + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return result; } - if (unlikely (data_scn->d.d_type != ELF_T_MOVE)) + elf = data_scn->s->elf; + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) { - /* The type of the data better should match. */ - __libelf_seterrno (ELF_E_DATA_MISMATCH); - return 0; + Elf32_Move *move; + + /* Check whether input values are too large for 32 bit conversion. */ + if (unlikely (src->m_poffset > 0xffffffffull) + || unlikely (GELF_M_SYM (src->m_info) > 0xffffff) + || unlikely (GELF_M_SIZE (src->m_info) > 0xff)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf32_Move, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + move = &((Elf32_Move *) data->d_buf)[ndx]; + + move->m_value = src->m_value; + move->m_info = ELF32_M_INFO (GELF_M_SYM (src->m_info), + GELF_M_SIZE (src->m_info)); + move->m_poffset = src->m_poffset; + move->m_repeat = src->m_repeat; + move->m_stride = src->m_stride; } + else + { + eu_static_assert (sizeof (GElf_Move) == sizeof (Elf64_Move)); - rwlock_wrlock (data_scn->s->elf->lock); + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, GElf_Move, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Move *) data->d_buf)[ndx] = *src; + } - ((GElf_Move *) data_scn->d.d_buf)[ndx] = *src; + result = 1; /* Mark the section as modified. */ data_scn->s->flags |= ELF_F_DIRTY; - rwlock_unlock (data_scn->s->elf->lock); + out: + rwlock_unlock (elf->lock); - return 1; + return result; } -- 2.53.0
