Merge branch 'master' into next
diff --git a/security/security.c b/security/security.c
index 24e060b..f2d8aa9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -389,42 +389,42 @@
 EXPORT_SYMBOL(security_inode_init_security);
 
 #ifdef CONFIG_SECURITY_PATH
-int security_path_mknod(struct path *path, struct dentry *dentry, int mode,
+int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
 			unsigned int dev)
 {
-	if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+	if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
 		return 0;
-	return security_ops->path_mknod(path, dentry, mode, dev);
+	return security_ops->path_mknod(dir, dentry, mode, dev);
 }
 EXPORT_SYMBOL(security_path_mknod);
 
-int security_path_mkdir(struct path *path, struct dentry *dentry, int mode)
+int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
 {
-	if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+	if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
 		return 0;
-	return security_ops->path_mkdir(path, dentry, mode);
+	return security_ops->path_mkdir(dir, dentry, mode);
 }
 
-int security_path_rmdir(struct path *path, struct dentry *dentry)
+int security_path_rmdir(struct path *dir, struct dentry *dentry)
 {
-	if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+	if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
 		return 0;
-	return security_ops->path_rmdir(path, dentry);
+	return security_ops->path_rmdir(dir, dentry);
 }
 
-int security_path_unlink(struct path *path, struct dentry *dentry)
+int security_path_unlink(struct path *dir, struct dentry *dentry)
 {
-	if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+	if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
 		return 0;
-	return security_ops->path_unlink(path, dentry);
+	return security_ops->path_unlink(dir, dentry);
 }
 
-int security_path_symlink(struct path *path, struct dentry *dentry,
+int security_path_symlink(struct path *dir, struct dentry *dentry,
 			  const char *old_name)
 {
-	if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+	if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
 		return 0;
-	return security_ops->path_symlink(path, dentry, old_name);
+	return security_ops->path_symlink(dir, dentry, old_name);
 }
 
 int security_path_link(struct dentry *old_dentry, struct path *new_dir,
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 3f2b270..e6654b5 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -541,8 +541,8 @@
 	case AVTAB_MEMBER:
 		/* Use the process effective MLS attributes. */
 		return mls_context_cpy_low(newcontext, scontext);
-	default:
-		return -EINVAL;
+
+	/* fall through */
 	}
 	return -EINVAL;
 }
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d6bb20c..07ddc81 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2555,7 +2555,7 @@
 	read_lock(&policy_rwlock);
 
 	*nclasses = policydb.p_classes.nprim;
-	*classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC);
+	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
 	if (!*classes)
 		goto out;
 
@@ -2602,7 +2602,7 @@
 	}
 
 	*nperms = match->permissions.nprim;
-	*perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC);
+	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
 	if (!*perms)
 		goto out;
 
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index e0d0354..6c60616 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -842,52 +842,27 @@
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
 		switch (tomoyo_acl_type2(ptr)) {
-			struct tomoyo_single_path_acl_record *acl1;
-			struct tomoyo_double_path_acl_record *acl2;
-			u16 perm;
+			struct tomoyo_single_path_acl_record *acl;
+			u32 perm;
+			u8 i;
 		case TOMOYO_TYPE_SINGLE_PATH_ACL:
-			acl1 = container_of(ptr,
-				    struct tomoyo_single_path_acl_record,
-					    head);
-			perm = acl1->perm;
-			if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL))
-				count++;
-			if (perm &
-			    ((1 << TOMOYO_TYPE_READ_ACL) |
-			     (1 << TOMOYO_TYPE_WRITE_ACL)))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_CREATE_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL))
-				count++;
+			acl = container_of(ptr,
+					   struct tomoyo_single_path_acl_record,
+					   head);
+			perm = acl->perm | (((u32) acl->perm_high) << 16);
+			for (i = 0; i < TOMOYO_MAX_SINGLE_PATH_OPERATION; i++)
+				if (perm & (1 << i))
+					count++;
+			if (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))
+				count -= 2;
 			break;
 		case TOMOYO_TYPE_DOUBLE_PATH_ACL:
-			acl2 = container_of(ptr,
+			perm = container_of(ptr,
 				    struct tomoyo_double_path_acl_record,
-					    head);
-			perm = acl2->perm;
-			if (perm & (1 << TOMOYO_TYPE_LINK_ACL))
-				count++;
-			if (perm & (1 << TOMOYO_TYPE_RENAME_ACL))
-				count++;
+					    head)->perm;
+			for (i = 0; i < TOMOYO_MAX_DOUBLE_PATH_OPERATION; i++)
+				if (perm & (1 << i))
+					count++;
 			break;
 		}
 	}
@@ -1426,7 +1401,7 @@
 	u8 bit;
 	const char *atmark = "";
 	const char *filename;
-	const u16 perm = ptr->perm;
+	const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16);
 
 	filename = ptr->filename->name;
 	for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION;
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 92169d2..bd10f9f 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -108,7 +108,7 @@
  *      (b) type & 0x80 : whether the entry is marked as "deleted".
  *
  * Packing "struct tomoyo_acl_info" allows
