Accept linkers representation for ELF segments with zero on-disk length.

For such segments, GNU bfd linker writes knowingly incorrect value
into the the file offset field of the program header entry, with the
motivation that file should not be mapped for creation of this segment
at all.

Relax checks for the ELF structure validity when on-disk segment
length is zero, and explicitely set mapping length to zero for such
segments to avoid validating rounding arithmetic.

PR:	217610
Reported by:	Robert Clausecker <fuz@fuz.su>
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2017-03-12 13:51:13 +00:00
parent 973d67c407
commit 9bcf2f2da0

View File

@ -522,7 +522,8 @@ __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset,
* While I'm here, might as well check for something else that
* is invalid: filsz cannot be greater than memsz.
*/
if ((off_t)filsz + offset > imgp->attr->va_size || filsz > memsz) {
if ((filsz != 0 && (off_t)filsz + offset > imgp->attr->va_size) ||
filsz > memsz) {
uprintf("elf_load_section: truncated ELF file\n");
return (ENOEXEC);
}
@ -538,7 +539,9 @@ __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset,
* early and copy the initialized data into that first page. We
* choose the second.
*/
if (memsz > filsz)
if (filsz == 0)
map_len = 0;
else if (memsz > filsz)
map_len = trunc_page_ps(offset + filsz, pagesize) - file_addr;
else
map_len = round_page_ps(offset + filsz, pagesize) - file_addr;
@ -570,7 +573,8 @@ __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset,
* segment in the file is extended to provide bss. It's a neat idea
* to try and save a page, but it's a pain in the behind to implement.
*/
copy_len = (offset + filsz) - trunc_page_ps(offset + filsz, pagesize);
copy_len = filsz == 0 ? 0 : (offset + filsz) - trunc_page_ps(offset +
filsz, pagesize);
map_addr = trunc_page_ps((vm_offset_t)vmaddr + filsz, pagesize);
map_len = round_page_ps((vm_offset_t)vmaddr + memsz, pagesize) -
map_addr;