mbox series

[RFC,v8,0/3] Add support for AT_INTERPRETED (was O_MAYEXEC)

Message ID 20200908075956.1069018-1-mic@digikod.net (mailing list archive)
Headers show
Series Add support for AT_INTERPRETED (was O_MAYEXEC) | expand

Message

Mickaël Salaün Sept. 8, 2020, 7:59 a.m. UTC
Hi,

This height patch series rework the previous O_MAYEXEC series by not
adding a new flag to openat2(2) but to faccessat2(2) instead.  As
suggested, this enables to perform the access check on a file descriptor
instead of on a file path (while opening it).  This may require two
checks (one on open and then with faccessat2) but it is a more generic
approach [8].

The IMA patch is removed for now because the only LSM hook triggered by
faccessat2(2) is inode_permission() which takes a struct inode as
argument.  However, struct path and then struct file are still available
in this syscall, which enables to add a new hook to fit the needs of IMA
and other path-based LSMs.

We also removed the three patches from Kees Cook which are no longer
required for this new implementation.

Goal of AT_INTERPRETED
======================

The goal of this patch series is to enable to control script execution
with interpreters help.  A new AT_INTERPRETED flag, usable through
faccessat2(2), is added to enable userspace script interpreters to
delegate to the kernel (and thus the system security policy) the
permission to interpret/execute scripts or other files containing what
can be seen as commands.

A simple system-wide security policy can be enforced by the system
administrator through a sysctl configuration consistent with the mount
points or the file access rights.  The documentation patch explains the
prerequisites.

Furthermore, the security policy can also be delegated to an LSM, either
a MAC system or an integrity system.  For instance, the new kernel
MAY_INTERPRETED_EXEC flag is required to close a major IMA
measurement/appraisal interpreter integrity gap by bringing the ability
to check the use of scripts [1].  Other uses are expected, such as for
magic-links [2], SGX integration [3], bpffs [4] or IPE [5].

Possible extended usage
=======================

For now, only the X_OK mode is compatible with the AT_INTERPRETED flag.
This enables to restrict the addition of new control flows in a process.
Using R_OK or W_OK with AT_INTERPRETED returns -EINVAL.

Possible future use-cases for R_OK with AT_INTERPRETED may be to check
configuration files that may impact the behavior of applications (i.e.
influence critical part of the current control flow).  Those should then
be trusted as well.  The W_OK with AT_INTERPRETED could be used to check
that a file descriptor is allowed to receive sensitive data such as
debug logs.

Prerequisite of its use
=======================

Userspace needs to adapt to take advantage of this new feature.  For
example, the PEP 578 [6] (Runtime Audit Hooks) enables Python 3.8 to be
extended with policy enforcement points related to code interpretation,
which can be used to align with the PowerShell audit features.
Additional Python security improvements (e.g. a limited interpreter
without -c, stdin piping of code) are on their way [7].

Examples
========

The initial idea comes from CLIP OS 4 and the original implementation
has been used for more than 12 years:
https://github.com/clipos-archive/clipos4_doc
Chrome OS has a similar approach:
https://chromium.googlesource.com/chromiumos/docs/+/master/security/noexec_shell_scripts.md

Userland patches can be found here:
https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC
Actually, there is more than the O_MAYEXEC changes (which matches this search)
e.g., to prevent Python interactive execution. There are patches for
Bash, Wine, Java (Icedtea), Busybox's ash, Perl and Python. There are
also some related patches which do not directly rely on O_MAYEXEC but
which restrict the use of browser plugins and extensions, which may be
seen as scripts too:
https://github.com/clipos-archive/clipos4_portage-overlay/tree/master/www-client

An introduction to O_MAYEXEC was given at the Linux Security Summit
Europe 2018 - Linux Kernel Security Contributions by ANSSI:
https://www.youtube.com/watch?v=chNjCRtPKQY&t=17m15s
The "write xor execute" principle was explained at Kernel Recipes 2018 -
CLIP OS: a defense-in-depth OS:
https://www.youtube.com/watch?v=PjRE0uBtkHU&t=11m14s
See also an overview article: https://lwn.net/Articles/820000/

This patch series can be applied on top of v5.9-rc4 .  This can be tested
with CONFIG_SYSCTL.  I would really appreciate constructive comments on
this patch series.

Previous version:
https://lore.kernel.org/lkml/20200723171227.446711-1-mic@digikod.net/

[1] https://lore.kernel.org/lkml/1544647356.4028.105.camel@linux.ibm.com/
[2] https://lore.kernel.org/lkml/20190904201933.10736-6-cyphar@cyphar.com/
[3] https://lore.kernel.org/lkml/CALCETrVovr8XNZSroey7pHF46O=kj_c5D9K8h=z2T_cNrpvMig@mail.gmail.com/
[4] https://lore.kernel.org/lkml/CALCETrVeZ0eufFXwfhtaG_j+AdvbzEWE0M3wjXMWVEO7pj+xkw@mail.gmail.com/
[5] https://lore.kernel.org/lkml/20200406221439.1469862-12-deven.desai@linux.microsoft.com/
[6] https://www.python.org/dev/peps/pep-0578/
[7] https://lore.kernel.org/lkml/0c70debd-e79e-d514-06c6-4cd1e021fa8b@python.org/
[8] https://lore.kernel.org/lkml/e7c1f99d7cdf706ca0867e5fb76ae4cb38bc83f5.camel@linux.ibm.com/