- * "struct tomoyo_single_path_acl_record" to embed "u16" and
+ * "struct tomoyo_single_path_acl_record" to embed "u8" + "u16" and
  * "struct tomoyo_double_path_acl_record" to embed "u8"
  * without enlarging their structure size.
  */
@@ -184,10 +184,13 @@
  * Directives held by this structure are "allow_read/write", "allow_execute",
  * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
  * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock",
- * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite".
+ * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite",
+ * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount"
+ * and "allow_unmount".
  */
 struct tomoyo_single_path_acl_record {
 	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */
+	u8 perm_high;
 	u16 perm;
 	/* Pointer to single pathname. */
 	const struct tomoyo_path_info *filename;
@@ -195,7 +198,7 @@
 
 /*
  * tomoyo_double_path_acl_record is a structure which is used for holding an
- * entry with two pathnames operation (i.e. link() and rename()).
+ * entry with two pathnames operation (i.e. link(), rename() and pivot_root()).
  * It has following fields.
  *
  *  (1) "head" which is a "struct tomoyo_acl_info".
@@ -203,7 +206,8 @@
  *  (3) "filename1" is the source/old pathname.
  *  (4) "filename2" is the destination/new pathname.
  *
- * Directives held by this structure are "allow_rename" and "allow_link".
+ * Directives held by this structure are "allow_rename", "allow_link" and
+ * "allow_pivot_root".
  */
 struct tomoyo_double_path_acl_record {
 	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 8346938..482f0e7 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -81,12 +81,20 @@
 	[TOMOYO_TYPE_TRUNCATE_ACL]   = "truncate",
 	[TOMOYO_TYPE_SYMLINK_ACL]    = "symlink",
 	[TOMOYO_TYPE_REWRITE_ACL]    = "rewrite",
+	[TOMOYO_TYPE_IOCTL_ACL]      = "ioctl",
+	[TOMOYO_TYPE_CHMOD_ACL]      = "chmod",
+	[TOMOYO_TYPE_CHOWN_ACL]      = "chown",
+	[TOMOYO_TYPE_CHGRP_ACL]      = "chgrp",
+	[TOMOYO_TYPE_CHROOT_ACL]     = "chroot",
+	[TOMOYO_TYPE_MOUNT_ACL]      = "mount",
+	[TOMOYO_TYPE_UMOUNT_ACL]     = "unmount",
 };
 
 /* Keyword array for double path operations. */
 static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = {
 	[TOMOYO_TYPE_LINK_ACL]    = "link",
 	[TOMOYO_TYPE_RENAME_ACL]  = "rename",
+	[TOMOYO_TYPE_PIVOT_ROOT_ACL] = "pivot_root",
 };
 
 /**
@@ -655,7 +663,7 @@
 					 domain,
 					 const struct tomoyo_path_info *
 					 filename,
-					 const u16 perm,
+					 const u32 perm,
 					 const bool may_use_pattern)
 {
 	struct tomoyo_acl_info *ptr;
@@ -668,8 +676,13 @@
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
 				   head);
-		if (!(acl->perm & perm))
-			continue;
+		if (perm <= 0xFFFF) {
+			if (!(acl->perm & perm))
+				continue;
+		} else {
+			if (!(acl->perm_high & (perm >> 16)))
+				continue;
+		}
 		if (may_use_pattern || !acl->filename->is_patterned) {
 			if (!tomoyo_path_matches_pattern(filename,
 							 acl->filename))
@@ -697,7 +710,7 @@
 				 const struct tomoyo_path_info *filename,
 				 const u8 operation)
 {
-	u16 perm = 0;
+	u32 perm = 0;
 
 	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
 		return 0;
@@ -830,13 +843,13 @@
 					 struct tomoyo_domain_info *
 					 const domain, const bool is_delete)
 {
-	static const u16 rw_mask =
+	static const u32 rw_mask =
 		(1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
 	const struct tomoyo_path_info *saved_filename;
 	struct tomoyo_acl_info *ptr;
 	struct tomoyo_single_path_acl_record *acl;
 	int error = -ENOMEM;
-	const u16 perm = 1 << type;
+	const u32 perm = 1 << type;
 
 	if (!domain)
 		return -EINVAL;
@@ -858,7 +871,10 @@
 		/* Special case. Clear all bits if marked as deleted. */
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			acl->perm = 0;
-		acl->perm |= perm;
+		if (perm <= 0xFFFF)
+			acl->perm |= perm;
+		else
+			acl->perm_high |= (perm >> 16);
 		if ((acl->perm & rw_mask) == rw_mask)
 			acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL;
 		else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))
@@ -871,7 +887,10 @@
 	acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
 	if (!acl)
 		goto out;
-	acl->perm = perm;
+	if (perm <= 0xFFFF)
+		acl->perm = perm;
+	else
+		acl->perm_high = (perm >> 16);
 	if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
 		acl->perm |= rw_mask;
 	acl->filename = saved_filename;
@@ -887,12 +906,15 @@
 				   head);
 		if (acl->filename != saved_filename)
 			continue;
