[-V5,10/24] vfs: Add permission flags for setting file attributes
diff mbox

Message ID 1298469131-16555-11-git-send-email-aneesh.kumar@linux.vnet.ibm.com
State New, archived
Headers show

Commit Message

Aneesh Kumar K.V Feb. 23, 2011, 1:51 p.m. UTC
None

Patch
diff mbox

diff --git a/fs/attr.c b/fs/attr.c
index f081b5a..793f34c 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -13,6 +13,20 @@ 
 #include <linux/fsnotify.h>
 #include <linux/fcntl.h>
 #include <linux/security.h>
+#include <linux/richacl.h>
+
+static int richacl_change_ok(struct inode *inode, int mask)
+{
+	if (!IS_RICHACL(inode))
+		return -EPERM;
+
+	if (inode->i_op->permission)
+		return inode->i_op->permission(inode, mask, 0);
+	else if (inode->i_op->check_acl)
+		return inode->i_op->check_acl(inode, mask, 0);
+	else
+		return -EPERM;
+}
 
 /**
  * inode_change_ok - check if attribute changes to an inode are allowed
@@ -47,20 +61,29 @@  int inode_change_ok(struct inode *inode, struct iattr *attr)
 	/* Make sure a caller can chown. */
 	if ((ia_valid & ATTR_UID) &&
 	    (current_fsuid() != inode->i_uid ||
-	     attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
-		return -EPERM;
+	     attr->ia_uid != inode->i_uid) &&
+	    (current_fsuid() != attr->ia_uid ||
+	     richacl_change_ok(inode, MAY_TAKE_OWNERSHIP)) &&
+	    !capable(CAP_CHOWN))
+		goto error;
 
 	/* Make sure caller can chgrp. */
-	if ((ia_valid & ATTR_GID) &&
-	    (current_fsuid() != inode->i_uid ||
-	    (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
-	    !capable(CAP_CHOWN))
-		return -EPERM;
+	if (ia_valid & ATTR_GID) {
+		int in_group = in_group_p(attr->ia_gid);
+		if ((current_fsuid() != inode->i_uid ||
+		     (!in_group && attr->ia_gid != inode->i_gid)) &&
+		    (!in_group ||
+		     richacl_change_ok(inode, MAY_TAKE_OWNERSHIP)) &&
+		    !capable(CAP_CHOWN))
+			goto error;
+	}
 
 	/* Make sure a caller can chmod. */
 	if (ia_valid & ATTR_MODE) {
-		if (!is_owner_or_cap(inode))
-			return -EPERM;
+		if (current_fsuid() != inode->i_uid &&
+		    richacl_change_ok(inode, MAY_CHMOD) &&
+		    !capable(CAP_FOWNER))
+			goto error;
 		/* Also check the setgid bit! */
 		if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
 				inode->i_gid) && !capable(CAP_FSETID))
@@ -69,11 +92,15 @@  int inode_change_ok(struct inode *inode, struct iattr *attr)
 
 	/* Check for setting the inode time. */
 	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
-		if (!is_owner_or_cap(inode))
-			return -EPERM;
+		if (current_fsuid() != inode->i_uid &&
+		    richacl_change_ok(inode, MAY_SET_TIMES) &&
+		    !capable(CAP_FOWNER))
+			goto error;
 	}
 
 	return 0;
+error:
+	return -EPERM;
 }
 EXPORT_SYMBOL(inode_change_ok);
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3ae23a2..1627592 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -66,6 +66,9 @@  struct inodes_stat_t {
 #define MAY_CREATE_DIR 256
 #define MAY_DELETE_CHILD 512
 #define MAY_DELETE_SELF 1024
+#define MAY_TAKE_OWNERSHIP 2048
+#define MAY_CHMOD 4096
+#define MAY_SET_TIMES 8192
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond