* Re: [dm-devel] [RFC PATCH v5 00/11] Integrity Policy Enforcement LSM (IPE)
From: James Morris @ 2020-08-11 21:03 UTC (permalink / raw)
To: Chuck Lever
Cc: Mimi Zohar, James Bottomley, Deven Bowers, Pavel Machek,
Sasha Levin, snitzer, dm-devel, tyhicks, agk, Paul Moore,
Jonathan Corbet, nramas, serge, pasha.tatashin, Jann Horn,
linux-block, Al Viro, Jens Axboe, mdsakib, open list, eparis,
linux-security-module, linux-audit, linux-fsdevel,
linux-integrity, jaskarankhurana
In-Reply-To: <329E8DBA-049E-4959-AFD4-9D118DEB176E@gmail.com>
On Sat, 8 Aug 2020, Chuck Lever wrote:
> My interest is in code integrity enforcement for executables stored
> in NFS files.
>
> My struggle with IPE is that due to its dependence on dm-verity, it
> does not seem to able to protect content that is stored separately
> from its execution environment and accessed via a file access
> protocol (FUSE, SMB, NFS, etc).
It's not dependent on DM-Verity, that's just one possible integrity
verification mechanism, and one of two supported in this initial
version. The other is 'boot_verified' for a verified or otherwise trusted
rootfs. Future versions will support FS-Verity, at least.
IPE was designed to be extensible in this way, with a strong separation of
mechanism and policy.
Whatever is implemented for NFS should be able to plug in to IPE pretty
easily.
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Miklos Szeredi @ 2020-08-11 20:56 UTC (permalink / raw)
To: Jann Horn
Cc: Casey Schaufler, Andy Lutomirski, Linus Torvalds, linux-fsdevel,
David Howells, Al Viro, Karel Zak, Jeff Layton, Miklos Szeredi,
Nicolas Dichtel, Christian Brauner, Lennart Poettering, Linux API,
Ian Kent, LSM, Linux Kernel Mailing List
In-Reply-To: <CAG48ez3Li+HjJ6-wJwN-A84WT2MFE131Dt+6YiU96s+7NO5wkQ@mail.gmail.com>
On Tue, Aug 11, 2020 at 10:37 PM Jann Horn <jannh@google.com> wrote:
> If you change the semantics of path strings, you'd have to be
> confident that the new semantics fit nicely with all the path
> validation routines that exist scattered across userspace, and don't
> expose new interfaces through file server software and setuid binaries
> and so on.
So that's where O_ALT comes in. If the application is consenting,
then that should prevent exploits. Or?
Thanks,
Miklos
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Jann Horn @ 2020-08-11 20:36 UTC (permalink / raw)
To: Miklos Szeredi
Cc: Casey Schaufler, Andy Lutomirski, Linus Torvalds, linux-fsdevel,
David Howells, Al Viro, Karel Zak, Jeff Layton, Miklos Szeredi,
Nicolas Dichtel, Christian Brauner, Lennart Poettering, Linux API,
Ian Kent, LSM, Linux Kernel Mailing List
In-Reply-To: <CAJfpegvUBpb+C2Ab=CLAwWffOaeCedr-b7ZZKZnKvF4ph1nJrw@mail.gmail.com>
On Tue, Aug 11, 2020 at 10:29 PM Miklos Szeredi <miklos@szeredi.hu> wrote:
> On Tue, Aug 11, 2020 at 6:17 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> > Since a////////b has known meaning, and lots of applications
> > play loose with '/', its really dangerous to treat the string as
> > special. We only get away with '.' and '..' because their behavior
> > was defined before many of y'all were born.
>
> So the founding fathers have set things in stone and now we can't
> change it. Right?
>
> Well that's how it looks... but let's think a little; we have '/' and
> '\0' that can't be used in filenames. Also '.' and '..' are
> prohibited names. It's not a trivial limitation, so applications are
> probably not used to dumping binary data into file names. And that
> means it's probably possible to find a fairly short combination that
> is never used in practice (probably containing the "/." sequence).
> Why couldn't we reserve such a combination now?
This isn't just about finding a string that "is never used in
practice". There is userspace software that performs security checks
based on the precise semantics that paths have nowadays, and those
security checks will sometimes happily let you use arbitrary binary
garbage in path components as long as there's no '\0' or '/' in there
and the name isn't "." or "..", because that's just how paths work on
Linux.
If you change the semantics of path strings, you'd have to be
confident that the new semantics fit nicely with all the path
validation routines that exist scattered across userspace, and don't
expose new interfaces through file server software and setuid binaries
and so on.
I really don't like this idea.
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Miklos Szeredi @ 2020-08-11 20:28 UTC (permalink / raw)
To: Casey Schaufler
Cc: Andy Lutomirski, Linus Torvalds, linux-fsdevel, David Howells,
Al Viro, Karel Zak, Jeff Layton, Miklos Szeredi, Nicolas Dichtel,
Christian Brauner, Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <a6cd01ed-918a-0ed7-aa87-0585db7b6852@schaufler-ca.com>
On Tue, Aug 11, 2020 at 6:17 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> Since a////////b has known meaning, and lots of applications
> play loose with '/', its really dangerous to treat the string as
> special. We only get away with '.' and '..' because their behavior
> was defined before many of y'all were born.
So the founding fathers have set things in stone and now we can't
change it. Right?
Well that's how it looks... but let's think a little; we have '/' and
'\0' that can't be used in filenames. Also '.' and '..' are
prohibited names. It's not a trivial limitation, so applications are
probably not used to dumping binary data into file names. And that
means it's probably possible to find a fairly short combination that
is never used in practice (probably containing the "/." sequence).
Why couldn't we reserve such a combination now?
I have no idea how to find such it, but other than that, I see no
theoretical problem with extending the list of reserved filenames.
Thanks,
Miklos
^ permalink raw reply
* Re: [PATCH v7 5/7] fs,doc: Enable to enforce noexec mounts or file exec through O_MAYEXEC
From: Eric W. Biederman @ 2020-08-11 19:58 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
Andrew Morton, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Deven Bowers, Dmitry Vyukov,
Eric Biggers, Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jann Horn, Jonathan Corbet, Kees Cook, Lakshmi Ramasubramanian,
Matthew Garrett, Matthew Wilcox, Michael Kerrisk, Mimi Zohar,
Philippe Trébuchet, Scott Shell, Sean Christopherson,
Shuah Khan, Steve Dower, Steve Grubb, Tetsuo Handa,
Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
linux-integrity, linux-security-module, linux-fsdevel,
Thibaut Sautereau, Randy Dunlap
In-Reply-To: <20200723171227.446711-6-mic@digikod.net>
Mickaël Salaün <mic@digikod.net> writes:
> Allow for the enforcement of the O_MAYEXEC openat2(2) flag. 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.
Ick!!!!!
This feels like being so open minded your brains fall out.
I can see having a sysctl that allows the new open flag to be ignored
so that the existing lack of enforcement when the flag is passed
continues.
But having the sysctl be fine grained seems like way too much rope.
I don't think the code needs to do more than enforce or not enforce this
logic.
You can test the sysctl once when you process O_MAYEXEC. But code such
as may_open should not have the conditional behavior. It should get an
appropriate set of flags that are always enforced. With the madness of
what to do left at the edge of userspace.
Anything else appears to be madness, overengineering, and a failure to
separate concerns.
Eric
> 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.
>
> Being able to restrict execution also enables to protect the kernel by
> restricting arbitrary syscalls that an attacker could perform with a
> crafted binary or certain script languages. It also improves multilevel
> isolation by reducing the ability of an attacker to use side channels
> with specific code. These restrictions can natively be enforced for ELF
> binaries (with the noexec mount option) but require this kernel
> extension to properly handle scripts (e.g., Python, Perl). To get a
> consistent execution policy, additional memory restrictions should also
> be enforced (e.g. thanks to SELinux).
>
> Because the O_MAYEXEC flag is a meant to enforce a system-wide security
> policy (but not application-centric policies), it does not make sense
> for userland to check the sysctl value. Indeed, this new flag only
> enables to extend the system ability to enforce a policy thanks to (some
> trusted) userland collaboration. Moreover, additional security policies
> could be managed by LSMs. This is a best-effort approach from the
> application developer point of view:
> https://lore.kernel.org/lkml/1477d3d7-4b36-afad-7077-a38f42322238@digikod.net/
>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
> Cc: Aleksa Sarai <cyphar@cyphar.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Randy Dunlap <rdunlap@infradead.org>
> ---
>
> Changes since v6:
> * Allow opening pipes, block devices and character devices with
> O_MAYEXEC when there is no enforced policy, but forbid any non-regular
> file opened with O_MAYEXEC otherwise (i.e. for any enforced policy).
> * Add a paragraph about the non-regular files policy.
> * Move path_noexec() calls out of the fast-path (suggested by Kees
> Cook).
>
> Changes since v5:
> * Remove the static enforcement configuration through Kconfig because it
> makes the code more simple like this, and because the current sysctl
> configuration can only be set with CAP_SYS_ADMIN, the same way mount
> options (i.e. noexec) can be set. If an harden distro wants to
> enforce a configuration, it should restrict capabilities or sysctl
> configuration. Furthermore, an LSM can easily leverage O_MAYEXEC to
> fit its need.
> * Move checks from inode_permission() to may_open() and make the error
> codes more consistent according to file types (in line with a previous
> commit): opening a directory with O_MAYEXEC returns EISDIR and other
> non-regular file types may return EACCES.
> * In may_open(), when OMAYEXEC_ENFORCE_FILE is set, replace explicit
> call to generic_permission() with an artificial MAY_EXEC to avoid
> double calls. This makes sense especially when an LSM policy forbids
> execution of a file.
> * Replace the custom proc_omayexec() with
> proc_dointvec_minmax_sysadmin(), and then replace the CAP_MAC_ADMIN
> check with a CAP_SYS_ADMIN one (suggested by Kees Cook and Stephen
> Smalley).
> * Use BIT() (suggested by Kees Cook).
> * Rename variables (suggested by Kees Cook).
> * Reword the kconfig help.
> * Import the documentation patch (suggested by Kees Cook):
> https://lore.kernel.org/lkml/20200505153156.925111-6-mic@digikod.net/
> * Update documentation and add LWN.net article.
>
> Changes since v4:
> * Add kernel configuration options to enforce O_MAYEXEC at build time,
> and disable the sysctl in such case (requested by James Morris).
> * Reword commit message.
>
> Changes since v3:
> * Update comment with O_MAYEXEC.
>
> Changes since v2:
> * Cosmetic changes.
>
> Changes since v1:
> * Move code from Yama to the FS subsystem (suggested by Kees Cook).
> * Make omayexec_inode_permission() static (suggested by Jann Horn).
> * Use mode 0600 for the sysctl.
> * Only match regular files (not directories nor other types), which
> follows the same semantic as commit 73601ea5b7b1 ("fs/open.c: allow
> opening only regular files during execve()").
> ---
> Documentation/admin-guide/sysctl/fs.rst | 49 +++++++++++++++++++++++++
> fs/namei.c | 24 ++++++++++++
> include/linux/fs.h | 1 +
> kernel/sysctl.c | 12 +++++-
> 4 files changed, 84 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst
> index 2a45119e3331..ce6e2081d3a9 100644
> --- a/Documentation/admin-guide/sysctl/fs.rst
> +++ b/Documentation/admin-guide/sysctl/fs.rst
> @@ -37,6 +37,7 @@ Currently, these files are in /proc/sys/fs:
> - inode-nr
> - inode-state
> - nr_open
> +- open_mayexec_enforce
> - overflowuid
> - overflowgid
> - pipe-user-pages-hard
> @@ -165,6 +166,54 @@ system needs to prune the inode list instead of allocating
> more.
>
>
> +open_mayexec_enforce
> +--------------------
> +
> +While being ignored by :manpage:`open(2)` and :manpage:`openat(2)`, the
> +``O_MAYEXEC`` flag can be passed to :manpage:`openat2(2)` to only open regular
> +files that are expected to be executable. If the file is not identified as
> +executable, then the syscall returns -EACCES. This may allow a script
> +interpreter to check executable permission before reading commands from a file,
> +or a dynamic linker to only load executable shared objects. One interesting
> +use case is to enforce a "write xor execute" policy through interpreters.
> +
> +The ability to restrict code execution must be thought as a system-wide policy,
> +which first starts by restricting mount points with the ``noexec`` option.
> +This option is also automatically applied to special filesystems such as /proc .
> +This prevents files on such mount points to be directly executed by the kernel
> +or mapped as executable memory (e.g. libraries). With script interpreters
> +using the ``O_MAYEXEC`` flag, the executable permission can then be checked
> +before reading commands from files. This makes it possible to enforce the
> +``noexec`` at the interpreter level, and thus propagates this security policy
> +to scripts. To be fully effective, these interpreters also need to handle the
> +other ways to execute code: command line parameters (e.g., option ``-e`` for
> +Perl), module loading (e.g., option ``-m`` for Python), stdin, file sourcing,
> +environment variables, configuration files, etc. According to the threat
> +model, it may be acceptable to allow some script interpreters (e.g. Bash) to
> +interpret commands from stdin, may it be a TTY or a pipe, because it may not be
> +enough to (directly) perform syscalls.
> +
> +There are two complementary security policies: enforce the ``noexec`` mount
> +option, and enforce executable file permission. These policies are handled by
> +the ``fs.open_mayexec_enforce`` sysctl (writable only with ``CAP_SYS_ADMIN``)
> +as a bitmask:
> +
> +1 - Mount restriction: checks that the mount options for the underlying VFS
> + mount do not prevent execution.
> +
> +2 - File permission restriction: checks that the to-be-opened file is marked as
> + executable for the current process (e.g., POSIX permissions).
> +
> +Note that as long as a policy is enforced, opening any non-regular file with
> +``O_MAYEXEC`` is denied (e.g. TTYs, pipe), even when such a file is marked as
> +executable or is on an executable mount point.
> +
> +Code samples can be found in tools/testing/selftests/openat2/omayexec_test.c
> +and interpreter patches (for the original O_MAYEXEC version) may be found at
> +https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC .
> +See also an overview article: https://lwn.net/Articles/820000/ .
> +
> +
> overflowgid & overflowuid
> -------------------------
>
> diff --git a/fs/namei.c b/fs/namei.c
> index 3f074ec77390..8ec13c7fd403 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"
> @@ -425,6 +426,11 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
> return 0;
> }
>
> +#define OPEN_MAYEXEC_ENFORCE_MOUNT BIT(0)
> +#define OPEN_MAYEXEC_ENFORCE_FILE BIT(1)
> +
> +int sysctl_open_mayexec_enforce __read_mostly;
> +
> /**
> * inode_permission - Check for access rights to a given inode
> * @inode: Inode to check permission on
> @@ -2861,11 +2867,29 @@ static int may_open(const struct path *path, int acc_mode, int flag)
> case S_IFSOCK:
> if (acc_mode & MAY_EXEC)
> return -EACCES;
> + /*
> + * Opening devices (e.g. TTYs) or pipes with O_MAYEXEC may be
> + * legitimate when there is no enforced policy.
> + */
> + if ((acc_mode & MAY_OPENEXEC) && sysctl_open_mayexec_enforce)
> + return -EACCES;
> flag &= ~O_TRUNC;
> break;
> case S_IFREG:
> if ((acc_mode & MAY_EXEC) && path_noexec(path))
> return -EACCES;
> + if (acc_mode & MAY_OPENEXEC) {
> + if ((sysctl_open_mayexec_enforce & OPEN_MAYEXEC_ENFORCE_MOUNT)
> + && path_noexec(path))
> + return -EACCES;
> + if (sysctl_open_mayexec_enforce & OPEN_MAYEXEC_ENFORCE_FILE)
> + /*
> + * Because acc_mode may change here, the next and only
> + * use of acc_mode should then be by the following call
> + * to inode_permission().
> + */
> + acc_mode |= MAY_EXEC;
> + }
> break;
> }
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 56f835c9a87a..071f37707ccc 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -83,6 +83,7 @@ extern int sysctl_protected_symlinks;
> extern int sysctl_protected_hardlinks;
> extern int sysctl_protected_fifos;
> extern int sysctl_protected_regular;
> +extern int sysctl_open_mayexec_enforce;
>
> typedef __kernel_rwf_t rwf_t;
>
> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> index db1ce7af2563..5008a2566e79 100644
> --- a/kernel/sysctl.c
> +++ b/kernel/sysctl.c
> @@ -113,6 +113,7 @@ static int sixty = 60;
>
> static int __maybe_unused neg_one = -1;
> static int __maybe_unused two = 2;
> +static int __maybe_unused three = 3;
> static int __maybe_unused four = 4;
> static unsigned long zero_ul;
> static unsigned long one_ul = 1;
> @@ -888,7 +889,6 @@ static int proc_taint(struct ctl_table *table, int write,
> return err;
> }
>
> -#ifdef CONFIG_PRINTK
> static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
> void *buffer, size_t *lenp, loff_t *ppos)
> {
> @@ -897,7 +897,6 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
>
> return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> }
> -#endif
>
> /**
> * struct do_proc_dointvec_minmax_conv_param - proc_dointvec_minmax() range checking structure
> @@ -3264,6 +3263,15 @@ static struct ctl_table fs_table[] = {
> .extra1 = SYSCTL_ZERO,
> .extra2 = &two,
> },
> + {
> + .procname = "open_mayexec_enforce",
> + .data = &sysctl_open_mayexec_enforce,
> + .maxlen = sizeof(int),
> + .mode = 0600,
> + .proc_handler = proc_dointvec_minmax_sysadmin,
> + .extra1 = SYSCTL_ZERO,
> + .extra2 = &three,
> + },
> #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
> {
> .procname = "binfmt_misc",
^ permalink raw reply
* Re: [PATCH v7 4/7] fs: Introduce O_MAYEXEC flag for openat2(2)
From: Eric W. Biederman @ 2020-08-11 19:51 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
Andrew Morton, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Deven Bowers, Dmitry Vyukov,
Eric Biggers, Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jann Horn, Jonathan Corbet, Kees Cook, Lakshmi Ramasubramanian,
Matthew Garrett, Matthew Wilcox, Michael Kerrisk, Mimi Zohar,
Philippe Trébuchet, Scott Shell, Sean Christopherson,
Shuah Khan, Steve Dower, Steve Grubb, Tetsuo Handa,
Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
linux-integrity, linux-security-module, linux-fsdevel,
Thibaut Sautereau
In-Reply-To: <20200723171227.446711-5-mic@digikod.net>
Mickaël Salaün <mic@digikod.net> writes:
> When the O_MAYEXEC flag is passed, openat2(2) may be subject to
> additional restrictions depending on a security policy managed by the
> kernel through a sysctl or implemented by an LSM thanks to the
> inode_permission hook. This new flag is ignored by open(2) and
> openat(2) because of their unspecified flags handling. When used with
> openat2(2), the default behavior is only to forbid to open a directory.
>
> The underlying idea is to be able to restrict scripts interpretation
> according to a policy defined by the system administrator. For this to
> be possible, script interpreters must use the O_MAYEXEC flag
> appropriately. To be fully effective, these interpreters also need to
> handle the other ways to execute code: command line parameters (e.g.,
> option -e for Perl), module loading (e.g., option -m for Python), stdin,
> file sourcing, environment variables, configuration files, etc.
> According to the threat model, it may be acceptable to allow some script
> interpreters (e.g. Bash) to interpret commands from stdin, may it be a
> TTY or a pipe, because it may not be enough to (directly) perform
> syscalls. Further documentation can be found in a following patch.
>
> Even without enforced security policy, userland interpreters can set it
> to enforce the system policy at their level, knowing that it will not
> break anything on running systems which do not care about this feature.
> However, on systems which want this feature enforced, there will be
> knowledgeable people (i.e. sysadmins who enforced O_MAYEXEC
> deliberately) to manage it. A simple security policy implementation,
> configured through a dedicated sysctl, is available in a following
> patch.
>
> O_MAYEXEC should not be confused with the O_EXEC flag which is intended
> for execute-only, which obviously doesn't work for scripts. However, a
> similar behavior could be implemented in userland with O_PATH:
> https://lore.kernel.org/lkml/1e2f6913-42f2-3578-28ed-567f6a4bdda1@digikod.net/
>
> The implementation of O_MAYEXEC almost duplicates what execve(2) and
> uselib(2) are already doing: setting MAY_OPENEXEC in acc_mode (which can
> then be checked as MAY_EXEC, if enforced).
You are allowing S_IFBLK, S_IFCHR, S_IFIFO, S_IFSOCK as targets for
O_MAYEXEC?
You are not requiring the opened script be executable?
You are not requring path_noexec? Despite the original patch that
inspired this was checking path_noexec?
I honestly think this patch is buggy. If you could reuse MAY_EXEC in
the kernel and mean what exec means when it says MAY_EXEC that would be
useful.
As it is this patch appears wrong and dangerously confusing as it implies
execness but does not implement execness.
If you were simply defining O_EXEC and reusing MAY_EXEC as it exists
or exists with cleanups in the kernel this would be a small change that
would seem to make reasonable sense. But as you are not reusing
anything from MAY_EXEC this code does not make any sense as I am reading
it.
Eric
> This is an updated subset of the patch initially written by Vincent
> Strubel for CLIP OS 4:
> https://github.com/clipos-archive/src_platform_clip-patches/blob/f5cb330d6b684752e403b4e41b39f7004d88e561/1901_open_mayexec.patch
> This patch has been used for more than 12 years with customized script
> interpreters. Some examples (with the original O_MAYEXEC) can be found
> here:
> https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC
>
> Co-developed-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr>
> Signed-off-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr>
> Co-developed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
> Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> Cc: Aleksa Sarai <cyphar@cyphar.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Deven Bowers <deven.desai@linux.microsoft.com>
> Cc: Kees Cook <keescook@chromium.org>
> ---
>
> Changes since v6:
> * Do not set __FMODE_EXEC for now because of inconsistent behavior:
> https://lore.kernel.org/lkml/202007160822.CCDB5478@keescook/
> * Returns EISDIR when opening a directory with O_MAYEXEC.
> * Removed Deven Bowers and Kees Cook Reviewed-by tags because of the
> current update.
>
> Changes since v5:
> * Update commit message.
>
> Changes since v3:
> * Switch back to O_MAYEXEC, but only handle it with openat2(2) which
> checks unknown flags (suggested by Aleksa Sarai). Cf.
> https://lore.kernel.org/lkml/20200430015429.wuob7m5ofdewubui@yavin.dot.cyphar.com/
>
> Changes since v2:
> * Replace O_MAYEXEC with RESOLVE_MAYEXEC from openat2(2). This change
> enables to not break existing application using bogus O_* flags that
> may be ignored by current kernels by using a new dedicated flag, only
> usable through openat2(2) (suggested by Jeff Layton). Using this flag
> will results in an error if the running kernel does not support it.
> User space needs to manage this case, as with other RESOLVE_* flags.
> The best effort approach to security (for most common distros) will
> simply consists of ignoring such an error and retry without
> RESOLVE_MAYEXEC. However, a fully controlled system may which to
> error out if such an inconsistency is detected.
>
> Changes since v1:
> * Set __FMODE_EXEC when using O_MAYEXEC to make this information
> available through the new fanotify/FAN_OPEN_EXEC event (suggested by
> Jan Kara and Matthew Bobrowski):
> https://lore.kernel.org/lkml/20181213094658.GA996@lithium.mbobrowski.org/
> ---
> fs/fcntl.c | 2 +-
> fs/namei.c | 4 ++--
> fs/open.c | 6 ++++++
> include/linux/fcntl.h | 2 +-
> include/linux/fs.h | 2 ++
> include/uapi/asm-generic/fcntl.h | 7 +++++++
> 6 files changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fcntl.c b/fs/fcntl.c
> index 2e4c0fa2074b..0357ad667563 100644
> --- a/fs/fcntl.c
> +++ b/fs/fcntl.c
> @@ -1033,7 +1033,7 @@ static int __init fcntl_init(void)
> * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
> * is defined as O_NONBLOCK on some platforms and not on others.
> */
> - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ !=
> + BUILD_BUG_ON(22 - 1 /* for O_RDONLY being 0 */ !=
> HWEIGHT32(
> (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) |
> __FMODE_EXEC | __FMODE_NONOTIFY));
> diff --git a/fs/namei.c b/fs/namei.c
> index ddc9b25540fe..3f074ec77390 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -428,7 +428,7 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
> /**
> * 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)
> *
> * 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
> @@ -2849,7 +2849,7 @@ static int may_open(const struct path *path, int acc_mode, int flag)
> case S_IFLNK:
> return -ELOOP;
> case S_IFDIR:
> - if (acc_mode & (MAY_WRITE | MAY_EXEC))
> + if (acc_mode & (MAY_WRITE | MAY_EXEC | MAY_OPENEXEC))
> return -EISDIR;
> break;
> case S_IFBLK:
> diff --git a/fs/open.c b/fs/open.c
> index 623b7506a6db..21c2c1020574 100644
> --- a/fs/open.c
> +++ b/fs/open.c
> @@ -987,6 +987,8 @@ inline struct open_how build_open_how(int flags, umode_t mode)
> .mode = mode & S_IALLUGO,
> };
>
> + /* O_MAYEXEC is ignored by syscalls relying on build_open_how(). */
> + how.flags &= ~O_MAYEXEC;
> /* O_PATH beats everything else. */
> if (how.flags & O_PATH)
> how.flags &= O_PATH_FLAGS;
> @@ -1054,6 +1056,10 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op)
> if (flags & __O_SYNC)
> flags |= O_DSYNC;
>
> + /* Checks execution permissions on open. */
> + if (flags & O_MAYEXEC)
> + acc_mode |= MAY_OPENEXEC;
> +
> op->open_flag = flags;
>
> /* O_TRUNC implies we need access checks for write permissions */
> diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
> index 7bcdcf4f6ab2..e188a360fa5f 100644
> --- a/include/linux/fcntl.h
> +++ b/include/linux/fcntl.h
> @@ -10,7 +10,7 @@
> (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
> O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \
> FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
> - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
> + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_MAYEXEC)
>
> /* List of all valid flags for the how->upgrade_mask argument: */
> #define VALID_UPGRADE_FLAGS \
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index f5abba86107d..56f835c9a87a 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -101,6 +101,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
> #define MAY_CHDIR 0x00000040
> /* called from RCU mode, don't block */
> #define MAY_NOT_BLOCK 0x00000080
> +/* the inode is opened with O_MAYEXEC */
> +#define MAY_OPENEXEC 0x00000100
>
> /*
> * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond
> diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h
> index 9dc0bf0c5a6e..bca90620119f 100644
> --- a/include/uapi/asm-generic/fcntl.h
> +++ b/include/uapi/asm-generic/fcntl.h
> @@ -97,6 +97,13 @@
> #define O_NDELAY O_NONBLOCK
> #endif
>
> +/*
> + * Code execution from file is intended, checks such permission. A simple
> + * policy can be enforced system-wide as explained in
> + * Documentation/admin-guide/sysctl/fs.rst .
> + */
> +#define O_MAYEXEC 040000000
> +
> #define F_DUPFD 0 /* dup */
> #define F_GETFD 1 /* get close_on_exec */
> #define F_SETFD 2 /* set/clear close_on_exec */
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Christian Brauner @ 2020-08-11 19:50 UTC (permalink / raw)
To: Lennart Poettering
Cc: Miklos Szeredi, Linus Torvalds, linux-fsdevel, David Howells,
Al Viro, Karel Zak, Jeff Layton, Miklos Szeredi, Nicolas Dichtel,
Christian Brauner, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <20200811193105.GA228302@gardel-login>
On Tue, Aug 11, 2020 at 09:31:05PM +0200, Lennart Poettering wrote:
> On Di, 11.08.20 20:49, Miklos Szeredi (miklos@szeredi.hu) wrote:
>
> > On Tue, Aug 11, 2020 at 6:05 PM Linus Torvalds
> > <torvalds@linux-foundation.org> wrote:
> >
> > > and then people do "$(srctree)/". If you haven't seen that kind of
> > > pattern where the pathname has two (or sometimes more!) slashes in the
> > > middle, you've led a very sheltered life.
> >
> > Oh, I have. That's why I opted for triple slashes, since that should
> > work most of the time even in those concatenated cases. And yes, I
> > know, most is not always, and this might just be hiding bugs, etc...
> > I think the pragmatic approach would be to try this and see how many
> > triple slash hits a normal workload gets and if it's reasonably low,
> > then hopefully that together with warnings for O_ALT would be enough.
>
> There's no point. Userspace relies on the current meaning of triple
> slashes. It really does.
>
> I know many places in systemd where we might end up with a triple
> slash. Here's a real-life example: some code wants to access the
> cgroup attribute 'cgroup.controllers' of the root cgroup. It thus
> generates the right path in the fs for it, which is the concatenation of
> "/sys/fs/cgroup/" (because that's where cgroupfs is mounted), of "/"
> (i.e. for the root cgroup) and of "/cgroup.controllers" (as that's the
> file the attribute is exposed under).
>
> And there you go:
>
> "/sys/fs/cgroup/" + "/" + "/cgroup.controllers" → "/sys/fs/cgroup///cgroup.controllers"
>
> This is a real-life thing. Don't break this please.
Taken from a log from a container:
lxc f4 20200810105815.742 TRACE cgfsng - cgroups/cgfsng.c:cg_legacy_handle_cpuset_hierarchy:552 - "cgroup.clone_children" was already set to "1"
lxc f4 20200810105815.742 WARN cgfsng - cgroups/cgfsng.c:mkdir_eexist_on_last:1152 - File exists - Failed to create directory "/sys/fs/cgroup/cpuset///lxc.monitor.f4"
lxc f4 20200810105815.743 INFO cgfsng - cgroups/cgfsng.c:cgfsng_monitor_create:1366 - The monitor process uses "lxc.monitor.f4" as cgroup
lxc f4 20200810105815.743 DEBUG storage - storage/storage.c:get_storage_by_name:211 - Detected rootfs type "dir"
lxc f4 20200810105815.743 TRACE cgfsng - cgroups/cgfsng.c:cg_legacy_handle_cpuset_hierarchy:552 - "cgroup.clone_children" was already set to "1"
lxc f4 20200810105815.743 WARN cgfsng - cgroups/cgfsng.c:mkdir_eexist_on_last:1152 - File exists - Failed to create directory "/sys/fs/cgroup/cpuset///lxc.payload.f4"
lxc f4 20200810105815.743 INFO cgfsng - cgroups/cgfsng.c:cgfsng_payload_create:1469 - The container process uses "lxc.payload.f4" as cgroup
lxc f4 20200810105815.744 TRACE start - start.c:lxc_spawn:1731 - Spawned container directly into target cgroup via cgroup2 fd 17
Christian
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Lennart Poettering @ 2020-08-11 19:31 UTC (permalink / raw)
To: Miklos Szeredi
Cc: Linus Torvalds, linux-fsdevel, David Howells, Al Viro, Karel Zak,
Jeff Layton, Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Linux API, Ian Kent, LSM, Linux Kernel Mailing List
In-Reply-To: <CAJfpeguo5nAWcmduX4frknQGiRJeaj9Rdj018xUBrwqOJhVufw@mail.gmail.com>
On Di, 11.08.20 20:49, Miklos Szeredi (miklos@szeredi.hu) wrote:
> On Tue, Aug 11, 2020 at 6:05 PM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>
> > and then people do "$(srctree)/". If you haven't seen that kind of
> > pattern where the pathname has two (or sometimes more!) slashes in the
> > middle, you've led a very sheltered life.
>
> Oh, I have. That's why I opted for triple slashes, since that should
> work most of the time even in those concatenated cases. And yes, I
> know, most is not always, and this might just be hiding bugs, etc...
> I think the pragmatic approach would be to try this and see how many
> triple slash hits a normal workload gets and if it's reasonably low,
> then hopefully that together with warnings for O_ALT would be enough.
There's no point. Userspace relies on the current meaning of triple
slashes. It really does.
I know many places in systemd where we might end up with a triple
slash. Here's a real-life example: some code wants to access the
cgroup attribute 'cgroup.controllers' of the root cgroup. It thus
generates the right path in the fs for it, which is the concatenation of
"/sys/fs/cgroup/" (because that's where cgroupfs is mounted), of "/"
(i.e. for the root cgroup) and of "/cgroup.controllers" (as that's the
file the attribute is exposed under).
And there you go:
"/sys/fs/cgroup/" + "/" + "/cgroup.controllers" → "/sys/fs/cgroup///cgroup.controllers"
This is a real-life thing. Don't break this please.
Lennart
--
Lennart Poettering, Berlin
^ permalink raw reply
* Re: [PATCH v7 3/7] exec: Move path_noexec() check earlier
From: Eric W. Biederman @ 2020-08-11 19:36 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
Andrew Morton, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Deven Bowers, Dmitry Vyukov,
Eric Biggers, Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jann Horn, Jonathan Corbet, Kees Cook, Lakshmi Ramasubramanian,
Matthew Garrett, Matthew Wilcox, Michael Kerrisk, Mimi Zohar,
Philippe Trébuchet, Scott Shell, Sean Christopherson,
Shuah Khan, Steve Dower, Steve Grubb, Tetsuo Handa,
Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
linux-integrity, linux-security-module, linux-fsdevel
In-Reply-To: <20200723171227.446711-4-mic@digikod.net>
Mickaël Salaün <mic@digikod.net> writes:
> From: Kees Cook <keescook@chromium.org>
>
> The path_noexec() check, like the regular file check, was happening too
> late, letting LSMs see impossible execve()s. Check it earlier as well
> in may_open() and collect the redundant fs/exec.c path_noexec() test
> under the same robustness comment as the S_ISREG() check.
>
> My notes on the call path, and related arguments, checks, etc:
A big question arises, that I think someone already asked.
Why perform this test in may_open directly instead of moving
it into inode_permission. That way the code can be shared with
faccessat, and any other code path that wants it?
That would look to provide a more maintainable kernel.
Eric
> do_open_execat()
> struct open_flags open_exec_flags = {
> .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
> .acc_mode = MAY_EXEC,
> ...
> do_filp_open(dfd, filename, open_flags)
> path_openat(nameidata, open_flags, flags)
> file = alloc_empty_file(open_flags, current_cred());
> do_open(nameidata, file, open_flags)
> may_open(path, acc_mode, open_flag)
> /* new location of MAY_EXEC vs path_noexec() test */
> inode_permission(inode, MAY_OPEN | acc_mode)
> security_inode_permission(inode, acc_mode)
> vfs_open(path, file)
> do_dentry_open(file, path->dentry->d_inode, open)
> security_file_open(f)
> open()
> /* old location of path_noexec() test */
>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Link: https://lore.kernel.org/r/20200605160013.3954297-4-keescook@chromium.org
> ---
> fs/exec.c | 12 ++++--------
> fs/namei.c | 4 ++++
> 2 files changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/fs/exec.c b/fs/exec.c
> index bdc6a6eb5dce..4eea20c27b01 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -147,10 +147,8 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
> * and check again at the very end too.
> */
> error = -EACCES;
> - if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)))
> - goto exit;
> -
> - if (path_noexec(&file->f_path))
> + if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) ||
> + path_noexec(&file->f_path)))
> goto exit;
>
> fsnotify_open(file);
> @@ -897,10 +895,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
> * and check again at the very end too.
> */
> err = -EACCES;
> - if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)))
> - goto exit;
> -
> - if (path_noexec(&file->f_path))
> + if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) ||
> + path_noexec(&file->f_path)))
> goto exit;
>
> err = deny_write_access(file);
> diff --git a/fs/namei.c b/fs/namei.c
> index a559ad943970..ddc9b25540fe 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -2863,6 +2863,10 @@ static int may_open(const struct path *path, int acc_mode, int flag)
> return -EACCES;
> flag &= ~O_TRUNC;
> break;
> + case S_IFREG:
> + if ((acc_mode & MAY_EXEC) && path_noexec(path))
> + return -EACCES;
> + break;
> }
>
> error = inode_permission(inode, MAY_OPEN | acc_mode);
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Christian Brauner @ 2020-08-11 19:39 UTC (permalink / raw)
To: Linus Torvalds
Cc: Miklos Szeredi, linux-fsdevel, David Howells, Al Viro, Karel Zak,
Jeff Layton, Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <CAHk-=wg_bfVf5eazwH2uXTG-auCYZUpq-xb1kDeNjY7yaXS7bw@mail.gmail.com>
On Tue, Aug 11, 2020 at 09:05:22AM -0700, Linus Torvalds wrote:
> On Tue, Aug 11, 2020 at 8:30 AM Miklos Szeredi <miklos@szeredi.hu> wrote:
> >
> > What's the disadvantage of doing it with a single lookup WITH an enabling flag?
> >
> > It's definitely not going to break anything, so no backward
> > compatibility issues whatsoever.
>
> No backwards compatibility issues for existing programs, no.
>
> But your suggestion is fundamentally ambiguous, and you most
> definitely *can* hit that if people start using this in new programs.
>
> Where does that "unified" pathname come from? It will be generated
> from "base filename + metadata name" in user space, and
>
> (a) the base filename might have double or triple slashes in it for
> whatever reasons.
>
> This is not some "made-up gotcha" thing - I see double slashes *all*
> the time when we have things like Makefiles doing
>
> srctree=../../src/
>
> and then people do "$(srctree)/". If you haven't seen that kind of
> pattern where the pathname has two (or sometimes more!) slashes in the
> middle, you've led a very sheltered life.
>
> (b) even if the new user space were to think about that, and remove
> those (hah! when have you ever seen user space do that?), as Al
> mentioned, the user *filesystem* might have pathnames with double
> slashes as part of symlinks.
>
> So now we'd have to make sure that when we traverse symlinks, that
> O_ALT gets cleared. Which means that it's not a unified namespace
> after all, because you can't make symlinks point to metadata.
>
> Or we'd retroactively change the semantics of a symlink, and that _is_
> a backwards compatibility issue. Not with old software, no, but it
> changes the meaning of old symlinks!
>
> So no, I don't think a unified namespace ends up working.
>
> And I say that as somebody who actually loves the concept. Ask Al: I
> have a few times pushed for "let's allow directory behavior on regular
> files", so that you could do things like a tar-filesystem, and access
> the contents of a tar-file by just doing
>
> cat my-file.tar/inside/the/archive.c
>
> or similar.
>
> Al has convinced me it's a horrible idea (and there you have a
> non-ambiguous marker: the slash at the end of a pathname that
> otherwise looks and acts as a non-directory)
>
Putting my kernel hat down, putting my userspace hat on.
I'm looking at this from a potential user of this interface.
I'm not a huge fan of the metadata fd approach I'd much rather have a
dedicated system call rather than opening a side-channel metadata fd
that I can read binary data from. Maybe I'm alone in this but I was
under the impression that other users including Ian, Lennart, and Karel
have said on-list in some form that they would prefer this approach.
There are even patches for systemd and libmount, I thought?
But if we want to go down a completely different route then I'd prefer
if this metadata fd with "special semantics" did not in any way alter
the meaning of regular paths. This has the potential to cause a lot of
churn for userspace. I think having to play concatenation games in
shared libraries for mount information is a bad plan in addition to all
the issues you raised here.
Christian
^ permalink raw reply
* Re: [PATCH v7 2/7] exec: Move S_ISREG() check earlier
From: Eric W. Biederman @ 2020-08-11 19:27 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
Andrew Morton, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Deven Bowers, Dmitry Vyukov,
Eric Biggers, Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jann Horn, Jonathan Corbet, Kees Cook, Lakshmi Ramasubramanian,
Matthew Garrett, Matthew Wilcox, Michael Kerrisk, Mimi Zohar,
Philippe Trébuchet, Scott Shell, Sean Christopherson,
Shuah Khan, Steve Dower, Steve Grubb, Tetsuo Handa,
Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
linux-integrity, linux-security-module, linux-fsdevel
In-Reply-To: <20200723171227.446711-3-mic@digikod.net>
Mickaël Salaün <mic@digikod.net> writes:
> From: Kees Cook <keescook@chromium.org>
>
> The execve(2)/uselib(2) syscalls have always rejected non-regular
> files. Recently, it was noticed that a deadlock was introduced when trying
> to execute pipes, as the S_ISREG() test was happening too late. This was
> fixed in commit 73601ea5b7b1 ("fs/open.c: allow opening only regular files
> during execve()"), but it was added after inode_permission() had already
> run, which meant LSMs could see bogus attempts to execute non-regular
> files.
>
> Move the test into the other inode type checks (which already look
> for other pathological conditions[1]). Since there is no need to use
> FMODE_EXEC while we still have access to "acc_mode", also switch the
> test to MAY_EXEC.
>
> Also include a comment with the redundant S_ISREG() checks at the end of
> execve(2)/uselib(2) to note that they are present to avoid any mistakes.
The comment is:
> + /*
> + * may_open() has already checked for this, so it should be
> + * impossible to trip now. But we need to be extra cautious
> + * and check again at the very end too.
> + */
Those comments scare me. Why do you need to be extra cautious?
How can the file type possibly change between may_open and anywhere?
The type of a file is immutable after it's creation.
If the comment said check just in case something went wrong with
code maintenance I could understand but that isn't what the comment
says.
Also the fallthrough change below really should be broken out into
it's own change.
> My notes on the call path, and related arguments, checks, etc:
>
> do_open_execat()
> struct open_flags open_exec_flags = {
> .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
> .acc_mode = MAY_EXEC,
> ...
> do_filp_open(dfd, filename, open_flags)
> path_openat(nameidata, open_flags, flags)
> file = alloc_empty_file(open_flags, current_cred());
> do_open(nameidata, file, open_flags)
> may_open(path, acc_mode, open_flag)
> /* new location of MAY_EXEC vs S_ISREG() test */
> inode_permission(inode, MAY_OPEN | acc_mode)
> security_inode_permission(inode, acc_mode)
> vfs_open(path, file)
> do_dentry_open(file, path->dentry->d_inode, open)
> /* old location of FMODE_EXEC vs S_ISREG() test */
> security_file_open(f)
> open()
>
> [1] https://lore.kernel.org/lkml/202006041910.9EF0C602@keescook/
>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Link: https://lore.kernel.org/r/20200605160013.3954297-3-keescook@chromium.org
> ---
> fs/exec.c | 14 ++++++++++++--
> fs/namei.c | 6 ++++--
> fs/open.c | 6 ------
> 3 files changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/fs/exec.c b/fs/exec.c
> index d7c937044d10..bdc6a6eb5dce 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -141,8 +141,13 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
> if (IS_ERR(file))
> goto out;
>
> + /*
> + * may_open() has already checked for this, so it should be
> + * impossible to trip now. But we need to be extra cautious
> + * and check again at the very end too.
> + */
> error = -EACCES;
> - if (!S_ISREG(file_inode(file)->i_mode))
> + if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)))
> goto exit;
>
> if (path_noexec(&file->f_path))
> @@ -886,8 +891,13 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
> if (IS_ERR(file))
> goto out;
>
> + /*
> + * may_open() has already checked for this, so it should be
> + * impossible to trip now. But we need to be extra cautious
> + * and check again at the very end too.
> + */
> err = -EACCES;
> - if (!S_ISREG(file_inode(file)->i_mode))
> + if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)))
> goto exit;
>
> if (path_noexec(&file->f_path))
> diff --git a/fs/namei.c b/fs/namei.c
> index 72d4219c93ac..a559ad943970 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -2849,16 +2849,18 @@ static int may_open(const struct path *path, int acc_mode, int flag)
> case S_IFLNK:
> return -ELOOP;
> case S_IFDIR:
> - if (acc_mode & MAY_WRITE)
> + if (acc_mode & (MAY_WRITE | MAY_EXEC))
> return -EISDIR;
> break;
> case S_IFBLK:
> case S_IFCHR:
> if (!may_open_dev(path))
> return -EACCES;
> - /*FALLTHRU*/
> + fallthrough;
^^^^^^^^^^^
That is an unrelated change and should be sent separately.
> case S_IFIFO:
> case S_IFSOCK:
> + if (acc_mode & MAY_EXEC)
> + return -EACCES;
> flag &= ~O_TRUNC;
> break;
> }
> diff --git a/fs/open.c b/fs/open.c
> index 6cd48a61cda3..623b7506a6db 100644
> --- a/fs/open.c
> +++ b/fs/open.c
> @@ -784,12 +784,6 @@ static int do_dentry_open(struct file *f,
> return 0;
> }
>
> - /* Any file opened for execve()/uselib() has to be a regular file. */
> - if (unlikely(f->f_flags & FMODE_EXEC && !S_ISREG(inode->i_mode))) {
> - error = -EACCES;
> - goto cleanup_file;
> - }
> -
> if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
> error = get_write_access(inode);
> if (unlikely(error))
^ permalink raw reply
* Re: [dm-devel] [RFC PATCH v5 00/11] Integrity Policy Enforcement LSM (IPE)
From: Pavel Machek @ 2020-08-11 19:30 UTC (permalink / raw)
To: James Bottomley
Cc: Chuck Lever, Mimi Zohar, James Morris, Deven Bowers, Sasha Levin,
snitzer, dm-devel, tyhicks, agk, Paul Moore, Jonathan Corbet,
nramas, serge, pasha.tatashin, Jann Horn, linux-block, Al Viro,
Jens Axboe, mdsakib, open list, eparis, linux-security-module,
linux-audit, linux-fsdevel, linux-integrity, jaskarankhurana
In-Reply-To: <1597159969.4325.21.camel@HansenPartnership.com>
[-- Attachment #1: Type: text/plain, Size: 2609 bytes --]
Hi!
> > > > (eg, a specification) will be critical for remote filesystems.
> > > >
> > > > If any of this is to be supported by a remote filesystem, then we
> > > > need an unencumbered description of the new metadata format
> > > > rather than code. GPL-encumbered formats cannot be contributed to
> > > > the NFS standard, and are probably difficult for other
> > > > filesystems that are not Linux-native, like SMB, as well.
> > >
> > > I don't understand what you mean by GPL encumbered formats. The
> > > GPL is a code licence not a data or document licence.
> >
> > IETF contributions occur under a BSD-style license incompatible
> > with the GPL.
> >
> > https://trustee.ietf.org/trust-legal-provisions.html
> >
> > Non-Linux implementers (of OEM storage devices) rely on such
> > standards processes to indemnify them against licensing claims.
>
> Well, that simply means we won't be contributing the Linux
> implementation, right? However, IETF doesn't require BSD for all
> implementations, so that's OK.
>
> > Today, there is no specification for existing IMA metadata formats,
> > there is only code. My lawyer tells me that because the code that
> > implements these formats is under GPL, the formats themselves cannot
> > be contributed to, say, the IETF without express permission from the
> > authors of that code. There are a lot of authors of the Linux IMA
> > code, so this is proving to be an impediment to contribution. That
> > blocks the ability to provide a fully-specified NFS protocol
> > extension to support IMA metadata formats.
>
> Well, let me put the counterpoint: I can write a book about how
> linux
You should probably talk to your lawyer.
> device drivers work (which includes describing the data formats), for
> instance, without having to get permission from all the authors ... or
> is your lawyer taking the view we should be suing Jonathan Corbet,
> Alessandro Rubini, and Greg Kroah-Hartman for licence infringement? In
> fact do they think we now have a huge class action possibility against
> O'Reilly and a host of other publishers ...
Because yes, you can reverse engineer for compatibility reasons --
doing clean room re-implementation (BIOS binary -> BIOS documentation
-> BIOS sources under different license), but that was only tested in
the US, is expensive, and I understand people might be uncomfortable
doing that.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
^ permalink raw reply
* [PATCH v2 2/2] ima: Fail rule parsing when asymmetric key measurement isn't supportable
From: Tyler Hicks @ 2020-08-11 19:26 UTC (permalink / raw)
To: Mimi Zohar, Dmitry Kasatkin
Cc: James Morris, Serge E . Hallyn, Lakshmi Ramasubramanian,
Tushar Sugandhi, Nayna Jain, linux-kernel, linux-integrity,
linux-security-module
In-Reply-To: <20200811192621.281675-1-tyhicks@linux.microsoft.com>
Measuring keys is currently only supported for asymmetric keys. In the
future, this might change.
For now, the "func=KEY_CHECK" and "keyrings=" options are only
appropriate when CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS is enabled. Make
this clear at policy load so that IMA policy authors don't assume that
these policy language constructs are supported.
Fixes: 2b60c0ecedf8 ("IMA: Read keyrings= option from the IMA policy")
Fixes: 5808611cccb2 ("IMA: Add KEY_CHECK func to measure keys")
Suggested-by: Nayna Jain <nayna@linux.ibm.com>
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
---
security/integrity/ima/ima_policy.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index ea224f00b305..fe1df373c113 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1233,7 +1233,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->func = POLICY_CHECK;
else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0)
entry->func = KEXEC_CMDLINE;
- else if (strcmp(args[0].from, "KEY_CHECK") == 0)
+ else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) &&
+ strcmp(args[0].from, "KEY_CHECK") == 0)
entry->func = KEY_CHECK;
else
result = -EINVAL;
@@ -1290,7 +1291,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
case Opt_keyrings:
ima_log_string(ab, "keyrings", args[0].from);
- if (entry->keyrings) {
+ if (!IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) ||
+ entry->keyrings) {
result = -EINVAL;
break;
}
--
2.25.1
^ permalink raw reply related
* [PATCH v2 1/2] ima: Pre-parse the list of keyrings in a KEY_CHECK rule
From: Tyler Hicks @ 2020-08-11 19:26 UTC (permalink / raw)
To: Mimi Zohar, Dmitry Kasatkin
Cc: James Morris, Serge E . Hallyn, Lakshmi Ramasubramanian,
Tushar Sugandhi, Nayna Jain, linux-kernel, linux-integrity,
linux-security-module
In-Reply-To: <20200811192621.281675-1-tyhicks@linux.microsoft.com>
The ima_keyrings buffer was used as a work buffer for strsep()-based
parsing of the "keyrings=" option of an IMA policy rule. This parsing
was re-performed each time an asymmetric key was added to a kernel
keyring for each loaded policy rule that contained a "keyrings=" option.
An example rule specifying this option is:
measure func=KEY_CHECK keyrings=a|b|c
The rule says to measure asymmetric keys added to any of the kernel
keyrings named "a", "b", or "c". The size of the buffer size was
equal to the size of the largest "keyrings=" value seen in a previously
loaded rule (5 + 1 for the NUL-terminator in the previous example) and
the buffer was pre-allocated at the time of policy load.
The pre-allocated buffer approach suffered from a couple bugs:
1) There was no locking around the use of the buffer so concurrent key
add operations, to two different keyrings, would result in the
strsep() loop of ima_match_keyring() to modify the buffer at the same
time. This resulted in unexpected results from ima_match_keyring()
and, therefore, could cause unintended keys to be measured or keys to
not be measured when IMA policy intended for them to be measured.
2) If the kstrdup() that initialized entry->keyrings in ima_parse_rule()
failed, the ima_keyrings buffer was freed and set to NULL even when a
valid KEY_CHECK rule was previously loaded. The next KEY_CHECK event
would trigger a call to strcpy() with a NULL destination pointer and
crash the kernel.
Remove the need for a pre-allocated global buffer by parsing the list of
keyrings in a KEY_CHECK rule at the time of policy load. The
ima_rule_entry will contain an array of string pointers which point to
the name of each keyring specified in the rule. No string processing
needs to happen at the time of asymmetric key add so iterating through
the list and doing a string comparison is all that's required at the
time of policy check.
In the process of changing how the "keyrings=" policy option is handled,
a couple additional bugs were fixed:
1) The rule parser accepted rules containing invalid "keyrings=" values
such as "a|b||c", "a|b|", or simply "|".
2) The /sys/kernel/security/ima/policy file did not display the entire
"keyrings=" value if the list of keyrings was longer than what could
fit in the fixed size tbuf buffer in ima_policy_show().
Fixes: 5c7bac9fb2c5 ("IMA: pre-allocate buffer to hold keyrings string")
Fixes: 2b60c0ecedf8 ("IMA: Read keyrings= option from the IMA policy")
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
---
security/integrity/ima/ima_policy.c | 138 +++++++++++++++++++---------
1 file changed, 93 insertions(+), 45 deletions(-)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 07f033634b27..ea224f00b305 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -59,6 +59,11 @@ enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB };
enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY };
+struct ima_rule_opt_list {
+ size_t count;
+ char *items[];
+};
+
struct ima_rule_entry {
struct list_head list;
int action;
@@ -78,7 +83,7 @@ struct ima_rule_entry {
int type; /* audit type */
} lsm[MAX_LSM_RULES];
char *fsname;
- char *keyrings; /* Measure keys added to these keyrings */
+ struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
struct ima_template_desc *template;
};
@@ -206,10 +211,6 @@ static LIST_HEAD(ima_policy_rules);
static LIST_HEAD(ima_temp_rules);
static struct list_head *ima_rules = &ima_default_rules;
-/* Pre-allocated buffer used for matching keyrings. */
-static char *ima_keyrings;
-static size_t ima_keyrings_len;
-
static int ima_policy __initdata;
static int __init default_measure_policy_setup(char *str)
@@ -253,6 +254,72 @@ static int __init default_appraise_policy_setup(char *str)
}
__setup("ima_appraise_tcb", default_appraise_policy_setup);
+static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
+{
+ struct ima_rule_opt_list *opt_list;
+ size_t count = 0;
+ char *src_copy;
+ char *cur, *next;
+ size_t i;
+
+ src_copy = match_strdup(src);
+ if (!src_copy)
+ return ERR_PTR(-ENOMEM);
+
+ next = src_copy;
+ while ((cur = strsep(&next, "|"))) {
+ /* Don't accept an empty list item */
+ if (!(*cur)) {
+ kfree(src_copy);
+ return ERR_PTR(-EINVAL);
+ }
+ count++;
+ }
+
+ /* Don't accept an empty list */
+ if (!count) {
+ kfree(src_copy);
+ return ERR_PTR(-EINVAL);
+ }
+
+ opt_list = kzalloc(struct_size(opt_list, items, count), GFP_KERNEL);
+ if (!opt_list) {
+ kfree(src_copy);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * strsep() has already replaced all instances of '|' with '\0',
+ * leaving a byte sequence of NUL-terminated strings. Reference each
+ * string with the array of items.
+ *
+ * IMPORTANT: Ownership of the allocated buffer is transferred from
+ * src_copy to the first element in the items array. To free the
+ * buffer, kfree() must only be called on the first element of the
+ * array.
+ */
+ for (i = 0, cur = src_copy; i < count; i++) {
+ opt_list->items[i] = cur;
+ cur = strchr(cur, '\0') + 1;
+ }
+ opt_list->count = count;
+
+ return opt_list;
+}
+
+static void ima_free_rule_opt_list(struct ima_rule_opt_list *opt_list)
+{
+ if (!opt_list)
+ return;
+
+ if (opt_list->count) {
+ kfree(opt_list->items[0]);
+ opt_list->count = 0;
+ }
+
+ kfree(opt_list);
+}
+
static void ima_lsm_free_rule(struct ima_rule_entry *entry)
{
int i;
@@ -274,7 +341,7 @@ static void ima_free_rule(struct ima_rule_entry *entry)
* the defined_templates list and cannot be freed here
*/
kfree(entry->fsname);
- kfree(entry->keyrings);
+ ima_free_rule_opt_list(entry->keyrings);
ima_lsm_free_rule(entry);
kfree(entry);
}
@@ -394,8 +461,8 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
static bool ima_match_keyring(struct ima_rule_entry *rule,
const char *keyring, const struct cred *cred)
{
- char *next_keyring, *keyrings_ptr;
bool matched = false;
+ size_t i;
if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
return false;
@@ -406,15 +473,8 @@ static bool ima_match_keyring(struct ima_rule_entry *rule,
if (!keyring)
return false;
- strcpy(ima_keyrings, rule->keyrings);
-
- /*
- * "keyrings=" is specified in the policy in the format below:
- * keyrings=.builtin_trusted_keys|.ima|.evm
- */
- keyrings_ptr = ima_keyrings;
- while ((next_keyring = strsep(&keyrings_ptr, "|")) != NULL) {
- if (!strcmp(next_keyring, keyring)) {
+ for (i = 0; i < rule->keyrings->count; i++) {
+ if (!strcmp(rule->keyrings->items[i], keyring)) {
matched = true;
break;
}
@@ -1065,7 +1125,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
bool uid_token;
struct ima_template_desc *template_desc;
int result = 0;
- size_t keyrings_len;
ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_INTEGRITY_POLICY_RULE);
@@ -1231,37 +1290,18 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
case Opt_keyrings:
ima_log_string(ab, "keyrings", args[0].from);
- keyrings_len = strlen(args[0].from) + 1;
-
- if ((entry->keyrings) ||
- (keyrings_len < 2)) {
+ if (entry->keyrings) {
result = -EINVAL;
break;
}
- if (keyrings_len > ima_keyrings_len) {
- char *tmpbuf;
-
- tmpbuf = krealloc(ima_keyrings, keyrings_len,
- GFP_KERNEL);
- if (!tmpbuf) {
- result = -ENOMEM;
- break;
- }
-
- ima_keyrings = tmpbuf;
- ima_keyrings_len = keyrings_len;
- }
-
- entry->keyrings = kstrdup(args[0].from, GFP_KERNEL);
- if (!entry->keyrings) {
- kfree(ima_keyrings);
- ima_keyrings = NULL;
- ima_keyrings_len = 0;
- result = -ENOMEM;
+ entry->keyrings = ima_alloc_rule_opt_list(args);
+ if (IS_ERR(entry->keyrings)) {
+ result = PTR_ERR(entry->keyrings);
+ entry->keyrings = NULL;
break;
}
- result = 0;
+
entry->flags |= IMA_KEYRINGS;
break;
case Opt_fsuuid:
@@ -1574,6 +1614,15 @@ static void policy_func_show(struct seq_file *m, enum ima_hooks func)
seq_printf(m, "func=%d ", func);
}
+static void ima_show_rule_opt_list(struct seq_file *m,
+ const struct ima_rule_opt_list *opt_list)
+{
+ size_t i;
+
+ for (i = 0; i < opt_list->count; i++)
+ seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]);
+}
+
int ima_policy_show(struct seq_file *m, void *v)
{
struct ima_rule_entry *entry = v;
@@ -1630,9 +1679,8 @@ int ima_policy_show(struct seq_file *m, void *v)
}
if (entry->flags & IMA_KEYRINGS) {
- if (entry->keyrings != NULL)
- snprintf(tbuf, sizeof(tbuf), "%s", entry->keyrings);
- seq_printf(m, pt(Opt_keyrings), tbuf);
+ seq_puts(m, "keyrings=");
+ ima_show_rule_opt_list(m, entry->keyrings);
seq_puts(m, " ");
}
--
2.25.1
^ permalink raw reply related
* [PATCH v2 0/2] ima: Fix keyrings race condition and other key related bugs
From: Tyler Hicks @ 2020-08-11 19:26 UTC (permalink / raw)
To: Mimi Zohar, Dmitry Kasatkin
Cc: James Morris, Serge E . Hallyn, Lakshmi Ramasubramanian,
Tushar Sugandhi, Nayna Jain, linux-kernel, linux-integrity,
linux-security-module
v2:
- Always return an ERR_PTR from ima_alloc_rule_opt_list() (Nayna)
- Add Lakshmi's Reviewed-by to both patches
- Rebased on commit 3db0d0c276a7 ("integrity: remove redundant
initialization of variable ret") of next-integrity
v1: https://lore.kernel.org/lkml/20200727140831.64251-1-tyhicks@linux.microsoft.com/
Nayna pointed out that the "keyrings=" option in an IMA policy rule
should only be accepted when CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS is
enabled:
https://lore.kernel.org/linux-integrity/336cc947-1f70-0286-6506-6df3d1d23a1d@linux.vnet.ibm.com/
While fixing this, the compiler warned me about the potential for the
ima_keyrings pointer to be NULL despite it being used, without a check
for NULL, as the destination address for the strcpy() in
ima_match_keyring().
It also became apparent that there was not adequate locking around the
use of the pre-allocated buffer that ima_keyrings points to. The kernel
keyring has a lock (.sem member of struct key) that ensures only one key
can be added to a given keyring at a time but there's no protection
against adding multiple keys to different keyrings at the same time.
The first patch in this series fixes both ima_keyrings related issues by
parsing the list of keyrings in a KEY_CHECK rule at policy load time
rather than deferring the parsing to policy check time. Once that fix is
in place, the second patch can enforce that
CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS must be enabled in order to use
"func=KEY_CHECK" or "keyrings=" options in IMA policy.
The new "keyrings=" value handling is done in a generic manner that can
be reused by other options in the future. This seems to make sense as
"appraise_type=" has similar style (though it doesn't need to be fully
parsed at this time) and using "|" as an alternation delimiter is
becoming the norm in IMA policy.
This series is based on commit 311aa6aafea4 ("ima: move
APPRAISE_BOOTPARAM dependency on ARCH_POLICY to runtime") in
next-integrity.
Tyler
Tyler Hicks (2):
ima: Pre-parse the list of keyrings in a KEY_CHECK rule
ima: Fail rule parsing when asymmetric key measurement isn't
supportable
security/integrity/ima/ima_policy.c | 142 +++++++++++++++++++---------
1 file changed, 96 insertions(+), 46 deletions(-)
--
2.25.1
^ permalink raw reply
* Re: [PATCH v7 1/7] exec: Change uselib(2) IS_SREG() failure to EACCES
From: Eric W. Biederman @ 2020-08-11 19:14 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
Andrew Morton, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Deven Bowers, Dmitry Vyukov,
Eric Biggers, Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jann Horn, Jonathan Corbet, Kees Cook, Lakshmi Ramasubramanian,
Matthew Garrett, Matthew Wilcox, Michael Kerrisk, Mimi Zohar,
Philippe Trébuchet, Scott Shell, Sean Christopherson,
Shuah Khan, Steve Dower, Steve Grubb, Tetsuo Handa,
Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
linux-integrity, linux-security-module, linux-fsdevel
In-Reply-To: <87eeodnh3v.fsf@x220.int.ebiederm.org>
ebiederm@xmission.com (Eric W. Biederman) writes:
> Mickaël Salaün <mic@digikod.net> writes:
>
>> From: Kees Cook <keescook@chromium.org>
>>
>> Change uselib(2)' S_ISREG() error return to EACCES instead of EINVAL so
>> the behavior matches execve(2), and the seemingly documented value.
>> The "not a regular file" failure mode of execve(2) is explicitly
>> documented[1], but it is not mentioned in uselib(2)[2] which does,
>> however, say that open(2) and mmap(2) errors may apply. The documentation
>> for open(2) does not include a "not a regular file" error[3], but mmap(2)
>> does[4], and it is EACCES.
>
> Do you have enough visibility into uselib to be certain this will change
> will not cause regressions?
>
> My sense of uselib is that it would be easier to remove the system call
> entirely (I think it's last use was in libc5) than to validate that a
> change like this won't cause problems for the users of uselib.
>
> For the kernel what is important are real world users and the manpages
> are only important as far as they suggest what the real world users
> do.
Hmm.
My apologies. After reading the next patch I see that what really makes
this safe is: 73601ea5b7b1 ("fs/open.c: allow opening only regular files
during execve()").
As in practice this change has already been made and uselib simply
can not reach the !S_ISREG test.
It might make sense to drop this patch or include that reference
in the next posting of this patch.
Eric
^ permalink raw reply
* Re: [PATCH v7 1/7] exec: Change uselib(2) IS_SREG() failure to EACCES
From: Eric W. Biederman @ 2020-08-11 18:59 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
Andrew Morton, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Deven Bowers, Dmitry Vyukov,
Eric Biggers, Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jann Horn, Jonathan Corbet, Kees Cook, Lakshmi Ramasubramanian,
Matthew Garrett, Matthew Wilcox, Michael Kerrisk, Mimi Zohar,
Philippe Trébuchet, Scott Shell, Sean Christopherson,
Shuah Khan, Steve Dower, Steve Grubb, Tetsuo Handa,
Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
linux-integrity, linux-security-module, linux-fsdevel
In-Reply-To: <20200723171227.446711-2-mic@digikod.net>
Mickaël Salaün <mic@digikod.net> writes:
> From: Kees Cook <keescook@chromium.org>
>
> Change uselib(2)' S_ISREG() error return to EACCES instead of EINVAL so
> the behavior matches execve(2), and the seemingly documented value.
> The "not a regular file" failure mode of execve(2) is explicitly
> documented[1], but it is not mentioned in uselib(2)[2] which does,
> however, say that open(2) and mmap(2) errors may apply. The documentation
> for open(2) does not include a "not a regular file" error[3], but mmap(2)
> does[4], and it is EACCES.
Do you have enough visibility into uselib to be certain this will change
will not cause regressions?
My sense of uselib is that it would be easier to remove the system call
entirely (I think it's last use was in libc5) than to validate that a
change like this won't cause problems for the users of uselib.
For the kernel what is important are real world users and the manpages
are only important as far as they suggest what the real world users do.
Eric
> [1] http://man7.org/linux/man-pages/man2/execve.2.html#ERRORS
> [2] http://man7.org/linux/man-pages/man2/uselib.2.html#ERRORS
> [3] http://man7.org/linux/man-pages/man2/open.2.html#ERRORS
> [4] http://man7.org/linux/man-pages/man2/mmap.2.html#ERRORS
>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
> Link: https://lore.kernel.org/r/20200605160013.3954297-2-keescook@chromium.org
> ---
> fs/exec.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/fs/exec.c b/fs/exec.c
> index e6e8a9a70327..d7c937044d10 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -141,11 +141,10 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
> if (IS_ERR(file))
> goto out;
>
> - error = -EINVAL;
> + error = -EACCES;
> if (!S_ISREG(file_inode(file)->i_mode))
> goto exit;
>
> - error = -EACCES;
> if (path_noexec(&file->f_path))
> goto exit;
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Miklos Szeredi @ 2020-08-11 18:49 UTC (permalink / raw)
To: Linus Torvalds
Cc: linux-fsdevel, David Howells, Al Viro, Karel Zak, Jeff Layton,
Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <CAHk-=wg_bfVf5eazwH2uXTG-auCYZUpq-xb1kDeNjY7yaXS7bw@mail.gmail.com>
On Tue, Aug 11, 2020 at 6:05 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> and then people do "$(srctree)/". If you haven't seen that kind of
> pattern where the pathname has two (or sometimes more!) slashes in the
> middle, you've led a very sheltered life.
Oh, I have. That's why I opted for triple slashes, since that should
work most of the time even in those concatenated cases. And yes, I
know, most is not always, and this might just be hiding bugs, etc...
I think the pragmatic approach would be to try this and see how many
triple slash hits a normal workload gets and if it's reasonably low,
then hopefully that together with warnings for O_ALT would be enough.
> (b) even if the new user space were to think about that, and remove
> those (hah! when have you ever seen user space do that?), as Al
> mentioned, the user *filesystem* might have pathnames with double
> slashes as part of symlinks.
>
> So now we'd have to make sure that when we traverse symlinks, that
> O_ALT gets cleared.
That's exactly what I implemented in the proof of concept patch.
> Which means that it's not a unified namespace
> after all, because you can't make symlinks point to metadata.
I don't think that's a great deal. Also I think other limitations
would make sense:
- no mounts allowed under ///
- no ./.. resolution after ///
- no hardlinks
- no special files, just regular and directory
- no seeking (regular or dir)
> cat my-file.tar/inside/the/archive.c
>
> or similar.
>
> Al has convinced me it's a horrible idea (and there you have a
> non-ambiguous marker: the slash at the end of a pathname that
> otherwise looks and acts as a non-directory)
Umm, can you remind me what's so horrible about that? Yeah, hard
linked directories are a no-no. But it doesn't have to be implemented
in a way to actually be a problem with hard links.
Thanks,
Miklos
^ permalink raw reply
* Re: [dm-devel] [RFC PATCH v5 00/11] Integrity Policy Enforcement LSM (IPE)
From: James Bottomley @ 2020-08-11 18:28 UTC (permalink / raw)
To: Chuck Lever
Cc: Mimi Zohar, James Morris, Deven Bowers, Pavel Machek, Sasha Levin,
snitzer, dm-devel, tyhicks, agk, Paul Moore, Jonathan Corbet,
nramas, serge, pasha.tatashin, Jann Horn, linux-block, Al Viro,
Jens Axboe, mdsakib, open list, eparis, linux-security-module,
linux-audit, linux-fsdevel, linux-integrity, jaskarankhurana
In-Reply-To: <16C3BF97-A7D3-488A-9D26-7C9B18AD2084@gmail.com>
On Tue, 2020-08-11 at 10:48 -0400, Chuck Lever wrote:
> Mimi's earlier point is that any IMA metadata format that involves
> unsigned digests is exposed to an alteration attack at rest or in
> transit, thus will not provide a robust end-to-end integrity
> guarantee.
I don't believe that is Mimi's point, because it's mostly not correct:
the xattr mechanism does provide this today. The point is the
mechanism we use for storing IMA hashes and signatures today is xattrs
because they have robust security properties for local filesystems that
the kernel enforces. This use goes beyond IMA, selinux labels for
instance use this property as well.
What I think you're saying is that NFS can't provide the robust
security for xattrs we've been relying on, so you need some other
mechanism for storing them.
I think Mimi's other point is actually that IMA uses a flat hash which
we derive by reading the entire file and then watching for mutations.
Since you cannot guarantee we get notice of mutation with NFS, the
entire IMA mechanism can't really be applied in its current form and we
have to resort to chunk at a time verifications that a Merkel tree
would provide. Doesn't this make moot any thinking about
standardisation in NFS for the current IMA flat hash mechanism because
we simply can't use it ... If I were to construct a prototype I'd have
to work out and securely cache the hash of ever chunk when verifying
the flat hash so I could recheck on every chunk read. I think that's
infeasible for large files.
James
^ permalink raw reply
* Re: [PATCH v7 0/7] Add support for O_MAYEXEC
From: Deven Bowers @ 2020-08-11 17:18 UTC (permalink / raw)
To: Mickaël Salaün, Jann Horn, Kees Cook, Mimi Zohar
Cc: Al Viro, Andrew Morton, kernel list, Aleksa Sarai,
Alexei Starovoitov, Andy Lutomirski, Christian Brauner,
Christian Heimes, Daniel Borkmann, Dmitry Vyukov, Eric Biggers,
Eric Chiang, Florian Weimer, James Morris, Jan Kara,
Jonathan Corbet, Lakshmi Ramasubramanian, Matthew Garrett,
Matthew Wilcox, Michael Kerrisk, Philippe Trébuchet,
Scott Shell, Sean Christopherson, Shuah Khan, Steve Dower,
Steve Grubb, Tetsuo Handa, Thibaut Sautereau, Vincent Strubel,
Kernel Hardening, Linux API, linux-integrity,
linux-security-module, linux-fsdevel
In-Reply-To: <0cc94c91-afd3-27cd-b831-8ea16ca8ca93@digikod.net>
On 8/11/2020 1:48 AM, Mickaël Salaün wrote:
[...snip]
>>> It is a
>>> good practice to check as soon as possible such properties, and it may
>>> enables to avoid (user space) time-of-check to time-of-use (TOCTOU)
>>> attacks (i.e. misuse of already open resources).
>>
>> The assumption that security checks should happen as early as possible
>> can actually cause security problems. For example, because seccomp was
>> designed to do its checks as early as possible, including before
>> ptrace, we had an issue for a long time where the ptrace API could be
>> abused to bypass seccomp filters.
>>
>> Please don't decide that a check must be ordered first _just_ because
>> it is a security check. While that can be good for limiting attack
>> surface, it can also create issues when the idea is applied too
>> broadly.
>
> I'd be interested with such security issue examples.
>
> I hope that delaying checks will not be an issue for mechanisms such as
> IMA or IPE:
> https://lore.kernel.org/lkml/1544699060.6703.11.camel@linux.ibm.com/
>
> Any though Mimi, Deven, Chrome OS folks?
>
I don't see an issue with IPE. As long as the hypothetical new syscall
and associated security hook have the file struct available in the
hook, it should integrate fairly easily.
[...snip]
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Al Viro @ 2020-08-11 16:39 UTC (permalink / raw)
To: Linus Torvalds
Cc: Miklos Szeredi, linux-fsdevel, David Howells, Karel Zak,
Jeff Layton, Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <CAHk-=wgHZig-+dXQeW4pPEjdYsrq=3bgc+vUhwiT2Ox4ipLHwg@mail.gmail.com>
On Tue, Aug 11, 2020 at 09:09:36AM -0700, Linus Torvalds wrote:
> On Tue, Aug 11, 2020 at 9:05 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > Except that you suddenly see non-directory dentries get children.
> > And a lot of dcache-related logics needs to be changed if that
> > becomes possible.
>
> Yeah, I think you'd basically need to associate a (dynamic)
> mount-point to that path when you start doing O_ALT. Or something.
Whee... That's going to be non-workable for xattrs - fgetxattr()
needs to work after unlink(). And you'd obviously need to prevent
crossing into that sucker on normal lookups, which would add quite
a few interesting twists around the automount points.
I'm not saying it's not doable, but it won't be anywhere near
straightforward. And API semantics questions are still there...
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Linus Torvalds @ 2020-08-11 16:30 UTC (permalink / raw)
To: Casey Schaufler
Cc: Andy Lutomirski, Miklos Szeredi, linux-fsdevel, David Howells,
Al Viro, Karel Zak, Jeff Layton, Miklos Szeredi, Nicolas Dichtel,
Christian Brauner, Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <a6cd01ed-918a-0ed7-aa87-0585db7b6852@schaufler-ca.com>
On Tue, Aug 11, 2020 at 9:17 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> This doesn't work so well for setxattr(), which we want to be atomic.
Well, it's not like the old interfaces could go away. But yes, doing
metadatafd = openat(fd, "metadataname", O_ALT | O_CREAT | O_EXCL)
to create a new xattr (and then write to it) would not act like
setxattr(). Even if you do it as one atomic write, a reader would see
that zero-sized xattr between the O_CREAT and the write.
Of course, we could just hide zero-sized xattrs from the legacy
interfaces and avoid things like that, but another option is to say
that only the legacy interfaces give that particular atomicity
guarantee.
> Since a////////b has known meaning, and lots of applications
> play loose with '/', its really dangerous to treat the string as
> special. We only get away with '.' and '..' because their behavior
> was defined before many of y'all were born.
Yeah, I really don't think it's a good idea to play with "//".
POSIX does allow special semantics for a pathname with "//" at the
*beginning*, but even that has been very questionable (and Linux has
never supported it).
Linus
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Linus Torvalds @ 2020-08-11 16:09 UTC (permalink / raw)
To: Al Viro
Cc: Miklos Szeredi, linux-fsdevel, David Howells, Karel Zak,
Jeff Layton, Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <20200811160534.GL1236603@ZenIV.linux.org.uk>
On Tue, Aug 11, 2020 at 9:05 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> Except that you suddenly see non-directory dentries get children.
> And a lot of dcache-related logics needs to be changed if that
> becomes possible.
Yeah, I think you'd basically need to associate a (dynamic)
mount-point to that path when you start doing O_ALT. Or something.
And it might not be reasonably implementable. I just think that as
_interface_ it's unambiguous and fairly clean, and if Miklos can
implement something like that, I think it would be maintainable.
No?
Linus
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Casey Schaufler @ 2020-08-11 16:17 UTC (permalink / raw)
To: Andy Lutomirski, Linus Torvalds
Cc: Miklos Szeredi, linux-fsdevel, David Howells, Al Viro, Karel Zak,
Jeff Layton, Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List, Casey Schaufler
In-Reply-To: <5C8E0FA8-274E-4B56-9B5A-88E768D01F3A@amacapital.net>
On 8/11/2020 8:39 AM, Andy Lutomirski wrote:
>
>> On Aug 11, 2020, at 8:20 AM, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>>
>> [ I missed the beginning of this discussion, so maybe this was already
>> suggested ]
>>
>>> On Tue, Aug 11, 2020 at 6:54 AM Miklos Szeredi <miklos@szeredi.hu> wrote:
>>>
>>>> E.g.
>>>> openat(AT_FDCWD, "foo/bar//mnt/info", O_RDONLY | O_ALT);
>>> Proof of concept patch and test program below.
>> I don't think this works for the reasons Al says, but a slight
>> modification might.
>>
>> IOW, if you do something more along the lines of
>>
>> fd = open(""foo/bar", O_PATH);
>> metadatafd = openat(fd, "metadataname", O_ALT);
>>
>> it might be workable.
>>
>> So you couldn't do it with _one_ pathname, because that is always
>> fundamentally going to hit pathname lookup rules.
>>
>> But if you start a new path lookup with new rules, that's fine.
>>
>> This is what I think xattrs should always have done, because they are
>> broken garbage.
>>
>> In fact, if we do it right, I think we could have "getxattr()" be 100%
>> equivalent to (modulo all the error handling that this doesn't do, of
>> course):
>>
>> ssize_t getxattr(const char *path, const char *name,
>> void *value, size_t size)
>> {known
>> int fd, attrfd;
>>
>> fd = open(path, O_PATH);
>> attrfd = openat(fd, name, O_ALT);
>> close(fd);
>> read(attrfd, value, size);
>> close(attrfd);
>> }
>>
>> and you'd still use getxattr() and friends as a shorthand (and for
>> POSIX compatibility), but internally in the kernel we'd have a
>> interface around that "xattrs are just file handles" model.
This doesn't work so well for setxattr(), which we want to be atomic.
> This is a lot like a less nutty version of NTFS streams, whereas the /// idea is kind of like an extra-nutty version of NTFS streams.
>
> I am personally not a fan of the in-band signaling implications of overloading /. For example, there is plenty of code out there that thinks that (a + “/“ + b) concatenates paths. With /// overloaded, this stops being true.
Since a////////b has known meaning, and lots of applications
play loose with '/', its really dangerous to treat the string as
special. We only get away with '.' and '..' because their behavior
was defined before many of y'all were born.
^ permalink raw reply
* Re: file metadata via fs API (was: [GIT PULL] Filesystem Information)
From: Linus Torvalds @ 2020-08-11 16:05 UTC (permalink / raw)
To: Miklos Szeredi
Cc: linux-fsdevel, David Howells, Al Viro, Karel Zak, Jeff Layton,
Miklos Szeredi, Nicolas Dichtel, Christian Brauner,
Lennart Poettering, Linux API, Ian Kent, LSM,
Linux Kernel Mailing List
In-Reply-To: <CAJfpegtWai+5Tzxi1_G+R2wEZz0q66uaOFndNE0YEQSDjq0f_A@mail.gmail.com>
On Tue, Aug 11, 2020 at 8:30 AM Miklos Szeredi <miklos@szeredi.hu> wrote:
>
> What's the disadvantage of doing it with a single lookup WITH an enabling flag?
>
> It's definitely not going to break anything, so no backward
> compatibility issues whatsoever.
No backwards compatibility issues for existing programs, no.
But your suggestion is fundamentally ambiguous, and you most
definitely *can* hit that if people start using this in new programs.
Where does that "unified" pathname come from? It will be generated
from "base filename + metadata name" in user space, and
(a) the base filename might have double or triple slashes in it for
whatever reasons.
This is not some "made-up gotcha" thing - I see double slashes *all*
the time when we have things like Makefiles doing
srctree=../../src/
and then people do "$(srctree)/". If you haven't seen that kind of
pattern where the pathname has two (or sometimes more!) slashes in the
middle, you've led a very sheltered life.
(b) even if the new user space were to think about that, and remove
those (hah! when have you ever seen user space do that?), as Al
mentioned, the user *filesystem* might have pathnames with double
slashes as part of symlinks.
So now we'd have to make sure that when we traverse symlinks, that
O_ALT gets cleared. Which means that it's not a unified namespace
after all, because you can't make symlinks point to metadata.
Or we'd retroactively change the semantics of a symlink, and that _is_
a backwards compatibility issue. Not with old software, no, but it
changes the meaning of old symlinks!
So no, I don't think a unified namespace ends up working.
And I say that as somebody who actually loves the concept. Ask Al: I
have a few times pushed for "let's allow directory behavior on regular
files", so that you could do things like a tar-filesystem, and access
the contents of a tar-file by just doing
cat my-file.tar/inside/the/archive.c
or similar.
Al has convinced me it's a horrible idea (and there you have a
non-ambiguous marker: the slash at the end of a pathname that
otherwise looks and acts as a non-directory)
Linus
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox