History

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>

Salvatore Mesoraca committed 8 years ago

Commit 30aba661 parent dc257274 files · +106 −3Browse files

Unified · Split

4 files
  1. Documentation/sysctl/fs.txt +36 −0
  2. fs/namei.c +50 −3
  3. include/linux/fs.h +2 −0
  4. kernel/sysctl.c +18 −0
Documentation/sysctl/fs.txt+36−0
@@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/fs: · 33 unmodified lines
34- overflowgid34- overflowgid
35- pipe-user-pages-hard35- pipe-user-pages-hard
36- pipe-user-pages-soft36- pipe-user-pages-soft
37- protected_fifos
37- protected_hardlinks38- protected_hardlinks
39- protected_regular
38- protected_symlinks40- protected_symlinks
39- suid_dumpable41- suid_dumpable
40- super-max42- super-max
@@ -182,6 +184,24 @@ applied. · 141 unmodified lines
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-based207A 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. · 14 unmodified lines
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-based243A long-standing class of security issues is the symlink-based
fs/namei.c+50−3
@@ -887,6 +887,8 @@ static inline void put_link(struct nameidata *nd) · 886 unmodified lines
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 situations894 * may_follow_link - Check symlink following for unsafe situations
@@ -1003,6 +1005,45 @@ static int may_linkat(struct path *link) · 110 unmodified lines
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_inline1047static __always_inline
1007const char *get_link(struct nameidata *nd)1048const char *get_link(struct nameidata *nd)
1008{1049{
@@ -3348,9 +3389,15 @@ finish_open: · 2339 unmodified lines
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;
include/linux/fs.h+2−0
@@ -74,6 +74,8 @@ extern struct inodes_stat_t inodes_stat; · 73 unmodified lines
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
kernel/sysctl.c+18−0
@@ -1807,6 +1807,24 @@ static struct ctl_table fs_table[] = { · 1806 unmodified lines
1807 .extra1 = &zero,1807 .extra1 = &zero,
1808 .extra2 = &one,1808 .extra2 = &one,
1809 },1809 },
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 },
1810 {1828 {
1811 .procname = "suid_dumpable",1829 .procname = "suid_dumpable",
1812 .data = &suid_dumpable,1830 .data = &suid_dumpable,