* loading of shared objects and executables @ 2012-10-22 6:47 Michael Zintakis 2012-10-22 8:41 ` Marc Glisse 2012-10-22 16:54 ` Bolshakov, Roman 0 siblings, 2 replies; 11+ messages in thread From: Michael Zintakis @ 2012-10-22 6:47 UTC (permalink / raw) To: gcc-help Though not strictly 100% GCC subject, it is still GCC-related. A couple of queries I am hoping someone would be able to address for me. I am trying to find out what is the process of loading a shared object file (.so) and the process of loading and executing a binary file (like /bin/bash for example) and what part of the Linux system (or files - like ld-linux.so may be?) is responsible for that process? In other words, when I try to execute a file, I presume "something" loads it first into memory, resolves what other shared objects need to be loaded and then loads them, before passing the execution to the entry point of that executable. I am not interested in the process of the actual execution or resolving the external references - just the loading process of shared objects and executables, nothing more than that (at least not at this stage anyway). Why would I like to know that? I am trying to "intervene" in this process, so that before every file (shared object or executable) is loaded, I "verify" it and then pass the appropriate control to the "standard" loaders for either execution or resolving external references, or raise an exception if I don't like the file or the shared object about to be loaded. All this would be done in a Linux environment (x86 - both 32 and 64-bit, as well as ARM), no Windoze! I would be glad if someone could give me a few pointers - at least to start with. Thanks! MZ ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-22 6:47 loading of shared objects and executables Michael Zintakis @ 2012-10-22 8:41 ` Marc Glisse 2012-10-22 16:54 ` Bolshakov, Roman 1 sibling, 0 replies; 11+ messages in thread From: Marc Glisse @ 2012-10-22 8:41 UTC (permalink / raw) To: Michael Zintakis; +Cc: gcc-help On Sat, 20 Oct 2012, Michael Zintakis wrote: > I am trying to find out what is the process of loading a shared object file > (.so) and the process of loading and executing a binary file (like /bin/bash > for example) and what part of the Linux system (or files - like ld-linux.so > may be?) is responsible for that process? I guess you could start from here: http://en.wikipedia.org/wiki/Dynamic_linker and follow the links. -- Marc Glisse ^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: loading of shared objects and executables 2012-10-22 6:47 loading of shared objects and executables Michael Zintakis 2012-10-22 8:41 ` Marc Glisse @ 2012-10-22 16:54 ` Bolshakov, Roman 2012-10-27 14:03 ` Michael Zintakis 1 sibling, 1 reply; 11+ messages in thread From: Bolshakov, Roman @ 2012-10-22 16:54 UTC (permalink / raw) To: Michael Zintakis; +Cc: gcc-help Hi, Mike. I also studied that in the spring. You can find a lot of details on the page: http://www.acsu.buffalo.edu/~charngda/elf.html Dynamic linker is loaded by kernel after the kernel reads ELF headers. Then it passes control to the entry point of the linker. If you use glibc the entry point is named _dl_start. So, in general, you need to make breakpoint on _dl_start. Roman ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-22 16:54 ` Bolshakov, Roman @ 2012-10-27 14:03 ` Michael Zintakis 2012-10-27 17:05 ` Ángel González 2012-10-27 19:26 ` Bolshakov, Roman 0 siblings, 2 replies; 11+ messages in thread From: Michael Zintakis @ 2012-10-27 14:03 UTC (permalink / raw) To: gcc-help Hi Roman, Bolshakov, Roman wrote: > I also studied that in the spring. You can find a lot of details on the page: http://www.acsu.buffalo.edu/~charngda/elf.html > Very good reference this, thank you - I'll look into it in more detail over the weekend! OK, in a nutshell, what I am after is, basically, two things: 1. Find the portion of the kernel code, which is responsible for the initial loading the file for execution (i.e. when I type "iptables" from the command line for example). This will help me to modify that code so that the file which is about to be loaded is "verified" first and raise a security exception if something is wrong with it. 2. Once I've done that, if there is a possibility to identify all .so (shared objects) on which this executable depends (by looking at its headers for example), I could do the same as step 1 above for all dependent .so files. If not, then I'll have to pass control to ld.so and intercept the point prior to where these .so are about to be loaded, so that I could do the verification - as in step one above, but for the shared objects. If everything checks out, then I'll pass control over to ld.so. I am guessing the picture when statically compiled executables are run is more or less the same with the exception of loading ÑÑ Ðµ shared libraries, as they are included as part of the file which needs to be executed - am I correct in thinking that? > Dynamic linker is loaded by kernel after the kernel reads ELF headers. And it is precisely at that point I need to take control to "verify" the executable and, if possible, all .so files on which this file depends. > Then it passes control to the entry point of the linker. If you use glibc the entry point is named _dl_start. So, in general, you need to make breakpoint on _dl_start. > I guess I would need to do that only if I could not find the .so files on which this executable depends, otherwise the verification could be done much earlier and I could then let ld.so do its job, right? ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-27 14:03 ` Michael Zintakis @ 2012-10-27 17:05 ` Ángel González 2012-10-27 18:51 ` Michael Zintakis 2012-10-27 19:26 ` Bolshakov, Roman 1 sibling, 1 reply; 11+ messages in thread From: Ángel González @ 2012-10-27 17:05 UTC (permalink / raw) To: Michael Zintakis; +Cc: gcc-help On 27/10/12 01:28, Michael Zintakis wrote: > Hi Roman, > > > Bolshakov, Roman wrote: >> I also studied that in the spring. You can find a lot of details on >> the page: http://www.acsu.buffalo.edu/~charngda/elf.html >> > Very good reference this, thank you - I'll look into it in more detail > over the weekend! OK, in a nutshell, what I am after is, basically, > two things: > > 1. Find the portion of the kernel code, which is responsible for the > initial loading the file for execution (i.e. when I type "iptables" > from the command line for example). This will help me to modify that > code so that the file which is about to be loaded is "verified" first > and raise a security exception if something is wrong with it. > 2. Once I've done that, if there is a possibility to identify all .so > (shared objects) on which this executable depends (by looking at its > headers for example), I could do the same as step 1 above for all > dependent .so files. If not, then I'll have to pass control to ld.so > and intercept the point prior to where these .so are about to be > loaded, so that I could do the verification - as in step one above, > but for the shared objects. If everything checks out, then I'll pass > control over to ld.so. > > I am guessing the picture when statically compiled executables are run > is more or less the same with the exception of loading ÑÑ Ðµ shared > libraries, as they are included as part of the file which needs to be > executed - am I correct in thinking that? > >> Dynamic linker is loaded by kernel after the kernel reads ELF headers. > And it is precisely at that point I need to take control to "verify" > the executable and, if possible, all .so files on which this file > depends. > >> Then it passes control to the entry point of the linker. If you use >> glibc the entry point is named _dl_start. So, in general, you need to >> make breakpoint on _dl_start. >> > I guess I would need to do that only if I could not find the .so files > on which this executable depends, otherwise the verification could be > done much earlier and I could then let ld.so do its job, right? > 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. 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(). The problem of verifying binaries (scripts) in dynamic languages, is worse anyway. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-27 17:05 ` Ángel González @ 2012-10-27 18:51 ` Michael Zintakis 2012-10-28 9:15 ` Bolshakov, Roman 2012-10-29 17:19 ` Ángel González 0 siblings, 2 replies; 11+ messages in thread From: Michael Zintakis @ 2012-10-27 18:51 UTC (permalink / raw) To: gcc-help > 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. ^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: loading of shared objects and executables 2012-10-27 18:51 ` Michael Zintakis @ 2012-10-28 9:15 ` Bolshakov, Roman 2012-10-28 15:31 ` Michael Zintakis 2012-10-29 17:19 ` Ángel González 1 sibling, 1 reply; 11+ messages in thread From: Bolshakov, Roman @ 2012-10-28 9:15 UTC (permalink / raw) To: gcc-help; +Cc: Michael Zintakis > 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. As Linux uses ELF, I personally like the second approach as it's much more consistent. > 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!). To make a custom section layout you can use linker scripts (http://sourceware.org/binutils/docs/ld/Scripts.html). ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-28 9:15 ` Bolshakov, Roman @ 2012-10-28 15:31 ` Michael Zintakis 0 siblings, 0 replies; 11+ messages in thread From: Michael Zintakis @ 2012-10-28 15:31 UTC (permalink / raw) To: gcc-help Hi Roman, >> or 2. create a separate header/section >> (called ".security" for example) and attach that verification data there. >> > > As Linux uses ELF, I personally like the second approach as it's much more consistent. > Indeed, much easier to create/maintain and is quite flexible as well (I could have multiple sections for multiple purposes - .security.sig.hash, .security.sig.name, .security.flags for example). > To make a custom section layout you can use linker scripts (http://sourceware.org/binutils/docs/ld/Scripts.html). > Yep, that was another good one - thank you! For already-built binaries I could use objcopy (I tested it earlier today and it is flawless!), so that folds up nicely for compiling new ELF binaries. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-27 18:51 ` Michael Zintakis 2012-10-28 9:15 ` Bolshakov, Roman @ 2012-10-29 17:19 ` Ángel González 1 sibling, 0 replies; 11+ messages in thread From: Ángel González @ 2012-10-29 17:19 UTC (permalink / raw) To: Michael Zintakis; +Cc: gcc-help On 27/10/12 16:02, Michael Zintakis wrote: >> 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. No, I was refering to a "userland loader". Such as instead of using mmap() with executable protection, doing a malloc() and then mprotect() [not actually supported by POSIX, but it works in Linux]. As you are making a hardened system, you probably also want to forbid writable and executable memory (when possible), so it will remove many holes of that kind. Still, the "rogue loader" cannot be completely detected just by kernel. The extreme example would be a program that parsed each instruction and executed it. As I said, it is very unlikely that such program got verified :) ^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: loading of shared objects and executables 2012-10-27 14:03 ` Michael Zintakis 2012-10-27 17:05 ` Ángel González @ 2012-10-27 19:26 ` Bolshakov, Roman 2012-10-28 13:12 ` Michael Zintakis 1 sibling, 1 reply; 11+ messages in thread From: Bolshakov, Roman @ 2012-10-27 19:26 UTC (permalink / raw) To: Michael Zintakis; +Cc: gcc-help Hi Mike, > 2. Once I've done that, if there is a possibility to identify all .so > (shared objects) on which this executable depends (by looking at its > headers for example), I could do the same as step 1 above for all > dependent .so files. If not, then I'll have to pass control to ld.so and > intercept the point prior to where these .so are about to be loaded, so > that I could do the verification - as in step one above, but for the > shared objects. If everything checks out, then I'll pass control over to > ld.so. I'm only not sure if the kernel know all the sorts of ELF sections and segments ld.so can handle. Probably you'll need to modify kernel code to walk over DYNAMIC segment (which keeps the list of dependencies) to verify the shared objects an application depends on. > I am guessing the picture when statically compiled executables are run > is more or less the same with the exception of loading тхе shared > libraries, as they are included as part of the file which needs to be > executed - am I correct in thinking that? Yes, but a statically linked executable can also call dlopen(), mmap() (As it was noted later). ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: loading of shared objects and executables 2012-10-27 19:26 ` Bolshakov, Roman @ 2012-10-28 13:12 ` Michael Zintakis 0 siblings, 0 replies; 11+ messages in thread From: Michael Zintakis @ 2012-10-28 13:12 UTC (permalink / raw) To: gcc-help Hi Roman, > I'm only not sure if the kernel know all the sorts of ELF sections and segments ld.so can handle. > Probably you'll need to modify kernel code to walk over DYNAMIC segment (which keeps the list > of dependencies) to verify the shared objects an application depends on. > It looks as though I have to reconsider my initial approach - even though I could read that segment (not an easy task though), there is no way the kernel alone could find all dependencies based on that section (there could be .so files, which have dependencies on other .so files and so on), so I have to change ld.so in order to be able to do what the kernel does and verify the files to be loaded. That would be in addition to the kernel doing the verification of the initial executable. > Yes, but a statically linked executable can also call dlopen(), mmap() (As it was noted later). > Yep, and given what I wrote in the previous paragraph above, it looks as though ld.so also needs to be capable of doing the verification. On a slightly brighter node, (dynamically) adding new sections to ELF turned out to be an easy task, even if the executable/.so file is already compiled/built - all I have to do is execute "objcopy --add-section <section_name>=<section_file> <infile>" and then "objcopy --set-section-flags <section_name>=<flags> <infile>" to set the appropriate flags to <section_name> ("readonly" in my case). As soon as this is done, the section is added (with its content set from the content of <section_file>) and the appropriate reallocation of the ELF binary is "automatically" done by objcopy. My initial intent was to create a new section in the ELF header, but I could not find an easy way to do that either during compile time or when the executable/.so file is already built, so placing my "custom" section in the ELF section header by using objcopy seems a good choice and I don't have to recompile everything. Next, I'll look for ways in which the binary/.so loading could be bypassed (to prevent verification) so that when I change the kernel and the ld.so code later on, to prevent that from happening and enforce verification in all cases, when desired. ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2012-10-28 15:31 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-10-22 6:47 loading of shared objects and executables Michael Zintakis 2012-10-22 8:41 ` Marc Glisse 2012-10-22 16:54 ` Bolshakov, Roman 2012-10-27 14:03 ` Michael Zintakis 2012-10-27 17:05 ` Ángel González 2012-10-27 18:51 ` Michael Zintakis 2012-10-28 9:15 ` Bolshakov, Roman 2012-10-28 15:31 ` Michael Zintakis 2012-10-29 17:19 ` Ángel González 2012-10-27 19:26 ` Bolshakov, Roman 2012-10-28 13:12 ` Michael Zintakis
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 read-only IMAP folder(s) and NNTP newsgroup(s).