Files
third_party_elfutils/libelf/gelf_getnote.c
T
Mark Wielaard 5199e15870 Recognize and parse GNU Property notes.
GNU Property notes are different from normal notes because they use
variable alignment/padding of their fields. They are 8 byte aligned,
but use 4 byte fields. The name is aligned at 4 bytes and padded so
that, the desc is aligned at 8 bytes. The whole note is padded to
8 bytes again. For normal notes all fields are both 4 bytes wide and
4 bytes aligned.

To recognize these new kind of ELF Notes a new Elf_Type is introduced,
ELF_T_NHDR8. This type is used in the xlate functions to determine
how to align and pad the various fields. Since the fields themselves
can now have different alignments we will have to keep track of the
current alignement and use either NOTE_ALIGN4 or NOTE_ALIGN8 to
determine the padding.

To set the correct Elf_Type on the Elf_Data we use either the section
sh_addralign or the segment p_align values. Assuming 8 means the
section or segment contains the new style notes, otherwise normal
notes.

When we cannot determine the "alignment" directly, like when parsing
special kernel sys files, we check the name "GNU" and type
"GNU_PROPERTY_TYPE_0" fields.

ebl_object_note now parses the new NT_GNU_PROPERTY_TYPE_0 and can
extract the GNU_PROPERTY_STACK_SIZE, GNU_PROPERTY_NO_COPY_ON_PROTECTED
and GNU_PROPERTY_X86_FEATURE_1_AND types GNU_PROPERTY_X86_FEATURE_1_IBT
and GNU_PROPERTY_X86_FEATURE_1_SHSTK.

Tests are added for extracting the note from sections or segments
as set by gcc -fcf-protection.

Signed-off-by: Mark Wielaard <mark@klomp.org>
2018-10-29 00:57:57 +01:00

116 lines
3.2 KiB
C

/* Get note information at the supplied offset.
Copyright (C) 2007, 2014, 2015, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
it under the terms of either
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at
your option) any later version
or
* the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version
or both in parallel, as here.
elfutils is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received copies of the GNU General Public License and
the GNU Lesser General Public License along with this program. If
not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <gelf.h>
#include <string.h>
#include "libelfP.h"
size_t
gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
size_t *name_offset, size_t *desc_offset)
{
if (data == NULL)
return 0;
if (unlikely (data->d_type != ELF_T_NHDR && data->d_type != ELF_T_NHDR8))
{
__libelf_seterrno (ELF_E_INVALID_HANDLE);
return 0;
}
/* It's easy to handle this type. It has the same size for 32 and
64 bit objects. */
assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr));
assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr));
rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock);
/* The data is already in the correct form. Just make sure the
offset is OK. */
if (unlikely (offset > data->d_size
|| data->d_size - offset < sizeof (GElf_Nhdr)))
{
__libelf_seterrno (ELF_E_OFFSET_RANGE);
offset = 0;
}
else
{
const GElf_Nhdr *n = data->d_buf + offset;
offset += sizeof *n;
if (offset > data->d_size)
offset = 0;
else
{
/* This is slightly tricky, offset is guaranteed to be 4
byte aligned, which is what we need for the name_offset.
And normally desc_offset is also 4 byte aligned, but not
for GNU Property notes, then it should be 8. So align
the offset, after adding the namesz, and include padding
in descsz to get to the end. */
*name_offset = offset;
offset += n->n_namesz;
if (offset > data->d_size)
offset = 0;
else
{
/* Include padding. Check below for overflow. */
GElf_Word descsz = (data->d_type == ELF_T_NHDR8
? NOTE_ALIGN8 (n->n_descsz)
: NOTE_ALIGN4 (n->n_descsz));
if (data->d_type == ELF_T_NHDR8)
offset = NOTE_ALIGN8 (offset);
else
offset = NOTE_ALIGN4 (offset);
if (unlikely (offset > data->d_size
|| data->d_size - offset < descsz
|| (descsz == 0 && n->n_descsz != 0)))
offset = 0;
else
{
*desc_offset = offset;
offset += descsz;
*result = *n;
}
}
}
}
rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock);
return offset;
}