[PATCH 3/3] Mapping read/write with fsuid

Alin Dobre alin.dobre at elastichosts.com
Wed Oct 2 10:47:35 EDT 2013


From: Alin Dobre <alinmd at gmail.com>

The fsuid mapping should replaces modifying the inode directly for
read/write operations.

Signed-off-by: Alin Dobre <alinmd at gmail.com>
---
 fs/idmapfs/file.c   | 42 ++++++++++++++++++++++++++++++++++++------
 fs/idmapfs/inode.c  |  6 +++---
 fs/idmapfs/lookup.c |  2 +-
 fs/idmapfs/wrapfs.h |  2 ++
 4 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/fs/idmapfs/file.c b/fs/idmapfs/file.c
index df44994..88697a0 100644
--- a/fs/idmapfs/file.c
+++ b/fs/idmapfs/file.c
@@ -11,6 +11,34 @@
 
 #include "wrapfs.h"
 
+int map_fsuid(void) {
+	struct cred *mapped_cred;
+
+	mapped_cred = prepare_creds();
+	if (!mapped_cred)
+		return -ENOMEM;
+	if (mapped_cred->fsuid != 1000) {
+		abort_creds(mapped_cred);
+		return 0;
+	}
+	mapped_cred->fsuid = 1001;
+	return commit_creds(mapped_cred);
+}
+
+int unmap_fsuid(void) {
+	struct cred *mapped_cred;
+
+	mapped_cred = prepare_creds();
+	if (!mapped_cred)
+		return -ENOMEM;
+	if (mapped_cred->fsuid != 1001) {
+		abort_creds(mapped_cred);
+		return 0;
+	}
+	mapped_cred->fsuid = 1000;
+	return commit_creds(mapped_cred);
+}
+
 static ssize_t wrapfs_read(struct file *file, char __user *buf,
 			   size_t count, loff_t *ppos)
 {
@@ -19,9 +47,9 @@ static ssize_t wrapfs_read(struct file *file, char __user *buf,
 	struct dentry *dentry = file->f_path.dentry;
 
 	lower_file = wrapfs_lower_file(file);
-	lower_file->f_inode->i_uid=map_id(lower_file->f_inode->i_uid);
+	map_fsuid();
 	err = vfs_read(lower_file, buf, count, ppos);
-	lower_file->f_inode->i_uid=unmap_id(lower_file->f_inode->i_uid);
+	unmap_fsuid();
 	/* update our inode atime upon a successful lower read */
 	if (err >= 0)
 		fsstack_copy_attr_atime(dentry->d_inode,
@@ -38,9 +66,9 @@ static ssize_t wrapfs_write(struct file *file, const char __user *buf,
 	struct dentry *dentry = file->f_path.dentry;
 
 	lower_file = wrapfs_lower_file(file);
-	lower_file->f_inode->i_uid=map_id(lower_file->f_inode->i_uid);
+	map_fsuid();
 	err = vfs_write(lower_file, buf, count, ppos);
-	lower_file->f_inode->i_uid=unmap_id(lower_file->f_inode->i_uid);
+	unmap_fsuid();
 	/* update our inode times+sizes upon a successful lower write */
 	if (err >= 0) {
 		fsstack_copy_inode_size(dentry->d_inode,
@@ -59,9 +87,9 @@ static int wrapfs_readdir(struct file *file, void *dirent, filldir_t filldir)
 	struct dentry *dentry = file->f_path.dentry;
 
 	lower_file = wrapfs_lower_file(file);
-	lower_file->f_inode->i_uid=map_id(lower_file->f_inode->i_uid);
+	map_fsuid();
 	err = vfs_readdir(lower_file, filldir, dirent);
-	lower_file->f_inode->i_uid=unmap_id(lower_file->f_inode->i_uid);
+	unmap_fsuid();
 	file->f_pos = lower_file->f_pos;
 	if (err >= 0)		/* copy the atime */
 		fsstack_copy_attr_atime(dentry->d_inode,
@@ -174,6 +202,7 @@ static int wrapfs_open(struct inode *inode, struct file *file)
 	struct file *lower_file = NULL;
 	struct path lower_path;
 
+	map_fsuid();
 	/* don't open unhashed/deleted files */
 	if (d_unhashed(file->f_path.dentry)) {
 		err = -ENOENT;
@@ -207,6 +236,7 @@ static int wrapfs_open(struct inode *inode, struct file *file)
 	else
 		fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode));
 out_err:
+	unmap_fsuid();
 	return err;
 }
 
diff --git a/fs/idmapfs/inode.c b/fs/idmapfs/inode.c
index 2b80e00..d38a5df1 100644
--- a/fs/idmapfs/inode.c
+++ b/fs/idmapfs/inode.c
@@ -24,11 +24,10 @@ static int wrapfs_create(struct inode *dir, struct dentry *dentry,
 	lower_parent_dentry = lock_parent(lower_dentry);
 
 	lower_dentry->d_inode->i_uid = map_id(lower_dentry->d_inode->i_uid);
-	lower_parent_dentry->d_inode->i_uid = map_id(lower_parent_dentry->d_inode->i_uid);
+	//lower_parent_dentry->d_inode->i_uid = map_id(lower_parent_dentry->d_inode->i_uid);
 	err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode,
 			 want_excl);
-	lower_dentry->d_inode->i_uid = unmap_id(lower_dentry->d_inode->i_uid);
-	lower_parent_dentry->d_inode->i_uid = unmap_id(lower_parent_dentry->d_inode->i_uid);
+	//lower_parent_dentry->d_inode->i_uid = unmap_id(lower_parent_dentry->d_inode->i_uid);
 	if (err)
 		goto out;
 	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
@@ -36,6 +35,7 @@ static int wrapfs_create(struct inode *dir, struct dentry *dentry,
 		goto out;
 	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
 	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
+	lower_dentry->d_inode->i_uid = unmap_id(lower_dentry->d_inode->i_uid);
 
 out:
 	unlock_dir(lower_parent_dentry);
diff --git a/fs/idmapfs/lookup.c b/fs/idmapfs/lookup.c
index 999b227..92816e3 100644
--- a/fs/idmapfs/lookup.c
+++ b/fs/idmapfs/lookup.c
@@ -205,13 +205,13 @@ int wrapfs_interpose(struct dentry *dentry, struct super_block *sb,
 	/* inherit lower inode number for wrapfs's inode */
 	lower_inode->i_uid=map_id(lower_inode->i_uid);
 	inode = wrapfs_iget(sb, lower_inode);
-	lower_inode->i_uid=unmap_id(lower_inode->i_uid);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		goto out;
 	}
 
 	d_add(dentry, inode);
+	lower_inode->i_uid=unmap_id(lower_inode->i_uid);
 
 out:
 	return err;
diff --git a/fs/idmapfs/wrapfs.h b/fs/idmapfs/wrapfs.h
index 59f46bc..a089862 100644
--- a/fs/idmapfs/wrapfs.h
+++ b/fs/idmapfs/wrapfs.h
@@ -63,6 +63,8 @@ extern int wrapfs_interpose(struct dentry *dentry, struct super_block *sb,
 /* UID/GID mapping */
 int map_id(int id);
 int unmap_id(int id);
+int map_fsuid(void);
+int unmap_fsuid(void);
 
 /* file private data */
 struct wrapfs_file_info {
-- 
1.8.3.2




More information about the Kernelnewbies mailing list