linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] implement uid and gid mount options for ext2
  2012-05-11 11:10 ` [PATCH resend split 0/3] implement uid and gid mount options for ext2, ext3 and ext4 Ludwig Nussel
@ 2012-05-11 11:10   ` Ludwig Nussel
  0 siblings, 0 replies; 7+ messages in thread
From: Ludwig Nussel @ 2012-05-11 11:10 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ludwig Nussel, linux-fsdevel, Jan Kara, Rob Landley,
	Andrew Morton, Andreas Dilger, Theodore Ts'o,
	open list:EXT2 FILE SYSTEM, open list:DOCUMENTATION

Signed-off-by: Ludwig Nussel <ludwig.nussel@suse.de>
---
 Documentation/filesystems/ext2.txt |    9 ++++++
 fs/ext2/ext2.h                     |    8 +++++
 fs/ext2/inode.c                    |   42 ++++++++++++++++++++------
 fs/ext2/super.c                    |   57 +++++++++++++++++++++++++++++++++++-
 4 files changed, 105 insertions(+), 11 deletions(-)

diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index 67639f9..fcc1002 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -42,6 +42,15 @@ orlov			(*)	Use the Orlov block allocator.
 resuid=n			The user ID which may use the reserved blocks.
 resgid=n			The group ID which may use the reserved blocks.
 
+uid=n[:m]			Make all files appear to belong to uid n.
+				Useful for e.g. removable media with fstab
+				options 'user,uid=useruid'. The optional second
+				uid m is actually written to the file system.
+
+gid=n[:m]			Make all files appear to belong to gid n.
+				The optional second gid m is actually written to
+				the file system.
+
 sb=n				Use alternate superblock at this location.
 
 user_xattr			Enable "user." POSIX Extended Attributes
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 0b2b4db..b584e45 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -84,6 +84,10 @@ struct ext2_sb_info {
 	unsigned long s_sb_block;
 	uid_t s_resuid;
 	gid_t s_resgid;
+	uid_t s_uid;          /* make all files appear to belong to this uid */
+	uid_t s_diskuid;      /* write this uid to disk (if s_uid != 0) */
+	gid_t s_gid;          /* make all files appear to belong to this gid */
+	gid_t s_diskgid;      /* write this gid to disk (if s_gid != 0) */
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
@@ -639,6 +643,10 @@ struct ext2_mount_options {
 	unsigned long s_mount_opt;
 	uid_t s_resuid;
 	gid_t s_resgid;
+	uid_t s_uid;
+	uid_t s_diskuid;
+	gid_t s_gid;
+	gid_t s_diskgid;
 };
 
 /*
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 740cad8..aabcb38 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1316,6 +1316,10 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
 		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
+	if (EXT2_SB(sb)->s_uid)
+		inode->i_uid = EXT2_SB(sb)->s_uid;
+	if (EXT2_SB(sb)->s_gid)
+		inode->i_gid = EXT2_SB(sb)->s_gid;
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -1419,6 +1423,10 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)
 	struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
 	int n;
 	int err = 0;
+	__le16 uid_low;
+	__le16 gid_low;
+	__le16 uid_high;
+	__le16 gid_high;
 
 	if (IS_ERR(raw_inode))
  		return -EIO;
@@ -1430,26 +1438,40 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)
 
 	ext2_get_inode_flags(ei);
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+	if (EXT2_SB(sb)->s_uid)
+		uid = EXT2_SB(sb)->s_diskuid;
+	if (EXT2_SB(sb)->s_gid)
+		gid = EXT2_SB(sb)->s_diskgid;
 	if (!(test_opt(sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
+		uid_low = cpu_to_le16(low_16_bits(uid));
+		gid_low = cpu_to_le16(low_16_bits(gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if (!ei->i_dtime) {
-			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid));
-			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid));
+			uid_high = cpu_to_le16(high_16_bits(uid));
+			gid_high = cpu_to_le16(high_16_bits(gid));
 		} else {
-			raw_inode->i_uid_high = 0;
-			raw_inode->i_gid_high = 0;
+			uid_high = 0;
+			gid_high = 0;
 		}
 	} else {
-		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(uid));
-		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(gid));
-		raw_inode->i_uid_high = 0;
-		raw_inode->i_gid_high = 0;
+		uid_low = cpu_to_le16(fs_high2lowuid(uid));
+		gid_low = cpu_to_le16(fs_high2lowgid(gid));
+		uid_high = 0;
+		gid_high = 0;
 	}
+	/* don't mangle uid/gid of existing files if override is active */
+	if (!EXT2_SB(sb)->s_uid || ei->i_state & EXT2_STATE_NEW) {
+		raw_inode->i_uid_high = uid_high;
+		raw_inode->i_uid_low = uid_low;
+	}
+	if (!EXT2_SB(sb)->s_gid || ei->i_state & EXT2_STATE_NEW) {
+		raw_inode->i_gid_high = gid_high;
+		raw_inode->i_gid_low = gid_low;
+	}
+
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 	raw_inode->i_size = cpu_to_le32(inode->i_size);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index e1025c7..0661574 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -236,6 +236,20 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root)
 	    le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {
 		seq_printf(seq, ",resgid=%u", sbi->s_resgid);
 	}
