Skip to content

Commit 30aba66

Browse files
smesotorvalds
authored andcommitted
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. [[email protected]: fix bug reported by Dan Carpenter] Link: https://lkml.kernel.org/r/20180426081456.GA7060@mwanda Link: http://lkml.kernel.org/r/[email protected] [[email protected]: drop pr_warn_ratelimited() in favor of audit changes in the future] [[email protected]: adjust commit subjet] Link: http://lkml.kernel.org/r/20180416175918.GA13494@beast Signed-off-by: Salvatore Mesoraca <[email protected]> Signed-off-by: Kees Cook <[email protected]> Suggested-by: Solar Designer <[email protected]> Suggested-by: Kees Cook <[email protected]> Cc: Al Viro <[email protected]> Cc: Dan Carpenter <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent dc25727 commit 30aba66

File tree

4 files changed

+106
-3
lines changed

4 files changed

+106
-3
lines changed

Documentation/sysctl/fs.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/fs:
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.
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.
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

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,8 @@ static inline void put_link(struct nameidata *nd)
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)
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 @@ static int do_last(struct nameidata *nd,
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ extern struct inodes_stat_t inodes_stat;
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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,24 @@ static struct ctl_table fs_table[] = {
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,

0 commit comments

Comments
 (0)