LKML Archive on lore.kernel.org
 help / color / Atom feed
From: "Mickaël Salaün" <mic@digikod.net>
To: Kees Cook <keescook@chromium.org>
Cc: linux-kernel@vger.kernel.org, "Aleksa Sarai" <cyphar@cyphar.com>,
	"Alexei Starovoitov" <ast@kernel.org>,
	"Al Viro" <viro@zeniv.linux.org.uk>,
	"Andy Lutomirski" <luto@kernel.org>,
	"Christian Heimes" <christian@python.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Deven Bowers" <deven.desai@linux.microsoft.com>,
	"Eric Chiang" <ericchiang@google.com>,
	"Florian Weimer" <fweimer@redhat.com>,
	"James Morris" <jmorris@namei.org>, "Jan Kara" <jack@suse.cz>,
	"Jann Horn" <jannh@google.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Lakshmi Ramasubramanian" <nramas@linux.microsoft.com>,
	"Matthew Garrett" <mjg59@google.com>,
	"Matthew Wilcox" <willy@infradead.org>,
	"Michael Kerrisk" <mtk.manpages@gmail.com>,
	"Mickaël Salaün" <mickael.salaun@ssi.gouv.fr>,
	"Mimi Zohar" <zohar@linux.ibm.com>,
	"Philippe Trébuchet" <philippe.trebuchet@ssi.gouv.fr>,
	"Scott Shell" <scottsh@microsoft.com>,
	"Sean Christopherson" <sean.j.christopherson@intel.com>,
	"Shuah Khan" <shuah@kernel.org>,
	"Steve Dower" <steve.dower@python.org>,
	"Steve Grubb" <sgrubb@redhat.com>,
	"Thibaut Sautereau" <thibaut.sautereau@ssi.gouv.fr>,
	"Vincent Strubel" <vincent.strubel@ssi.gouv.fr>,
	kernel-hardening@lists.openwall.com, linux-api@vger.kernel.org,
	linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH v5 3/6] fs: Enable to enforce noexec mounts or file exec through O_MAYEXEC
Date: Wed, 13 May 2020 13:09:26 +0200
Message-ID: <6dbae682-e805-5567-39bd-4434d2cb9759@digikod.net> (raw)
In-Reply-To: <202005121422.411001F1@keescook>


On 12/05/2020 23:48, Kees Cook wrote:
> On Tue, May 05, 2020 at 05:31:53PM +0200, Mickaël Salaün wrote:
>> Enable to forbid access to files open with O_MAYEXEC.  Thanks to the
>> noexec option from the underlying VFS mount, or to the file execute
>> permission, userspace can enforce these execution policies.  This may
>> allow script interpreters to check execution permission before reading
>> commands from a file, or dynamic linkers to allow shared object loading.
> 
> Some language tailoring. I might change the first sentence to:
> 
> Allow for the enforcement of the O_MAYEXEC openat2(2) flag.

OK

> 
>> Add a new sysctl fs.open_mayexec_enforce to enable system administrators
>> to enforce two complementary security policies according to the
>> installed system: enforce the noexec mount option, and enforce
>> executable file permission.  Indeed, because of compatibility with
>> installed systems, only system administrators are able to check that
>> this new enforcement is in line with the system mount points and file
>> permissions.  A following patch adds documentation.
>>
>> For tailored Linux distributions, it is possible to enforce such
>> restriction at build time thanks to the CONFIG_OMAYEXEC_STATIC option.
>> The policy can then be configured with CONFIG_OMAYEXEC_ENFORCE_MOUNT and
>> CONFIG_OMAYEXEC_ENFORCE_FILE.
> 
> OMAYEXEC feels like the wrong name here. Maybe something closer to the
> sysctl name? CONFIG_OPEN_MAYEXEC?
> 
> And I think it's not needed to have 3 configs for this. That's a lot of
> mess for a corner case option. I think I would model this after other
> sysctl CONFIGs, and just call this CONFIG_OPEN_MAYEXEC_DEFAULT.
OK, I guess you mean to store the default integer value of the sysctl in
this config option.

> 
> Is _disabling_ the sysctl needed? This patch gets much smaller without
> the ..._STATIC bit. (And can we avoid "static", it means different
> things to different people. How about invert the logic and call it
> CONFIG_OPEN_MAYEXEC_SYSCTL?)

