mbox series

[RFC,v1,0/5] Add support for O_MAYEXEC

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

Message

Mickaël Salaün Dec. 12, 2018, 8:17 a.m. UTC
Hi,

The goal of this patch series is to control script interpretation.  A
new O_MAYEXEC flag used by sys_open() is added to enable userland script
interpreter to delegate to the kernel (and thus the system security
policy) the permission to interpret scripts or other files containing
what can be seen as commands.

The security policy is the responsibility of an LSM.  A basic
system-wide policy is implemented with Yama and configurable through a
sysctl.

The initial idea come from CLIP OS and the original implementation has
been used for more than 10 years:
https://github.com/clipos-archive/clipos4_doc

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

This patch series can be applied on top of v4.20-rc6.  This can be
tested with CONFIG_SECURITY_YAMA.  I would really appreciate
constructive comments on this RFC.

Regards,

Mickaël Salaün (5):
  fs: Add support for an O_MAYEXEC flag on sys_open()
  fs: Add a MAY_EXECMOUNT flag to infer the noexec mount propertie
  Yama: Enforces noexec mounts or file executability through O_MAYEXEC
  selftest/yama: Add tests for O_MAYEXEC enforcing
  doc: Add documentation for Yama's open_mayexec_enforce

 Documentation/admin-guide/LSM/Yama.rst       |  41 +++
 MAINTAINERS                                  |   1 +
 fs/fcntl.c                                   |   2 +-
 fs/namei.c                                   |   2 +
 fs/open.c                                    |   4 +
 include/linux/fcntl.h                        |   2 +-
 include/linux/fs.h                           |   4 +
 include/uapi/asm-generic/fcntl.h             |   3 +
 security/yama/Kconfig                        |   3 +-
 security/yama/yama_lsm.c                     |  82 +++++-
 tools/testing/selftests/Makefile             |   1 +
 tools/testing/selftests/yama/.gitignore      |   1 +
 tools/testing/selftests/yama/Makefile        |  19 ++
 tools/testing/selftests/yama/config          |   2 +
 tools/testing/selftests/yama/test_omayexec.c | 276 +++++++++++++++++++
 15 files changed, 439 insertions(+), 4 deletions(-)
 create mode 100644 tools/testing/selftests/yama/.gitignore
 create mode 100644 tools/testing/selftests/yama/Makefile
 create mode 100644 tools/testing/selftests/yama/config
 create mode 100644 tools/testing/selftests/yama/test_omayexec.c

Comments

Jordan Glover Dec. 12, 2018, 4:29 p.m. UTC | #1
On Wednesday, December 12, 2018 9:17 AM, Mickaël Salaün <mic@digikod.net> wrote:

> Hi,
>
> The goal of this patch series is to control script interpretation. A
> new O_MAYEXEC flag used by sys_open() is added to enable userland script
> interpreter to delegate to the kernel (and thus the system security
> policy) the permission to interpret scripts or other files containing
> what can be seen as commands.
>
> The security policy is the responsibility of an LSM. A basic
> system-wide policy is implemented with Yama and configurable through a
> sysctl.
>
> The initial idea come from CLIP OS and the original implementation has
> been used for more than 10 years:
> https://github.com/clipos-archive/clipos4_doc
>
> 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
>
> This patch series can be applied on top of v4.20-rc6. This can be
> tested with CONFIG_SECURITY_YAMA. I would really appreciate
> constructive comments on this RFC.
>
> Regards,
>

Are various interpreters upstreams interested in adding support
for O_MAYEXEC if it land in kernel? Did you contacted them about this?

