aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSalvatore Mesoraca <s.mesoraca16@gmail.com>2018-08-23 20:00:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-23 21:48:43 -0400
commit30aba6656f61ed44cba445a3c0d38b296fa9e8f5 (patch)
tree6c10f9e466500d7ede78400bb7b58896dd66016a
parentdc2572791d3a41bab94400af2b6bca9d71ccd303 (diff)
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@gmail.com: 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@gmail.com [keescook@chromium.org: drop pr_warn_ratelimited() in favor of audit changes in the future] [keescook@chromium.org: adjust commit subjet] Link: http://lkml.kernel.org/r/20180416175918.GA13494@beast Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com> Signed-off-by: Kees Cook <keescook@chromium.org> Suggested-by: Solar Designer <solar@openwall.com> Suggested-by: Kees Cook <keescook@chromium.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/sysctl/fs.txt36
-rw-r--r--fs/namei.c53
-rw-r--r--include/linux/fs.h2
-rw-r--r--kernel/sysctl.c18
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:
34- overflowgid 34- overflowgid
35- pipe-user-pages-hard 35- pipe-user-pages-hard
36- pipe-user-pages-soft 36- pipe-user-pages-soft
37- protected_fifos
37- protected_hardlinks 38- protected_hardlinks
39- protected_regular
38- protected_symlinks 40- protected_symlinks
39- suid_dumpable 41- suid_dumpable
40- super-max 42- super-max
@@ -182,6 +184,24 @@ applied.
182 184
183============================================================== 185==============================================================
184 186
187protected_fifos:
188
189The intent of this protection is to avoid unintentional writes to
190an attacker-controlled FIFO, where a program expected to create a regular
191file.
192
193When set to "0", writing to FIFOs is unrestricted.
194
195When set to "1" don't allow O_CREAT open on FIFOs that we don't own
196in world writable sticky directories, unless they are owned by the
197owner of the directory.
198
199When set to "2" it also applies to group writable sticky directories.
200
201This protection is based on the restrictions in Openwall.
202
203==============================================================
204
185protected_hardlinks: 205protected_hardlinks:
186 206
187A long-standing class of security issues is the hardlink-based 207A 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.
202 222
203============================================================== 223==============================================================
204 224
225protected_regular:
226
227This protection is similar to protected_fifos, but it
228avoids writes to an attacker-controlled regular file, where a program
229expected to create one.
230
231When set to "0", writing to regular files is unrestricted.
232
233When set to "1" don't allow O_CREAT open on regular files that we
234don't own in world writable sticky directories, unless they are
235owned by the owner of the directory.
236
237When set to "2" it also applies to group writable sticky directories.
238
239==============================================================
240
205protected_symlinks: 241protected_symlinks:
206 242
207A long-standing class of security issues is the symlink-based 243A 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)
887 887
888int sysctl_protected_symlinks __read_mostly = 0; 888int sysctl_protected_symlinks __read_mostly = 0;
889int sysctl_protected_hardlinks __read_mostly = 0; 889int sysctl_protected_hardlinks __read_mostly = 0;
890int sysctl_protected_fifos __read_mostly;
891int sysctl_protected_regular __read_mostly;
890 892
891/** 893/**
892 * may_follow_link - Check symlink following for unsafe situations 894 * may_follow_link - Check symlink following for unsafe situations
@@ -1003,6 +1005,45 @@ static int may_linkat(struct path *link)
1003 return -EPERM; 1005 return -EPERM;
1004} 1006}
1005 1007
1008/**
1009 * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory
1010 * should be allowed, or not, on files that already
1011 * exist.
1012 * @dir: the sticky parent directory
1013 * @inode: the inode of the file to open
1014 *
1015 * Block an O_CREAT open of a FIFO (or a regular file) when:
1016 * - sysctl_protected_fifos (or sysctl_protected_regular) is enabled
1017 * - the file already exists
1018 * - we are in a sticky directory
1019 * - we don't own the file
1020 * - the owner of the directory doesn't own the file
1021 * - the directory is world writable
1022 * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2
1023 * the directory doesn't have to be world writable: being group writable will
1024 * be enough.
1025 *
1026 * Returns 0 if the open is allowed, -ve on error.
1027 */
1028static int may_create_in_sticky(struct dentry * const dir,
1029 struct inode * const inode)
1030{
1031 if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
1032 (!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
1033 likely(!(dir->d_inode->i_mode & S_ISVTX)) ||
1034 uid_eq(inode->i_uid, dir->d_inode->i_uid) ||
1035 uid_eq(current_fsuid(), inode->i_uid))
1036 return 0;
1037
1038 if (likely(dir->d_inode->i_mode & 0002) ||
1039 (dir->d_inode->i_mode & 0020 &&
1040 ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) ||
1041 (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) {
1042 return -EACCES;
1043 }
1044 return 0;
1045}
1046
1006static __always_inline 1047static __always_inline
1007const char *get_link(struct nameidata *nd) 1048const char *get_link(struct nameidata *nd)
1008{ 1049{
@@ -3348,9 +3389,15 @@ finish_open:
3348 if (error) 3389 if (error)
3349 return error; 3390 return error;
3350 audit_inode(nd->name, nd->path.dentry, 0); 3391 audit_inode(nd->name, nd->path.dentry, 0);
3351 error = -EISDIR; 3392 if (open_flag & O_CREAT) {
3352 if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) 3393 error = -EISDIR;
3353 goto out; 3394 if (d_is_dir(nd->path.dentry))
3395 goto out;
3396 error = may_create_in_sticky(dir,
3397 d_backing_inode(nd->path.dentry));
3398 if (unlikely(error))
3399 goto out;
3400 }
3354 error = -ENOTDIR; 3401 error = -ENOTDIR;
3355 if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) 3402 if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
3356 goto out; 3403 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;
74extern int leases_enable, lease_break_time; 74extern int leases_enable, lease_break_time;
75extern int sysctl_protected_symlinks; 75extern int sysctl_protected_symlinks;
76extern int sysctl_protected_hardlinks; 76extern int sysctl_protected_hardlinks;
77extern int sysctl_protected_fifos;
78extern int sysctl_protected_regular;
77 79
78typedef __kernel_rwf_t rwf_t; 80typedef __kernel_rwf_t rwf_t;
79 81
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 71ceb6c13c1a..cc02050fd0c4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1808,6 +1808,24 @@ static struct ctl_table fs_table[] = {
1808 .extra2 = &one, 1808 .extra2 = &one,
1809 }, 1809 },
1810 { 1810 {
1811 .procname = "protected_fifos",
1812 .data = &sysctl_protected_fifos,
1813 .maxlen = sizeof(int),
1814 .mode = 0600,
1815 .proc_handler = proc_dointvec_minmax,
1816 .extra1 = &zero,
1817 .extra2 = &two,
1818 },
1819 {
1820 .procname = "protected_regular",
1821 .data = &sysctl_protected_regular,
1822 .maxlen = sizeof(int),
1823 .mode = 0600,
1824 .proc_handler = proc_dointvec_minmax,
1825 .extra1 = &zero,
1826 .extra2 = &two,
1827 },
1828 {
1811 .procname = "suid_dumpable", 1829 .procname = "suid_dumpable",
1812 .data = &suid_dumpable, 1830 .data = &suid_dumpable,
1813 .maxlen = sizeof(int), 1831 .maxlen = sizeof(int),