linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* elf_set_personality()
@ 2012-02-27 12:36 Peter De Schrijver
  2012-02-27 13:04 ` elf_set_personality() Russell King - ARM Linux
  0 siblings, 1 reply; 8+ messages in thread
From: Peter De Schrijver @ 2012-02-27 12:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Commit ID 5e143436d04465c937c1a242808a99c46393af3e
(fix personality flag propagation across an exec) makes a child process
inherit a number of personality flags from its parent. This includes the
READ_IMPLIES_EXEC flag. Unfortunately this causes problems when debugging
android applications using gdbserver. It appears that gdbserver on android
has an executable stack. This causes the kernel to set the READ_IMPLIES_EXEC
flag on the gdbserver process. So the child android process will also get this
flag. As soon as the android tries to mmap a readonly android shmem segment
(using the ashmem driver), ashmem will return EPERM, because the segment has
been exposed as readonly without exec permissions and the kernel will modify
any readonly mmap request into read and execute.

Why does the READ_IMPLIES_EXEC flag need to be propagated? Would it be
acceptable to not propagate it to child processes?

Thanks,

Peter.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 12:36 elf_set_personality() Peter De Schrijver
@ 2012-02-27 13:04 ` Russell King - ARM Linux
  2012-02-27 15:03   ` elf_set_personality() Peter De Schrijver
  0 siblings, 1 reply; 8+ messages in thread
From: Russell King - ARM Linux @ 2012-02-27 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 02:36:12PM +0200, Peter De Schrijver wrote:
> Commit ID 5e143436d04465c937c1a242808a99c46393af3e
> (fix personality flag propagation across an exec) makes a child process
> inherit a number of personality flags from its parent. This includes the
> READ_IMPLIES_EXEC flag.

So, READ_IMPLIES_EXEC will only be leaked if it's already set.

> Unfortunately this causes problems when debugging
> android applications using gdbserver. It appears that gdbserver on android
> has an executable stack. This causes the kernel to set the READ_IMPLIES_EXEC
> flag on the gdbserver process.

Ok.

> So the child android process will also get this flag.

And that means that attempting to mmap() stuff will also get executable
protections in addition.

> As soon as the android tries to mmap a readonly android shmem segment
> (using the ashmem driver), ashmem will return EPERM, because the segment has
> been exposed as readonly without exec permissions and the kernel will modify
> any readonly mmap request into read and execute.

This sounds like a problem.  If you have two applications trying to use
the ashmem driver, one without READ_IMPLIES_EXEC and one with
READ_IMPLIES_EXEC, then it seems that ashmem will prevent the
READ_IMPLIES_EXEC one from using such regions.  That sounds like a
(different) bug to me.

> Why does the READ_IMPLIES_EXEC flag need to be propagated? Would it be
> acceptable to not propagate it to child processes?

It shouldn't propagate.  But I think it's uncovered a separate problem
in the ashmem driver.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 13:04 ` elf_set_personality() Russell King - ARM Linux
@ 2012-02-27 15:03   ` Peter De Schrijver
  2012-02-27 15:20     ` elf_set_personality() Robert Love
  0 siblings, 1 reply; 8+ messages in thread
From: Peter De Schrijver @ 2012-02-27 15:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 02:04:53PM +0100, Russell King - ARM Linux wrote:
> On Mon, Feb 27, 2012 at 02:36:12PM +0200, Peter De Schrijver wrote:
> > Commit ID 5e143436d04465c937c1a242808a99c46393af3e
> > (fix personality flag propagation across an exec) makes a child process
> > inherit a number of personality flags from its parent. This includes the
> > READ_IMPLIES_EXEC flag.
> 
> So, READ_IMPLIES_EXEC will only be leaked if it's already set.
> 
> > Unfortunately this causes problems when debugging
> > android applications using gdbserver. It appears that gdbserver on android
> > has an executable stack. This causes the kernel to set the READ_IMPLIES_EXEC
> > flag on the gdbserver process.
> 
> Ok.
> 
> > So the child android process will also get this flag.
> 
> And that means that attempting to mmap() stuff will also get executable
> protections in addition.
> 
> > As soon as the android tries to mmap a readonly android shmem segment
> > (using the ashmem driver), ashmem will return EPERM, because the segment has
> > been exposed as readonly without exec permissions and the kernel will modify
> > any readonly mmap request into read and execute.
> 
> This sounds like a problem.  If you have two applications trying to use
> the ashmem driver, one without READ_IMPLIES_EXEC and one with
> READ_IMPLIES_EXEC, then it seems that ashmem will prevent the
> READ_IMPLIES_EXEC one from using such regions.  That sounds like a
> (different) bug to me.
> 

