Re: [PATCH] namei: allow restricted O_CREAT of FIFOs and regular files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Oct 23, 2018 at 7:37 PM, Loic <hackurx@xxxxxxxxxx> wrote:
> Hello,
>
> Please picked up this patch for linux 4.9 and 4.14 (linux 4.4 needs a small modification).
> Indeed, this code will be beneficial to the GNU/Linux distributions that use a longterm kernel.

Thanks for doing these (and 4.4). It'll be nice to have this available.

Reviewed-by: Kees Cook <keescook@xxxxxxxxxxxx>

-Kees

>
> Compiled/tested without problem.
>
> Thank.
>
> [ Upstream commit 30aba6656f61ed44cba445a3c0d38b296fa9e8f5 ]
>
> From: Salvatore Mesoraca <s.mesoraca16@xxxxxxxxx>
> Date: Thu, 23 Aug 2018 17:00:35 -0700
> Subject: namei: allow restricted O_CREAT of FIFOs and regular files
>
> Disallows open of FIFOs or regular files not owned by the user in world
> writable sticky directories, unless the owner is the same as that of the
> directory or the file is opened without the O_CREAT flag.  The purpose
> is to make data spoofing attacks harder.  This protection can be turned
> on and off separately for FIFOs and regular files via sysctl, just like
> the symlinks/hardlinks protection.  This patch is based on Openwall's
> "HARDEN_FIFO" feature by Solar Designer.
>
> This is a brief list of old vulnerabilities that could have been prevented
> by this feature, some of them even allow for privilege escalation:
>
> CVE-2000-1134
> CVE-2007-3852
> CVE-2008-0525
> CVE-2009-0416
> CVE-2011-4834
> CVE-2015-1838
> CVE-2015-7442
> CVE-2016-7489
>
> This list is not meant to be complete.  It's difficult to track down all
> vulnerabilities of this kind because they were often reported without any
> mention of this particular attack vector.  In fact, before
> hardlinks/symlinks restrictions, fifos/regular files weren't the favorite
> vehicle to exploit them.
>
> [s.mesoraca16@xxxxxxxxx: fix bug reported by Dan Carpenter]
>   Link: https://lkml.kernel.org/r/20180426081456.GA7060@mwanda
>   Link: http://lkml.kernel.org/r/1524829819-11275-1-git-send-email-s.mesoraca16@xxxxxxxxx
> [keescook@xxxxxxxxxxxx: drop pr_warn_ratelimited() in favor of audit changes in the future]
> [keescook@xxxxxxxxxxxx: adjust commit subjet]
> Link: http://lkml.kernel.org/r/20180416175918.GA13494@beast
> Signed-off-by: Salvatore Mesoraca <s.mesoraca16@xxxxxxxxx>
> Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
> Suggested-by: Solar Designer <solar@xxxxxxxxxxxx>
> Suggested-by: Kees Cook <keescook@xxxxxxxxxxxx>
> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> Cc: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
> ---
>  Documentation/sysctl/fs.txt | 36 ++++++++++++++++++++++++++++++
>  fs/namei.c                  | 53 ++++++++++++++++++++++++++++++++++++++++++---
>  include/linux/fs.h          |  2 ++
>  kernel/sysctl.c             | 18 +++++++++++++++
>  4 files changed, 106 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
> index 6c00c1e2743f..819caf8ca05f 100644
> --- a/Documentation/sysctl/fs.txt
> +++ b/Documentation/sysctl/fs.txt
> @@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/fs:
>  - overflowgid
>  - pipe-user-pages-hard
>  - pipe-user-pages-soft
> +- protected_fifos
>  - protected_hardlinks
> +- protected_regular
>  - protected_symlinks
>  - suid_dumpable
>  - super-max
> @@ -182,6 +184,24 @@ applied.
>
>  ==============================================================
>
> +protected_fifos:
> +
> +The intent of this protection is to avoid unintentional writes to
> +an attacker-controlled FIFO, where a program expected to create a regular
> +file.
> +
> +When set to "0", writing to FIFOs is unrestricted.
> +
> +When set to "1" don't allow O_CREAT open on FIFOs that we don't own
> +in world writable sticky directories, unless they are owned by the
> +owner of the directory.
> +
> +When set to "2" it also applies to group writable sticky directories.
> +
> +This protection is based on the restrictions in Openwall.
> +
> +==============================================================
> +
>  protected_hardlinks:
>
>  A long-standing class of security issues is the hardlink-based
> @@ -202,6 +222,22 @@ This protection is based on the restrictions in Openwall and grsecurity.
>
>  ==============================================================
>
> +protected_regular:
> +
> +This protection is similar to protected_fifos, but it
> +avoids writes to an attacker-controlled regular file, where a program
> +expected to create one.
> +
> +When set to "0", writing to regular files is unrestricted.
> +
> +When set to "1" don't allow O_CREAT open on regular files that we
> +don't own in world writable sticky directories, unless they are
> +owned by the owner of the directory.
> +
> +When set to "2" it also applies to group writable sticky directories.
> +
> +==============================================================
> +
>  protected_symlinks:
>
>  A long-standing class of security issues is the symlink-based
> diff --git a/fs/namei.c b/fs/namei.c
> index ae6aa9ae757c..0cab6494978c 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -887,6 +887,8 @@ static inline void put_link(struct nameidata *nd)
>
>  int sysctl_protected_symlinks __read_mostly = 0;
>  int sysctl_protected_hardlinks __read_mostly = 0;
> +int sysctl_protected_fifos __read_mostly;
> +int sysctl_protected_regular __read_mostly;
>
>  /**
>   * may_follow_link - Check symlink following for unsafe situations
> @@ -1003,6 +1005,45 @@ static int may_linkat(struct path *link)
>         return -EPERM;
>  }
>
> +/**
> + * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory
> + *                       should be allowed, or not, on files that already
> + *                       exist.
> + * @dir: the sticky parent directory
> + * @inode: the inode of the file to open
> + *
> + * Block an O_CREAT open of a FIFO (or a regular file) when:
> + *   - sysctl_protected_fifos (or sysctl_protected_regular) is enabled
> + *   - the file already exists
> + *   - we are in a sticky directory
> + *   - we don't own the file
> + *   - the owner of the directory doesn't own the file
> + *   - the directory is world writable
> + * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2
> + * the directory doesn't have to be world writable: being group writable will
> + * be enough.
> + *
> + * Returns 0 if the open is allowed, -ve on error.
> + */
> +static int may_create_in_sticky(struct dentry * const dir,
> +                               struct inode * const inode)
> +{
> +       if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
> +           (!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
> +           likely(!(dir->d_inode->i_mode & S_ISVTX)) ||
> +           uid_eq(inode->i_uid, dir->d_inode->i_uid) ||
> +           uid_eq(current_fsuid(), inode->i_uid))
> +               return 0;
> +
> +       if (likely(dir->d_inode->i_mode & 0002) ||
> +           (dir->d_inode->i_mode & 0020 &&
> +            ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) ||
> +             (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) {
> +               return -EACCES;
> +       }
> +       return 0;
> +}
> +
>  static __always_inline
>  const char *get_link(struct nameidata *nd)
>  {
> @@ -3348,9 +3389,15 @@ finish_open:
>         if (error)
>                 return error;
>         audit_inode(nd->name, nd->path.dentry, 0);
> -       error = -EISDIR;
> -       if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
> -               goto out;
> +       if (open_flag & O_CREAT) {
> +               error = -EISDIR;
> +               if (d_is_dir(nd->path.dentry))
> +                       goto out;
> +               error = may_create_in_sticky(dir,
> +                                            d_backing_inode(nd->path.dentry));
> +               if (unlikely(error))
> +                       goto out;
> +       }
>         error = -ENOTDIR;
>         if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
>                 goto out;
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index e5710541183b..33322702c910 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -74,6 +74,8 @@ extern struct inodes_stat_t inodes_stat;
>  extern int leases_enable, lease_break_time;
>  extern int sysctl_protected_symlinks;
>  extern int sysctl_protected_hardlinks;
> +extern int sysctl_protected_fifos;
> +extern int sysctl_protected_regular;
>
>  typedef __kernel_rwf_t rwf_t;
>
> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> index 71ceb6c13c1a..cc02050fd0c4 100644
> --- a/kernel/sysctl.c
> +++ b/kernel/sysctl.c
> @@ -1807,6 +1807,24 @@ static struct ctl_table fs_table[] = {
>                 .extra1         = &zero,
>                 .extra2         = &one,
>         },
> +       {
> +               .procname       = "protected_fifos",
> +               .data           = &sysctl_protected_fifos,
> +               .maxlen         = sizeof(int),
> +               .mode           = 0600,
> +               .proc_handler   = proc_dointvec_minmax,
> +               .extra1         = &zero,
> +               .extra2         = &two,
> +       },
> +       {
> +               .procname       = "protected_regular",
> +               .data           = &sysctl_protected_regular,
> +               .maxlen         = sizeof(int),
> +               .mode           = 0600,
> +               .proc_handler   = proc_dointvec_minmax,
> +               .extra1         = &zero,
> +               .extra2         = &two,
> +       },
>         {
>                 .procname       = "suid_dumpable",
>                 .data           = &suid_dumpable,
> --
> cgit 1.2-0.3.lf.el7



-- 
Kees Cook



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux