Signed-off-by: Ludwig Nussel <ludwig.nussel@xxxxxxx> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html