[devel] verify-elf lint=normal (elflint)
Alexey Tourbin
at на altlinux.ru
Чт Дек 24 04:33:04 UTC 2009
On Thu, Dec 24, 2009 at 03:57:22AM +0300, Alexey Tourbin wrote:
> On Mon, Dec 21, 2009 at 11:08:52PM +0300, Dmitry V. Levin wrote:
> > glibc-6:2.10.1-alt8
> > loadable segment [1] is writable but contains no writable sections
> > verify-elf: WARNING: ./sbin/glibc_preinstall: eu-elflint failed
>
> > klibc-1.5.15-alt4
> > loadable segment [3] is writable but contains no writable sections
> > verify-elf: WARNING: ./lib/mkinitrd/klibc/bin/cat: eu-elflint failed
> > [9 lines skipped]
> > verify-elf: WARNING: ./lib/mkinitrd/klibc/bin/umount: eu-elflint failed
> > loadable segment [3] is writable but contains no writable sections
> > verify-elf: WARNING: ./usr/lib/klibc/bin/cat: eu-elflint failed
> > [12 lines skipped]
> > section [ 4] '.interp' present in object file
> > section [ 4] '.interp' has SHF_ALLOC flag set but there is no loadable segment
> > verify-elf: WARNING: ./usr/lib/klibc/lib/interp.o: eu-elflint failed
>
> > util-linux-2.16.1-alt3
> > loadable segment [1] is writable but contains no writable sections
> > verify-elf: WARNING: ./sbin/nologin: eu-elflint failed
> > verify-elf: WARNING: ./usr/bin/pause: eu-elflint failed
>
> It looks like all klibc executables (compiled with klcc) are subject
> to this warning. Let's try to fix it before we discuss whether
> lint=normal should be on by default.
Let's test a simple program to examine the problem.
$ cat test.c
int foo = 0;
int main()
{
return 0;
}
$ klcc test.c && readelf --segments a.out && eu-elflint --gnu-ld a.out
Elf file type is EXEC (Executable file)
Entry point 0x4000e8
There are 3 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000001ac 0x00000000000001ac R E 200000
LOAD 0x00000000000001b0 0x00000000006001b0 0x00000000006001b0
0x0000000000000000 0x0000000000000030 RW 200000
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
Section to Segment mapping:
Segment Sections...
00 .text
01 .bss
02
loadable segment [1] is writable but contains no writable sections
$
The last line, which is eu-elflint output, suggests there's a problem.
Now, if we replace "foo = 0" with "foo = 1", the test will pass.
$ cat test.c
int foo = 1;
int main()
{
return 0;
}
$ klcc test.c && readelf --segments a.out && eu-elflint --gnu-ld a.out
Elf file type is EXEC (Executable file)
Entry point 0x4000e8
There are 3 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000001ac 0x00000000000001ac R E 200000
LOAD 0x00000000000001ac 0x00000000006001ac 0x00000000006001ac
0x0000000000000004 0x000000000000002c RW 200000
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RWE 8
Section to Segment mapping:
Segment Sections...
00 .text
01 .data .bss
02
No errors
$
(The last line now says "No errors".)
So the problem is that, while ".data" section contributes to the ELF
segment being writable, ".bss" section alone does not.
Let's see the code.
elfutils-0.143/src/elflint.c:
3694 if (ehdr->e_type != ET_REL && (shdr->sh_flags & SHF_ALLOC) != 0)
3695 {
3696 /* Make sure the section is contained in a loaded segment
3697 and that the initialization part matches NOBITS sections. */
3698 int pcnt;
3699 GElf_Phdr phdr_mem;
3700 GElf_Phdr *phdr;
3701
3702 for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
3703 if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL
3704 && ((phdr->p_type == PT_LOAD
3705 && (shdr->sh_flags & SHF_TLS) == 0)
3706 || (phdr->p_type == PT_TLS
3707 && (shdr->sh_flags & SHF_TLS) != 0))
3708 && phdr->p_offset <= shdr->sh_offset
3709 && (phdr->p_offset + phdr->p_filesz > shdr->sh_offset
3710 || (phdr->p_offset + phdr->p_memsz > shdr->sh_offset
3711 && shdr->sh_type == SHT_NOBITS)))
3712 {
3713 /* Found the segment. */
3714 if (phdr->p_offset + phdr->p_memsz
3715 < shdr->sh_offset + shdr->sh_size)
3716 ERROR (gettext ("\
3717 section [%2zu] '%s' not fully contained in segment of program header entry %d\n"),
3718 cnt, section_name (ebl, cnt), pcnt);
3719
3720 if (shdr->sh_type == SHT_NOBITS)
3721 {
3722 if (shdr->sh_offset < phdr->p_offset + phdr->p_filesz
3723 && !is_debuginfo)
3724 ERROR (gettext ("\
3725 section [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d\n"),
3726 cnt, section_name (ebl, cnt), pcnt);
3727 }
3728 else
3729 {
3730 const GElf_Off end = phdr->p_offset + phdr->p_filesz;
3731 if (shdr->sh_offset > end ||
3732 (shdr->sh_offset == end && shdr->sh_size != 0))
3733 ERROR (gettext ("\
3734 section [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"),
3735 cnt, section_name (ebl, cnt), pcnt);
3736 }
3737
3738 if (shdr->sh_type != SHT_NOBITS)
3739 {
3740 if ((shdr->sh_flags & SHF_EXECINSTR) != 0)
3741 {
3742 segment_flags[pcnt] |= PF_X;
3743 if ((phdr->p_flags & PF_X) == 0)
3744 ERROR (gettext ("\
3745 section [%2zu] '%s' is executable in nonexecutable segment %d\n"),
3746 cnt, section_name (ebl, cnt), pcnt);
3747 }
3748
3749 if ((shdr->sh_flags & SHF_WRITE) != 0)
3750 {
3751 segment_flags[pcnt] |= PF_W;
3752 if (0 /* XXX vdso images have this */
3753 && (phdr->p_flags & PF_W) == 0)
3754 ERROR (gettext ("\
3755 section [%2zu] '%s' is writable in unwritable segment %d\n"),
3756 cnt, section_name (ebl, cnt), pcnt);
3757 }
3758 }
This code tests each allocatable section (3694) and, among other things,
sets segments_flags (3742, 3751) -- permissions which corresponding ELF
segment should have (the segments are tested later against segments_flags).
However, only NOBITS sections contribute to ELF segment flags (3738).
This is possibly wrong: ".bss" section, despite the fact that it is
NOBITS (filled with zeroes upon startup), should be writable.
Here's a dumb patch which fixes the problem.
--- src/elflint.c- 2009-12-24 01:09:24 +0000
+++ src/elflint.c 2009-12-24 03:48:23 +0000
@@ -3794,7 +3794,10 @@ section [%2zu] '%s' has not type NOBITS
section [%2zu] '%s' is executable in nonexecutable segment %d\n"),
cnt, section_name (ebl, cnt), pcnt);
}
+ }
+ if (shdr->sh_type != SHT_NOBITS || strcmp (scnname, ".bss") == 0)
+ {
if ((shdr->sh_flags & SHF_WRITE) != 0)
{
segment_flags[pcnt] |= PF_W;
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя : отсутствует
Тип : application/pgp-signature
Размер : 198 байтов
Описание: отсутствует
Url : <http://lists.altlinux.org/pipermail/devel/attachments/20091224/ae0dcf61/attachment-0001.bin>
Подробная информация о списке рассылки Devel