[Devel] [PATCH 5/6] userns strict: hook ext2

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


>From nobody Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serue at us.ibm.com>
Date: Wed, 28 Mar 2007 15:06:47 -0500
Subject: [PATCH 5/6] userns strict: hook ext2

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

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

---

 fs/ext2/acl.c                  |    4 +++-
 fs/ext2/balloc.c               |   13 ++++++++++---
 fs/ext2/ialloc.c               |    5 +++++
 fs/ext2/inode.c                |    2 ++
 fs/ext2/ioctl.c                |   12 ++++++++----
 fs/ext2/super.c                |    4 ++++
 fs/ext2/xattr_trusted.c        |    3 ++-
 include/linux/ext2_fs_sb.h     |    1 +
 include/linux/user_namespace.h |   16 ++++++++++++++++
 9 files changed, 51 insertions(+), 9 deletions(-)

04b91190fbcaf388100bc748062724e384f1d868
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 7c420b8..7bb1ccd 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -9,6 +9,7 @@ #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
+#include <linux/user_namespace.h>
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
@@ -464,7 +465,8 @@ ext2_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/ext2/balloc.c b/fs/ext2/balloc.c
index 538c221..2924f0e 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -16,6 +16,7 @@ #include <linux/quotaops.h>
 #include <linux/sched.h>
 #include <linux/buffer_head.h>
 #include <linux/capability.h>
+#include <linux/user_namespace.h>
 
 /*
  * balloc.c contains the blocks allocation and deallocation routines
@@ -1127,9 +1128,15 @@ static int ext2_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/ext2/ialloc.c b/fs/ext2/ialloc.c
index 86a2f3b..34f16ab 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -17,6 +17,7 @@ #include <linux/sched.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
 #include <linux/random.h>
+#include <linux/user_namespace.h>
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
@@ -133,6 +134,9 @@ void ext2_free_inode (struct inode * ino
 	/* 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;
+
 	if (ino < EXT2_FIRST_INO(sb) ||
 	    ino > le32_to_cpu(es->s_inodes_count)) {
 		ext2_error (sb, "ext2_free_inode",
@@ -563,6 +567,7 @@ got:
 	sb->s_dirt = 1;
 	mark_buffer_dirty(bh2);
 	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/ext2/inode.c b/fs/ext2/inode.c
index 5deb23b..dcca474 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -31,6 +31,7 @@ #include <linux/module.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
+#include <linux/user_namespace.h>
 #include "ext2.h"
 #include "acl.h"
 #include "xip.h"
@@ -1168,6 +1169,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/ext2/ioctl.c b/fs/ext2/ioctl.c
index 315a98b..2326804 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -13,6 +13,7 @@ #include <linux/time.h>
 #include <linux/sched.h>
 #include <linux/compat.h>
 #include <linux/smp_lock.h>
+#include <linux/user_namespace.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
@@ -36,7 +37,8 @@ int ext2_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))
@@ -55,7 +57,7 @@ int ext2_ioctl (struct inode * inode, st
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
 		if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
-			if (!capable(CAP_LINUX_IMMUTABLE)) {
+			if (!task_ino_capable(inode, CAP_LINUX_IMMUTABLE)) {
 				mutex_unlock(&inode->i_mutex);
 				return -EPERM;
 			}
@@ -74,7 +76,8 @@ int ext2_ioctl (struct inode * inode, st
 	case EXT2_IOC_GETVERSION:
 		return put_user(inode->i_generation, (int __user *) arg);
 	case EXT2_IOC_SETVERSION:
-		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;
@@ -99,7 +102,8 @@ int ext2_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(rsv_window_size, (int __user *)arg))
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 932579b..75ce9e8 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -29,6 +29,7 @@ #include <linux/smp_lock.h>
 #include <linux/vfs.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 #include "ext2.h"
 #include "xattr.h"
@@ -125,6 +126,7 @@ static void ext2_put_super (struct super
 			brelse (sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
 	kfree(sbi->s_debts);
+	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);
@@ -742,6 +744,7 @@ #endif
 
 	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
 	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+	sbi->s_resuidns = get_task_user_ns(current);
 	
 	set_opt(sbi->s_mount_opt, RESERVATION);
 
@@ -990,6 +993,7 @@ failed_mount_group_desc:
 	kfree(sbi->s_group_desc);
 	kfree(sbi->s_debts);
 failed_mount:
+	put_user_ns(sbi->s_resuidns);
 	brelse(bh);
 failed_sbi:
 	sb->s_fs_info = NULL;
diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c
index f28a6a4..d24729a 100644
--- a/fs/ext2/xattr_trusted.c
+++ b/fs/ext2/xattr_trusted.c
@@ -11,6 +11,7 @@ #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/smp_lock.h>
 #include <linux/ext2_fs.h>
+#include <linux/user_namespace.h>
 #include "xattr.h"
 
 #define XATTR_TRUSTED_PREFIX "trusted."
@@ -22,7 +23,7 @@ ext2_xattr_trusted_list(struct inode *in
 	const int 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/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
index b1b69bc..bdbc7cd 100644
--- a/include/linux/ext2_fs_sb.h
+++ b/include/linux/ext2_fs_sb.h
@@ -85,6 +85,7 @@ struct ext2_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;
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 073f3e0..e87d6f5 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -27,6 +27,8 @@ static inline struct user_namespace *get
 	return ns;
 }
 
+extern struct user_namespace *get_task_user_ns(struct task_struct *tsk);
+
 extern struct user_namespace *copy_user_ns(int flags,
 					   struct user_namespace *old_ns);
 extern void free_user_ns(struct kref *kref);
@@ -76,6 +78,10 @@ task_inode_same_fsuid(struct task_struct
 	return 1;
 }
 
+/* the set of helpers is really getting out of hand.  consolidate
+ * in thr next release
+ */
+
 /*
  * task_ino_capable:
  * Again, when userns keys exist, we will need to check for a
@@ -95,6 +101,16 @@ static inline struct user_namespace *get
 	return &init_user_ns;
 }
 
+static inline struct user_namespace *task_user_ns(struct task_struct *tsk)
+{
+	return &init_user_ns;
+}
+
+static inline struct user_namespace *get_task_user_ns(struct task_struct *tsk)
+{
+	return &init_user_ns;
+}
+
 static inline struct user_namespace *copy_user_ns(int flags,
 						  struct user_namespace *old_ns)
 {
-- 
1.3.2




More information about the Devel mailing list