+	if (sbi->s_uid) {
+		if (sbi->s_uid != sbi->s_diskuid)
+			seq_printf(seq, ",uid=%u:%u",
+				sbi->s_uid, sbi->s_diskuid);
+		else
+			seq_printf(seq, ",uid=%u", sbi->s_uid);
+	}
+	if (sbi->s_gid) {
+		if (sbi->s_gid != sbi->s_diskgid)
+			seq_printf(seq, ",gid=%u:%u",
+				sbi->s_gid, sbi->s_diskgid);
+		else
+			seq_printf(seq, ",gid=%u", sbi->s_gid);
+	}
 	if (test_opt(sb, ERRORS_RO)) {
 		int def_errors = le16_to_cpu(es->s_errors);
 
@@ -393,7 +407,8 @@ enum {
 	Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
 	Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
 	Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
-	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
+	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation,
+	Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid
 };
 
 static const match_table_t tokens = {
@@ -427,6 +442,10 @@ static const match_table_t tokens = {
 	{Opt_usrquota, "usrquota"},
 	{Opt_reservation, "reservation"},
 	{Opt_noreservation, "noreservation"},
+	{Opt_uid, "uid=%u"},
+	{Opt_diskuid, "uid=%u:%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_diskgid, "gid=%u:%u"},
 	{Opt_err, NULL}
 };
 
@@ -568,6 +587,34 @@ static int parse_options(char *options, struct super_block *sb)
 			clear_opt(sbi->s_mount_opt, RESERVATION);
 			ext2_msg(sb, KERN_INFO, "reservations OFF");
 			break;
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return 0;
+			sbi->s_uid = sbi->s_diskuid = option;
+			break;
+		case Opt_diskuid:
+			if (match_int(&args[0], &option))
+				return 0;
+			sbi->s_uid = option;
+
+			if (match_int(&args[1], &option))
+				return 0;
+			sbi->s_diskuid = option;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return 0;
+			sbi->s_gid = sbi->s_diskgid = option;
+			break;
+		case Opt_diskgid:
+			if (match_int(&args[0], &option))
+				return 0;
+			sbi->s_gid = option;
+
+			if (match_int(&args[1], &option))
+				return 0;
+			sbi->s_diskgid = option;
+			break;
 		case Opt_ignore:
 			break;
 		default:
@@ -1214,6 +1261,10 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 	old_opts.s_mount_opt = sbi->s_mount_opt;
 	old_opts.s_resuid = sbi->s_resuid;
 	old_opts.s_resgid = sbi->s_resgid;
+	old_opts.s_uid = sbi->s_uid;
+	old_opts.s_diskuid = sbi->s_diskuid;
+	old_opts.s_gid = sbi->s_gid;
+	old_opts.s_diskgid = sbi->s_diskgid;
 
 	/*
 	 * Allow the "check" option to be passed as a remount option.
@@ -1300,6 +1351,10 @@ restore_opts:
 	sbi->s_mount_opt = old_opts.s_mount_opt;
 	sbi->s_resuid = old_opts.s_resuid;
 	sbi->s_resgid = old_opts.s_resgid;
+	sbi->s_uid = old_opts.s_uid;
+	sbi->s_diskuid = old_opts.s_diskuid;
+	sbi->s_gid = old_opts.s_gid;
+	sbi->s_diskgid = old_opts.s_diskgid;
 	sb->s_flags = old_sb_flags;
 	spin_unlock(&sbi->s_lock);
 	return err;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 0/3] implement uid and gid mount options for ext2, ext3 and ext4
@ 2012-08-02 11:54 Ludwig Nussel
  2012-08-02 11:54 ` [PATCH 1/3] implement uid and gid mount options for ext2 Ludwig Nussel
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Ludwig Nussel @ 2012-08-02 11:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ludwig Nussel, linux-fsdevel, Jan Kara, Rob Landley,
	Andrew Morton, Andreas Dilger, Theodore Ts'o,
	open list:EXT2 FILE SYSTEM, open list:DOCUMENTATION

When using 'real' file systems on removable storage devices such as
hard disks or usb sticks people quickly face the problem that their
Linux users have different uids on different machines. Therefore one
cannot modify or even read files created on a different machine
without running chown as root or storing everything with mode 777.
Simple file systems such as vfat don't have that problem as they
don't store file ownership information and one can pass the uid
files should belong to as mount option.

The following three patches implement the uid (and gid) mount option
for ext2, ext3 and ext4 to make them actually useful on removable
media. If a file system is mounted with the uid option all files
appear to be owned by the specified uid. Only newly created files
actually end up with that uid as owner on disk though. Ownership of
existing files cannot be changed permanently if the uid option was
specified.
Optionally a second uid (diskuid) can be specified. This one is actually
written to the file system then. Useful if the filesytem is also used on a
system that does not support the uid option.

The feature can be used in two ways. Firstly via fstab by having the
admin add 'uid=useruid' in the fs_mntops column in addition to the
'user' or 'users' option. Secondly via e.g. udisks which would
automatically pass the uid of the calling user as option.

Ludwig Nussel (3):
  implement uid and gid mount options for ext2
  implement uid and gid mount options for ext3
  implement uid and gid mount options for ext4

 Documentation/filesystems/ext2.txt |    9 ++++
 Documentation/filesystems/ext3.txt |    9 ++++
 Documentation/filesystems/ext4.txt |    9 ++++
 fs/ext2/ext2.h                     |    8 +++
 fs/ext2/inode.c                    |   48 +++++++++++++-----
 fs/ext2/super.c                    |   95 +++++++++++++++++++++++++++++++++++-
 fs/ext3/ext3.h                     |    8 +++
 fs/ext3/inode.c                    |   54 ++++++++++++++------
 fs/ext3/super.c                    |   95 +++++++++++++++++++++++++++++++++++-
 fs/ext4/ext4.h                     |    4 ++
 fs/ext4/inode.c                    |   52 ++++++++++++++------
 fs/ext4/super.c                    |   87 ++++++++++++++++++++++++++++++++-
 12 Dateien geändert, 433 Zeilen hinzugefügt(+), 45 Zeilen entfernt(-)

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] implement uid and gid mount options for ext2
  2012-08-02 11:54 [PATCH 0/3] implement uid and gid mount options for ext2, ext3 and ext4 Ludwig Nussel
@ 2012-08-02 11:54 ` Ludwig Nussel
  2012-08-02 12:06   ` Alan Cox
  2012-08-02 11:54 ` [PATCH 2/3] implement uid and gid mount options for ext3 Ludwig Nussel
  2012-08-02 11:54 ` [PATCH 3/3] implement uid and gid mount options for ext4 Ludwig Nussel
  2 siblings, 1 reply; 7+ messages in thread
From: Ludwig Nussel @ 2012-08-02 11:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ludwig Nussel, linux-fsdevel, Jan Kara, Rob Landley,
	Andrew Morton, Andreas Dilger, Theodore Ts'o,
	open list:EXT2 FILE SYSTEM, open list:DOCUMENTATION

Signed-off-by: Ludwig Nussel <ludwig.nussel@suse.de>
---
 Documentation/filesystems/ext2.txt |    9 ++++
 fs/ext2/ext2.h                     |    8 +++
 fs/ext2/inode.c                    |   48 +++++++++++++-----
 fs/ext2/super.c                    |   95 +++++++++++++++++++++++++++++++++++-
 4 Dateien geändert, 147 Zeilen hinzugefügt(+), 13 Zeilen entfernt(-)

diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index 67639f9..fcc1002 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -42,6 +42,15 @@ orlov			(*)	Use the Orlov block allocator.
 resuid=n			The user ID which may use the reserved blocks.
 resgid=n			The group ID which may use the reserved blocks.
 
+uid=n[:m]			Make all files appear to belong to uid n.
+				Useful for e.g. removable media with fstab
+				options 'user,uid=useruid'. The optional second
+				uid m is actually written to the file system.
+
+gid=n[:m]			Make all files appear to belong to gid n.
+				The optional second gid m is actually written to
+				the file system.
+
 sb=n				Use alternate superblock at this location.
 
 user_xattr			Enable "user." POSIX Extended Attributes
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index d9a17d0..160d5d8 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -84,6 +84,10 @@ struct ext2_sb_info {
 	unsigned long s_sb_block;
 	kuid_t s_resuid;
 	kgid_t s_resgid;
+	kuid_t s_uid;          /* make all files appear to belong to this uid */
+	kuid_t s_diskuid;      /* write this uid to disk (if s_uid != 0) */
+	kgid_t s_gid;          /* make all files appear to belong to this gid */
+	kgid_t s_diskgid;      /* write this gid to disk (if s_gid != 0) */
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
@@ -639,6 +643,10 @@ struct ext2_mount_options {
 	unsigned long s_mount_opt;
 	kuid_t s_resuid;
 	kgid_t s_resgid;
+	kuid_t s_uid;
+	kuid_t s_diskuid;
+	kgid_t s_gid;
+	kgid_t s_diskgid;
 };
 
 /*
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 6363ac6..b2320e4 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1321,8 +1321,14 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
 		i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
-	i_uid_write(inode, i_uid);
-	i_gid_write(inode, i_gid);
+	if (uid_valid(EXT2_SB(sb)->s_uid))
+		inode->i_uid = EXT2_SB(sb)->s_uid;
+	else
+		i_uid_write(inode, i_uid);
+	if (gid_valid(EXT2_SB(sb)->s_gid))
+		inode->i_gid = EXT2_SB(sb)->s_gid;
+	else
+		i_gid_write(inode, i_gid);
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -1426,6 +1432,10 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)
 	struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
 	int n;
 	int err = 0;
+	__le16 uid_low;
+	__le16 gid_low;
+	__le16 uid_high;
+	__le16 gid_high;
 
 	if (IS_ERR(raw_inode))
  		return -EIO;
@@ -1437,26 +1447,40 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)
 
 	ext2_get_inode_flags(ei);
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+	if (uid_valid(EXT2_SB(sb)->s_uid))
+		uid = from_kuid(&init_user_ns, EXT2_SB(sb)->s_diskuid);
+	if (gid_valid(EXT2_SB(sb)->s_gid))
+		gid = from_kgid(&init_user_ns, EXT2_SB(sb)->s_diskgid);
 	if (!(test_opt(sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
+		uid_low = cpu_to_le16(low_16_bits(uid));
+		gid_low = cpu_to_le16(low_16_bits(gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if (!ei->i_dtime) {
-			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid));
-			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid));
+			uid_high = cpu_to_le16(high_16_bits(uid));
+			gid_high = cpu_to_le16(high_16_bits(gid));
 		} else {
-			raw_inode->i_uid_high = 0;
-			raw_inode->i_gid_high = 0;
+			uid_high = 0;
+			gid_high = 0;
 		}
 	} else {
-		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(uid));
-		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(gid));
-		raw_inode->i_uid_high = 0;
-		raw_inode->i_gid_high = 0;
+		uid_low = cpu_to_le16(fs_high2lowuid(uid));
+		gid_low = cpu_to_le16(fs_high2lowgid(gid));
+		uid_high = 0;
+		gid_high = 0;
+	}
+	/* don't mangle uid/gid of existing files if override is active */
+	if (!uid_valid(EXT2_SB(sb)->s_uid) || ei->i_state & EXT2_STATE_NEW) {
+		raw_inode->i_uid_high = uid_high;
+		raw_inode->i_uid_low = uid_low;
 	}
+	if (!gid_valid(EXT2_SB(sb)->s_gid) || ei->i_state & EXT2_STATE_NEW) {
+		raw_inode->i_gid_high = gid_high;
+		raw_inode->i_gid_low = gid_low;
+	}
+
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 	raw_inode->i_size = cpu_to_le32(inode->i_size);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index af74d9e..0f91dfb 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -237,6 +237,24 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root)
 		seq_printf(seq, ",resgid=%u",
 				from_kgid_munged(&init_user_ns, sbi->s_resgid));
 	}
+	if (uid_valid(sbi->s_uid)) {
+		if (!uid_eq(sbi->s_uid, sbi->s_diskuid))
+			seq_printf(seq, ",uid=%u:%u",
+				from_kuid_munged(&init_user_ns, sbi->s_uid),
+				from_kuid_munged(&init_user_ns, sbi->s_diskuid));
+		else
+			seq_printf(seq, ",uid=%u",
+				from_kuid_munged(&init_user_ns, sbi->s_uid));
+	}
+	if (gid_valid(sbi->s_gid)) {
+		if (!gid_eq(sbi->s_gid, sbi->s_diskgid))
+			seq_printf(seq, ",gid=%u:%u",
+				from_kgid_munged(&init_user_ns, sbi->s_gid),
+				from_kgid_munged(&init_user_ns, sbi->s_diskgid));
+		else
+			seq_printf(seq, ",gid=%u",
+				from_kgid_munged(&init_user_ns, sbi->s_gid));
+	}
 	if (test_opt(sb, ERRORS_RO)) {
 		int def_errors = le16_to_cpu(es->s_errors);
 
@@ -390,7 +408,8 @@ enum {
 	Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
 	Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
 	Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
-	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
+	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation,
+	Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid
 };
 
 static const match_table_t tokens = {
@@ -424,6 +443,10 @@ static const match_table_t tokens = {
 	{Opt_usrquota, "usrquota"},
 	{Opt_reservation, "reservation"},
 	{Opt_noreservation, "noreservation"},
+	{Opt_uid, "uid=%u"},
+	{Opt_diskuid, "uid=%u:%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_diskgid, "gid=%u:%u"},
 	{Opt_err, NULL}
 };
 
@@ -578,6 +601,64 @@ static int parse_options(char *options, struct super_block *sb)
 			clear_opt(sbi->s_mount_opt, RESERVATION);
 			ext2_msg(sb, KERN_INFO, "reservations OFF");
 			break;
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return 0;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+			}
+			sbi->s_uid = sbi->s_diskuid = uid;
+			break;
+		case Opt_diskuid:
+			if (match_int(&args[0], &option))
+				return 0;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+			}
+			sbi->s_uid = uid;
+
+			if (match_int(&args[1], &option))
+				return 0;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+			}
+			sbi->s_diskuid = uid;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return 0;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_gid = sbi->s_diskgid = gid;
+			break;
+		case Opt_diskgid:
+			if (match_int(&args[0], &option))
+				return 0;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_gid = gid;
+
+			if (match_int(&args[1], &option))
+				return 0;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_diskgid = gid;
+			break;
 		case Opt_ignore:
 			break;
 		default:
@@ -853,6 +934,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 
 	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
 	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
+	sbi->s_uid = INVALID_UID;
+	sbi->s_gid = INVALID_GID;
+	sbi->s_diskuid = INVALID_UID;
+	sbi->s_diskgid = INVALID_GID;
 	
 	set_opt(sbi->s_mount_opt, RESERVATION);
 
@@ -1256,6 +1341,10 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 	old_opts.s_mount_opt = sbi->s_mount_opt;
 	old_opts.s_resuid = sbi->s_resuid;
 	old_opts.s_resgid = sbi->s_resgid;
+	old_opts.s_uid = sbi->s_uid;
+	old_opts.s_diskuid = sbi->s_diskuid;
+	old_opts.s_gid = sbi->s_gid;
+	old_opts.s_diskgid = sbi->s_diskgid;
 
 	/*
 	 * Allow the "check" option to be passed as a remount option.
@@ -1342,6 +1431,10 @@ restore_opts:
 	sbi->s_mount_opt = old_opts.s_mount_opt;
 	sbi->s_resuid = old_opts.s_resuid;
 	sbi->s_resgid = old_opts.s_resgid;
+	sbi->s_uid = old_opts.s_uid;
+	sbi->s_diskuid = old_opts.s_diskuid;
+	sbi->s_gid = old_opts.s_gid;
+	sbi->s_diskgid = old_opts.s_diskgid;
 	sb->s_flags = old_sb_flags;
 	spin_unlock(&sbi->s_lock);
 	return err;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] implement uid and gid mount options for ext3
  2012-08-02 11:54 [PATCH 0/3] implement uid and gid mount options for ext2, ext3 and ext4 Ludwig Nussel
  2012-08-02 11:54 ` [PATCH 1/3] implement uid and gid mount options for ext2 Ludwig Nussel
@ 2012-08-02 11:54 ` Ludwig Nussel
  2012-08-02 11:54 ` [PATCH 3/3] implement uid and gid mount options for ext4 Ludwig Nussel
  2 siblings, 0 replies; 7+ messages in thread
From: Ludwig Nussel @ 2012-08-02 11:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ludwig Nussel, linux-fsdevel, Jan Kara, Rob Landley,
	Andrew Morton, Andreas Dilger, Theodore Ts'o,
	open list:EXT2 FILE SYSTEM, open list:DOCUMENTATION

Signed-off-by: Ludwig Nussel <ludwig.nussel@suse.de>
---
 Documentation/filesystems/ext3.txt |    9 ++++
 fs/ext3/ext3.h                     |    8 +++
 fs/ext3/inode.c                    |   54 ++++++++++++++------
 fs/ext3/super.c                    |   95 +++++++++++++++++++++++++++++++++++-
 4 Dateien geändert, 149 Zeilen hinzugefügt(+), 17 Zeilen entfernt(-)

diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt
index 293855e..bd586d9 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -124,6 +124,15 @@ resgid=n		The group ID which may use the reserved blocks.
 
 resuid=n		The user ID which may use the reserved blocks.
 
+uid=n[:m]		Make all files appear to belong to uid n.
+			Useful for e.g. removable media with fstab
+			options 'user,uid=useruid'. The optional second
+			uid m is actually written to the file system.
+
+gid=n[:m]		Make all files appear to belong to gid n.
+			The optional second gid m is actually written to
+			the file system.
+
 sb=n			Use alternate superblock at this location.
 
 quota			These options are ignored by the filesystem. They
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
index e85ff15..401114d 100644
--- a/fs/ext3/ext3.h
+++ b/fs/ext3/ext3.h
@@ -245,6 +245,10 @@ struct ext3_mount_options {
 	unsigned long s_mount_opt;
 	kuid_t s_resuid;
 	kgid_t s_resgid;
+	kuid_t s_uid;
+	kuid_t s_diskuid;
+	kgid_t s_gid;
+	kgid_t s_diskgid;
 	unsigned long s_commit_interval;
 #ifdef CONFIG_QUOTA
 	int s_jquota_fmt;
@@ -639,6 +643,10 @@ struct ext3_sb_info {
 	ext3_fsblk_t s_sb_block;
 	kuid_t s_resuid;
 	kgid_t s_resgid;
+	kuid_t s_uid;          /* make all files appear to belong to this uid */
+	kuid_t s_diskuid;      /* write this uid to disk (if s_uid != 0) */
+	kgid_t s_gid;          /* make all files appear to belong to this gid */
+	kgid_t s_diskgid;      /* write this gid to disk (if s_gid != 0) */
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 9a4a5c4..c1176ae 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2915,8 +2915,14 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
 		i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
-	i_uid_write(inode, i_uid);
-	i_gid_write(inode, i_gid);
+	if (uid_valid(EXT3_SB(sb)->s_uid))
+		inode->i_uid = EXT3_SB(sb)->s_uid;
+	else
+		i_uid_write(inode, i_uid);
+	if (gid_valid(EXT3_SB(sb)->s_gid))
+		inode->i_gid = EXT3_SB(sb)->s_gid;
+	else
+		i_gid_write(inode, i_gid);
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -3074,6 +3080,10 @@ static int ext3_do_update_inode(handle_t *handle,
 	int err = 0, rc, block;
 	uid_t i_uid;
 	gid_t i_gid;
+	__le16 uid_low;
+	__le16 gid_low;
+	__le16 uid_high;
+	__le16 gid_high;
 
 again:
 	/* we can't allow multiple procs in here at once, its a bit racey */
@@ -3088,30 +3098,42 @@ again:
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	i_uid = i_uid_read(inode);
 	i_gid = i_gid_read(inode);
+	if (uid_valid(EXT3_SB(inode->i_sb)->s_uid))
+		i_uid = from_kuid(&init_user_ns, EXT3_SB(inode->i_sb)->s_diskuid);
+	if (gid_valid(EXT3_SB(inode->i_sb)->s_gid))
+		i_gid = from_kgid(&init_user_ns, EXT3_SB(inode->i_sb)->s_diskgid);
 	if(!(test_opt(inode->i_sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
+		uid_low = cpu_to_le16(low_16_bits(i_uid));
+		gid_low = cpu_to_le16(low_16_bits(i_gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if(!ei->i_dtime) {
-			raw_inode->i_uid_high =
-				cpu_to_le16(high_16_bits(i_uid));
-			raw_inode->i_gid_high =
-				cpu_to_le16(high_16_bits(i_gid));
+			uid_high = cpu_to_le16(high_16_bits(i_uid));
+			gid_high = cpu_to_le16(high_16_bits(i_gid));
 		} else {
-			raw_inode->i_uid_high = 0;
-			raw_inode->i_gid_high = 0;
+			uid_high = 0;
+			gid_high = 0;
 		}
 	} else {
-		raw_inode->i_uid_low =
-			cpu_to_le16(fs_high2lowuid(i_uid));
-		raw_inode->i_gid_low =
-			cpu_to_le16(fs_high2lowgid(i_gid));
-		raw_inode->i_uid_high = 0;
-		raw_inode->i_gid_high = 0;
+		uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
+		gid_low = cpu_to_le16(fs_high2lowgid(i_gid));
+		uid_high = 0;
+		gid_high = 0;
+	}
+	/* don't mangle uid/gid of existing files if override is active */
+	if (!uid_valid(EXT3_SB(inode->i_sb)->s_uid) ||
+			ext3_test_inode_state(inode, EXT3_STATE_NEW)) {
+		raw_inode->i_uid_high = uid_high;
+		raw_inode->i_uid_low = uid_low;
 	}
+	if (!gid_valid(EXT3_SB(inode->i_sb)->s_gid) ||
+			ext3_test_inode_state(inode, EXT3_STATE_NEW)) {
+		raw_inode->i_gid_high = gid_high;
+		raw_inode->i_gid_low = gid_low;
+	}
+
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 	raw_inode->i_size = cpu_to_le32(ei->i_disksize);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..730c532 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -627,6 +627,24 @@ static int ext3_show_options(struct seq_file *seq, struct dentry *root)
 		seq_printf(seq, ",resgid=%u",
 				from_kgid_munged(&init_user_ns, sbi->s_resgid));
 	}
+	if (uid_valid(sbi->s_uid)) {
+		if (!uid_eq(sbi->s_uid, sbi->s_diskuid))
+			seq_printf(seq, ",uid=%u:%u",
+				from_kuid_munged(&init_user_ns, sbi->s_uid),
+				from_kuid_munged(&init_user_ns, sbi->s_diskuid));
+		else
+			seq_printf(seq, ",uid=%u",
+				from_kuid_munged(&init_user_ns, sbi->s_uid));
+	}
+	if (gid_valid(sbi->s_gid)) {
+		if (!gid_eq(sbi->s_gid, sbi->s_diskgid))
+			seq_printf(seq, ",gid=%u:%u",
+				from_kgid_munged(&init_user_ns, sbi->s_gid),
+				from_kgid_munged(&init_user_ns, sbi->s_diskgid));
+		else
+			seq_printf(seq, ",gid=%u",
+				from_kgid_munged(&init_user_ns, sbi->s_gid));
+	}
 	if (test_opt(sb, ERRORS_RO)) {
 		int def_errors = le16_to_cpu(es->s_errors);
 
@@ -822,7 +840,8 @@ enum {
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
 	Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
-	Opt_resize, Opt_usrquota, Opt_grpquota
+	Opt_resize, Opt_usrquota, Opt_grpquota,
+	Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid
 };
 
 static const match_table_t tokens = {
@@ -879,6 +898,10 @@ static const match_table_t tokens = {
 	{Opt_barrier, "barrier"},
 	{Opt_nobarrier, "nobarrier"},
 	{Opt_resize, "resize"},
+	{Opt_uid, "uid=%u"},
+	{Opt_diskuid, "uid=%u:%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_diskgid, "gid=%u:%u"},
 	{Opt_err, NULL},
 };
 
@@ -1282,6 +1305,64 @@ set_qf_format:
 			ext3_msg(sb, KERN_WARNING,
 				"warning: ignoring deprecated bh option");
 			break;
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return 0;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+			}
+			sbi->s_uid = sbi->s_diskuid = uid;
+			break;
+		case Opt_diskuid:
+			if (match_int(&args[0], &option))
+				return 0;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+			}
+			sbi->s_uid = uid;
+
+			if (match_int(&args[1], &option))
+				return 0;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+				return -1;
+			}
+			sbi->s_diskuid = uid;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return 0;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_gid = sbi->s_diskgid = gid;
+			break;
+		case Opt_diskgid:
+			if (match_int(&args[0], &option))
+				return 0;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_gid = gid;
+
+			if (match_int(&args[1], &option))
+				return 0;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid)) {
+				ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+				return -1;
+			}
+			sbi->s_diskgid = gid;
+			break;
 		default:
 			ext3_msg(sb, KERN_ERR,
 				"error: unrecognized mount option \"%s\" "
@@ -1668,6 +1749,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = make_kuid(&init_user_ns, EXT3_DEF_RESUID);
 	sbi->s_resgid = make_kgid(&init_user_ns, EXT3_DEF_RESGID);
+	sbi->s_uid = INVALID_UID;
+	sbi->s_gid = INVALID_GID;
+	sbi->s_diskuid = INVALID_UID;
+	sbi->s_diskgid = INVALID_GID;
 	sbi->s_sb_block = sb_block;
 
 	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
@@ -2611,6 +2696,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 	old_opts.s_mount_opt = sbi->s_mount_opt;
 	old_opts.s_resuid = sbi->s_resuid;
 	old_opts.s_resgid = sbi->s_resgid;
+	old_opts.s_uid = sbi->s_uid;
+	old_opts.s_diskuid = sbi->s_diskuid;
+	old_opts.s_gid = sbi->s_gid;
+	old_opts.s_diskgid = sbi->s_diskgid;
 	old_opts.s_commit_interval = sbi->s_commit_interval;
 #ifdef CONFIG_QUOTA
 	old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
@@ -2722,6 +2811,10 @@ restore_opts:
 	sbi->s_mount_opt = old_opts.s_mount_opt;
 	sbi->s_resuid = old_opts.s_resuid;
 	sbi->s_resgid = old_opts.s_resgid;
+	sbi->s_uid = old_opts.s_uid;
+	sbi->s_diskuid = old_opts.s_diskuid;
+	sbi->s_gid = old_opts.s_gid;
+	sbi->s_diskgid = old_opts.s_diskgid;
 	sbi->s_commit_interval = old_opts.s_commit_interval;
 #ifdef CONFIG_QUOTA
 	sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] implement uid and gid mount options for ext4
  2012-08-02 11:54 [PATCH 0/3] implement uid and gid mount options for ext2, ext3 and ext4 Ludwig Nussel
  2012-08-02 11:54 ` [PATCH 1/3] implement uid and gid mount options for ext2 Ludwig Nussel
  2012-08-02 11:54 ` [PATCH 2/3] implement uid and gid mount options for ext3 Ludwig Nussel
@ 2012-08-02 11:54 ` Ludwig Nussel
  2 siblings, 0 replies; 7+ messages in thread
From: Ludwig Nussel @ 2012-08-02 11:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ludwig Nussel, linux-fsdevel, Jan Kara, Rob Landley,
	Andrew Morton, Andreas Dilger, Theodore Ts'o,
	open list:EXT2 FILE SYSTEM, open list:DOCUMENTATION

Signed-off-by: Ludwig Nussel <ludwig.nussel@suse.de>
---
 Documentation/filesystems/ext4.txt |    9 ++++
 fs/ext4/ext4.h                     |    4 ++
 fs/ext4/inode.c                    |   52 +++++++++++++++------
 fs/ext4/super.c                    |   87 +++++++++++++++++++++++++++++++++++-
 4 Dateien geändert, 137 Zeilen hinzugefügt(+), 15 Zeilen entfernt(-)

diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 1b7f9ac..b388ab5 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -245,6 +245,15 @@ resgid=n		The group ID which may use the reserved blocks.
 
 resuid=n		The user ID which may use the reserved blocks.
 
+uid=n[:m]		Make all files appear to belong to uid n.
+			Useful for e.g. removable media with fstab
+			options 'user,uid=useruid'. The optional second
+			uid m is actually written to the file system.
+
+gid=n[:m]		Make all files appear to belong to gid n.
+			The optional second gid m is actually written to
+			the file system.
+
 sb=n			Use alternate superblock at this location.
 
 quota			These options are ignored by the filesystem. They
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c3411d4..070e3ad 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1177,6 +1177,10 @@ struct ext4_sb_info {
 	ext4_fsblk_t s_sb_block;
 	kuid_t s_resuid;
 	kgid_t s_resgid;
+	kuid_t s_uid;          /* make all files appear to belong to this uid */
+	kuid_t s_diskuid;      /* write this uid to disk (if s_uid != 0) */
+	kgid_t s_gid;          /* make all files appear to belong to this gid */
+	kgid_t s_diskgid;      /* write this gid to disk (if s_gid != 0) */
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 6324f74..b02ec15 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3838,8 +3838,14 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
 		i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
-	i_uid_write(inode, i_uid);
-	i_gid_write(inode, i_gid);
+	if (uid_valid(EXT4_SB(sb)->s_uid))
+		inode->i_uid = EXT4_SB(sb)->s_uid;
+	else
+		i_uid_write(inode, i_uid);
+	if (gid_valid(EXT4_SB(sb)->s_gid))
+		inode->i_gid = EXT4_SB(sb)->s_gid;
+	else
+		i_gid_write(inode, i_gid);
 	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 
 	ext4_clear_state_flags(ei);	/* Only relevant on 32-bit archs */
@@ -4054,6 +4060,10 @@ static int ext4_do_update_inode(handle_t *handle,
 	int err = 0, rc, block;
 	uid_t i_uid;
 	gid_t i_gid;
+	__le16 uid_low;
+	__le16 gid_low;
+	__le16 uid_high;
+	__le16 gid_high;
 
 	/* For fields not not tracking in the in-memory inode,
 	 * initialise them to zero for new inodes. */
@@ -4064,28 +4074,42 @@ static int ext4_do_update_inode(handle_t *handle,
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	i_uid = i_uid_read(inode);
 	i_gid = i_gid_read(inode);
+	if (uid_valid(EXT4_SB(inode->i_sb)->s_uid))
+		i_uid = from_kuid(&init_user_ns, EXT4_SB(inode->i_sb)->s_diskuid);
+	if (gid_valid(EXT4_SB(inode->i_sb)->s_gid))
+		i_gid = from_kgid(&init_user_ns, EXT4_SB(inode->i_sb)->s_diskgid);
 	if (!(test_opt(inode->i_sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
+		uid_low = cpu_to_le16(low_16_bits(i_uid));
+		gid_low = cpu_to_le16(low_16_bits(i_gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if (!ei->i_dtime) {
-			raw_inode->i_uid_high =
-				cpu_to_le16(high_16_bits(i_uid));
-			raw_inode->i_gid_high =
-				cpu_to_le16(high_16_bits(i_gid));
+			uid_high = cpu_to_le16(high_16_bits(i_uid));
+			gid_high = cpu_to_le16(high_16_bits(i_gid));
 		} else {
-			raw_inode->i_uid_high = 0;
-			raw_inode->i_gid_high = 0;
+			uid_high = 0;
+			gid_high = 0;
 		}
 	} else {
-		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(i_gid));
-		raw_inode->i_uid_high = 0;
-		raw_inode->i_gid_high = 0;
+		uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
+		gid_low = cpu_to_le16(fs_high2lowgid(i_gid));
+		uid_high = 0;
+		gid_high = 0;
+	}
+	/* don't mangle uid/gid of existing files if override is active */
+	if (!uid_valid(EXT4_SB(inode->i_sb)->s_uid) ||
+			ext4_test_inode_state(inode, EXT4_STATE_NEW)) {
+		raw_inode->i_uid_high = uid_high;
+		raw_inode->i_uid_low = uid_low;
 	}
+	if (!gid_valid(EXT4_SB(inode->i_sb)->s_gid) ||
+			ext4_test_inode_state(inode, EXT4_STATE_NEW)) {
+		raw_inode->i_gid_high = gid_high;
+		raw_inode->i_gid_low = gid_low;
+	}
+
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 
 	EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..927c020 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1229,6 +1229,7 @@ enum {
 	Opt_inode_readahead_blks, Opt_journal_ioprio,
 	Opt_dioread_nolock, Opt_dioread_lock,
 	Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
+	Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid,
 };
 
 static const match_table_t tokens = {
@@ -1307,6 +1308,10 @@ static const match_table_t tokens = {
 	{Opt_removed, "reservation"},	/* mount option from ext2/3 */
 	{Opt_removed, "noreservation"}, /* mount option from ext2/3 */
 	{Opt_removed, "journal=%u"},	/* mount option from ext2/3 */
+	{Opt_uid, "uid=%u"},
+	{Opt_diskuid, "uid=%u:%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_diskgid, "gid=%u:%u"},
 	{Opt_err, NULL},
 };
 
@@ -1553,6 +1558,54 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 			return -1;
 		*journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
 		return 1;
+	case Opt_uid:
+		uid = make_kuid(current_user_ns(), arg);
+		if (!uid_valid(uid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+			return -1;
+		}
+		sbi->s_uid = sbi->s_diskuid = uid;
+		return 1;
+	case Opt_diskuid:
+		uid = make_kuid(current_user_ns(), arg);
+		if (!uid_valid(uid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+			return -1;
+		}
+		sbi->s_uid = uid;
+		if (match_int(&args[1], &arg))
+			return -1;
+		uid = make_kuid(current_user_ns(), arg);
+		if (!uid_valid(uid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+			return -1;
+		}
+		sbi->s_diskuid = uid;
+		return 1;
+	case Opt_gid:
+		gid = make_kgid(current_user_ns(), arg);
+		if (!gid_valid(gid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+			return -1;
+		}
+		sbi->s_gid = sbi->s_diskgid = gid;
+		return 1;
+	case Opt_diskgid:
+		gid = make_kgid(current_user_ns(), arg);
+		if (!gid_valid(gid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+			return -1;
+		}
+		sbi->s_gid = gid;
+		if (match_int(&args[1], &arg))
+			return -1;
+		gid = make_kgid(current_user_ns(), arg);
+		if (!gid_valid(gid)) {
+			ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+			return -1;
+		}
+		sbi->s_diskgid = gid;
+		return 1;
 	}
 
 	for (m = ext4_mount_opts; m->token != Opt_err; m++) {
@@ -1768,7 +1821,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
 	char sep = nodefs ? '\n' : ',';
 
 #define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep)
-#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg)
+#define SEQ_OPTS_PRINT(str, args...) seq_printf(seq, "%c" str, sep, ##args)
 
 	if (sbi->s_sb_block != 1)
 		SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block);
@@ -1795,6 +1848,22 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
 	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
 		SEQ_OPTS_PRINT("resgid=%u",
 				from_kgid_munged(&init_user_ns, sbi->s_resgid));
+	if (uid_valid(sbi->s_uid)) {
+		if (!uid_eq(sbi->s_uid, sbi->s_diskuid))
+			SEQ_OPTS_PRINT("uid=%u:%u",
+				from_kuid_munged(&init_user_ns, sbi->s_uid),
+				from_kuid_munged(&init_user_ns, sbi->s_diskuid));
+		else
+			SEQ_OPTS_PRINT("uid=%u", from_kuid_munged(&init_user_ns, sbi->s_uid));
+	}
+	if (gid_valid(sbi->s_gid)) {
+		if (!gid_eq(sbi->s_gid, sbi->s_diskgid))
+			SEQ_OPTS_PRINT("gid=%u:%u",
+				from_kgid_munged(&init_user_ns, sbi->s_gid),
+				from_kgid_munged(&init_user_ns, sbi->s_diskgid));
+		else
+			SEQ_OPTS_PRINT("gid=%u", from_kgid_munged(&init_user_ns, sbi->s_gid));
+	}
 	def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
 	if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
 		SEQ_OPTS_PUTS("errors=remount-ro");
@@ -3243,6 +3312,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID);
 	sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID);
+	sbi->s_uid = INVALID_UID;
+	sbi->s_gid = INVALID_GID;
+	sbi->s_diskuid = INVALID_UID;
+	sbi->s_diskgid = INVALID_GID;
 	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
 	sbi->s_sb_block = sb_block;
 	if (sb->s_bdev->bd_part)
@@ -4535,6 +4608,10 @@ struct ext4_mount_options {
 	unsigned long s_mount_opt2;
 	kuid_t s_resuid;
 	kgid_t s_resgid;
+	kuid_t s_uid;
+	kuid_t s_diskuid;
+	kgid_t s_gid;
+	kgid_t s_diskgid;
 	unsigned long s_commit_interval;
 	u32 s_min_batch_time, s_max_batch_time;
 #ifdef CONFIG_QUOTA
@@ -4565,6 +4642,10 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 	old_opts.s_mount_opt2 = sbi->s_mount_opt2;
 	old_opts.s_resuid = sbi->s_resuid;
 	old_opts.s_resgid = sbi->s_resgid;
+	old_opts.s_uid = sbi->s_uid;
+	old_opts.s_diskuid = sbi->s_diskuid;
+	old_opts.s_gid = sbi->s_gid;
+	old_opts.s_diskgid = sbi->s_diskgid;
 	old_opts.s_commit_interval = sbi->s_commit_interval;
 	old_opts.s_min_batch_time = sbi->s_min_batch_time;
 	old_opts.s_max_batch_time = sbi->s_max_batch_time;
@@ -4732,6 +4813,10 @@ restore_opts:
 	sbi->s_mount_opt2 = old_opts.s_mount_opt2;
 	sbi->s_resuid = old_opts.s_resuid;
 	sbi->s_resgid = old_opts.s_resgid;
+	sbi->s_uid = old_opts.s_uid;
+	sbi->s_diskuid = old_opts.s_diskuid;
+	sbi->s_gid = old_opts.s_gid;
+	sbi->s_diskgid = old_opts.s_diskgid;
 	sbi->s_commit_interval = old_opts.s_commit_interval;
 	sbi->s_min_batch_time = old_opts.s_min_batch_time;
 	sbi->s_max_batch_time = old_opts.s_max_batch_time;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] implement uid and gid mount options for ext2
  2012-08-02 11:54 ` [PATCH 1/3] implement uid and gid mount options for ext2 Ludwig Nussel
@ 2012-08-02 12:06   ` Alan Cox
  2012-08-02 13:00     ` Eric W. Biederman
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Cox @ 2012-08-02 12:06 UTC (permalink / raw)
  To: Ludwig Nussel
  Cc: linux-kernel, linux-fsdevel, Jan Kara, Rob Landley, Andrew Morton,
	Andreas Dilger, Theodore Ts'o, open list:EXT2 FILE SYSTEM,
	open list:DOCUMENTATION

> +uid=n[:m]			Make all files appear to belong to uid n.
> +				Useful for e.g. removable media with fstab
> +				options 'user,uid=useruid'. The optional second
> +				uid m is actually written to the file system.

So what happens if I insert a USB key containing a device node to the
hard disk ? Why is this functionality useful in the current form ?

(ie I think you need an actual rational security model first)


Also why is this at the per fs level duplicating stuff each time rather
than at the vfs level - this seems to be vfs level functionality.

> +
> +gid=n[:m]			Make all files appear to belong to gid n.
> +				The optional second gid m is actually written to
> +				the file system.

Your documentation seems only half completed ?

Alan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] implement uid and gid mount options for ext2
  2012-08-02 12:06   ` Alan Cox
@ 2012-08-02 13:00     ` Eric W. Biederman
  0 siblings, 0 replies; 7+ messages in thread
From: Eric W. Biederman @ 2012-08-02 13:00 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ludwig Nussel, linux-kernel, linux-fsdevel, Jan Kara, Rob Landley,
	Andrew Morton, Andreas Dilger, Theodore Ts'o,
	open list:EXT2 FILE SYSTEM, open list:DOCUMENTATION

Alan Cox <alan@lxorguk.ukuu.org.uk> writes:

>> +uid=n[:m]			Make all files appear to belong to uid n.
>> +				Useful for e.g. removable media with fstab
>> +				options 'user,uid=useruid'. The optional second
>> +				uid m is actually written to the file system.
>
> So what happens if I insert a USB key containing a device node to the
> hard disk ? Why is this functionality useful in the current form ?
>
> (ie I think you need an actual rational security model first)

> Also why is this at the per fs level duplicating stuff each time rather
> than at the vfs level - this seems to be vfs level functionality.

Even more fun there is essentially a generic implementation in the user
namespaces.  What needs to be implemented to support this is support for
mounting in a non-default user namespace, and then all of the mapping
functionality is generic.  Which I presume will imply MS_NODEV.

Eric

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-08-02 13:00 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-02 11:54 [PATCH 0/3] implement uid and gid mount options for ext2, ext3 and ext4 Ludwig Nussel
2012-08-02 11:54 ` [PATCH 1/3] implement uid and gid mount options for ext2 Ludwig Nussel
2012-08-02 12:06   ` Alan Cox
2012-08-02 13:00     ` Eric W. Biederman
2012-08-02 11:54 ` [PATCH 2/3] implement uid and gid mount options for ext3 Ludwig Nussel
2012-08-02 11:54 ` [PATCH 3/3] implement uid and gid mount options for ext4 Ludwig Nussel
     [not found] <1336660924-9598-1-git-send-email-ludwig.nussel@suse.d>
2012-05-11 11:10 ` [PATCH resend split 0/3] implement uid and gid mount options for ext2, ext3 and ext4 Ludwig Nussel
2012-05-11 11:10   ` [PATCH 1/3] implement uid and gid mount options for ext2 Ludwig Nussel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).