Regards,

Mickaël Salaün (3):
  fs: Introduce AT_INTERPRETED flag for faccessat2(2)
  fs,doc: Enable to configure exec checks for AT_INTERPRETED
  selftest/interpreter: Add tests for AT_INTERPRETED enforcing

 Documentation/admin-guide/sysctl/fs.rst       |  54 +++
 fs/open.c                                     |  67 ++-
 include/linux/fs.h                            |   3 +
 include/uapi/linux/fcntl.h                    |  12 +-
 kernel/sysctl.c                               |  12 +-
 .../testing/selftests/interpreter/.gitignore  |   2 +
 tools/testing/selftests/interpreter/Makefile  |  18 +
 tools/testing/selftests/interpreter/config    |   1 +
 .../interpreter/interpreted_access_test.c     | 384 ++++++++++++++++++
 9 files changed, 548 insertions(+), 5 deletions(-)
 create mode 100644 tools/testing/selftests/interpreter/.gitignore
 create mode 100644 tools/testing/selftests/interpreter/Makefile
 create mode 100644 tools/testing/selftests/interpreter/config
 create mode 100644 tools/testing/selftests/interpreter/interpreted_access_test.c

Comments

Al Viro Sept. 8, 2020, 6:50 p.m. UTC | #1
On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
> Hi,
> 
> This height patch series rework the previous O_MAYEXEC series by not
> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
> suggested, this enables to perform the access check on a file descriptor
> instead of on a file path (while opening it).  This may require two
> checks (one on open and then with faccessat2) but it is a more generic
> approach [8].

Again, why is that folded into lookup/open/whatnot, rather than being
an operation applied to a file (e.g. O_PATH one)?
Mickaël Salaün Sept. 9, 2020, 7:19 a.m. UTC | #2
On 08/09/2020 20:50, Al Viro wrote:
> On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
>> Hi,
>>
>> This height patch series rework the previous O_MAYEXEC series by not
>> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
>> suggested, this enables to perform the access check on a file descriptor
>> instead of on a file path (while opening it).  This may require two
>> checks (one on open and then with faccessat2) but it is a more generic
>> approach [8].
> 
> Again, why is that folded into lookup/open/whatnot, rather than being
> an operation applied to a file (e.g. O_PATH one)?
> 

I don't understand your question. AT_INTERPRETED can and should be used
with AT_EMPTY_PATH. The two checks I wrote about was for IMA.
Matthew Wilcox Sept. 9, 2020, 5:08 p.m. UTC | #3
On Wed, Sep 09, 2020 at 09:19:11AM +0200, Mickaël Salaün wrote:
> 
> On 08/09/2020 20:50, Al Viro wrote:
> > On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
> >> Hi,
> >>
> >> This height patch series rework the previous O_MAYEXEC series by not
> >> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
> >> suggested, this enables to perform the access check on a file descriptor
> >> instead of on a file path (while opening it).  This may require two
> >> checks (one on open and then with faccessat2) but it is a more generic
> >> approach [8].
> > 
> > Again, why is that folded into lookup/open/whatnot, rather than being
> > an operation applied to a file (e.g. O_PATH one)?
> 
> I don't understand your question. AT_INTERPRETED can and should be used
> with AT_EMPTY_PATH. The two checks I wrote about was for IMA.

Al is saying you should add a new syscall, not try to fold it into
some existing syscall.

I agree with him.  Add a new syscall, just like you were told to do it
last time.
Al Viro Sept. 9, 2020, 5:13 p.m. UTC | #4
On Wed, Sep 09, 2020 at 09:19:11AM +0200, Mickaël Salaün wrote:
> 
> On 08/09/2020 20:50, Al Viro wrote:
> > On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
> >> Hi,
> >>
> >> This height patch series rework the previous O_MAYEXEC series by not
> >> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
> >> suggested, this enables to perform the access check on a file descriptor
> >> instead of on a file path (while opening it).  This may require two
> >> checks (one on open and then with faccessat2) but it is a more generic
> >> approach [8].
> > 
> > Again, why is that folded into lookup/open/whatnot, rather than being
> > an operation applied to a file (e.g. O_PATH one)?
> > 
> 
> I don't understand your question. AT_INTERPRETED can and should be used
> with AT_EMPTY_PATH. The two checks I wrote about was for IMA.

