diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6d0b1ccb5b99f1aff76d94a256068de1f4682a7b..ac79f9ef2da810f98d9485de6eb309a291882705 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2711,12 +2711,18 @@ static int selinux_inode_permission(struct inode *inode, int mask) static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) { const struct cred *cred = current_cred(); + unsigned int ia_valid = iattr->ia_valid; + + /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ + if (ia_valid & ATTR_FORCE) { + ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE | + ATTR_FORCE); + if (!ia_valid) + return 0; + } - if (iattr->ia_valid & ATTR_FORCE) - return 0; - - if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | - ATTR_ATIME_SET | ATTR_MTIME_SET)) + if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | + ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);