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 15:04:33
On Sun, Jun 20, 2004 at 09:24:46PM +0200, Emmanuel Dreyfus wrote:
> Chuck Silvers <chuq@chuq.com> wrote:
> 
> > > 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.
> 
> IS there a way to check that? If signal delivery is okay, where can it
> break?

well, the real test would be writing some programs that create mappings
that are supposed to be non-executable and then run them on the OS we're
emulating to see whether or not we can execute instructions from those
mappings.


> > > 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).  
> 
> I propose P_NOEXECMAP, defined to 1 for native binaries, defaulting to 0
> for everything else.
> 
> > let's check the flag in
> > the vmcmd_* functions instead of in all the emulation code.
> 
> We can modify the required protection mask and add an execute bit if
> P_NOEXECMAP is no set, in the following functions:
> vmcmd_map_pagedvn()
> vmcmd_readvn()
> vmcmd_map_zero()
> exec_setup_stack()   
> 
> > > 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?
> 
> We can do that for the next binary executed by execve and inherit the
> property accross forks. That way it would be available on a per-process
> basis, and it would even be usable for ill-programmed NetBSD binaries
> that non executable mappings broke. What about something like this?
> 
> sysctl -w proc.$$.noexecmap=1 
> 
> But that would end up with eating one more bit in struct proc, to tell
> that the P_NOEXECMAP bit is forced and should not be modified to a
> per-emulation default value at execve time.

oh...  you're looking at this as a per-process flag, I was thinking it
would be a per-emulation flag.  having it be per-process would work too.

but it occurs to me that the problem is a little different than I was
thinking.  in order to faithfully emulate the behaviour of another OS
we'll need to know exactly in which cases that OS maps things executable
when they "should" be non-executable.  I would guess that it probably
goes beyond just what's going on during execve(), and that usually
we'll find that an OS that doesn't do everything correctly will be
making *all* mappings executable, even mmap() mappings without PROT_EXEC.
so in this case, the vmcmd_* functions are too high-level... we would
really want to change the behaviour of pmap_enter().  so on powerpc,
this would mean that if the per-process flag is set then we'll just
never set the SR_NOEXEC flag in the hardware.

so I think we need a bit more info on what exactly is the behaviour
that we're trying to emulate.

-Chuck