diff options
-rw-r--r-- | fs/attr.c | 7 | ||||
-rw-r--r-- | fs/xattr.c | 7 | ||||
-rw-r--r-- | include/linux/fs.h | 13 | ||||
-rw-r--r-- | mm/filemap.c | 14 |
4 files changed, 37 insertions, 4 deletions
@@ -175,6 +175,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
175 | return -EPERM; | 175 | return -EPERM; |
176 | } | 176 | } |
177 | 177 | ||
178 | if ((ia_valid & ATTR_MODE)) { | ||
179 | mode_t amode = attr->ia_mode; | ||
180 | /* Flag setting protected by i_mutex */ | ||
181 | if (is_sxid(amode)) | ||
182 | inode->i_flags &= ~S_NOSEC; | ||
183 | } | ||
184 | |||
178 | now = current_fs_time(inode->i_sb); | 185 | now = current_fs_time(inode->i_sb); |
179 | 186 | ||
180 | attr->ia_ctime = now; | 187 | attr->ia_ctime = now; |
diff --git a/fs/xattr.c b/fs/xattr.c index 4be2e7666d02..f060663ab70c 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -91,7 +91,11 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, | |||
91 | { | 91 | { |
92 | struct inode *inode = dentry->d_inode; | 92 | struct inode *inode = dentry->d_inode; |
93 | int error = -EOPNOTSUPP; | 93 | int error = -EOPNOTSUPP; |
94 | int issec = !strncmp(name, XATTR_SECURITY_PREFIX, | ||
95 | XATTR_SECURITY_PREFIX_LEN); | ||
94 | 96 | ||
97 | if (issec) | ||
98 | inode->i_flags &= ~S_NOSEC; | ||
95 | if (inode->i_op->setxattr) { | 99 | if (inode->i_op->setxattr) { |
96 | error = inode->i_op->setxattr(dentry, name, value, size, flags); | 100 | error = inode->i_op->setxattr(dentry, name, value, size, flags); |
97 | if (!error) { | 101 | if (!error) { |
@@ -99,8 +103,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, | |||
99 | security_inode_post_setxattr(dentry, name, value, | 103 | security_inode_post_setxattr(dentry, name, value, |
100 | size, flags); | 104 | size, flags); |
101 | } | 105 | } |
102 | } else if (!strncmp(name, XATTR_SECURITY_PREFIX, | 106 | } else if (issec) { |
103 | XATTR_SECURITY_PREFIX_LEN)) { | ||
104 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; | 107 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
105 | error = security_inode_setsecurity(inode, suffix, value, | 108 | error = security_inode_setsecurity(inode, suffix, value, |
106 | size, flags); | 109 | size, flags); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 573028df050d..c55d6b7cd5d6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -237,6 +237,7 @@ struct inodes_stat_t { | |||
237 | #define S_PRIVATE 512 /* Inode is fs-internal */ | 237 | #define S_PRIVATE 512 /* Inode is fs-internal */ |
238 | #define S_IMA 1024 /* Inode has an associated IMA struct */ | 238 | #define S_IMA 1024 /* Inode has an associated IMA struct */ |
239 | #define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */ | 239 | #define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */ |
240 | #define S_NOSEC 4096 /* no suid or xattr security attributes */ | ||
240 | 241 | ||
241 | /* | 242 | /* |
242 | * Note that nosuid etc flags are inode-specific: setting some file-system | 243 | * Note that nosuid etc flags are inode-specific: setting some file-system |
@@ -273,6 +274,7 @@ struct inodes_stat_t { | |||
273 | #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) | 274 | #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) |
274 | #define IS_IMA(inode) ((inode)->i_flags & S_IMA) | 275 | #define IS_IMA(inode) ((inode)->i_flags & S_IMA) |
275 | #define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT) | 276 | #define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT) |
277 | #define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC) | ||
276 | 278 | ||
277 | /* the read-only stuff doesn't really belong here, but any other place is | 279 | /* the read-only stuff doesn't really belong here, but any other place is |
278 | probably as bad and I don't want to create yet another include file. */ | 280 | probably as bad and I don't want to create yet another include file. */ |
@@ -2582,5 +2584,16 @@ int __init get_filesystem_list(char *buf); | |||
2582 | #define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \ | 2584 | #define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \ |
2583 | (flag & __FMODE_NONOTIFY))) | 2585 | (flag & __FMODE_NONOTIFY))) |
2584 | 2586 | ||
2587 | static inline int is_sxid(mode_t mode) | ||
2588 | { | ||
2589 | return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP)); | ||
2590 | } | ||
2591 | |||
2592 | static inline void inode_has_no_xattr(struct inode *inode) | ||
2593 | { | ||
2594 | if (!is_sxid(inode->i_mode)) | ||
2595 | inode->i_flags |= S_NOSEC; | ||
2596 | } | ||
2597 | |||
2585 | #endif /* __KERNEL__ */ | 2598 | #endif /* __KERNEL__ */ |
2586 | #endif /* _LINUX_FS_H */ | 2599 | #endif /* _LINUX_FS_H */ |
diff --git a/mm/filemap.c b/mm/filemap.c index dac95a24deac..d7b10578a64b 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1982,16 +1982,26 @@ static int __remove_suid(struct dentry *dentry, int kill) | |||
1982 | int file_remove_suid(struct file *file) | 1982 | int file_remove_suid(struct file *file) |
1983 | { | 1983 | { |
1984 | struct dentry *dentry = file->f_path.dentry; | 1984 | struct dentry *dentry = file->f_path.dentry; |
1985 | int killsuid = should_remove_suid(dentry); | 1985 | struct inode *inode = dentry->d_inode; |
1986 | int killpriv = security_inode_need_killpriv(dentry); | 1986 | int killsuid; |
1987 | int killpriv; | ||
1987 | int error = 0; | 1988 | int error = 0; |
1988 | 1989 | ||
1990 | /* Fast path for nothing security related */ | ||
1991 | if (IS_NOSEC(inode)) | ||
1992 | return 0; | ||
1993 | |||
1994 | killsuid = should_remove_suid(dentry); | ||
1995 | killpriv = security_inode_need_killpriv(dentry); | ||
1996 | |||
1989 | if (killpriv < 0) | 1997 | if (killpriv < 0) |
1990 | return killpriv; | 1998 | return killpriv; |
1991 | if (killpriv) | 1999 | if (killpriv) |
1992 | error = security_inode_killpriv(dentry); | 2000 | error = security_inode_killpriv(dentry); |
1993 | if (!error && killsuid) | 2001 | if (!error && killsuid) |
1994 | error = __remove_suid(dentry, killsuid); | 2002 | error = __remove_suid(dentry, killsuid); |
2003 | if (!error) | ||
2004 | inode->i_flags |= S_NOSEC; | ||
1995 | 2005 | ||
1996 | return error; | 2006 | return error; |
1997 | } | 2007 | } |