So recently I wrote a Linux Security Module (LSM) which would deny execution of commands, unless an extended attribute existed upon the filesystem belonging to the executables.
The whitelist
-LSM worked well, but it soon became apparent that it was a little pointless. Most security changes are pointless unless you define what you're defending against - your "threat model".
In my case it was written largely as a learning experience, but also because I figured it seemed like it could be useful. However it wasn't actually as useful because you soon realize that you have to whitelist too much:
- The
redis-server
binary must be executable, to theredis
-user, otherwise it won't run. /usr/bin/git
must be executable to thegit
user.
In short there comes a point where user alice
must run executable blah
. If alice
can run it, then so can mallory
. At which point you realize the exercise is not so useful.
Taking a step back I realized that what I wanted to to prevent was the execution of unknown/unexpected, and malicious binaries How do you identify known-good binaries? Well hashes & checksums are good. So for my second attempt I figured I'd not look for a mere "flag" on a binary, instead look for a valid hash.
Now my second LSM is invoked for every binary that is executed by a user:
- When a binary is executed the
sha1
hash is calculated of the files contents. - If that matches the value stored in an extended attribute the execution is permitted.
- If the extended-attribute is missing, or the checksum doesn't match, then the execution is denied.
In practice this is the same behaviour as the previous LSM - a binary is either executable, because there is a good hash, or it is not, because it is missing or bogus. If somebody deploys a binary rootkit this will definitely stop it from executing, but of course there is a huge hole - scripting-languages:
- If
/usr/bin/perl
is whitelisted then/usr/bin/perl /tmp/exploit.pl
will succeed. - If
/usr/bin/python
is whitelisted then the same applies.
Despite that the project was worthwhile, I can clearly describe what it is designed to achieve ("Deny the execution of unknown binaries", and "Deny binaries that have been modified"), and I learned how to hash a file from kernel-space - which was surprisingly simple.
(Yes I know about
IMA
andEVM
- this was a simple project for learning purposes. Public-key signatures will be something I'll look at next/soon/later. :)
Perhaps the only other thing to explore is the complexity in allowing/denying actions based on the user - in a human-readable fashion, not via UIDs. So www-data
can execute some programs, alice
can run a different set of binaries, and git
can only run /usr/bin/git
.
Of course down that path lies apparmour, selinux, and madness..
Tags: kernel-programming, linux-security-module, lsm, security 2 comments
https://vincent.bernat.im/en
Hey!
Wouldn't your security module easily be circumvented if a user just execute anything through the dynamic linker? /lib64/ld-linux-x86-64.so.2 /bin/ls