Jordan
Mickaël Salaün Dec. 12, 2018, 5:01 p.m. UTC | #2
Le 12/12/2018 à 17:29, Jordan Glover a écrit :
> On Wednesday, December 12, 2018 9:17 AM, Mickaël Salaün <mic@digikod.net> wrote:
> 
>> Hi,
>>
>> The goal of this patch series is to control script interpretation. A
>> new O_MAYEXEC flag used by sys_open() is added to enable userland script
>> interpreter to delegate to the kernel (and thus the system security
>> policy) the permission to interpret scripts or other files containing
>> what can be seen as commands.
>>
>> The security policy is the responsibility of an LSM. A basic
>> system-wide policy is implemented with Yama and configurable through a
>> sysctl.
>>
>> The initial idea come from CLIP OS and the original implementation has
>> been used for more than 10 years:
>> https://github.com/clipos-archive/clipos4_doc
>>
>> 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
>>
>> This patch series can be applied on top of v4.20-rc6. This can be
>> tested with CONFIG_SECURITY_YAMA. I would really appreciate
>> constructive comments on this RFC.
>>
>> Regards,
>>
> 
> Are various interpreters upstreams interested in adding support
> for O_MAYEXEC if it land in kernel? Did you contacted them about this?

I think the first step is to be OK on the kernel side. We will then be
able to help upstream interpreters implement this feature. It should be
OK because the behavior doesn't change by default, i.e. if the sysadmin
doesn't configure (and test) the whole system. Some examples of modified
interpreters can be found at
https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC
.

 Mickaël
James Morris Dec. 12, 2018, 7:51 p.m. UTC | #3
On Wed, 12 Dec 2018, Mickaël Salaün wrote:

> Hi,
> 
> The goal of this patch series is to control script interpretation.  A
> new O_MAYEXEC flag used by sys_open() is added to enable userland script
> interpreter to delegate to the kernel (and thus the system security
> policy) the permission to interpret scripts or other files containing
> what can be seen as commands.
> 
> The security policy is the responsibility of an LSM.  A basic
> system-wide policy is implemented with Yama and configurable through a
> sysctl.

If you're depending on the script interpreter to flag that the user may 
execute code, this seems to be equivalent in security terms to depending 
on the user.  e.g. what if the user uses ptrace and clears O_MAYEXEC?
Florian Weimer Dec. 12, 2018, 8:13 p.m. UTC | #4
* James Morris:

> If you're depending on the script interpreter to flag that the user may 
> execute code, this seems to be equivalent in security terms to depending 
> on the user.  e.g. what if the user uses ptrace and clears O_MAYEXEC?

The argument I've heard is this: Using ptrace (and adding the +x
attribute) are auditable events.

Florian
James Morris Dec. 12, 2018, 11:40 p.m. UTC | #5
On Wed, 12 Dec 2018, Florian Weimer wrote:

> * James Morris:
> 
> > If you're depending on the script interpreter to flag that the user may 
> > execute code, this seems to be equivalent in security terms to depending 
> > on the user.  e.g. what if the user uses ptrace and clears O_MAYEXEC?
> 
> The argument I've heard is this: Using ptrace (and adding the +x
> attribute) are auditable events.

I guess you could also preload a modified libc which strips the flag.
Matthew Wilcox Dec. 13, 2018, 3:02 a.m. UTC | #6
On Wed, Dec 12, 2018 at 09:17:07AM +0100, Mickaël Salaün wrote:
> The goal of this patch series is to control script interpretation.  A
> new O_MAYEXEC flag used by sys_open() is added to enable userland script
> interpreter to delegate to the kernel (and thus the system security
> policy) the permission to interpret scripts or other files containing
> what can be seen as commands.

I don't have a problem with the concept, but we're running low on O_ bits.
Does this have to be done before the process gets a file descriptor,
or could we have a new syscall?  Since we're going to be changing the
interpreters anyway, it doesn't seem like too much of an imposition to
ask them to use:

	int verify_for_exec(int fd)

instead of adding an O_MAYEXEC.
Florian Weimer Dec. 13, 2018, 5:13 a.m. UTC | #7
* James Morris:

> On Wed, 12 Dec 2018, Florian Weimer wrote:
>
>> * James Morris:
>> 
>> > If you're depending on the script interpreter to flag that the user may 
>> > execute code, this seems to be equivalent in security terms to depending 
>> > on the user.  e.g. what if the user uses ptrace and clears O_MAYEXEC?
>> 
>> The argument I've heard is this: Using ptrace (and adding the +x
>> attribute) are auditable events.
>
> I guess you could also preload a modified libc which strips the flag.

My understanding is that this new libc would have to come somewhere, and
making it executable would be an auditable even as well.

Thanks,
Florian
Florian Weimer Dec. 13, 2018, 5:22 a.m. UTC | #8
* Matthew Wilcox:

> On Wed, Dec 12, 2018 at 09:17:07AM +0100, Mickaël Salaün wrote:
>> The goal of this patch series is to control script interpretation.  A
>> new O_MAYEXEC flag used by sys_open() is added to enable userland script
>> interpreter to delegate to the kernel (and thus the system security
>> policy) the permission to interpret scripts or other files containing
>> what can be seen as commands.
>
> I don't have a problem with the concept, but we're running low on O_ bits.
> Does this have to be done before the process gets a file descriptor,
> or could we have a new syscall?  Since we're going to be changing the
> interpreters anyway, it doesn't seem like too much of an imposition to
> ask them to use:
>
> 	int verify_for_exec(int fd)
>
> instead of adding an O_MAYEXEC.

Will this work for auditing?

Maybe add an interface which explicitly upgrades O_PATH descriptors, and
give that a separate flag argument?  I suppose that would be more
friendly to auditing.

Thanks,
Florian
Mimi Zohar Dec. 13, 2018, 11:04 a.m. UTC | #9
On Wed, 2018-12-12 at 19:02 -0800, Matthew Wilcox wrote:
> On Wed, Dec 12, 2018 at 09:17:07AM +0100, Mickaël Salaün wrote:
> > The goal of this patch series is to control script interpretation.  A
> > new O_MAYEXEC flag used by sys_open() is added to enable userland script
> > interpreter to delegate to the kernel (and thus the system security
> > policy) the permission to interpret scripts or other files containing
> > what can be seen as commands.
> 
> I don't have a problem with the concept, but we're running low on O_ bits.
> Does this have to be done before the process gets a file descriptor,
> or could we have a new syscall?  Since we're going to be changing the
> interpreters anyway, it doesn't seem like too much of an imposition to
> ask them to use:
> 
> 	int verify_for_exec(int fd)
> 
> instead of adding an O_MAYEXEC.

The indication needs to be set during file open, before the open
returns to the caller.  This is the point where ima_file_check()
verifies the file's signature.  On failure, access to the file is
denied.

Mimi
Florian Weimer Dec. 13, 2018, 11:26 a.m. UTC | #10
* Mimi Zohar:

> The indication needs to be set during file open, before the open
> returns to the caller.  This is the point where ima_file_check()
> verifies the file's signature.  On failure, access to the file is
> denied.

Does this verification happen for open with O_PATH?

Thanks,
Florian
Matthew Wilcox Dec. 13, 2018, 12:16 p.m. UTC | #11
On Thu, Dec 13, 2018 at 06:04:20AM -0500, Mimi Zohar wrote:
> > I don't have a problem with the concept, but we're running low on O_ bits.
> > Does this have to be done before the process gets a file descriptor,
> > or could we have a new syscall?  Since we're going to be changing the
> > interpreters anyway, it doesn't seem like too much of an imposition to
> > ask them to use:
> > 
> > 	int verify_for_exec(int fd)
> > 
> > instead of adding an O_MAYEXEC.
> 
> The indication needs to be set during file open, before the open
> returns to the caller.  This is the point where ima_file_check()
> verifies the file's signature.  On failure, access to the file is
> denied.

I understand that's what happens today, but do we need to do it that way?
There's no harm in the interpreter having an fd to a file if it knows
not to execute it.  This is different from a program opening a file and
having the LSM deny access to it because it violates the security model.
Mimi Zohar Dec. 13, 2018, 12:16 p.m. UTC | #12
[Cc'ing linux-integrity]

On Thu, 2018-12-13 at 12:26 +0100, Florian Weimer wrote:
> * Mimi Zohar:
> 
> > The indication needs to be set during file open, before the open
> > returns to the caller.  This is the point where ima_file_check()
> > verifies the file's signature.  On failure, access to the file is
> > denied.
> 
> Does this verification happen for open with O_PATH?

Interesting!  According to the manpage, userspace cannot read/write to
the file.  It looks like do_o_path() intentionally skips do_last(),
with the call to ima_file_check().  If the file data isn't being
accessed, does the file's integrity need to be verified?

Mimi
Mickaël Salaün Dec. 13, 2018, 2:57 p.m. UTC | #13
On 13/12/2018 06:13, Florian Weimer wrote:
> * James Morris:
> 
>> On Wed, 12 Dec 2018, Florian Weimer wrote:
>>
>>> * James Morris:
>>>
>>>> If you're depending on the script interpreter to flag that the user may 
>>>> execute code, this seems to be equivalent in security terms to depending 
>>>> on the user.  e.g. what if the user uses ptrace and clears O_MAYEXEC?

This security mechanism makes sense in an hardened system where the user
is not allowed to import and execute new file (write xor execute
policy). This can be enforced with appropriate mount points a more
advanced access control policy.

>>>
>>> The argument I've heard is this: Using ptrace (and adding the +x
>>> attribute) are auditable events.
>>
>> I guess you could also preload a modified libc which strips the flag.
> 
> My understanding is that this new libc would have to come somewhere, and
> making it executable would be an auditable even as well.

