Re: Updated: [PATCH] hardening: add PROT_FINAL prot flag to mmap/mprotect
From: Ard Biesheuvel
Date: Thu Oct 04 2012 - 09:56:28 EST
2012/10/4 PaX Team <pageexec@xxxxxxxxxxx>:
Thanks for taking a look at this matter.
>> >> This is mainly intended for the dynamic linker,
>> >> which sets up the address space on behalf of
>> >> dynamic binaries. By using this flag, it can
>> >> prevent exploited code from remapping read-only
>> >> executable code or data sections read-write.
>
> now this last paragraph/sentence seems to be the closest thing that
> describes a scenario where we have some vulnerability (i'm guessing
> of the memory corruption kind) that allows an attacker (exploit writer)
> to force the attacked vulnerable application to perform a gratuitous
> mprotect(PROT_WRITE|PROT_EXEC) on some library/etc mapping and prepare
> it for shellcode injection/execution (a.k.a. 'game over' or the 'holy
> grail' ;). so far so good. the question that arises here is that what
> prevents the same exploit technique (say, ret2libc in this case) from
> executing an open/mmap(PROT_WRITE|PROT_EXEC) of the very same library
> that PROT_FINAL would protect? or just a plain anon mmap that is just as
> good for shellcode execution? in other words, if the attacker can make
> the attacked application execute mprotect with arbitrary parameters,
> then why can't the same attacker execute open/mmap/etc as well, completely
> circumventing the proposed solution? i hope you see now why this issue
> has to be settled before anyone looks into the implementation details.
>
The main difference here is that it is much easier to doctor a set of
stack frames that issues a mprotect(+PROT_EXEC) on the whole address
space than it is to re-issue the exact same mmap() call (with
MAP_FIXED this time, and the exact offset the kernel decided to load
it this time around) that will put the same code/data in exactly the
same place in memory (relocated and all) without blowing up your
process. In our specific implementation, it is mainly about rodata
(public keys) rather than executable code, but the same applies; for
us, it is more about rigging binaries: the attacker may not be
interested in hijacking the whole process, but just nop'ing out some
code that makes the process behave more to his liking.
>> The 'interface' we use is a LSM .ko which registers handlers for
>> mmap() and mprotect() that fail the respective invocations if the
>> passed arguments do not adhere to the policy.
>
> i'm guessing again that their LSM tries to tackle the above described
> scenarios except we don't know if this LSM will ever become public,
> whether/how other LSMs will acquire the same capabilities and why it's
> not mentioned in the PROT_FINAL submission that by itself this feature
> doesn't increase security. i'm also wondering what kind of policy can
> allow ld.so to load a library but forbid it a second time, it doesn't
> seem compatible with real-life cases (think dynamically loaded and
> unloaded plugins), not to mention the control of anonymous mappings.
>
The LSM encapsulates the policy, and relies on the PROT_FINAL feature.
The fact that the policy can impose the use of PROT_FINAL in
particular cases makes the implementation of the policy potentially
much simpler than that of PaX MPROTECT (but not necessarily as
secure).
However, let's decide first whether there is a point to having some
control over the VM_MAY* flags directly. If yes, then the patch makes
sense, otherwise it doesn't. How policies may be built on top of that
is part of another debate.
> last but not least, just saw this from Ard while not on CC:
>
>> ptrace() doesn't care whether or not the process itself can write to
>> its .text segment.
>
> ptrace cares about VM_MAYWRITE which PROT_FINAL can take away (under
> PaX MPROTECT'ed processes cannot be debugged with sw breakpoints).
>
My bad: I spent some time looking at access_process_vm() but could not
find any references to the vma permissions.
>> Could we at least agree on the fundamental notion that the special
>> powers the loader has to modify .text and .rodata sections are hardly
>> ever needed by the programs themselves? In that sense, this is similar
>> to dropping root privileges when not required anymore, and that is
>> typically recognized as a sensible idea.
>
> the difference is that the uid is a process-wide attribute, whereas
> PROT_FINAL isn't, unlike PaX's MPROTECT. in other words, dropping root
> is irreversible but PROT_FINAL isn't, one just has to create an entirely
> new mapping to acquire the access rights that PROT_FINAL was supposed to
> prevent (again, all this modulo an LSM and policies).
>
There remains a fundamental difference between the ability to
manipulate existing mappings and creating entirely new ones.
Especially when trying to manipulate GOT/PLT or vtable entries or
tweak the behavior of a program in other subtle ways, mmap()'ing the
same file again is just not going to cut it.
Regards,
Ard.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/