I added this in response to James's comment:
https://lore.kernel.org/lkml/alpine.LRH.2.21.2005020405210.5924@namei.org/
I'm fine to let the sysctl visible whatever the kernel config is. It
makes the code simpler. I guess tailored security distros already
protect sysctl entries anyway.

> 
> Further notes below...
> 
>> [...]
>> diff --git a/fs/namei.c b/fs/namei.c
>> index 33b6d372e74a..70f179f6bc6c 100644
>> --- a/fs/namei.c
>> +++ b/fs/namei.c
>> @@ -39,6 +39,7 @@
>>  #include <linux/bitops.h>
>>  #include <linux/init_task.h>
>>  #include <linux/uaccess.h>
>> +#include <linux/sysctl.h>
>>  
>>  #include "internal.h"
>>  #include "mount.h"
>> @@ -411,10 +412,90 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
>>  	return 0;
>>  }
>>  
>> +#define OMAYEXEC_ENFORCE_NONE	0
> 
> Like the CONFIG, I'd stay close to the sysctl, OPEN_MAYEXEC_ENFORCE_...
> 
>> +#define OMAYEXEC_ENFORCE_MOUNT	(1 << 0)
>> +#define OMAYEXEC_ENFORCE_FILE	(1 << 1)
> 
> Please use BIT(0), BIT(1)...
> 
>> +#define _OMAYEXEC_LAST		OMAYEXEC_ENFORCE_FILE
>> +#define _OMAYEXEC_MASK		((_OMAYEXEC_LAST << 1) - 1)
>> +
>> +#ifdef CONFIG_OMAYEXEC_STATIC
>> +const int sysctl_omayexec_enforce =
>> +#ifdef CONFIG_OMAYEXEC_ENFORCE_MOUNT
>> +	OMAYEXEC_ENFORCE_MOUNT |
>> +#endif
>> +#ifdef CONFIG_OMAYEXEC_ENFORCE_FILE
>> +	OMAYEXEC_ENFORCE_FILE |
>> +#endif
>> +	OMAYEXEC_ENFORCE_NONE;
>> +#else /* CONFIG_OMAYEXEC_STATIC */
>> +int sysctl_omayexec_enforce __read_mostly = OMAYEXEC_ENFORCE_NONE;
>> +#endif /* CONFIG_OMAYEXEC_STATIC */
> 
> 
> If you keep CONFIG_OPEN_MAYEXEC_SYSCTL, you could do this in namei.h:
> 
> #ifdef CONFIG_OPEN_MAYEXEC_SYSCTL
> #define __sysctl_writable	__read_mostly
> #else
> #define __sysctl_write		const
> #endif
> 
> Then with my proposed change to the enforce CONFIG, all of this is
> reduced to simply:
> 
> int open_mayexec_enforce __sysctl_writable = CONFIG_OPEN_MAYEXEC_DEFAULT;

Except the position of the const, this is clearer indeed.

> 
>> +
>> +/*
>> + * Handle open_mayexec_enforce sysctl
>> + */
>> +#if defined(CONFIG_SYSCTL) && !defined(CONFIG_OMAYEXEC_STATIC)
>> +int proc_omayexec(struct ctl_table *table, int write, void __user *buffer,
>> +		size_t *lenp, loff_t *ppos)
>> +{
>> +	int error;
>> +
>> +	if (write) {
>> +		struct ctl_table table_copy;
>> +		int tmp_mayexec_enforce;
>> +
>> +		if (!capable(CAP_MAC_ADMIN))
>> +			return -EPERM;
>> +
>> +		tmp_mayexec_enforce = *((int *)table->data);
>> +		table_copy = *table;
>> +		/* Do not erase sysctl_omayexec_enforce. */
>> +		table_copy.data = &tmp_mayexec_enforce;
>> +		error = proc_dointvec(&table_copy, write, buffer, lenp, ppos);
>> +		if (error)
>> +			return error;
>> +
>> +		if ((tmp_mayexec_enforce | _OMAYEXEC_MASK) != _OMAYEXEC_MASK)
>> +			return -EINVAL;
>> +
>> +		*((int *)table->data) = tmp_mayexec_enforce;
>> +	} else {
>> +		error = proc_dointvec(table, write, buffer, lenp, ppos);
>> +		if (error)
>> +			return error;
>> +	}
>> +	return 0;
>> +}
>> +#endif
> 
> I don't think any of this is needed. There are no complex bit field
> interactions to check for. The sysctl is min=0, max=3. The only thing
> special here is checking CAP_MAC_ADMIN. I would just add
> proc_dointvec_minmax_macadmin(), like we have for ..._minmax_sysadmin().