Auditing is a possible use case as well, but the W^X idea is to deny use
of libraries which are not in an executable mount point, i.e. only
execute trusted code.
Mickaël Salaün Dec. 13, 2018, 3:17 p.m. UTC | #14
On 13/12/2018 04:02, Matthew Wilcox wrote:
> On Wed, Dec 12, 2018 at 09:17:07AM +0100, Mickaël Salaün wrote:
>> The goal of this patch series is to control script interpretation.  A
>> new O_MAYEXEC flag used by sys_open() is added to enable userland script
>> interpreter to delegate to the kernel (and thus the system security
>> policy) the permission to interpret scripts or other files containing
>> what can be seen as commands.
> 
> I don't have a problem with the concept, but we're running low on O_ bits.
> Does this have to be done before the process gets a file descriptor,
> or could we have a new syscall?  Since we're going to be changing the
> interpreters anyway, it doesn't seem like too much of an imposition to
> ask them to use:
> 
> 	int verify_for_exec(int fd)
> 
> instead of adding an O_MAYEXEC.
> 

Adding a new syscall for this simple use case seems excessive. I think
that the open/openat syscall familly are the right place to do an atomic
open and permission check, the same way the kernel does for other file
access. Moreover, it will be easier to patch upstream interpreters
without the burden of handling a (new) syscall that may not exist on the
running system, whereas unknown open flags are ignored.
Matthew Wilcox Dec. 13, 2018, 5:13 p.m. UTC | #15
On Thu, Dec 13, 2018 at 04:17:29PM +0100, Mickaël Salaün wrote:
> On 13/12/2018 04:02, Matthew Wilcox wrote:
> > On Wed, Dec 12, 2018 at 09:17:07AM +0100, Mickaël Salaün wrote:
> >> The goal of this patch series is to control script interpretation.  A
> >> new O_MAYEXEC flag used by sys_open() is added to enable userland script
> >> interpreter to delegate to the kernel (and thus the system security
> >> policy) the permission to interpret scripts or other files containing
> >> what can be seen as commands.
> > 
> > I don't have a problem with the concept, but we're running low on O_ bits.
> > Does this have to be done before the process gets a file descriptor,
> > or could we have a new syscall?  Since we're going to be changing the
> > interpreters anyway, it doesn't seem like too much of an imposition to
> > ask them to use:
> > 
> > 	int verify_for_exec(int fd)
> > 
> > instead of adding an O_MAYEXEC.
> 
> Adding a new syscall for this simple use case seems excessive. I think

We have somewhat less than 400 syscalls today.  We have 20 O_ bits defined.
Obviously there's a lower practical limit on syscalls, but in principle
we could have up to 2^32 syscalls, and there are only 12 O_ bits remaining.

> that the open/openat syscall familly are the right place to do an atomic
> open and permission check, the same way the kernel does for other file
> access. Moreover, it will be easier to patch upstream interpreters
> without the burden of handling a (new) syscall that may not exist on the
> running system, whereas unknown open flags are ignored.

