Thread (80 messages) flat view 80 messages, 12 authors, 2024-08-09

Re: [RFC PATCH v19 0/5] Script execution control (was O_MAYEXEC)

From: Roberto Sassu <hidden>
Date: 2024-07-16 15:58:21
Also in: linux-fsdevel, linux-integrity, linux-security-module, lkml
Subsystem: extended verification module (evm), integrity measurement architecture (ima), security subsystem, the rest · Maintainers: Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Paul Moore, James Morris, "Serge E. Hallyn", Linus Torvalds

On Tue, 2024-07-09 at 22:43 +0200, Mickaël Salaün wrote:
On Mon, Jul 08, 2024 at 04:35:38PM -0400, Mimi Zohar wrote:
quoted
Hi Mickaël,

On Thu, 2024-07-04 at 21:01 +0200, Mickaël Salaün wrote:
quoted
Hi,

The ultimate goal of this patch series is to be able to ensure that
direct file execution (e.g. ./script.sh) and indirect file execution
(e.g. sh script.sh) lead to the same result, especially from a security
point of view.

Overview
--------

This patch series is a new approach of the initial O_MAYEXEC feature,
and a revamp of the previous patch series.  Taking into account the last
reviews [1], we now stick to the kernel semantic for file executability.
One major change is the clear split between access check and policy
management.

The first patch brings the AT_CHECK flag to execveat(2).  The goal is to
enable user space to check if a file could be executed (by the kernel).
Unlike stat(2) that only checks file permissions, execveat2(2) +
AT_CHECK take into account the full context, including mount points
(noexec), caller's limits, and all potential LSM extra checks (e.g.
argv, envp, credentials).

The second patch brings two new securebits used to set or get a security
policy for a set of processes.  For this to be meaningful, all
executable code needs to be trusted.  In practice, this means that
(malicious) users can be restricted to only run scripts provided (and
trusted) by the system.

[1] https://lore.kernel.org/r/CAHk-=wjPGNLyzeBMWdQu+kUdQLHQugznwY7CvWjmvNW47D5sog@mail.gmail.com (local)

Script execution
----------------

One important thing to keep in mind is that the goal of this patch
series is to get the same security restrictions with these commands:
* ./script.py
* python script.py
* python < script.py
* python -m script.pyT
This is really needed, but is it the "only" purpose of this patch set or can it
be used to also monitor files the script opens (for read) with the intention of
executing.
This feature can indeed also be used to monitor files requested by
scripts to be executed e.g. using
https://docs.python.org/3/library/io.html#io.open_code

IMA/EVM can include this check in its logs.
quoted
quoted
However, on secure systems, we should be able to forbid these commands
because there is no way to reliably identify the origin of the script:
* xargs -a script.py -d '\r' -- python -c
* cat script.py | python
* python

Background
----------

Compared to the previous patch series, there is no more dedicated
syscall nor sysctl configuration.  This new patch series only add new
flags: one for execveat(2) and four for prctl(2).

This kind of script interpreter restriction may already be used in
hardened systems, which may need to fork interpreters and install
different versions of the binaries.  This mechanism should enable to
avoid the use of duplicate binaries (and potential forked source code)
for secure interpreters (e.g. secure Python [2]) by making it possible
to dynamically enforce restrictions or not.

The ability to control script execution is also required to close a
major IMA measurement/appraisal interpreter integrity [3].
Definitely.  But it isn't limited to controlling script execution, but also
measuring the script.  Will it be possible to measure and appraise the indirect
script calls with this patch set?
Yes. You should only need to implement security_bprm_creds_for_exec()
for IMA/EVM.

BTW, I noticed that IMA only uses the security_bprm_check() hook (which
can be called several times for one execve), but
security_bprm_creds_for_exec() might be more appropriate.
Ok, I tried a trivial modification to have this working:
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f04f43af651c..2a6b04c91601 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -554,6 +554,14 @@ static int ima_bprm_check(struct linux_binprm *bprm)
                                   MAY_EXEC, CREDS_CHECK);
 }
 
+static int ima_bprm_creds_for_exec(struct linux_binprm *bprm)
+{
+       if (!bprm->is_check)
+               return 0;
+
+       return ima_bprm_check(bprm);
+}
+
 /**
  * ima_file_check - based on policy, collect/store measurement.
  * @file: pointer to the file to be measured
@@ -1177,6 +1185,7 @@ static int __init init_ima(void)
 
 static struct security_hook_list ima_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
+       LSM_HOOK_INIT(bprm_creds_for_exec, ima_bprm_creds_for_exec),
        LSM_HOOK_INIT(file_post_open, ima_file_check),
        LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
        LSM_HOOK_INIT(file_release, ima_file_free),

I also adapted the Clip OS 4 patch for bash.

The result seems good so far:

# echo "measure fowner=2000 func=BPRM_CHECK" > /sys/kernel/security/ima/policy

# ./bash /root/test.sh
Hello World

# cat /sys/kernel/security/ima/ascii_runtime_measurements
10 35435d0858d895b90097306171a2e5fcc7f5da9e ima-ng sha256:0e4acf326a82c6bded9d86f48d272d7a036b6490081bb6466ecc2a0e416b244a boot_aggregate
10 4cd9df168a2cf8d18be46543e66c76a53ca6a03d ima-ng sha256:e7f3c2dab66f56fef963fbab55fc6d64bc22a5f900c29042e6ecd87e08f2b535 /root/test.sh

So, it is there.

It works only with +x permission. If not, I get:

# ./bash /root/test.sh
./bash: /root/test.sh: Permission denied

But the Clip OS 4 patch does not cover the redirection case:

# ./bash < /root/test.sh
Hello World

Do you have a more recent patch for that?

Thanks

Roberto
quoted
Mimi
quoted
This new execveat + AT_CHECK should not be confused with the O_EXEC flag
(for open) which is intended for execute-only, which obviously doesn't
work for scripts.

I gave a talk about controlling script execution where I explain the
previous approaches [4].  The design of the WIP RFC I talked about
changed quite a bit since then.

[2] https://github.com/zooba/spython
[3] https://lore.kernel.org/lkml/20211014130125.6991-1-zohar@linux.ibm.com/ (local)
[4] https://lssna2023.sched.com/event/1K7bO
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help