compartment and the --cap option
Hello everybody!
I am currently trying to bring several daemons on my system into a chroot
jail using Marc Heuse's 'compartment' tool. So far all works quite well
but the fine tuning is still to be done. I am wondering what kind of
security enhancements can be done by using compartments '--cap' option.
Since the documentation of this feature is not very exhaustive i am still
looking for some missing link to understand this correctly. Maybe someone
here could help me with that.
If I understand that correctly, capabilities are a partitioning of root's
privileges and using the --cap option i can influence the privileges of a
newly started process no matter whether it will run as root or not. So,
for example, the command 'compartment --chroot /some/dir --cap none
--verbose /daemon/with_uid0/port_below_1024' should fail miserably because
the daemon won't be able to bind to it's port. But exactly this works and
i am wondering why (compartment tells me that it successfully set caps to
0x0).
I am using SuSE 7.2 with a (stock) Kernel 2.4.9 (but it also happens
with a SuSE 2.2.19). /proc/sys/kernel/cap_bound says -257, say everything
except CAP_SETPCAP.
So thinking about that and the stuff i've read in the 'capfaq' from
http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.2/capfaq-...
i have the following questions:
- Is it true that --cap only works with CAP_INIT_EFF_SET and
CAP_INIT_INH_SET set to -1 in
[...] So, for example, the command 'compartment --chroot /some/dir --cap none --verbose /daemon/with_uid0/port_below_1024' should fail miserably because the daemon won't be able to bind to it's port. But exactly this works and i am wondering why (compartment tells me that it successfully set caps to 0x0). [...] The problem here is the following: I've made my tests with the proftpd and bind9 that have to start as root in order to bind to their well known ports below 1024. Compartment in fact set the three capsets to zero, but i did not recognize that these programs also make use of the capset() syscall to risen their privileges
- Is it true that --cap only works with CAP_INIT_EFF_SET and CAP_INIT_INH_SET set to -1 in
in order to get the CAP_SETPCAP privilege? These defines seem not to manipulate the capsets of the init process as i first thought but they set the systemwide default for /proc/.../cap_bound. The init process seems to have always full privileges, but i did not check
On Sun, 2 Sep 2001, Andreas Amann wrote: Once again: hello everybody! after doing some experiments this morning i think i've found the major problem with compartment's --cap option (although: compartment has nothing to to with that!). themselves. In fact, this seems to be totally legal because the value in /proc/sys/kernel/cap_bound was set to -256 and seems to be the systemwide default-setting any process becomes after startup. This value includes the CAP_NET_BIND_SERVICE capability. So they were able to start up cleanly. Another funny thing is: after switching over to user nobody, group nogroup proftpd set its capabilities to zero (to be seen via /proc/<PID>/status). After setting cap_bound to a lower value without the CAP_NET_BIND_SERVICE cap, those services failed as expected. this so far. Setting these defines to -1 would in fact be a quite bad idea. To make things still a bit more complicated you can't set cap_bound to a higher value without the CAP_SETPCAP privilege (only init seems to have it by default but can't make use of it), although it is told that you are able to modify it via /dev/mem because of a bug (see http://home.netcom.com/~spoon/lcap/). Although a good idea, capabilities don't seem to be quite useful at the moment (programmers may think different!). But maybe someone is able to enlighten me in this point.... Nevertheless, sorry for wasting your time. Next time i will think about it a second time before making a posting here.... with kind regards Andreas Amann mailto:andreas.amann@epost.de
newly started process no matter whether it will run as root or not. So, for example, the command 'compartment --chroot /some/dir --cap none --verbose /daemon/with_uid0/port_below_1024' should fail miserably because the daemon won't be able to bind to it's port. But exactly this works and i am wondering why (compartment tells me that it successfully set caps to 0x0). I am using SuSE 7.2 with a (stock) Kernel 2.4.9 (but it also happens with a SuSE 2.2.19). /proc/sys/kernel/cap_bound says -257, say everything except CAP_SETPCAP.
I've been playing around with it last weekend, too, and I can verify the problem. Something is wrong here, and I've decided to dig up some kernel code to find out.
So thinking about that and the stuff i've read in the 'capfaq' from http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.2/capfaq-... i have the following questions:
- Is it true that --cap only works with CAP_INIT_EFF_SET and CAP_INIT_INH_SET set to -1 in
in order to get the CAP_SETPCAP privilege?
Inheritable means that the children will have these capabilities.
- If so, doesn't it give even more problems when granting the CAP_SETPCAP right to init? I think this would mean that every process started by init will have it. - If not, do i totally missunderstand something and everything is working well except me?
Not sure yet. :-/ If anybody else is playing around with it as well, please step up!
Thanks in advance to everyone who will be so friendly to help me with that!
With kind regards
Andreas Amann mailto:andreas.amann@epost.de
Thanks,
Roman.
--
- -
| Roman Drahtmüller
On Mon, 3 Sep 2001, Roman Drahtmueller wrote: Roman: First of all: thank you very much for your response! Makes me feel of not beeing lost in space all alone ;-)
newly started process no matter whether it will run as root or not. So, for example, the command 'compartment --chroot /some/dir --cap none --verbose /daemon/with_uid0/port_below_1024' should fail miserably because the daemon won't be able to bind to it's port. But exactly this works and i am wondering why (compartment tells me that it successfully set caps to 0x0). I am using SuSE 7.2 with a (stock) Kernel 2.4.9 (but it also happens with a SuSE 2.2.19). /proc/sys/kernel/cap_bound says -257, say everything except CAP_SETPCAP.
I've been playing around with it last weekend, too, and I can verify the problem. Something is wrong here, and I've decided to dig up some kernel code to find out.
Although i am not very good in c-programming i also had a look at some kernel sources and made some further tests. I think the relevant piece of code can be found in /usr/src/linux/fs/exec.c lines 659ff in function 'compute_creds' (kernel 2.4.9). I may be wrong but i don't think that the behaviour of the kernel when applying a processe's caps is wrong. It seems to be intended and is not a bug in compartment, the libc or the kernel-code. The flow seems to be the following: - compartment starts, does a chroot and anything else it has to do and sets its own capabilities to the specified cmdline value (say CAP_NET_BIND_SERVICE = 0x400) so cap_effective = cap_permitted = cap_inheritable = 0x400. Stopping the process with gdb at this point and having a look at /proc/<PID>/status confirms that. - After that, compartment does an execvp(). - The kernel examines the file to be executed and computes the caps of the new process applying the rules mentioned above. Since there is actually no support for capabilities in ext2 (but this will change; see http:/acl.bestbits.at/) the file's caps are all set to 0xFFFFFFFF. So the bounding value in /proc/sys/kernel/cap_bound will in effect be applied to cap_effective and cap_permitted. cap_inheritable stays the same as in the calling process (compartment), say 0x400. Again, looking at /proc/<PID>/status confirms that. - compartment dies and the new process starts working with the following caps: cap_permitted=cap_effective=0xFFFFFEF; cap_inheritable=0x400. Conclusion: the capability thing actually makes no sense from an admins point of view. A programmer can already use it to lower the 'power' of an application. It will then make sense when there is a possibility to specifiy an executable's caps via the filesystem because the kernel uses these values to compute the final caps of a process in combination with the caller's caps. To be able to use the --caps option right now you would have to make some 'hacks' in the kernel-code in the meantime. The only real buggy thing is the following: the value of /proc/sys/kernel/cap_bounds is directly mapped to memory as you can read at http://home.netcom.com/~spoon/. I tested that and it still works in Kernel 2.4.9. With a simple fwrite() to /dev/mem you are able to modify the bounding value to a _higher_ value. /proc forbids that.
So thinking about that and the stuff i've read in the 'capfaq' from http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.2/capfaq-... i have the following questions:
- Is it true that --cap only works with CAP_INIT_EFF_SET and CAP_INIT_INH_SET set to -1 in
in order to get the CAP_SETPCAP privilege? Inheritable means that the children will have these capabilities.
Actually: True for the cap_inheritable value only because this is not changed anyways. False in respect of the meaning that a child process cannot have more rights than its parent process.
- If so, doesn't it give even more problems when granting the CAP_SETPCAP right to init? I think this would mean that every process started by init will have it. - If not, do i totally missunderstand something and everything is working well except me?
Not sure yet. :-/
Init by default is the only process with the CAP_SETPCAP right. If i am well informed, this cap will be dropped in future.
If anybody else is playing around with it as well, please step up!
I would be very thankful if one of the more sophisticated programmers could confirm or disprove my thoughts.
Thanks, Roman.
Once again: thanks to you. with kind regards Andreas Amann mailto:andreas.amann@epost.de
Err, one last remark to my previous posting. You must already think i like to write to myself, but i want to bring this to an end and could not go to bed before making a last try........... On Mon, 3 Sep 2001, Andreas Amann wrote:
To be able to use the --caps option right now you would have to make some 'hacks' in the kernel-code in the meantime.
I made the following changes in /usr/src/linux/fs/exec.c: Lines 676ff ---------------------------------------------------------------------- Comment out 'working': 676: kernel_cap_t new_permitted; //, working; 677: int do_unlock = 0; 678: Comment out these four lines: 679: //new_permitted = cap_intersect(bprm->cap_permitted, cap_bset); 680: //working = cap_intersect(bprm->cap_inheritable, 681: // current->cap_inheritable); 682: //new_permitted = cap_combine(new_permitted, working); 683: Add the following line: 684: new_permitted = cap_intersect(current->cap_inheritable, cap_bset); Changes in /usr/src/linux/include/linux/capability.h Line 305 ---------------------------------------------------------------------- Change #define CAP_INIT_INH_SET to_cap_t(0) into #define CAP_INIT_INH_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) After compiling a new kernel the system should start up as usual but you are able to use the --cap option of compartment to specify the caps of the new process. BUT: Please, please keep in mind that i'm not totally sure what will be broken by that behind the scenes. My knowledge in c-programming is quite small. So better see it as a 'proof of concept'. But if nobody can find a bad error i would say, it could be a nice configuration option for the next SuSE kernel. Maybe..... with kind regards Andreas Amann mailto:andreas.amann@epost.de
participants (2)
-
Andreas Amann
-
Roman Drahtmueller