On Tue, Oct 23, 2018 at 7:54 PM, Loic <hackurx@xxxxxxxxxx> wrote: > Hello, > > Please picked up this patch for linux 4.4 (backported version). > Indeed, this code will be beneficial to the GNU/Linux distributions that use a longterm kernel. > > Compiled/tested without problem. Reviewed-by: Kees Cook <keescook@xxxxxxxxxxxx> -Kees > > 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> > [backported to 4.4 by Loic] > Cc: Loic <hackurx@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 -Nurp a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt > --- a/Documentation/sysctl/fs.txt 2018-10-20 09:52:38.000000000 +0200 > +++ b/Documentation/sysctl/fs.txt 2018-10-23 18:08:20.398649373 +0200 > @@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/ > - 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 restrict > > ============================================================== > > +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 -Nurp a/fs/namei.c b/fs/namei.c > --- a/fs/namei.c 2018-10-20 09:52:38.000000000 +0200 > +++ b/fs/namei.c 2018-10-23 18:09:35.450879869 +0200 > @@ -869,6 +869,8 @@ static inline void put_link(struct namei > > 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 > @@ -982,6 +984,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) > { > @@ -3166,9 +3207,15 @@ finish_open: > error = -ELOOP; > goto out; > } > - 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 -Nurp a/include/linux/fs.h b/include/linux/fs.h > --- a/include/linux/fs.h 2018-10-20 09:52:38.000000000 +0200 > +++ b/include/linux/fs.h 2018-10-23 18:08:20.402649386 +0200 > @@ -65,6 +65,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; > > struct buffer_head; > typedef int (get_block_t)(struct inode *inode, sector_t iblock, > diff -Nurp a/kernel/sysctl.c b/kernel/sysctl.c > --- a/kernel/sysctl.c 2018-10-20 09:52:38.000000000 +0200 > +++ b/kernel/sysctl.c 2018-10-23 18:08:20.402649386 +0200 > @@ -1716,6 +1716,24 @@ static struct ctl_table fs_table[] = { > .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, > .maxlen = sizeof(int), -- Kees Cook