While working on the second article in the environmental contamination series I found that 1/2 of the article was spent wading through the security structure and Flask implementation in the kernel. Since this is an important and recurring topic I figured I would split it out into a separate article and just link to this from future articles. I want to warn you, as most shallow explanations of kernel mechanisms, this may seem confusing since some details are left out. I encourage you to explore these on your own until you have satisfied your craving.
When it comes to making certain security decisions the kernel makes use of capabilities or other mechanisms (such as SELinux) which render a decision that the kernel then enforces or passes off to userland for use there. The kernel asks for these decisions through function calls or “hooks”. We need to have a rudimentary understanding of how these hooks work if we’re to understand how the security mechanism behind SELinux.
First place we need to look is include/security/security.h[2]. If you’re drawn into the “why”s I suggest you backtrace from the SELinux hooks (security/selinux/hooks.c) to the security operations structure (include/linux/security.h) but we will go straight to security.h. Look at the *_bprm_secureexec function headers. This highlights that how the security hooks and capabilities work with and without of security modules. Look at the #ifdef on lines 91 and the corresponding #else on line 1949. If the CONFIG_SECURITY kernel config option IS NOT enabled this security check falls back to the traditional capability security checks[1]. If the CONFIG_SECURITY option IS enabled this check propagates through one or more of several security hooks.
The kernel uses a security struct provided by LSM called security_ops (line 1037) to support a variety of security models. The security_ops maintains a set of pointers to functions that are defined by the security model you use. Some of the pointers are used during initialization, others shutdown, and others are the actual security hooks described above. These security hooks are called from various critical points in the kernel deemed to be security relevant[3]. The kernel LSM is a partial implementation of the Flask architecture with some caveats such as revocation and caching[4]. Thus, the security hooks simply return a decision regarding the access, a simple yes or no, and the place that called the hook is responsible for enforcing this decision[5].
As a quick example lets look at the ability to set our user id. If we look in kernel/sys.c we will find the function sys_setuid on line 779. The first thing done in this function (aside from delcaring variables) is to check with the security_task_setuid function (line 785). This function is defined in include/linux/security.h on lines 2346 and 1714. Both are very simple inline functions. The former is used if CONFIG_SECURITY is not enabled and merely returns 0. The latter is used when CONFIG_SECURITY is enabled and simply calls the security hook found in the security_ops task_setuid function pointer. So here we see that separation of the decision from the enforcement as defined by the Flask architecture. The decision is rendered by the hook, or security server, and the decision is enforced by caller, or the object manager.
If CONFIG_SECURITY is enabled but no specific security module is installed it means no real security_ops struct is available so it falls through the dummy security_ops which just passes it onto the capability hooks mentioned above. However, if a security module is installed it leverages these hooks instead of the “dummy” hooks.
Hopefully this is enough to help one wade through the kernel enforcement and security server mechanism.
[1] As far as I know, secureexec was not part of the POSIX capability specification, rather it is a Linux specific extenstion to this specification. Please correct me if I’m wrong on this point (and all other points
).
[2] The research for this article was done on the 2.6.15 kernel with the Gentoo r7 patchset applied.
[3] “Security relevant” is arguable as is the acutal functionality of the LSM. If you follow the LSM and LKML you will find that the LSM implementation is sub-optimal for most security models and has it’s flaws. None the less this is the best model we have at the moment so we have to make the best of it.
[4] Some of these issues, such as caching, are addressed by the SELinux module itself, but not by LSM.
[5] Refer to this excerpt from the Flask paper for a diagram depicting this separation of enforcement from decision.
feed
No comment yet