Subject: Re: Non executable mappings and compatibility options bugs
To: Emmanuel Dreyfus <manu@netbsd.org>
From: Chuck Silvers <chuq@chuq.com>
List: tech-kern
Date: 06/20/2004 10:55:23
hi,

On Sun, Jun 20, 2004 at 03:15:13PM +0200, Emmanuel Dreyfus wrote:
> Hi
> 
> Wiz reported me a bug in COMPAT_LINUX/powerpc that might be an unwanted
> consequence of non executable mappings: Linux's ldconfig will randomly
> crash with either SIGSEGV or SIGILL.
> 
> Tracking down the problem with GDB, it occurs always at the same place,
> in a function called __DTOR_END__:
> 
> Program received signal SIGILL, Illegal instruction.
> 0x1007ff84 in __DTOR_END__ ()
> (gdb) x/1i $pc
> 0x1007ff84 <__DTOR_END__+4>:    blrl
> 
> The instruction is perfectly legal, I assume the problem is just that
> the memory is mapped as non executable. 
> 
> This function comes from the .dtors ELF section:
> 
>  12 .dtors        00000008  1007ff4c  1007ff4c  0006ff4c  2**2
>                   CONTENTS, ALLOC, LOAD, DATA
> 
> ldconfig is a static binary, the section has LOAD set, so as I
> understand, it's the kernel's job to load that section. It's done in
> elf32_load_file() and elf32_load_psection()
> 
> This section is not CODE, it's DATA, so we load it without the execute
> bit set, and this is the cause of the problem.
> 
> Questions:
> 1) Do I understand the proble correctly?

the permissions bits are actually separate from the CODE/DATA stuff in ELF,
look at the "flags" field in the program header output from objdump -p:

% objdump -p /bin/ls

/bin/ls:     file format elf32-i386

Program Header:
    PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
         filesz 0x000000c0 memsz 0x000000c0 flags r-x
  INTERP off    0x000000f4 vaddr 0x080480f4 paddr 0x080480f4 align 2**0
         filesz 0x00000013 memsz 0x00000013 flags r--
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x000043b8 memsz 0x000043b8 flags r-x
    LOAD off    0x000043b8 vaddr 0x0804d3b8 paddr 0x0804d3b8 align 2**12
         filesz 0x00000230 memsz 0x000004b4 flags rw-
 DYNAMIC off    0x00004438 vaddr 0x0804d438 paddr 0x0804d438 align 2**2
         filesz 0x000000b8 memsz 0x000000b8 flags rw-
    NOTE off    0x00000108 vaddr 0x08048108 paddr 0x08048108 align 2**2
         filesz 0x00000018 memsz 0x00000018 flags r--


but most likely the permissions for the .dtors section in your case
are "rw-".


> 2) How does it affect other ports and other COMPAT_* options? As a lot
> of OSes don't support non executable mappings, so I beleive we break
> many things by defaulting to non executable mappings for them. I already
> had to modify linux_exec_setup_stack() to get dynamic Linux/PowerPC
> binaries linking again. I suspect the problem exists for other ports as
> well.

it would be safest to default to making everything executable for other
emulations until it can be verified that those binaries work ok with
non-executable mappings.  this seems fine to me.


> 3) How to fix it properly? I'm not sure duplicating the whole
> elf32_load_psection() is a good idea. The other way would be to flag the
> exec package as wanting execute bits everywhere, and add a test for that
> in elf32_load_psection() and exec_setup_stack() 

let's use a flag in struct emul to enable it (and undo the duplication of
exec_setup_stack() that you already added).  let's check the flag in
the vmcmd_* functions instead of in all the emulation code.


> If we go that way, it woulds probably make sense to have a sysctl to
> force non executable mappings for OSes that don't support them: it may
> break things but you get more security.

that would be fine.  do we have support for per-emulation sysctls?


> 4) Do we want to fix that for 2.0?

we'll know better once we see what the diffs look like.
so far it sounds simple enough that there wouldn't be much risk.
(we could leave out the sysctl stuff until later, if that helps.)

-Chuck