* [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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ messages in thread