linux-application-whitelisting / fapolicyd

File Access Policy Daemon
GNU General Public License v3.0
199 stars 56 forks source link

Effectiveness of fapolicyd #131

Open maage opened 3 years ago

maage commented 3 years ago

packages

I've been testing fapolicyd and have some notes when using default ruleset.

Mainly my gripe is about:

https://github.com/linux-application-whitelisting/fapolicyd/blob/6ed039f4ec176b0bab96093e505d9f1f5f4ca3f3/init/fapolicyd.rules.known-libs#L37

/bin /sbin change if used in shebang

You can use /bin or /sbin to avoid shebang rules.

$ python3 ./tst-bin-python-shebang.py
OK
$ python3 ./tst-usr-bin-python-shebang.py
python3: can't open file '/home/user/tst-usr-bin-python-shebang.py': [Errno 1] Operation not permitted

This actually following two issues, but kind of common, so should be handled especially.

You probably do not want users to go to #!/bin/python3 shebang by default.

Shebang write-once

You can not open any file with shebang other than shellscript if not trusted. For example writing python shebang creates a write once file. After writing it first time, you can not edit it any more. You can only remove it.

This might not be something you want to enable by default as user might not expect that.

This can also be used as a denial of service attack if attacker is able to write into any important file. You need to have root to fix things back.

Shebang is not required for script languages to run the script

If you want to run any untrusted script executable, just write the script without shebang and give the script as command line parameter.

$ python3 file_without_shebang.py
OK

stdin not limited

And also you can run most scripts like:

$ cat file_without_shebang | python3
OK

As far as python3 exec is allowed, this works as there is no open action from stdin for fapolicyd to deny.

Further thoughts

I think something like this could be used here too: Add trusted_for(2) (was O_MAYEXEC)

Generally there is no way to see if script opens a file as to be interpreted and executed or just as a data file.

I guess you can try to whitelist all programs that you trust not to execute the files they open, but it gets tedious really fast. Probably it would be easier to implement negation on subject rule and list all the interpeters as exe/comm instead. Meaning allow all exe but interpereters to open any untrusted file regardless of shebang.

%file_openers=/usr/bin/vim,/usr/bin/cat,/usr/bin/grep,/usr/bin/wc,/usr/bin/less
allow perm=open exe=%file_openers trust=1 : all

Or you can whitelist paths like /home. And accept users can run scripts like python3 ./tst-usr-bin-python-shebang.py.

allow perm=open trust=1 : dir=/home
stevegrubb commented 3 years ago

I wished that there was a better way to respond to such a lengthy issue. But to sum it up, these are all known issues and will be addressed to varying degrees in the future. I just haven't had much time this year to work on this project or some of these would be solved by now.

jullrey commented 2 years ago

I was able to allow seeing and editing my python3 files with the shbang at the top by modify the %languages variable, in the fapolicyd.rules file, and changing the two occurances of "python" to "python3". But I still couldn't figure out the rules needet to execute them. Will have to settle for using the 'fapolicyd-cli --file add /home/username/bin/test.py' command.

roman-abra commented 9 months ago

I was trying to limit interpreters (python) to run trusted scripts only (no interactive shell or pipeline). But when you call python3 trusted_script.py, you actually invoke at least two rules:

exe=/usr/bin/bash : path=/usr/bin/python3.8 ftype=application/x-executable
exe=/usr/bin/python3.8 : path=/path/to/trusted_script.py ftype=text/x-python

If you set/usr/bin/python3.8 as trusted or allow/usr/bin/bash to run it, you essentially remove all restrictions from it and allow interactive and pipeline options. If you don't allow it, it never runs. So all or nothing.

But I found a workaround: Compile a run_python binary (C) that receives a script (file) as a parameter. It runs /usr/bin/python3.8 <script_file>. This way you can configure the rules to: Allow /usr/bin/bash to run /usr/bin/run_python. You can add run_python to trusted files instead of this rule. Allow/usr/bin/run_python to run whatever it wants. Allow/usr/bin/python3.8 to open and run only trusted files. Block everything else /usr/bin/python3.8 tries to run.

allow perm=execute exe=/usr/bin/bash : path=/usr/bin/run_python
allow perm=any exe=/usr/bin/run_python : all
allow perm=any exe=/usr/bin/python3.8 : all trust=1
deny_audit perm=any exe=/usr/bin/python3.8 : all

Now you can call run_python /path/to/trusted_script.py and it will work. But this won't:

python3
python3 /path/to/trusted_script.py
python3 /path/to/un_trusted_script.py
run_python /path/to/un_trusted_script.py
cat  /path/to/trusted_script.py | python3

One last thing, to be able to run scripts without explicitly calling "run_python", you need to change the link from /usr/bin/python3 -> python3.8 to /usr/bin/python3 -> run_python

Hope this solution helps someone until there is official support.