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
3434 - overflowgid
3535 - pipe-user-pages-hard
3636 - pipe-user-pages-soft
37+- protected_fifos
3738 - protected_hardlinks
39+- protected_regular
3840 - protected_symlinks
3941 - suid_dumpable
4042 - super-max
@@ -182,6 +184,24 @@ applied. · 141 unmodified lines
182184
183185 ==============================================================
184186
187+protected_fifos:
188+
189+The intent of this protection is to avoid unintentional writes to
190+an attacker-controlled FIFO, where a program expected to create a regular
191+file.
192+
193+When set to "0", writing to FIFOs is unrestricted.
194+
195+When set to "1" don't allow O_CREAT open on FIFOs that we don't own
196+in world writable sticky directories, unless they are owned by the
197+owner of the directory.
198+
199+When set to "2" it also applies to group writable sticky directories.
200+
201+This protection is based on the restrictions in Openwall.
202+
203+==============================================================
204+
185205 protected_hardlinks:
186206
187207 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. · 14 unmodified lines
202222
203223 ==============================================================
204224
225+protected_regular:
226+
227+This protection is similar to protected_fifos, but it
228+avoids writes to an attacker-controlled regular file, where a program
229+expected to create one.
230+
231+When set to "0", writing to regular files is unrestricted.
232+
233+When set to "1" don't allow O_CREAT open on regular files that we
234+don't own in world writable sticky directories, unless they are
235+owned by the owner of the directory.
236+
237+When set to "2" it also applies to group writable sticky directories.
238+
239+==============================================================
240+
205241 protected_symlinks:
206242
207243 A 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
887887
888888 int sysctl_protected_symlinks __read_mostly = 0;
889889 int sysctl_protected_hardlinks __read_mostly = 0;
890+int sysctl_protected_fifos __read_mostly;
891+int sysctl_protected_regular __read_mostly;
890892
891893 /**
892894 * may_follow_link - Check symlink following for unsafe situations
@@ -1003,6 +1005,45 @@ static int may_linkat(struct path *link) · 110 unmodified lines
10031005 return -EPERM;
10041006 }
10051007
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+ */
1028+static 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+
10061047 static __always_inline
10071048 const char *get_link(struct nameidata *nd)
10081049 {
@@ -3348,9 +3389,15 @@ finish_open: · 2339 unmodified lines
33483389 if (error)
33493390 return error;
33503391 audit_inode(nd->name, nd->path.dentry, 0);
3351− error = -EISDIR;
3352− if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
3353− goto out;
3392+ if (open_flag & O_CREAT) {
3393+ error = -EISDIR;
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+ }
33543401 error = -ENOTDIR;
33553402 if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
33563403 goto out;
include/linux/fs.h+2−0
@@ -74,6 +74,8 @@ extern struct inodes_stat_t inodes_stat; · 73 unmodified lines
7474 extern int leases_enable, lease_break_time;
7575 extern int sysctl_protected_symlinks;
7676 extern int sysctl_protected_hardlinks;
77+extern int sysctl_protected_fifos;
78+extern int sysctl_protected_regular;
7779
7880 typedef __kernel_rwf_t rwf_t;
7981
kernel/sysctl.c+18−0
@@ -1807,6 +1807,24 @@ static struct ctl_table fs_table[] = { · 1806 unmodified lines
18071807 .extra1 = &zero,
18081808 .extra2 = &one,
18091809 },
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+ },
18101828 {
18111829 .procname = "suid_dumpable",
18121830 .data = &suid_dumpable,