[PATCH 6/6] userns strict: hook ext3

Serge E. Hallyn serue at us.ibm.com
Mon Jun 4 12:42:20 PDT 2007


>From nobody Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serue at us.ibm.com>
Date: Wed, 28 Mar 2007 13:11:19 -0500
Subject: [PATCH 6/6] userns strict: hook ext3

Add a user namespace pointer to the ext3 superblock and inode.

Signed-off-by: Serge E. Hallyn <serue at us.ibm.com>

---

 fs/ext3/acl.c              |    4 +++-
 fs/ext3/balloc.c           |   13 ++++++++++---
 fs/ext3/ialloc.c           |    5 +++++
 fs/ext3/inode.c            |    2 ++
 fs/ext3/ioctl.c            |   18 +++++++++++-------
 fs/ext3/super.c            |    4 ++++
 fs/ext3/xattr_trusted.c    |    3 ++-
 include/linux/ext3_fs_sb.h |    1 +
 8 files changed, 38 insertions(+), 12 deletions(-)

d51e324bced6f12d2fc7906dbfc355f4cd2bc8bc
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 1e5038d..35b64a9 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -11,6 +11,7 @@ #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
+#include <linux/user_namespace.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -489,7 +490,8 @@ ext3_xattr_set_acl(struct inode *inode, 
 
 	if (!test_opt(inode->i_sb, POSIX_ACL))
 		return -EOPNOTSUPP;
