summaryrefslogtreecommitdiffstats
path: root/src/elflint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/elflint.c')
-rw-r--r--src/elflint.c253
1 files changed, 119 insertions, 134 deletions
diff --git a/src/elflint.c b/src/elflint.c
index 37936b1f..e855d483 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -96,6 +96,9 @@ static void process_file (int fd, Elf *elf, const char *prefix,
bool only_one);
static void process_elf_file (Elf *elf, const char *prefix, const char *suffix,
const char *fname, size_t size, bool only_one);
+static void check_note_section (Ebl *ebl, GElf_Ehdr *ehdr,
+ GElf_Shdr *shdr, int idx);
+
/* Report an error. */
#define ERROR(str, args...) \
@@ -3499,6 +3502,10 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"),
check_group (ebl, ehdr, shdr, cnt);
break;
+ case SHT_NOTE:
+ check_note_section (ebl, ehdr, shdr, cnt);
+ break;
+
case SHT_GNU_versym:
/* We cannot process this section now since we have no guarantee
that the verneed and verdef sections have already been read.
@@ -3565,163 +3572,141 @@ no .gnu.versym section present but .gnu.versym_d or .gnu.versym_r section exist\
}
-static void
-check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt)
+static GElf_Off
+check_note_data (Ebl *ebl, const GElf_Ehdr *ehdr,
+ Elf_Data *data, int shndx, int phndx, GElf_Off start)
{
- if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
- && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
- ERROR (gettext ("\
-phdr[%d]: no note entries defined for the type of file\n"),
- cnt);
-
- if (is_debuginfo)
- /* The p_offset values in a separate debug file are bogus. */
- return;
-
- char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz);
-
- /* ELF64 files often use note section entries in the 32-bit format.
- The p_align field is set to 8 in case the 64-bit format is used.
- In case the p_align value is 0 or 4 the 32-bit format is
- used. */
- GElf_Xword align = phdr->p_align == 0 || phdr->p_align == 4 ? 4 : 8;
-#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1))
-
- GElf_Xword idx = 0;
- while (idx < phdr->p_filesz)
+ size_t offset = 0;
+ size_t last_offset = 0;
+ GElf_Nhdr nhdr;
+ size_t name_offset;
+ size_t desc_offset;
+ while (offset < data->d_size
+ && (offset = gelf_getnote (data, offset,
+ &nhdr, &name_offset, &desc_offset)) > 0)
{
- uint64_t namesz;
- uint64_t descsz;
- uint64_t type;
- uint32_t namesz32;
- uint32_t descsz32;
-
- if (align == 4)
- {
- uint32_t *ptr = (uint32_t *) (notemem + idx);
-
- if ((__BYTE_ORDER == __LITTLE_ENDIAN
- && ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
- || (__BYTE_ORDER == __BIG_ENDIAN
- && ehdr->e_ident[EI_DATA] == ELFDATA2LSB))
- {
- namesz32 = namesz = bswap_32 (*ptr);
- ++ptr;
- descsz32 = descsz = bswap_32 (*ptr);
- ++ptr;
- type = bswap_32 (*ptr);
- }
- else
- {
- namesz32 = namesz = *ptr++;
- descsz32 = descsz = *ptr++;
- type = *ptr;
- }
- }
- else
- {
- uint64_t *ptr = (uint64_t *) (notemem + idx);
- uint32_t *ptr32 = (uint32_t *) (notemem + idx);
-
- if ((__BYTE_ORDER == __LITTLE_ENDIAN
- && ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
- || (__BYTE_ORDER == __BIG_ENDIAN
- && ehdr->e_ident[EI_DATA] == ELFDATA2LSB))
- {
- namesz = bswap_64 (*ptr);
- ++ptr;
- descsz = bswap_64 (*ptr);
- ++ptr;
- type = bswap_64 (*ptr);
-
- namesz32 = bswap_32 (*ptr32);
- ++ptr32;
- descsz32 = bswap_32 (*ptr32);
- }
- else
- {
- namesz = *ptr++;
- descsz = *ptr++;
- type = *ptr;
-
- namesz32 = *ptr32++;
- descsz32 = *ptr32;
- }
- }
-
- if (idx + 3 * align > phdr->p_filesz
- || (idx + 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz)
- > phdr->p_filesz))
- {
- if (ehdr->e_ident[EI_CLASS] == ELFCLASS64
- && idx + 3 * 4 <= phdr->p_filesz
- && (idx + 3 * 4 + ALIGNED_LEN (namesz32) + ALIGNED_LEN (descsz32)
- <= phdr->p_filesz))
- ERROR (gettext ("\
-phdr[%d]: note entries probably in form of a 32-bit ELF file\n"), cnt);
- else
- ERROR (gettext ("phdr[%d]: extra %zu bytes after last note\n"),
- cnt, (size_t) (phdr->p_filesz - idx));
- break;
- }
+ last_offset = offset;
/* Make sure it is one of the note types we know about. */
if (ehdr->e_type == ET_CORE)
- {
- switch (type)
- {
- case NT_PRSTATUS:
- case NT_FPREGSET:
- case NT_PRPSINFO:
- case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */
- case NT_PLATFORM:
- case NT_AUXV:
- case NT_GWINDOWS:
- case NT_ASRS:
- case NT_PSTATUS:
- case NT_PSINFO:
- case NT_PRCRED:
- case NT_UTSNAME:
- case NT_LWPSTATUS:
- case NT_LWPSINFO:
- case NT_PRFPXREG:
- /* Known type. */
- break;
+ switch (nhdr.n_type)
+ {
+ case NT_PRSTATUS:
+ case NT_FPREGSET:
+ case NT_PRPSINFO:
+ case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */
+ case NT_PLATFORM:
+ case NT_AUXV:
+ case NT_GWINDOWS:
+ case NT_ASRS:
+ case NT_PSTATUS:
+ case NT_PSINFO:
+ case NT_PRCRED:
+ case NT_UTSNAME:
+ case NT_LWPSTATUS:
+ case NT_LWPSINFO:
+ case NT_PRFPXREG:
+ /* Known type. */
+ break;
- default:
+ default:
+ if (shndx == 0)
ERROR (gettext ("\
-phdr[%d]: unknown core file note type %" PRIu64 " at offset %" PRIu64 "\n"),
- cnt, type, idx);
- }
- }
+phdr[%d]: unknown core file note type %" PRIu32 " at offset %" PRIu64 "\n"),
+ phndx, (uint32_t) nhdr.n_type, start + offset);
+ else
+ ERROR (gettext ("\
+section [%2d] '%s': unknown core file note type %" PRIu32
+ " at offset %Zu\n"),
+ shndx, section_name (ebl, shndx),
+ (uint32_t) nhdr.n_type, offset);
+ }
else
- switch (type)
+ switch (nhdr.n_type)
{
- case NT_GNU_ABI_TAG: /* aka NT_VERSION */
+ case NT_GNU_ABI_TAG:
case NT_GNU_HWCAP:
case NT_GNU_BUILD_ID:
- /* Known type. */
break;
case 0:
/* Linux vDSOs use a type 0 note for the kernel version word. */
- if (namesz == sizeof "Linux"
- && !memcmp (notemem + idx + 3 * align, "Linux", sizeof "Linux"))
+ if (nhdr.n_namesz == sizeof "Linux"
+ && !memcmp (data->d_buf + name_offset, "Linux", sizeof "Linux"))
break;
default:
- ERROR (gettext ("\
-phdr[%d]: unknown object file note type %" PRIu64 " at offset %" PRIu64 "\n"),
- cnt, type, idx);
+ if (shndx == 0)
+ ERROR (gettext ("\
+phdr[%d]: unknown object file note type %" PRIu32 " at offset %Zu\n"),
+ phndx, (uint32_t) nhdr.n_type, offset);
+ else
+ ERROR (gettext ("\
+section [%2d] '%s': unknown object file note type %" PRIu32
+ " at offset %Zu\n"),
+ shndx, section_name (ebl, shndx),
+ (uint32_t) nhdr.n_type, offset);
}
-
- /* Move to the next entry. */
- idx += 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz);
}
- gelf_freechunk (ebl->elf, notemem);
+ return last_offset;
+}
+
+static void
+check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt)
+{
+ if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
+ && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ ERROR (gettext ("\
+phdr[%d]: no note entries defined for the type of file\n"),
+ cnt);
+
+ if (is_debuginfo)
+ /* The p_offset values in a separate debug file are bogus. */
+ return;
+
+ GElf_Off notes_size = 0;
+ Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
+ phdr->p_offset, phdr->p_filesz,
+ ELF_T_NHDR);
+ if (data != NULL)
+ notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset);
+
+ if (notes_size == 0)
+ ERROR (gettext ("phdr[%d]: cannot get content of note section: %s\n"),
+ cnt, elf_errmsg (-1));
+ else if (notes_size != phdr->p_filesz)
+ ERROR (gettext ("phdr[%d]: extra %" PRIu64 " bytes after last note\n"),
+ cnt, phdr->p_filesz - notes_size);
}
+static void
+check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
+{
+ Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
+ if (data == NULL)
+ {
+ ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
+ idx, section_name (ebl, idx));
+ return;
+ }
+
+ if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
+ && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ ERROR (gettext ("\
+section [%2d] '%s': no note entries defined for the type of file\n"),
+ idx, section_name (ebl, idx));
+
+ GElf_Off notes_size = check_note_data (ebl, ehdr, data, idx, 0, 0);
+
+ if (notes_size == 0)
+ ERROR (gettext ("section [%2d] '%s': cannot get content of note section\n"),
+ idx, section_name (ebl, idx));
+ else if (notes_size != shdr->sh_size)
+ ERROR (gettext ("section [%2d] '%s': extra %" PRIu64
+ " bytes after last note\n"),
+ idx, section_name (ebl, idx), shdr->sh_size - notes_size);
+}
static void
check_program_header (Ebl *ebl, GElf_Ehdr *ehdr)