-		acl->perm &= ~perm;
+		if (perm <= 0xFFFF)
+			acl->perm &= ~perm;
+		else
+			acl->perm_high &= ~(perm >> 16);
 		if ((acl->perm & rw_mask) != rw_mask)
 			acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL);
 		else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
 			acl->perm &= ~rw_mask;
-		if (!acl->perm)
+		if (!acl->perm && !acl->perm_high)
 			ptr->type |= TOMOYO_ACL_DELETED;
 		error = 0;
 		break;
@@ -1172,7 +1194,7 @@
 }
 
 /**
- * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink".
+ * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
  *
  * @domain:    Pointer to "struct tomoyo_domain_info".
  * @operation: Type of operation.
@@ -1196,6 +1218,7 @@
 	switch (operation) {
 	case TOMOYO_TYPE_MKDIR_ACL:
 	case TOMOYO_TYPE_RMDIR_ACL:
+	case TOMOYO_TYPE_CHROOT_ACL:
 		if (!buf->is_dir) {
 			/*
 			 * tomoyo_get_path() reserves space for appending "/."
@@ -1249,7 +1272,7 @@
 }
 
 /**
- * tomoyo_check_2path_perm - Check permission for "rename" and "link".
+ * tomoyo_check_2path_perm - Check permission for "rename", "link" and "pivot_root".
  *
  * @domain:    Pointer to "struct tomoyo_domain_info".
  * @operation: Type of operation.
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 8a00ade..ad9555f 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -194,6 +194,60 @@
 	return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
 }
 
+static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
+			     unsigned long arg)
+{
+	return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_IOCTL_ACL,
+				       &file->f_path);
+}
+
+static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+			     mode_t mode)
+{
+	struct path path = { mnt, dentry };
+	return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_CHMOD_ACL,
+				       &path);
+}
+
+static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+	int error = 0;
+	if (uid != (uid_t) -1)
+		error = tomoyo_check_1path_perm(tomoyo_domain(),
+						TOMOYO_TYPE_CHOWN_ACL, path);
+	if (!error && gid != (gid_t) -1)
+		error = tomoyo_check_1path_perm(tomoyo_domain(),
+						TOMOYO_TYPE_CHGRP_ACL, path);
+	return error;
+}
+
+static int tomoyo_path_chroot(struct path *path)
+{
+	return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_CHROOT_ACL,
+				       path);
+}
+
+static int tomoyo_sb_mount(char *dev_name, struct path *path,
+			   char *type, unsigned long flags, void *data)
+{
+	return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_MOUNT_ACL,
+				       path);
+}
+
+static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
+{
+	struct path path = { mnt, mnt->mnt_root };
+	return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_UMOUNT_ACL,
+				       &path);
+}
+
+static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)
+{
+	return tomoyo_check_2path_perm(tomoyo_domain(),
+				       TOMOYO_TYPE_PIVOT_ROOT_ACL,
+				       new_path, old_path);
+}
+
 /*
  * tomoyo_security_ops is a "struct security_operations" which is used for
  * registering TOMOYO.
@@ -215,6 +269,13 @@
 	.path_mknod          = tomoyo_path_mknod,
 	.path_link           = tomoyo_path_link,
 	.path_rename         = tomoyo_path_rename,
+	.file_ioctl          = tomoyo_file_ioctl,
+	.path_chmod          = tomoyo_path_chmod,
+	.path_chown          = tomoyo_path_chown,
+	.path_chroot         = tomoyo_path_chroot,
+	.sb_mount            = tomoyo_sb_mount,
+	.sb_umount           = tomoyo_sb_umount,
+	.sb_pivotroot        = tomoyo_sb_pivotroot,
 };
 
 static int __init tomoyo_init(void)
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h
index ed75832..bf3986a 100644
--- a/security/tomoyo/tomoyo.h
+++ b/security/tomoyo/tomoyo.h
@@ -62,11 +62,19 @@
 #define TOMOYO_TYPE_TRUNCATE_ACL     12
 #define TOMOYO_TYPE_SYMLINK_ACL      13
 #define TOMOYO_TYPE_REWRITE_ACL      14
-#define TOMOYO_MAX_SINGLE_PATH_OPERATION 15
+#define TOMOYO_TYPE_IOCTL_ACL        15
+#define TOMOYO_TYPE_CHMOD_ACL        16
+#define TOMOYO_TYPE_CHOWN_ACL        17
+#define TOMOYO_TYPE_CHGRP_ACL        18
+#define TOMOYO_TYPE_CHROOT_ACL       19
+#define TOMOYO_TYPE_MOUNT_ACL        20
+#define TOMOYO_TYPE_UMOUNT_ACL       21
+#define TOMOYO_MAX_SINGLE_PATH_OPERATION 22
 
 #define TOMOYO_TYPE_LINK_ACL         0
 #define TOMOYO_TYPE_RENAME_ACL       1
-#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2
+#define TOMOYO_TYPE_PIVOT_ROOT_ACL   2
+#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 3
 
 #define TOMOYO_DOMAINPOLICY          0
 #define TOMOYO_EXCEPTIONPOLICY       1