Good point. I don't know anything about the design ideas behind ashmem though.
Can anyone from android comment on this?

> > Why does the READ_IMPLIES_EXEC flag need to be propagated? Would it be
> > acceptable to not propagate it to child processes?
> 
> It shouldn't propagate.  But I think it's uncovered a separate problem

Ok. Should I write a patch for this? Seems easy enough to also clear the
READ_IMPLIES_EXEC bit when copying the child personality from the parent?

> in the ashmem driver.

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 15:03   ` elf_set_personality() Peter De Schrijver
@ 2012-02-27 15:20     ` Robert Love
  2012-02-27 16:41       ` elf_set_personality() Russell King - ARM Linux
  0 siblings, 1 reply; 8+ messages in thread
From: Robert Love @ 2012-02-27 15:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 10:03 AM, Peter De Schrijver
<pdeschrijver@nvidia.com> wrote:
> On Mon, Feb 27, 2012 at 02:04:53PM +0100, Russell King - ARM Linux wrote:
> > This sounds like a problem. ?If you have two applications trying to use
> > the ashmem driver, one without READ_IMPLIES_EXEC and one with
> > READ_IMPLIES_EXEC, then it seems that ashmem will prevent the
> > READ_IMPLIES_EXEC one from using such regions. ?That sounds like a
> > (different) bug to me.
>
> Good point. I don't know anything about the design ideas behind ashmem
> though.
> Can anyone from android comment on this?

The problem is this code snippet:

    /* requested protection bits must match our allowed protection mask */
    if (unlikely((vma->vm_flags & ~asma->prot_mask) & PROT_MASK)) {
            ret = -EPERM;
	    goto out;
    }

Coupled with this snippet:

    /* does the application expect PROT_READ to imply PROT_EXEC? */
    if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
            prot |= PROT_EXEC;

One fix is to remove the second snippet altogether. I added it to be
diligent; Android doesn't have a specific use for it afaik.

An alternative is to keep the code as-is. Note the bug isn't quite as
described: It isn't the case that two processes, one with
READ_IMPLIES_EXEC and one without, will always fail to both map an
ashmem region. The failure case is when a process creates a region
PROT_READ & ~PROT_EXEC and then a second process with
READ_IMPLIES_EXEC tries to map the region PROT_READ with the implicit
PROT_EXEC. I'm not sure what to do here. This seems like a legit
reason to fail.

          Robert

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 15:20     ` elf_set_personality() Robert Love
@ 2012-02-27 16:41       ` Russell King - ARM Linux
  2012-02-27 17:09         ` elf_set_personality() Robert Love
  0 siblings, 1 reply; 8+ messages in thread
From: Russell King - ARM Linux @ 2012-02-27 16:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 10:20:23AM -0500, Robert Love wrote:
> On Mon, Feb 27, 2012 at 10:03 AM, Peter De Schrijver
> <pdeschrijver@nvidia.com> wrote:
> > On Mon, Feb 27, 2012 at 02:04:53PM +0100, Russell King - ARM Linux wrote:
> > > This sounds like a problem. ?If you have two applications trying to use
> > > the ashmem driver, one without READ_IMPLIES_EXEC and one with
> > > READ_IMPLIES_EXEC, then it seems that ashmem will prevent the
> > > READ_IMPLIES_EXEC one from using such regions. ?That sounds like a
> > > (different) bug to me.
> >
> > Good point. I don't know anything about the design ideas behind ashmem
> > though.
> > Can anyone from android comment on this?
> 
> The problem is this code snippet:
> 
>     /* requested protection bits must match our allowed protection mask */
>     if (unlikely((vma->vm_flags & ~asma->prot_mask) & PROT_MASK)) {
>             ret = -EPERM;
> 	    goto out;
>     }
> 
> Coupled with this snippet:
> 
>     /* does the application expect PROT_READ to imply PROT_EXEC? */
>     if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
>             prot |= PROT_EXEC;

You're missing another place - mm/mmap.c:

        /*
         * Does the application expect PROT_READ to imply PROT_EXEC?
         *
         * (the exception is when the underlying filesystem is noexec
         *  mounted, in which case we dont add PROT_EXEC.)
         */
        if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
                if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC)))
                        prot |= PROT_EXEC;

So, a thread with READ_IMPLIES_EXEC with a mmap() containing PROT_READ
will always appear with PROT_READ | PROT_EXEC, which then gets
translated to VM_READ | VM_EXEC.

> One fix is to remove the second snippet altogether. I added it to be
> diligent; Android doesn't have a specific use for it afaik.
> 
> An alternative is to keep the code as-is. Note the bug isn't quite as
> described: It isn't the case that two processes, one with
> READ_IMPLIES_EXEC and one without, will always fail to both map an
> ashmem region. The failure case is when a process creates a region
> PROT_READ & ~PROT_EXEC and then a second process with
> READ_IMPLIES_EXEC tries to map the region PROT_READ with the implicit
> PROT_EXEC. I'm not sure what to do here. This seems like a legit
> reason to fail.

It seems that vanilla mmap() of a file does not deny a mapping containing
PROT_EXEC of a file with read-write-noexec permissions - it permits it,
but it does fail mapping a file PROT_WRITE which wasn't opened for write.

Moreover, it's not actually possible to prevent execution of code if
you have read permission - if you can read a mapping, you can copy it
into an executable mapping and then execute copied code.

So, I don't think there's any reason to prevent PROT_EXEC in a hard and
fast manner.  If you don't want to go that far, what about:

	prot_mask = PROT_MASK;
	if (current->personality & READ_IMPLIES_EXEC)
		prot_mask &= ~PROT_EXEC;
	if (vma->vm_flags & ~asma->prot_mask & prot_mask) {
		ret = -EPERM;
		goto out;
	}

which would mean !READ_IMPLIES_EXEC threads would get the full permission
checking, but a READ_IMPLIES_EXEC thread would still be able to attach
to a r/w only shared mapping.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 16:41       ` elf_set_personality() Russell King - ARM Linux
@ 2012-02-27 17:09         ` Robert Love
  2012-02-27 17:16           ` elf_set_personality() Russell King - ARM Linux
  0 siblings, 1 reply; 8+ messages in thread
From: Robert Love @ 2012-02-27 17:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 11:41 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> It seems that vanilla mmap() of a file does not deny a mapping containing
> PROT_EXEC of a file with read-write-noexec permissions - it permits it,
> but it does fail mapping a file PROT_WRITE which wasn't opened for write.
>
> Moreover, it's not actually possible to prevent execution of code if
> you have read permission - if you can read a mapping, you can copy it
> into an executable mapping and then execute copied code.
>
> So, I don't think there's any reason to prevent PROT_EXEC in a hard and
> fast manner. ?If you don't want to go that far, what about:
>
> ? ? ? ?prot_mask = PROT_MASK;
> ? ? ? ?if (current->personality & READ_IMPLIES_EXEC)
> ? ? ? ? ? ? ? ?prot_mask &= ~PROT_EXEC;
> ? ? ? ?if (vma->vm_flags & ~asma->prot_mask & prot_mask) {
> ? ? ? ? ? ? ? ?ret = -EPERM;
> ? ? ? ? ? ? ? ?goto out;
> ? ? ? ?}
>
> which would mean !READ_IMPLIES_EXEC threads would get the full permission
> checking, but a READ_IMPLIES_EXEC thread would still be able to attach
> to a r/w only shared mapping.

ashmem should behave however vanilla mmap behaves. There is no reason
to be different and I'd prefer to consolidate or at least copy the
code.

It is unfortunate that each implementer of fops->mmap needs to
manually handle the READ_IMPLIES_EXEC case.

        Robert

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 17:09         ` elf_set_personality() Robert Love
@ 2012-02-27 17:16           ` Russell King - ARM Linux
  2012-02-27 17:18             ` elf_set_personality() Robert Love
  0 siblings, 1 reply; 8+ messages in thread
