loading of shared objects and executables

Michael Zintakis michael.zintakis@googlemail.com
Sat Oct 27 18:51:00 GMT 2012


> Don't forget about dlopen()
> The appropiate place would generally be on the dynamic linker, except
> for static binaries.
>
> I would probably try to hook the mmap() calls with PROT_EXEC and block
> them if it isn't a verified file.
>   
Duly noted, thanks.

> A verified binary could bypass it by loading another program in a
> different way, but as I guess you wouldn't "verify" such binary, that's
> probably ok, since normal users will use mmap().
I would aim to prevent such a case - I'll seek to modify the appropriate 
kernel functions responsible for loading/execution (process.c, exec.c 
etc) and will only allow the binary formats which can be verified to be 
loaded/executed. This should be OK, at least in my case, because I plan 
to use this on a hardened system, so the case of loading anything else, 
apart from elf-type binaries is not likely. Another possible way of 
"preventing" verification would be to replace ld.so with a rogue one, 
but I'll make the kernel check that as well.

Currently, I am torn between adopting two quite different approaches 
(still have quite a bit to catch up on on the good reference Roman was 
kind enough to provide though): 1. attach all verification data at the 
end of a given executable/.so file (by "verification data" I mean, at 
the very least, a hash on the entire executable/.so file, calculated 
using a private key, and a signature ID - as text - for the public key 
to be used to verify that hash); or 2. create a separate header/section 
(called ".security" for example) and attach that verification data there.

I'm inclined to use the second approach, not least because it could 
survive any potential stripping, though it would be more involved as I 
would have to, somehow, instruct the linker to create this additional 
section and also include the verification data just after the 
executable/.so file is built (in other words, to invoke the creation of 
the verification data as part of the linking process). If I adopt this 
route, I am still to figure out how to go about this as my knowledge of 
the gcc linker doesn't go that deep (yet!).

The first approach - to attach the verification data at the end of the 
file - has the benefit of adding verification data on files already 
built, without the need to recompile them, but as I pointed out above, I 
would try the "custom" header section first and if I can't pursue it, 
then I'll adopt this one.

>  The problem of verifying binaries (scripts) in dynamic languages, is worse anyway.
>   
Indeed. Java, perl, python, bash, to just name a few - can't be 
protected against, not to mention executing a "verified" "dd 
if=/dev/zero of=/dev/sda bs=512 count=1000" for example, but no defence 
or protection built is ever 100% secure, so of course there are 
potential exploits no matter what system is used.



More information about the Gcc-help mailing list