Once more, with feeling: don't hide that behind existing syscalls.
If you want to tell LSM have a look at given fs object in a special
way, *add* *a* *new* *system* *call* *for* *doing* *just* *that*.
Mickaël Salaün Sept. 9, 2020, 5:55 p.m. UTC | #5
On 09/09/2020 19:08, Matthew Wilcox wrote:
> On Wed, Sep 09, 2020 at 09:19:11AM +0200, Mickaël Salaün wrote:
>>
>> On 08/09/2020 20:50, Al Viro wrote:
>>> On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
>>>> Hi,
>>>>
>>>> This height patch series rework the previous O_MAYEXEC series by not
>>>> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
>>>> suggested, this enables to perform the access check on a file descriptor
>>>> instead of on a file path (while opening it).  This may require two
>>>> checks (one on open and then with faccessat2) but it is a more generic
>>>> approach [8].
>>>
>>> Again, why is that folded into lookup/open/whatnot, rather than being
>>> an operation applied to a file (e.g. O_PATH one)?
>>
>> I don't understand your question. AT_INTERPRETED can and should be used
>> with AT_EMPTY_PATH. The two checks I wrote about was for IMA.
> 
> Al is saying you should add a new syscall, not try to fold it into
> some existing syscall.
> 
> I agree with him.  Add a new syscall, just like you were told to do it
> last time.
> 

OK, but I didn't receive a response for my proposition to extend
faccessat2(2).
Mickaël Salaün Sept. 9, 2020, 5:56 p.m. UTC | #6
On 09/09/2020 19:13, Al Viro wrote:
> On Wed, Sep 09, 2020 at 09:19:11AM +0200, Mickaël Salaün wrote:
>>
>> On 08/09/2020 20:50, Al Viro wrote:
>>> On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
>>>> Hi,
>>>>
>>>> This height patch series rework the previous O_MAYEXEC series by not
>>>> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
>>>> suggested, this enables to perform the access check on a file descriptor
>>>> instead of on a file path (while opening it).  This may require two
>>>> checks (one on open and then with faccessat2) but it is a more generic
>>>> approach [8].
>>>
>>> Again, why is that folded into lookup/open/whatnot, rather than being
>>> an operation applied to a file (e.g. O_PATH one)?
>>>
>>
>> I don't understand your question. AT_INTERPRETED can and should be used
>> with AT_EMPTY_PATH. The two checks I wrote about was for IMA.
> 
> Once more, with feeling: don't hide that behind existing syscalls.
> If you want to tell LSM have a look at given fs object in a special
> way, *add* *a* *new* *system* *call* *for* *doing* *just* *that*.
> 

Fine, I'll do it. It will look a lot like this one though.
Thibaut Sautereau Sept. 10, 2020, 9:26 a.m. UTC | #7
On Wed, Sep 09, 2020 at 06:08:51PM +0100, Matthew Wilcox wrote:
> On Wed, Sep 09, 2020 at 09:19:11AM +0200, Mickaël Salaün wrote:
> > 
> > On 08/09/2020 20:50, Al Viro wrote:
> > > On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
> > >> Hi,
> > >>
> > >> This height patch series rework the previous O_MAYEXEC series by not
> > >> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
> > >> suggested, this enables to perform the access check on a file descriptor
> > >> instead of on a file path (while opening it).  This may require two
> > >> checks (one on open and then with faccessat2) but it is a more generic
> > >> approach [8].
> > > 
> > > Again, why is that folded into lookup/open/whatnot, rather than being
> > > an operation applied to a file (e.g. O_PATH one)?
> > 
> > I don't understand your question. AT_INTERPRETED can and should be used
> > with AT_EMPTY_PATH. The two checks I wrote about was for IMA.
> 
> Al is saying you should add a new syscall, not try to fold it into
> some existing syscall.
> 
> I agree with him.  Add a new syscall, just like you were told to do it
> last time.

Sure, we'll do it. In the meantime, could we at least get an explanation
about why using faccessat2() instead of a new syscall is wrong? I could
see the reasons for separating the exec checks from the file opening,
but this time I don't understand. Is it because it brings too much
complexity to do_faccessat()?
James Morris Sept. 12, 2020, 12:16 a.m. UTC | #8
On Wed, 9 Sep 2020, Al Viro wrote:

> On Wed, Sep 09, 2020 at 09:19:11AM +0200, Mickaël Salaün wrote:
> > 
> > On 08/09/2020 20:50, Al Viro wrote:
> > > On Tue, Sep 08, 2020 at 09:59:53AM +0200, Mickaël Salaün wrote:
> > >> Hi,
> > >>
> > >> This height patch series rework the previous O_MAYEXEC series by not
> > >> adding a new flag to openat2(2) but to faccessat2(2) instead.  As
> > >> suggested, this enables to perform the access check on a file descriptor
> > >> instead of on a file path (while opening it).  This may require two
> > >> checks (one on open and then with faccessat2) but it is a more generic
> > >> approach [8].
> > > 
> > > Again, why is that folded into lookup/open/whatnot, rather than being
> > > an operation applied to a file (e.g. O_PATH one)?
> > > 
> > 
> > I don't understand your question. AT_INTERPRETED can and should be used
> > with AT_EMPTY_PATH. The two checks I wrote about was for IMA.
> 
> Once more, with feeling: don't hide that behind existing syscalls.
> If you want to tell LSM have a look at given fs object in a special
> way, *add* *a* *new* *system* *call* *for* *doing* *just* *that*.

It's not just for LSM, though, and it has identical semantics from the 
caller's POV as faccessat().