OK

> 
>> +
>> +/**
>> + * omayexec_inode_permission - Check O_MAYEXEC before accessing an inode
>> + *
>> + * @inode: Inode to check permission on
>> + * @mask: Right to check for (%MAY_OPENEXEC, %MAY_EXECMOUNT, %MAY_EXEC)
>> + *
>> + * Returns 0 if access is permitted, -EACCES otherwise.
>> + */
>> +static inline int omayexec_inode_permission(struct inode *inode, int mask)
>> +{
>> +	if (!(mask & MAY_OPENEXEC))
>> +		return 0;
>> +
>> +	if ((sysctl_omayexec_enforce & OMAYEXEC_ENFORCE_MOUNT) &&
>> +			!(mask & MAY_EXECMOUNT))
>> +		return -EACCES;
>> +
>> +	if (sysctl_omayexec_enforce & OMAYEXEC_ENFORCE_FILE)
>> +		return generic_permission(inode, MAY_EXEC);
>> +
>> +	return 0;
>> +}
> 
> More naming nits: I think this should be called may_openexec() to match
> the other may_*() functions.

Other *_inode_permission() functions have a similar meaning and the same
signature. The may_*() functions have various signatures. What do the
filesystem folks prefer?

> 
>> +
>>  /**
>>   * inode_permission - Check for access rights to a given inode
>>   * @inode: Inode to check permission on
>> - * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
>> + * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, %MAY_OPENEXEC,
>> + *        %MAY_EXECMOUNT)
>>   *
>>   * Check for read/write/execute permissions on an inode.  We use fs[ug]id for
>>   * this, letting us set arbitrary permissions for filesystem access without
>> @@ -454,6 +535,10 @@ int inode_permission(struct inode *inode, int mask)
>>  	if (retval)
>>  		return retval;
>>  
>> +	retval = omayexec_inode_permission(inode, mask);
>> +	if (retval)
>> +		return retval;
>> +
>>  	return security_inode_permission(inode, mask);
>>  }
>>  EXPORT_SYMBOL(inode_permission);
>> diff --git a/include/linux/fs.h b/include/linux/fs.h
>> index 79435fca6c3e..39c80a64d054 100644
>> --- a/include/linux/fs.h
>> +++ b/include/linux/fs.h
>> @@ -83,6 +83,9 @@ extern int sysctl_protected_symlinks;
>>  extern int sysctl_protected_hardlinks;
>>  extern int sysctl_protected_fifos;
>>  extern int sysctl_protected_regular;
>> +#ifndef CONFIG_OMAYEXEC_STATIC
>> +extern int sysctl_omayexec_enforce;
>> +#endif
> 
> Now there's no need to wrap this in ifdef.

Right, if the sysctl can't be disabled with a kernel configuration.

> 
>>  
>>  typedef __kernel_rwf_t rwf_t;
>>  
>> @@ -3545,6 +3548,8 @@ int proc_nr_dentry(struct ctl_table *table, int write,
>>  		  void __user *buffer, size_t *lenp, loff_t *ppos);
>>  int proc_nr_inodes(struct ctl_table *table, int write,
>>  		   void __user *buffer, size_t *lenp, loff_t *ppos);
>> +int proc_omayexec(struct ctl_table *table, int write, void __user *buffer,
>> +		size_t *lenp, loff_t *ppos);
>>  int __init get_filesystem_list(char *buf);
>>  
>>  #define __FMODE_EXEC		((__force int) FMODE_EXEC)
>> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
>> index 8a176d8727a3..29bbf79f444c 100644
>> --- a/kernel/sysctl.c
>> +++ b/kernel/sysctl.c
>> @@ -1892,6 +1892,15 @@ static struct ctl_table fs_table[] = {
>>  		.extra1		= SYSCTL_ZERO,
>>  		.extra2		= &two,
>>  	},
>> +#ifndef CONFIG_OMAYEXEC_STATIC
>> +	{
>> +		.procname       = "open_mayexec_enforce",
>> +		.data           = &sysctl_omayexec_enforce,
>> +		.maxlen         = sizeof(int),
>> +		.mode           = 0600,
>> +		.proc_handler   = proc_omayexec,
> 
> This can just be min/max of 0/3 with a new macadmin handler.

OK

> 
>> +	},
>> +#endif
>>  #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
>>  	{
>>  		.procname	= "binfmt_misc",
>> diff --git a/security/Kconfig b/security/Kconfig
>> index cd3cc7da3a55..d8fac9240d14 100644
>> --- a/security/Kconfig
>> +++ b/security/Kconfig
>> @@ -230,6 +230,32 @@ config STATIC_USERMODEHELPER_PATH
>>  	  If you wish for all usermode helper programs to be disabled,
>>  	  specify an empty string here (i.e. "").
>>  
>> +menuconfig OMAYEXEC_STATIC
>> +	tristate "Configure O_MAYEXEC behavior at build time"
>> +	---help---
>> +	  Enable to enforce O_MAYEXEC at build time, and disable the dedicated
>> +	  fs.open_mayexec_enforce sysctl.
>> +
>> +	  See Documentation/admin-guide/sysctl/fs.rst for more details.
>> +
>> +if OMAYEXEC_STATIC
>> +
>> +config OMAYEXEC_ENFORCE_MOUNT
>> +	bool "Mount restriction"
>> +	default y
>> +	---help---
>> +	  Forbid opening files with the O_MAYEXEC option if their underlying VFS is
>> +	  mounted with the noexec option or if their superblock forbids execution
>> +	  of its content (e.g., /proc).
>> +
>> +config OMAYEXEC_ENFORCE_FILE
>> +	bool "File permission restriction"
>> +	---help---
>> +	  Forbid opening files with the O_MAYEXEC option if they are not marked as
>> +	  executable for the current process (e.g., POSIX permissions).
>> +
>> +endif # OMAYEXEC_STATIC
>> +
>>  source "security/selinux/Kconfig"
>>  source "security/smack/Kconfig"
>>  source "security/tomoyo/Kconfig"
>> -- 
>> 2.26.2
>>
> 
> Otherwise, yeah, the intent here looks good to me.
> 

  reply index

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-05 15:31 [PATCH v5 0/6] Add support for O_MAYEXEC Mickaël Salaün
2020-05-05 15:31 ` [PATCH v5 1/6] fs: Add support for an O_MAYEXEC flag on openat2(2) Mickaël Salaün
2020-05-12 21:05   ` Kees Cook
2020-05-12 21:40     ` Christian Heimes
2020-05-12 22:56       ` Kees Cook
2020-05-13 10:13     ` Mickaël Salaün
2020-05-05 15:31 ` [PATCH v5 2/6] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property Mickaël Salaün
2020-05-12 21:09   ` Kees Cook
2020-05-14  8:14     ` Lev R. Oshvang .
2020-05-14 15:48       ` Kees Cook
2020-05-17 16:57         ` Lev R. Oshvang .
2020-05-05 15:31 ` [PATCH v5 3/6] fs: Enable to enforce noexec mounts or file exec through O_MAYEXEC Mickaël Salaün
2020-05-05 15:44   ` Randy Dunlap
2020-05-05 16:55     ` Mickaël Salaün
2020-05-05 17:40       ` Randy Dunlap
2020-05-12 21:48   ` Kees Cook
2020-05-13 11:09     ` Mickaël Salaün [this message]
2020-05-13 15:37   ` Stephen Smalley
2020-05-13 23:27     ` Kees Cook
2020-05-14  3:05       ` Kees Cook
2020-05-14 10:12         ` David Laight
2020-05-14 12:22         ` Stephen Smalley
2020-05-14 14:41           ` Kees Cook
2020-05-14 15:52             ` Stephen Smalley
2020-05-14 15:45           ` Kees Cook
2020-05-14 16:10             ` Stephen Smalley
2020-05-14 19:16               ` Mickaël Salaün
2020-05-15  0:58                 ` Tetsuo Handa
2020-05-15  8:01                 ` How about just O_EXEC? (was Re: [PATCH v5 3/6] fs: Enable to enforce noexec mounts or file exec through O_MAYEXEC) Kees Cook
2020-05-15  8:43                   ` Florian Weimer
2020-05-15 14:37                     ` Kees Cook
2020-05-15 14:43                       ` Florian Weimer
2020-05-15 15:50                         ` Kees Cook
2020-05-18  7:26                           ` Florian Weimer
2020-05-19  2:23                           ` Aleksa Sarai
2020-05-19 10:13                             ` Mickaël Salaün
2020-05-15 11:04                   ` Mickaël Salaün
2020-05-15 15:46                     ` Kees Cook
2020-05-15 18:24                       ` Mickaël Salaün
2020-05-14 19:21       ` [PATCH v5 3/6] fs: Enable to enforce noexec mounts or file exec through O_MAYEXEC Mickaël Salaün
2020-05-05 15:31 ` [PATCH v5 4/6] selftest/openat2: Add tests for O_MAYEXEC enforcing Mickaël Salaün
2020-05-12 21:57   ` Kees Cook
2020-05-13 11:18     ` Mickaël Salaün
2020-05-05 15:31 ` [PATCH v5 5/6] doc: Add documentation for the fs.open_mayexec_enforce sysctl Mickaël Salaün
2020-05-12 22:00   ` Kees Cook
2020-05-13 11:20     ` Mickaël Salaün
2020-05-05 15:31 ` [PATCH v5 6/6] ima: add policy support for the new file open MAY_OPENEXEC flag Mickaël Salaün
2020-05-05 15:36 ` [PATCH v5 0/6] Add support for O_MAYEXEC Mickaël Salaün
2020-05-06 13:58   ` Lev R. Oshvang .
2020-05-06 15:41     ` Aleksa Sarai
2020-05-07  8:30     ` Mickaël Salaün
2020-05-07  8:05 ` David Laight
2020-05-07  8:36   ` Mickaël Salaün
2020-05-07  9:00     ` David Laight
2020-05-07  9:30       ` Mickaël Salaün
2020-05-07  9:44         ` David Laight
2020-05-07 13:38           ` Mickaël Salaün
2020-05-08  7:15             ` Lev R. Oshvang .
2020-05-08 14:01               ` Mimi Zohar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6dbae682-e805-5567-39bd-4434d2cb9759@digikod.net \
    --to=mic@digikod.net \
    --cc=ast@kernel.org \
    --cc=christian@python.org \
    --cc=corbet@lwn.net \
    --cc=cyphar@cyphar.com \
    --cc=daniel@iogearbox.net \
    --cc=deven.desai@linux.microsoft.com \
    --cc=ericchiang@google.com \
    --cc=fweimer@redhat.com \
    --cc=jack@suse.cz \
    --cc=jannh@google.com \
    --cc=jmorris@namei.org \
    --cc=keescook@chromium.org \
    --cc=kernel-hardening@lists.openwall.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mickael.salaun@ssi.gouv.fr \
    --cc=mjg59@google.com \
    --cc=mtk.manpages@gmail.com \
    --cc=nramas@linux.microsoft.com \
    --cc=philippe.trebuchet@ssi.gouv.fr \
    --cc=scottsh@microsoft.com \
    --cc=sean.j.christopherson@intel.com \
    --cc=sgrubb@redhat.com \
    --cc=shuah@kernel.org \
    --cc=steve.dower@python.org \
    --cc=thibaut.sautereau@ssi.gouv.fr \
    --cc=vincent.strubel@ssi.gouv.fr \
    --cc=viro@zeniv.linux.org.uk \
    --cc=willy@infradead.org \
    --cc=zohar@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

LKML Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/lkml/0 lkml/git/0.git
	git clone --mirror https://lore.kernel.org/lkml/1 lkml/git/1.git
	git clone --mirror https://lore.kernel.org/lkml/2 lkml/git/2.git
	git clone --mirror https://lore.kernel.org/lkml/3 lkml/git/3.git
	git clone --mirror https://lore.kernel.org/lkml/4 lkml/git/4.git
	git clone --mirror https://lore.kernel.org/lkml/5 lkml/git/5.git
	git clone --mirror https://lore.kernel.org/lkml/6 lkml/git/6.git
	git clone --mirror https://lore.kernel.org/lkml/7 lkml/git/7.git
	git clone --mirror https://lore.kernel.org/lkml/8 lkml/git/8.git
	git clone --mirror https://lore.kernel.org/lkml/9 lkml/git/9.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 lkml lkml/ https://lore.kernel.org/lkml \
		linux-kernel@vger.kernel.org
	public-inbox-index lkml

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-kernel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git