This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] libelf: find 1st section instead of assuming


Hi Mark,

On 2016-06-23, Mark Wielaard <mjw@redhat.com> wrote:
>> When getting section headers it is assumed that the first section
>> is on the first section list. However, it is possible that the
>> first section list only contains the zeroth section, in which
>> case either illegal memory access occurs or elf_nextscn()
>> erroneously returns NULL.
>> 
>> With this patch, checks are added to avoid the illegal memory
>> access and (if available) the second section list is looked at
>> to find the first section.
>
> Both changes to updatenull and nextscn do make sense to me.
>
> I assume this wasn't just theoretical? I didn't immediately see how
> this situation occurs. Do you happen to have an example/testcase?

The situation occurs when adding sections to an existing ELF file that
has none. You can see that in:

    libelf/elf_begin.c:file_read_elf()

When an ELF file is opened with ELF_C_RDWR or ELF_C_RDWR_MMAP, scnmax is
set to 1. That leads to the first section being placed on the second
section list when elf_newscn() is called.

Below is a relatively simple program to demonstrate this. This program
adds customized section notes to core files. It is being developed as a
feature for the minicoredumper project.

John Ogness

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <libelf.h>
#include <gelf.h>
#include <sys/types.h>
#include <sys/stat.h>

static int add_shstrtab_section(Elf *e, GElf_Off offset, GElf_Word *size)
{
	GElf_Shdr shdr;
	Elf_Data *data;
	Elf_Scn *scn;

	scn = elf_newscn(e);
	if (!scn)
		return -1;

	data = elf_newdata(scn);
	if (!data)
		return -1;

	data->d_align = 1;
	data->d_off = 0;
	data->d_buf = "\0.debug\0.shstrtab";
	data->d_type = ELF_T_BYTE;
	data->d_size = 18;
	data->d_version = EV_CURRENT;

	if (gelf_getshdr(scn, &shdr) == NULL)
		return -1;

	shdr.sh_name = 8;
	shdr.sh_type = SHT_STRTAB;
	shdr.sh_flags = SHF_STRINGS;
	shdr.sh_entsize = 0;
	shdr.sh_size = data->d_size;
	shdr.sh_offset = offset;
	shdr.sh_addralign = 1;

	gelf_update_shdr(scn, &shdr);

	*size = shdr.sh_size;

	return 0;
}

static int add_debug_section(Elf *e, GElf_Off offset, GElf_Word size)
{
	GElf_Shdr shdr;
	Elf_Scn *scn;

	scn = elf_newscn(e);
	if (!scn)
		return -1;

	if (gelf_getshdr(scn, &shdr) == NULL)
		return -1;

	shdr.sh_name = 1;
	shdr.sh_type = SHT_PROGBITS;
	shdr.sh_flags = 0;
	shdr.sh_entsize = 0;
	shdr.sh_offset = offset;
	shdr.sh_size = size;
	shdr.sh_addralign = 1;

	gelf_update_shdr(scn, &shdr);

	return 0;
}

int main(int argc, const char *argv[])
{
	size_t last_offset;
	GElf_Ehdr ehdr;
	GElf_Word size;
	struct stat sb;
	int ret;
	Elf *e;
	int fd;

	if (elf_version(EV_CURRENT) == EV_NONE)
		return 1;

	fd = open(argv[1], O_RDWR);
	if (fd < 0)
		return 1;

	e = elf_begin(fd, ELF_C_RDWR, NULL);
	if (!e)
		return 1;

	elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);

	if (gelf_getehdr(e, &ehdr) == NULL)
		return 1;

	/* use file size as last offset */
	if (fstat(fd, &sb) != 0)
		return 1;
	last_offset = sb.st_size;

	/* cover everything after the elf header to ensure
	 * that there are no gaps for libelf to fill */
	if (add_debug_section(e, ehdr.e_ehsize,
	    last_offset - ehdr.e_ehsize) != 0) {
		return 1;
	}

	if (add_shstrtab_section(e, last_offset, &size) != 0)
		return 1;

	last_offset += size;

	ehdr.e_shoff = last_offset;
	ehdr.e_shstrndx = 2;
	gelf_update_ehdr(e, &ehdr);

	elf_flagelf(e, ELF_C_SET, ELF_F_DIRTY);

	ret = elf_update(e, ELF_C_WRITE);
	if (ret < 0)
		return 1;

	elf_end(e);

	close(fd);

	return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]