-	if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+	if (!task_inode_same_fsuid(current, inode) &&
+			!task_ino_capable(inode, CAP_FOWNER))
 		return -EPERM;
 
 	if (value) {
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index ca8aee6..ab4076d 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -19,6 +19,7 @@ #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
+#include <linux/user_namespace.h>
 
 /*
  * balloc.c contains the blocks allocation and deallocation routines
@@ -1359,9 +1360,15 @@ static int ext3_has_free_blocks(struct e
 
 	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
 	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
-	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		sbi->s_resuid != current->fsuid &&
-		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+	if (free_blocks < root_blocks + 1) {
+		if (sbi->s_resuidns != task_user_ns(current))
+			return 0;
+		if (capable(CAP_SYS_RESOURCE))
+			return 1;
+		if (sbi->s_resuid == current->fsuid)
+			return 1;
+		if (sbi->s_resgid != 0 && in_group_p (sbi->s_resgid))
+			return 1;
 		return 0;
 	}
 	return 1;
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index e45dbd6..eb31b83 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -23,6 +23,7 @@ #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/random.h>
 #include <linux/bitops.h>
+#include <linux/user_namespace.h>
 
 #include <asm/byteorder.h>
 
@@ -133,6 +134,9 @@ void ext3_free_inode (handle_t *handle, 
 	/* Do this BEFORE marking the inode not in use or returning an error */
 	clear_inode (inode);
 
+	put_user_ns(inode->i_userns);
+	inode->i_userns = NULL;
+
 	es = EXT3_SB(sb)->s_es;
 	if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
 		ext3_error (sb, "ext3_free_inode",
@@ -547,6 +551,7 @@ got:
 	sb->s_dirt = 1;
 
 	inode->i_uid = current->fsuid;
+	inode->i_userns = get_task_user_ns(current);
 	if (test_opt (sb, GRPID))
 		inode->i_gid = dir->i_gid;
 	else if (dir->i_mode & S_ISGID) {
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 535c5a5..2ec63bb 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -37,6 +37,7 @@ #include <linux/writeback.h>
 #include <linux/mpage.h>
 #include <linux/uio.h>
 #include <linux/bio.h>
+#include <linux/user_namespace.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -2667,6 +2668,7 @@ #endif
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
 	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
 	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	inode->i_userns = get_task_user_ns(current);
 	if(!(test_opt (inode->i_sb, NO_UID32))) {
 		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 9b8090d..6874367 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -15,6 +15,7 @@ #include <linux/ext3_jbd.h>
 #include <linux/time.h>
 #include <linux/compat.h>
 #include <linux/smp_lock.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 
 int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
@@ -40,7 +41,8 @@ int ext3_ioctl (struct inode * inode, st
 		if (IS_RDONLY(inode))
 			return -EROFS;
 
-		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ 		if (!task_inode_same_fsuid(current, inode) &&
+				!task_ino_capable(inode, CAP_FOWNER))
 			return -EACCES;
 
 		if (get_user(flags, (int __user *) arg))
@@ -62,7 +64,7 @@ int ext3_ioctl (struct inode * inode, st
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
 		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
-			if (!capable(CAP_LINUX_IMMUTABLE)) {
+			if (!task_ino_capable(inode, CAP_LINUX_IMMUTABLE)) {
 				mutex_unlock(&inode->i_mutex);
 				return -EPERM;
 			}
@@ -73,7 +75,7 @@ int ext3_ioctl (struct inode * inode, st
 		 * the relevant capability.
 		 */
 		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
-			if (!capable(CAP_SYS_RESOURCE)) {
+			if (!task_ino_capable(inode, CAP_SYS_RESOURCE)) {
 				mutex_unlock(&inode->i_mutex);
 				return -EPERM;
 			}
@@ -121,7 +123,8 @@ flags_err:
 		__u32 generation;
 		int err;
 
-		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+		if (!task_inode_same_fsuid(current, inode) &&
+				!task_ino_capable(inode, CAP_FOWNER))
 			return -EPERM;
 		if (IS_RDONLY(inode))
 			return -EROFS;
@@ -180,7 +183,8 @@ #endif
 		if (IS_RDONLY(inode))
 			return -EROFS;
 
-		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+		if (!task_inode_same_fsuid(current, inode) &&
+				!task_ino_capable(inode, CAP_FOWNER))
 			return -EACCES;
 
 		if (get_user(rsv_window_size, (int __user *)arg))
@@ -209,7 +213,7 @@ #endif
 		struct super_block *sb = inode->i_sb;
 		int err;
 
-		if (!capable(CAP_SYS_RESOURCE))
+		if (!task_ino_capable(inode, CAP_SYS_RESOURCE))
 			return -EPERM;
 
 		if (IS_RDONLY(inode))
@@ -230,7 +234,7 @@ #endif
 		struct super_block *sb = inode->i_sb;
 		int err;
 
-		if (!capable(CAP_SYS_RESOURCE))
+		if (!task_ino_capable(inode, CAP_SYS_RESOURCE))
 			return -EPERM;
 
 		if (IS_RDONLY(inode))
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 80dfa27..19e32ee 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -35,6 +35,7 @@ #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
+#include <linux/user_namespace.h>
 
 #include <asm/uaccess.h>
 
@@ -403,6 +404,7 @@ static void ext3_put_super (struct super
 	for (i = 0; i < sbi->s_gdb_count; i++)
 		brelse(sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
+	put_user_ns(sbi->s_resuidns);
 	percpu_counter_destroy(&sbi->s_freeblocks_counter);
 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
 	percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -1417,6 +1419,7 @@ static int ext3_fill_super (struct super
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = EXT3_DEF_RESUID;
 	sbi->s_resgid = EXT3_DEF_RESGID;
+	sbi->s_resuidns = get_task_user_ns(current);
 
 	unlock_kernel();
 
@@ -1825,6 +1828,7 @@ #endif
 	brelse(bh);
 out_fail:
 	sb->s_fs_info = NULL;
+	put_user_ns(sbi->s_resuidns);
 	kfree(sbi);
 	lock_kernel();
 	return -EINVAL;
diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c
index 86d91f1..d37bfdd 100644
--- a/fs/ext3/xattr_trusted.c
+++ b/fs/ext3/xattr_trusted.c
@@ -12,6 +12,7 @@ #include <linux/fs.h>
 #include <linux/smp_lock.h>
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
+#include <linux/user_namespace.h>
 #include "xattr.h"
 
 #define XATTR_TRUSTED_PREFIX "trusted."
@@ -23,7 +24,7 @@ ext3_xattr_trusted_list(struct inode *in
 	const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1;
 	const size_t total_len = prefix_len + name_len + 1;
 
-	if (!capable(CAP_SYS_ADMIN))
+	if (!task_ino_capable(inode, CAP_SYS_ADMIN))
 		return 0;
 
 	if (list && total_len <= list_size) {
diff --git a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h
index f61309c..2a68a21 100644
--- a/include/linux/ext3_fs_sb.h
+++ b/include/linux/ext3_fs_sb.h
@@ -44,6 +44,7 @@ struct ext3_sb_info {
 	unsigned long  s_mount_opt;
 	uid_t s_resuid;
 	gid_t s_resgid;
+	struct user_namespace *s_resuidns;
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
-- 
1.3.2



More information about the Containers mailing list