[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