Ah, but that's the problem.  The interpreter can see an -ENOSYS response
and handle it appropriately.  If the flag is silently ignored, the
interpreter has no idea whether it can do a racy check or whether to
skip even trying to do the check.
Mickaël Salaün Dec. 13, 2018, 5:36 p.m. UTC | #16
On 13/12/2018 18:13, Matthew Wilcox wrote:
> On Thu, Dec 13, 2018 at 04:17:29PM +0100, Mickaël Salaün wrote:
>> On 13/12/2018 04:02, Matthew Wilcox wrote:
>>> On Wed, Dec 12, 2018 at 09:17:07AM +0100, Mickaël Salaün wrote:
>>>> The goal of this patch series is to control script interpretation.  A
>>>> new O_MAYEXEC flag used by sys_open() is added to enable userland script
>>>> interpreter to delegate to the kernel (and thus the system security
>>>> policy) the permission to interpret scripts or other files containing
>>>> what can be seen as commands.
>>>
>>> I don't have a problem with the concept, but we're running low on O_ bits.
>>> Does this have to be done before the process gets a file descriptor,
>>> or could we have a new syscall?  Since we're going to be changing the
>>> interpreters anyway, it doesn't seem like too much of an imposition to
>>> ask them to use:
>>>
>>> 	int verify_for_exec(int fd)
>>>
>>> instead of adding an O_MAYEXEC.
>>
>> Adding a new syscall for this simple use case seems excessive. I think
> 
> We have somewhat less than 400 syscalls today.  We have 20 O_ bits defined.
> Obviously there's a lower practical limit on syscalls, but in principle
> we could have up to 2^32 syscalls, and there are only 12 O_ bits remaining.
> 
>> that the open/openat syscall familly are the right place to do an atomic
>> open and permission check, the same way the kernel does for other file
>> access. Moreover, it will be easier to patch upstream interpreters
>> without the burden of handling a (new) syscall that may not exist on the
>> running system, whereas unknown open flags are ignored.
> 
> Ah, but that's the problem.  The interpreter can see an -ENOSYS response
> and handle it appropriately.  If the flag is silently ignored, the
> interpreter has no idea whether it can do a racy check or whether to
> skip even trying to do the check.

Right, but the interpreter should interpret the script if the open with
O_MAYEXEC succeed (but not otherwise): it may be because the flag is
known by the kernel and the system policy allow this call, or because
the (old) kernel doesn't known about this flag (which is fine and needed
for backward compatibility). The script interpretation must not failed
if the kernel doesn't support O_MAYEXEC, it is then useless for the
interpreter to do any additional check.
Matthew Wilcox Dec. 13, 2018, 5:44 p.m. UTC | #17
On Thu, Dec 13, 2018 at 06:36:15PM +0100, Mickaël Salaün wrote:
> On 13/12/2018 18:13, Matthew Wilcox wrote:
> > On Thu, Dec 13, 2018 at 04:17:29PM +0100, Mickaël Salaün wrote:
> >> Adding a new syscall for this simple use case seems excessive. I think
> > 
> > We have somewhat less than 400 syscalls today.  We have 20 O_ bits defined.
> > Obviously there's a lower practical limit on syscalls, but in principle
> > we could have up to 2^32 syscalls, and there are only 12 O_ bits remaining.
> > 
> >> that the open/openat syscall familly are the right place to do an atomic
> >> open and permission check, the same way the kernel does for other file
> >> access. Moreover, it will be easier to patch upstream interpreters
> >> without the burden of handling a (new) syscall that may not exist on the
> >> running system, whereas unknown open flags are ignored.
> > 
> > Ah, but that's the problem.  The interpreter can see an -ENOSYS response
> > and handle it appropriately.  If the flag is silently ignored, the
> > interpreter has no idea whether it can do a racy check or whether to
> > skip even trying to do the check.
> 
> Right, but the interpreter should interpret the script if the open with
> O_MAYEXEC succeed (but not otherwise): it may be because the flag is
> known by the kernel and the system policy allow this call, or because
> the (old) kernel doesn't known about this flag (which is fine and needed
> for backward compatibility). The script interpretation must not failed
> if the kernel doesn't support O_MAYEXEC, it is then useless for the
> interpreter to do any additional check.

If that's the way interpreters want to work, then that's fine.  They
can just call the verify() syscall and ignore the -ENOSYS.  Done.

Or somebody who cares very, very deeply can change the interpreter to
decline to run any scripts if the kernel returns -ENOSYS.