From: Russell King - ARM Linux @ 2012-02-27 17:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 12:09:00PM -0500, Robert Love wrote:
> On Mon, Feb 27, 2012 at 11:41 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > It seems that vanilla mmap() of a file does not deny a mapping containing
> > PROT_EXEC of a file with read-write-noexec permissions - it permits it,
> > but it does fail mapping a file PROT_WRITE which wasn't opened for write.
> >
> > Moreover, it's not actually possible to prevent execution of code if
> > you have read permission - if you can read a mapping, you can copy it
> > into an executable mapping and then execute copied code.
> >
> > So, I don't think there's any reason to prevent PROT_EXEC in a hard and
> > fast manner. ?If you don't want to go that far, what about:
> >
> > ? ? ? ?prot_mask = PROT_MASK;
> > ? ? ? ?if (current->personality & READ_IMPLIES_EXEC)
> > ? ? ? ? ? ? ? ?prot_mask &= ~PROT_EXEC;
> > ? ? ? ?if (vma->vm_flags & ~asma->prot_mask & prot_mask) {
> > ? ? ? ? ? ? ? ?ret = -EPERM;
> > ? ? ? ? ? ? ? ?goto out;
> > ? ? ? ?}
> >
> > which would mean !READ_IMPLIES_EXEC threads would get the full permission
> > checking, but a READ_IMPLIES_EXEC thread would still be able to attach
> > to a r/w only shared mapping.
> 
> ashmem should behave however vanilla mmap behaves.

Well, it's fairly clear that it doesn't, because it has more stringent
permission checks than vanilla mmap.

> There is no reason to be different and I'd prefer to consolidate or at
> least copy the code.
> 
> It is unfortunate that each implementer of fops->mmap needs to
> manually handle the READ_IMPLIES_EXEC case.

That would mean ignoring PROT_EXEC entirely.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* elf_set_personality()
  2012-02-27 17:16           ` elf_set_personality() Russell King - ARM Linux
@ 2012-02-27 17:18             ` Robert Love
  0 siblings, 0 replies; 8+ messages in thread
From: Robert Love @ 2012-02-27 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 27, 2012 at 12:16 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
>> There is no reason to be different and I'd prefer to consolidate or at
>> least copy the code.
>>
>> It is unfortunate that each implementer of fops->mmap needs to
>> manually handle the READ_IMPLIES_EXEC case.
>
> That would mean ignoring PROT_EXEC entirely.

Right. I was agreeing with your first suggestion.

As goes vanilla mmap, so goes ashmem.

I no longer work on Android, but I can put together a patch.

      Robert

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-02-27 17:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-27 12:36 elf_set_personality() Peter De Schrijver
2012-02-27 13:04 ` elf_set_personality() Russell King - ARM Linux
2012-02-27 15:03   ` elf_set_personality() Peter De Schrijver
2012-02-27 15:20     ` elf_set_personality() Robert Love
2012-02-27 16:41       ` elf_set_personality() Russell King - ARM Linux
2012-02-27 17:09         ` elf_set_personality() Robert Love
2012-02-27 17:16           ` elf_set_personality() Russell King - ARM Linux
2012-02-27 17:18             ` elf_set_personality() Robert Love

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).