diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/attr.c | 8 | ||||
| -rw-r--r-- | fs/binfmt_elf.c | 12 | ||||
| -rw-r--r-- | fs/binfmt_elf_fdpic.c | 12 | ||||
| -rw-r--r-- | fs/compat.c | 4 | ||||
| -rw-r--r-- | fs/devpts/inode.c | 24 | ||||
| -rw-r--r-- | fs/ecryptfs/messaging.c | 2 | ||||
| -rw-r--r-- | fs/exec.c | 15 | ||||
| -rw-r--r-- | fs/ext2/balloc.c | 5 | ||||
| -rw-r--r-- | fs/ext2/ext2.h | 8 | ||||
| -rw-r--r-- | fs/ext2/inode.c | 20 | ||||
| -rw-r--r-- | fs/ext2/super.c | 31 | ||||
| -rw-r--r-- | fs/ext3/balloc.c | 5 | ||||
| -rw-r--r-- | fs/ext3/ext3.h | 8 | ||||
| -rw-r--r-- | fs/ext3/inode.c | 32 | ||||
| -rw-r--r-- | fs/ext3/super.c | 35 | ||||
| -rw-r--r-- | fs/ext4/balloc.c | 4 | ||||
| -rw-r--r-- | fs/ext4/ext4.h | 4 | ||||
| -rw-r--r-- | fs/ext4/ialloc.c | 4 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 34 | ||||
| -rw-r--r-- | fs/ext4/migrate.c | 4 | ||||
| -rw-r--r-- | fs/ext4/super.c | 38 | ||||
| -rw-r--r-- | fs/fcntl.c | 6 | ||||
| -rw-r--r-- | fs/inode.c | 10 | ||||
| -rw-r--r-- | fs/ioprio.c | 18 | ||||
| -rw-r--r-- | fs/locks.c | 2 | ||||
| -rw-r--r-- | fs/namei.c | 29 | ||||
| -rw-r--r-- | fs/nfsd/auth.c | 5 | ||||
| -rw-r--r-- | fs/open.c | 16 | ||||
| -rw-r--r-- | fs/proc/array.c | 15 | ||||
| -rw-r--r-- | fs/proc/base.c | 93 | ||||
| -rw-r--r-- | fs/proc/inode.c | 4 | ||||
| -rw-r--r-- | fs/proc/proc_sysctl.c | 4 | ||||
| -rw-r--r-- | fs/proc/root.c | 2 | ||||
| -rw-r--r-- | fs/stat.c | 12 | ||||
| -rw-r--r-- | fs/sysfs/inode.c | 4 | 
35 files changed, 349 insertions, 180 deletions
diff --git a/fs/attr.c b/fs/attr.c index 73f69a6ce9e..584620e5dee 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -47,14 +47,14 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)  	/* Make sure a caller can chown. */  	if ((ia_valid & ATTR_UID) && -	    (current_fsuid() != inode->i_uid || -	     attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) +	    (!uid_eq(current_fsuid(), inode->i_uid) || +	     !uid_eq(attr->ia_uid, inode->i_uid)) && !capable(CAP_CHOWN))  		return -EPERM;  	/* Make sure caller can chgrp. */  	if ((ia_valid & ATTR_GID) && -	    (current_fsuid() != inode->i_uid || -	    (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && +	    (!uid_eq(current_fsuid(), inode->i_uid) || +	    (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&  	    !capable(CAP_CHOWN))  		return -EPERM; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 16f73541707..e658dd134b9 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -226,10 +226,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,  	NEW_AUX_ENT(AT_BASE, interp_load_addr);  	NEW_AUX_ENT(AT_FLAGS, 0);  	NEW_AUX_ENT(AT_ENTRY, exec->e_entry); -	NEW_AUX_ENT(AT_UID, cred->uid); -	NEW_AUX_ENT(AT_EUID, cred->euid); -	NEW_AUX_ENT(AT_GID, cred->gid); -	NEW_AUX_ENT(AT_EGID, cred->egid); +	NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); +	NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); +	NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); +	NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid));   	NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));  	NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);  	NEW_AUX_ENT(AT_EXECFN, bprm->exec); @@ -1356,8 +1356,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,  	psinfo->pr_flag = p->flags;  	rcu_read_lock();  	cred = __task_cred(p); -	SET_UID(psinfo->pr_uid, cred->uid); -	SET_GID(psinfo->pr_gid, cred->gid); +	SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); +	SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));  	rcu_read_unlock();  	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index d390a0fffc6..3d77cf81ba3 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -627,10 +627,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,  	NEW_AUX_ENT(AT_BASE,	interp_params->elfhdr_addr);  	NEW_AUX_ENT(AT_FLAGS,	0);  	NEW_AUX_ENT(AT_ENTRY,	exec_params->entry_addr); -	NEW_AUX_ENT(AT_UID,	(elf_addr_t) cred->uid); -	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) cred->euid); -	NEW_AUX_ENT(AT_GID,	(elf_addr_t) cred->gid); -	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) cred->egid); +	NEW_AUX_ENT(AT_UID,	(elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid)); +	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid)); +	NEW_AUX_ENT(AT_GID,	(elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid)); +	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));  	NEW_AUX_ENT(AT_SECURE,	security_bprm_secureexec(bprm));  	NEW_AUX_ENT(AT_EXECFN,	bprm->exec); @@ -1421,8 +1421,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,  	psinfo->pr_flag = p->flags;  	rcu_read_lock();  	cred = __task_cred(p); -	SET_UID(psinfo->pr_uid, cred->uid); -	SET_GID(psinfo->pr_gid, cred->gid); +	SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); +	SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));  	rcu_read_unlock();  	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); diff --git a/fs/compat.c b/fs/compat.c index f2944ace7a7..0781e619a62 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -144,8 +144,8 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)  	tmp.st_nlink = stat->nlink;  	if (tmp.st_nlink != stat->nlink)  		return -EOVERFLOW; -	SET_UID(tmp.st_uid, stat->uid); -	SET_GID(tmp.st_gid, stat->gid); +	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); +	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));  	tmp.st_rdev = old_encode_dev(stat->rdev);  	if ((u64) stat->size > MAX_NON_LFS)  		return -EOVERFLOW; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 10f5e0b484d..979c1e309c7 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -98,8 +98,8 @@ static struct vfsmount *devpts_mnt;  struct pts_mount_opts {  	int setuid;  	int setgid; -	uid_t   uid; -	gid_t   gid; +	kuid_t   uid; +	kgid_t   gid;  	umode_t mode;  	umode_t ptmxmode;  	int newinstance; @@ -158,11 +158,13 @@ static inline struct super_block *pts_sb_from_inode(struct inode *inode)  static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)  {  	char *p; +	kuid_t uid; +	kgid_t gid;  	opts->setuid  = 0;  	opts->setgid  = 0; -	opts->uid     = 0; -	opts->gid     = 0; +	opts->uid     = GLOBAL_ROOT_UID; +	opts->gid     = GLOBAL_ROOT_GID;  	opts->mode    = DEVPTS_DEFAULT_MODE;  	opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;  	opts->max     = NR_UNIX98_PTY_MAX; @@ -184,13 +186,19 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)  		case Opt_uid:  			if (match_int(&args[0], &option))  				return -EINVAL; -			opts->uid = option; +			uid = make_kuid(current_user_ns(), option); +			if (!uid_valid(uid)) +				return -EINVAL; +			opts->uid = uid;  			opts->setuid = 1;  			break;  		case Opt_gid:  			if (match_int(&args[0], &option))  				return -EINVAL; -			opts->gid = option; +			gid = make_kgid(current_user_ns(), option); +			if (!gid_valid(gid)) +				return -EINVAL; +			opts->gid = gid;  			opts->setgid = 1;  			break;  		case Opt_mode: @@ -315,9 +323,9 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root)  	struct pts_mount_opts *opts = &fsi->mount_opts;  	if (opts->setuid) -		seq_printf(seq, ",uid=%u", opts->uid); +		seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, opts->uid));  	if (opts->setgid) -		seq_printf(seq, ",gid=%u", opts->gid); +		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, opts->gid));  	seq_printf(seq, ",mode=%03o", opts->mode);  #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES  	seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index ab224809051..a750f957b14 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -303,7 +303,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,  		mutex_unlock(&ecryptfs_daemon_hash_mux);  		goto wake_up;  	} -	tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns; +	tsk_user_ns = __task_cred(msg_ctx->task)->user_ns;  	ctx_euid = task_euid(msg_ctx->task);  	rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);  	rcu_read_unlock(); diff --git a/fs/exec.c b/fs/exec.c index 1e8efdc8041..52c9e2ff6e6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1139,7 +1139,7 @@ void setup_new_exec(struct linux_binprm * bprm)  	/* This is the point of no return */  	current->sas_ss_sp = current->sas_ss_size = 0; -	if (current_euid() == current_uid() && current_egid() == current_gid()) +	if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid()))  		set_dumpable(current->mm, 1);  	else  		set_dumpable(current->mm, suid_dumpable); @@ -1153,8 +1153,8 @@ void setup_new_exec(struct linux_binprm * bprm)  	current->mm->task_size = TASK_SIZE;  	/* install the new credentials */ -	if (bprm->cred->uid != current_euid() || -	    bprm->cred->gid != current_egid()) { +	if (!uid_eq(bprm->cred->uid, current_euid()) || +	    !gid_eq(bprm->cred->gid, current_egid())) {  		current->pdeath_signal = 0;  	} else {  		would_dump(bprm, bprm->file); @@ -1299,8 +1299,11 @@ int prepare_binprm(struct linux_binprm *bprm)  	    !current->no_new_privs) {  		/* Set-uid? */  		if (mode & S_ISUID) { +			if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid)) +				return -EPERM;  			bprm->per_clear |= PER_CLEAR_ON_SETID;  			bprm->cred->euid = inode->i_uid; +  		}  		/* Set-gid? */ @@ -1310,6 +1313,8 @@ int prepare_binprm(struct linux_binprm *bprm)  		 * executable.  		 */  		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { +			if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) +				return -EPERM;  			bprm->per_clear |= PER_CLEAR_ON_SETID;  			bprm->cred->egid = inode->i_gid;  		} @@ -2142,7 +2147,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)  	if (__get_dumpable(cprm.mm_flags) == 2) {  		/* Setuid core dump mode */  		flag = O_EXCL;		/* Stop rewrite attacks */ -		cred->fsuid = 0;	/* Dump root private */ +		cred->fsuid = GLOBAL_ROOT_UID;	/* Dump root private */  	}  	retval = coredump_wait(exit_code, &core_state); @@ -2243,7 +2248,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)  		 * Dont allow local users get cute and trick others to coredump  		 * into their pre-created files.  		 */ -		if (inode->i_uid != current_fsuid()) +		if (!uid_eq(inode->i_uid, current_fsuid()))  			goto close_fail;  		if (!cprm.file->f_op || !cprm.file->f_op->write)  			goto close_fail; diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index a8cbe1bc6ad..030c6d277e1 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -1193,8 +1193,9 @@ static int ext2_has_free_blocks(struct ext2_sb_info *sbi)  	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);  	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);  	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && -		sbi->s_resuid != current_fsuid() && -		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { +		!uid_eq(sbi->s_resuid, current_fsuid()) && +		(gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) || +		 !in_group_p (sbi->s_resgid))) {  		return 0;  	}  	return 1; diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 0b2b4db5bdc..d9a17d0b124 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -82,8 +82,8 @@ struct ext2_sb_info {  	struct buffer_head ** s_group_desc;  	unsigned long  s_mount_opt;  	unsigned long s_sb_block; -	uid_t s_resuid; -	gid_t s_resgid; +	kuid_t s_resuid; +	kgid_t s_resgid;  	unsigned short s_mount_state;  	unsigned short s_pad;  	int s_addr_per_block_bits; @@ -637,8 +637,8 @@ static inline void verify_offsets(void)   */  struct ext2_mount_options {  	unsigned long s_mount_opt; -	uid_t s_resuid; -	gid_t s_resgid; +	kuid_t s_resuid; +	kgid_t s_resgid;  };  /* diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 740cad8dcd8..f9fa95f8443 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1293,6 +1293,8 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)  	struct inode *inode;  	long ret = -EIO;  	int n; +	uid_t i_uid; +	gid_t i_gid;  	inode = iget_locked(sb, ino);  	if (!inode) @@ -1310,12 +1312,14 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)  	}  	inode->i_mode = le16_to_cpu(raw_inode->i_mode); -	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); +	i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); +	i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);  	if (!(test_opt (inode->i_sb, NO_UID32))) { -		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; +		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);  	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); @@ -1413,8 +1417,8 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)  	struct ext2_inode_info *ei = EXT2_I(inode);  	struct super_block *sb = inode->i_sb;  	ino_t ino = inode->i_ino; -	uid_t uid = inode->i_uid; -	gid_t gid = inode->i_gid; +	uid_t uid = i_uid_read(inode); +	gid_t gid = i_gid_read(inode);  	struct buffer_head * bh;  	struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);  	int n; @@ -1529,8 +1533,8 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)  	if (is_quota_modification(inode, iattr))  		dquot_initialize(inode); -	if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || -	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { +	if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) || +	    (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {  		error = dquot_transfer(inode, iattr);  		if (error)  			return error; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index e1025c7a437..38f816071dd 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -228,13 +228,15 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root)  		seq_puts(seq, ",grpid");  	if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS))  		seq_puts(seq, ",nogrpid"); -	if (sbi->s_resuid != EXT2_DEF_RESUID || +	if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT2_DEF_RESUID)) ||  	    le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { -		seq_printf(seq, ",resuid=%u", sbi->s_resuid); +		seq_printf(seq, ",resuid=%u", +				from_kuid_munged(&init_user_ns, sbi->s_resuid));  	} -	if (sbi->s_resgid != EXT2_DEF_RESGID || +	if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT2_DEF_RESGID)) ||  	    le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { -		seq_printf(seq, ",resgid=%u", sbi->s_resgid); +		seq_printf(seq, ",resgid=%u", +				from_kgid_munged(&init_user_ns, sbi->s_resgid));  	}  	if (test_opt(sb, ERRORS_RO)) {  		int def_errors = le16_to_cpu(es->s_errors); @@ -436,6 +438,8 @@ static int parse_options(char *options, struct super_block *sb)  	struct ext2_sb_info *sbi = EXT2_SB(sb);  	substring_t args[MAX_OPT_ARGS];  	int option; +	kuid_t uid; +	kgid_t gid;  	if (!options)  		return 1; @@ -462,12 +466,23 @@ static int parse_options(char *options, struct super_block *sb)  		case Opt_resuid:  			if (match_int(&args[0], &option))  				return 0; -			sbi->s_resuid = option; +			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_resuid = uid;  			break;  		case Opt_resgid:  			if (match_int(&args[0], &option))  				return 0; -			sbi->s_resgid = option; +			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_resgid = gid;  			break;  		case Opt_sb:  			/* handled by get_sb_block() instead of here */ @@ -841,8 +856,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)  	else  		set_opt(sbi->s_mount_opt, ERRORS_RO); -	sbi->s_resuid = le16_to_cpu(es->s_def_resuid); -	sbi->s_resgid = le16_to_cpu(es->s_def_resgid); +	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));  	set_opt(sbi->s_mount_opt, RESERVATION); diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index baac1b129fb..25cd6089211 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -1439,8 +1439,9 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi, int use_reservation)  	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);  	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);  	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && -		!use_reservation && sbi->s_resuid != current_fsuid() && -		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { +		!use_reservation && !uid_eq(sbi->s_resuid, current_fsuid()) && +		(gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) || +		 !in_group_p (sbi->s_resgid))) {  		return 0;  	}  	return 1; diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h index b6515fd7e56..7977973a24f 100644 --- a/fs/ext3/ext3.h +++ b/fs/ext3/ext3.h @@ -243,8 +243,8 @@ struct ext3_new_group_data {   */  struct ext3_mount_options {  	unsigned long s_mount_opt; -	uid_t s_resuid; -	gid_t s_resgid; +	kuid_t s_resuid; +	kgid_t s_resgid;  	unsigned long s_commit_interval;  #ifdef CONFIG_QUOTA  	int s_jquota_fmt; @@ -637,8 +637,8 @@ struct ext3_sb_info {  	struct buffer_head ** s_group_desc;  	unsigned long  s_mount_opt;  	ext3_fsblk_t s_sb_block; -	uid_t s_resuid; -	gid_t s_resgid; +	kuid_t s_resuid; +	kgid_t s_resgid;  	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 10d7812f602..a09790a412b 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2891,6 +2891,8 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)  	transaction_t *transaction;  	long ret;  	int block; +	uid_t i_uid; +	gid_t i_gid;  	inode = iget_locked(sb, ino);  	if (!inode) @@ -2907,12 +2909,14 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)  	bh = iloc.bh;  	raw_inode = ext3_raw_inode(&iloc);  	inode->i_mode = le16_to_cpu(raw_inode->i_mode); -	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); +	i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); +	i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);  	if(!(test_opt (inode->i_sb, NO_UID32))) { -		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; +		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);  	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); @@ -3068,6 +3072,8 @@ static int ext3_do_update_inode(handle_t *handle,  	struct ext3_inode_info *ei = EXT3_I(inode);  	struct buffer_head *bh = iloc->bh;  	int err = 0, rc, block; +	uid_t i_uid; +	gid_t i_gid;  again:  	/* we can't allow multiple procs in here at once, its a bit racey */ @@ -3080,27 +3086,29 @@ again:  	ext3_get_inode_flags(ei);  	raw_inode->i_mode = cpu_to_le16(inode->i_mode); +	i_uid = i_uid_read(inode); +	i_gid = i_gid_read(inode);  	if(!(test_opt(inode->i_sb, NO_UID32))) { -		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); -		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); +		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));  /*   * 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(inode->i_uid)); +				cpu_to_le16(high_16_bits(i_uid));  			raw_inode->i_gid_high = -				cpu_to_le16(high_16_bits(inode->i_gid)); +				cpu_to_le16(high_16_bits(i_gid));  		} else {  			raw_inode->i_uid_high = 0;  			raw_inode->i_gid_high = 0;  		}  	} else {  		raw_inode->i_uid_low = -			cpu_to_le16(fs_high2lowuid(inode->i_uid)); +			cpu_to_le16(fs_high2lowuid(i_uid));  		raw_inode->i_gid_low = -			cpu_to_le16(fs_high2lowgid(inode->i_gid)); +			cpu_to_le16(fs_high2lowgid(i_gid));  		raw_inode->i_uid_high = 0;  		raw_inode->i_gid_high = 0;  	} @@ -3262,8 +3270,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)  	if (is_quota_modification(inode, attr))  		dquot_initialize(inode); -	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { +	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || +	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {  		handle_t *handle;  		/* (user+group)*(old+new) structure, inode write (sb, diff --git a/fs/ext3/super.c b/fs/ext3/super.c index cf0b5921cf0..94ef7e61612 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -617,13 +617,15 @@ static int ext3_show_options(struct seq_file *seq, struct dentry *root)  		seq_puts(seq, ",grpid");  	if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS))  		seq_puts(seq, ",nogrpid"); -	if (sbi->s_resuid != EXT3_DEF_RESUID || +	if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT3_DEF_RESUID)) ||  	    le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { -		seq_printf(seq, ",resuid=%u", sbi->s_resuid); +		seq_printf(seq, ",resuid=%u", +				from_kuid_munged(&init_user_ns, sbi->s_resuid));  	} -	if (sbi->s_resgid != EXT3_DEF_RESGID || +	if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT3_DEF_RESGID)) ||  	    le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { -		seq_printf(seq, ",resgid=%u", sbi->s_resgid); +		seq_printf(seq, ",resgid=%u", +				from_kgid_munged(&init_user_ns, sbi->s_resgid));  	}  	if (test_opt(sb, ERRORS_RO)) {  		int def_errors = le16_to_cpu(es->s_errors); @@ -967,6 +969,8 @@ static int parse_options (char *options, struct super_block *sb,  	substring_t args[MAX_OPT_ARGS];  	int data_opt = 0;  	int option; +	kuid_t uid; +	kgid_t gid;  #ifdef CONFIG_QUOTA  	int qfmt;  #endif @@ -1000,12 +1004,23 @@ static int parse_options (char *options, struct super_block *sb,  		case Opt_resuid:  			if (match_int(&args[0], &option))  				return 0; -			sbi->s_resuid = option; +			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_resuid = uid;  			break;  		case Opt_resgid:  			if (match_int(&args[0], &option))  				return 0; -			sbi->s_resgid = option; +			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_resgid = gid;  			break;  		case Opt_sb:  			/* handled by get_sb_block() instead of here */ @@ -1651,8 +1666,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  	}  	sb->s_fs_info = sbi;  	sbi->s_mount_opt = 0; -	sbi->s_resuid = EXT3_DEF_RESUID; -	sbi->s_resgid = EXT3_DEF_RESGID; +	sbi->s_resuid = make_kuid(&init_user_ns, EXT3_DEF_RESUID); +	sbi->s_resgid = make_kgid(&init_user_ns, EXT3_DEF_RESGID);  	sbi->s_sb_block = sb_block;  	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); @@ -1716,8 +1731,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  	else  		set_opt(sbi->s_mount_opt, ERRORS_RO); -	sbi->s_resuid = le16_to_cpu(es->s_def_resuid); -	sbi->s_resgid = le16_to_cpu(es->s_def_resgid); +	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));  	/* enable barriers by default */  	set_opt(sbi->s_mount_opt, BARRIER); diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 4bbd07a6fa1..c45c41129a3 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -461,8 +461,8 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi,  		return 1;  	/* Hm, nope.  Are (enough) root reserved clusters available? */ -	if (sbi->s_resuid == current_fsuid() || -	    ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || +	if (uid_eq(sbi->s_resuid, current_fsuid()) || +	    (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) ||  	    capable(CAP_SYS_RESOURCE) ||  		(flags & EXT4_MB_USE_ROOT_BLOCKS)) { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0e01e90add8..c21b1de51af 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1153,8 +1153,8 @@ struct ext4_sb_info {  	unsigned int s_mount_flags;  	unsigned int s_def_mount_opt;  	ext4_fsblk_t s_sb_block; -	uid_t s_resuid; -	gid_t s_resgid; +	kuid_t s_resuid; +	kgid_t s_resgid;  	unsigned short s_mount_state;  	unsigned short s_pad;  	int s_addr_per_block_bits; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 409c2ee7750..9f9acac6c43 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -808,8 +808,8 @@ got:  	}  	if (owner) {  		inode->i_mode = mode; -		inode->i_uid = owner[0]; -		inode->i_gid = owner[1]; +		i_uid_write(inode, owner[0]); +		i_gid_write(inode, owner[1]);  	} else if (test_opt(sb, GRPID)) {  		inode->i_mode = mode;  		inode->i_uid = current_fsuid(); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c77b0bd2c71..07eaf565fdc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3630,6 +3630,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)  	journal_t *journal = EXT4_SB(sb)->s_journal;  	long ret;  	int block; +	uid_t i_uid; +	gid_t i_gid;  	inode = iget_locked(sb, ino);  	if (!inode) @@ -3645,12 +3647,14 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)  		goto bad_inode;  	raw_inode = ext4_raw_inode(&iloc);  	inode->i_mode = le16_to_cpu(raw_inode->i_mode); -	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); +	i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); +	i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);  	if (!(test_opt(inode->i_sb, NO_UID32))) { -		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; +		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);  	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));  	ext4_clear_state_flags(ei);	/* Only relevant on 32-bit archs */ @@ -3870,6 +3874,8 @@ static int ext4_do_update_inode(handle_t *handle,  	struct ext4_inode_info *ei = EXT4_I(inode);  	struct buffer_head *bh = iloc->bh;  	int err = 0, rc, block; +	uid_t i_uid; +	gid_t i_gid;  	/* For fields not not tracking in the in-memory inode,  	 * initialise them to zero for new inodes. */ @@ -3878,27 +3884,27 @@ static int ext4_do_update_inode(handle_t *handle,  	ext4_get_inode_flags(ei);  	raw_inode->i_mode = cpu_to_le16(inode->i_mode); +	i_uid = i_uid_read(inode); +	i_gid = i_gid_read(inode);  	if (!(test_opt(inode->i_sb, NO_UID32))) { -		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); -		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); +		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));  /*   * 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(inode->i_uid)); +				cpu_to_le16(high_16_bits(i_uid));  			raw_inode->i_gid_high = -				cpu_to_le16(high_16_bits(inode->i_gid)); +				cpu_to_le16(high_16_bits(i_gid));  		} else {  			raw_inode->i_uid_high = 0;  			raw_inode->i_gid_high = 0;  		}  	} else { -		raw_inode->i_uid_low = -			cpu_to_le16(fs_high2lowuid(inode->i_uid)); -		raw_inode->i_gid_low = -			cpu_to_le16(fs_high2lowgid(inode->i_gid)); +		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;  	} @@ -4084,8 +4090,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)  	if (is_quota_modification(inode, attr))  		dquot_initialize(inode); -	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { +	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || +	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {  		handle_t *handle;  		/* (user+group)*(old+new) structure, inode write (sb, diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index f39f80f8f2c..f1bb32ec016 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -466,8 +466,8 @@ int ext4_ext_migrate(struct inode *inode)  	}  	goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *  		EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; -	owner[0] = inode->i_uid; -	owner[1] = inode->i_gid; +	owner[0] = i_uid_read(inode); +	owner[1] = i_gid_read(inode);  	tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,  				   S_IFREG, NULL, goal, owner);  	if (IS_ERR(tmp_inode)) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e1fb1d5de58..436b4223df6 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1448,6 +1448,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,  {  	struct ext4_sb_info *sbi = EXT4_SB(sb);  	const struct mount_opts *m; +	kuid_t uid; +	kgid_t gid;  	int arg = 0;  #ifdef CONFIG_QUOTA @@ -1474,10 +1476,20 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,  			 "Ignoring removed %s option", opt);  		return 1;  	case Opt_resuid: -		sbi->s_resuid = arg; +		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_resuid = uid;  		return 1;  	case Opt_resgid: -		sbi->s_resgid = arg; +		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_resgid = gid;  		return 1;  	case Opt_abort:  		sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; @@ -1732,12 +1744,14 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,  		SEQ_OPTS_PRINT("%s", token2str(m->token));  	} -	if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID || +	if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) ||  	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) -		SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid); -	if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID || +		SEQ_OPTS_PRINT("resuid=%u", +				from_kuid_munged(&init_user_ns, sbi->s_resuid)); +	if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) ||  	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) -		SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid); +		SEQ_OPTS_PRINT("resgid=%u", +				from_kgid_munged(&init_user_ns, sbi->s_resgid));  	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"); @@ -2980,8 +2994,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	}  	sb->s_fs_info = sbi;  	sbi->s_mount_opt = 0; -	sbi->s_resuid = EXT4_DEF_RESUID; -	sbi->s_resgid = EXT4_DEF_RESGID; +	sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID); +	sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID);  	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;  	sbi->s_sb_block = sb_block;  	if (sb->s_bdev->bd_part) @@ -3060,8 +3074,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	if (def_mount_opts & EXT4_DEFM_DISCARD)  		set_opt(sb, DISCARD); -	sbi->s_resuid = le16_to_cpu(es->s_def_resuid); -	sbi->s_resgid = le16_to_cpu(es->s_def_resgid); +	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_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;  	sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;  	sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; @@ -4213,8 +4227,8 @@ static int ext4_unfreeze(struct super_block *sb)  struct ext4_mount_options {  	unsigned long s_mount_opt;  	unsigned long s_mount_opt2; -	uid_t s_resuid; -	gid_t s_resgid; +	kuid_t s_resuid; +	kgid_t s_resgid;  	unsigned long s_commit_interval;  	u32 s_min_batch_time, s_max_batch_time;  #ifdef CONFIG_QUOTA diff --git a/fs/fcntl.c b/fs/fcntl.c index 75e7c1f3a08..d078b75572a 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -532,9 +532,9 @@ static inline int sigio_perm(struct task_struct *p,  	rcu_read_lock();  	cred = __task_cred(p); -	ret = ((fown->euid == 0 || -		fown->euid == cred->suid || fown->euid == cred->uid || -		fown->uid  == cred->suid || fown->uid  == cred->uid) && +	ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) || +		uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) || +		uid_eq(fown->uid,  cred->suid) || uid_eq(fown->uid,  cred->uid)) &&  	       !security_file_send_sigiotask(p, fown, sig));  	rcu_read_unlock();  	return ret; diff --git a/fs/inode.c b/fs/inode.c index 9f4f5fecc09..deb72f6c2b4 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -135,8 +135,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)  	inode->i_fop = &empty_fops;  	inode->__i_nlink = 1;  	inode->i_opflags = 0; -	inode->i_uid = 0; -	inode->i_gid = 0; +	i_uid_write(inode, 0); +	i_gid_write(inode, 0);  	atomic_set(&inode->i_writecount, 0);  	inode->i_size = 0;  	inode->i_blocks = 0; @@ -1732,11 +1732,9 @@ EXPORT_SYMBOL(inode_init_owner);   */  bool inode_owner_or_capable(const struct inode *inode)  { -	struct user_namespace *ns = inode_userns(inode); - -	if (current_user_ns() == ns && current_fsuid() == inode->i_uid) +	if (uid_eq(current_fsuid(), inode->i_uid))  		return true; -	if (ns_capable(ns, CAP_FOWNER)) +	if (inode_capable(inode, CAP_FOWNER))  		return true;  	return false;  } diff --git a/fs/ioprio.c b/fs/ioprio.c index 0f1b9515213..5e6dbe8958f 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -37,8 +37,8 @@ int set_task_ioprio(struct task_struct *task, int ioprio)  	rcu_read_lock();  	tcred = __task_cred(task); -	if (tcred->uid != cred->euid && -	    tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) { +	if (!uid_eq(tcred->uid, cred->euid) && +	    !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) {  		rcu_read_unlock();  		return -EPERM;  	} @@ -65,6 +65,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)  	struct task_struct *p, *g;  	struct user_struct *user;  	struct pid *pgrp; +	kuid_t uid;  	int ret;  	switch (class) { @@ -110,16 +111,19 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)  			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);  			break;  		case IOPRIO_WHO_USER: +			uid = make_kuid(current_user_ns(), who); +			if (!uid_valid(uid)) +				break;  			if (!who)  				user = current_user();  			else -				user = find_user(who); +				user = find_user(uid);  			if (!user)  				break;  			do_each_thread(g, p) { -				if (__task_cred(p)->uid != who) +				if (!uid_eq(task_uid(p), uid))  					continue;  				ret = set_task_ioprio(p, ioprio);  				if (ret) @@ -174,6 +178,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)  	struct task_struct *g, *p;  	struct user_struct *user;  	struct pid *pgrp; +	kuid_t uid;  	int ret = -ESRCH;  	int tmpio; @@ -203,16 +208,17 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)  			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);  			break;  		case IOPRIO_WHO_USER: +			uid = make_kuid(current_user_ns(), who);  			if (!who)  				user = current_user();  			else -				user = find_user(who); +				user = find_user(uid);  			if (!user)  				break;  			do_each_thread(g, p) { -				if (__task_cred(p)->uid != user->uid) +				if (!uid_eq(task_uid(p), user->uid))  					continue;  				tmpio = get_task_ioprio(p);  				if (tmpio < 0) diff --git a/fs/locks.c b/fs/locks.c index 0d68f1f8179..4f441e46cef 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1446,7 +1446,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)  	struct inode *inode = dentry->d_inode;  	int error; -	if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) +	if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))  		return -EACCES;  	if (!S_ISREG(inode->i_mode))  		return -EINVAL; diff --git a/fs/namei.c b/fs/namei.c index f9e883c1b85..e70ebab9624 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -218,10 +218,7 @@ static int acl_permission_check(struct inode *inode, int mask)  {  	unsigned int mode = inode->i_mode; -	if (current_user_ns() != inode_userns(inode)) -		goto other_perms; - -	if (likely(current_fsuid() == inode->i_uid)) +	if (likely(uid_eq(current_fsuid(), inode->i_uid)))  		mode >>= 6;  	else {  		if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { @@ -234,7 +231,6 @@ static int acl_permission_check(struct inode *inode, int mask)  			mode >>= 3;  	} -other_perms:  	/*  	 * If the DACs are ok we don't need any capability check.  	 */ @@ -270,10 +266,10 @@ int generic_permission(struct inode *inode, int mask)  	if (S_ISDIR(inode->i_mode)) {  		/* DACs are overridable for directories */ -		if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) +		if (inode_capable(inode, CAP_DAC_OVERRIDE))  			return 0;  		if (!(mask & MAY_WRITE)) -			if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) +			if (inode_capable(inode, CAP_DAC_READ_SEARCH))  				return 0;  		return -EACCES;  	} @@ -283,7 +279,7 @@ int generic_permission(struct inode *inode, int mask)  	 * at least one exec bit set.  	 */  	if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) -		if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) +		if (inode_capable(inode, CAP_DAC_OVERRIDE))  			return 0;  	/* @@ -291,7 +287,7 @@ int generic_permission(struct inode *inode, int mask)  	 */  	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;  	if (mask == MAY_READ) -		if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) +		if (inode_capable(inode, CAP_DAC_READ_SEARCH))  			return 0;  	return -EACCES; @@ -1934,19 +1930,15 @@ static int user_path_parent(int dfd, const char __user *path,   */  static inline int check_sticky(struct inode *dir, struct inode *inode)  { -	uid_t fsuid = current_fsuid(); +	kuid_t fsuid = current_fsuid();  	if (!(dir->i_mode & S_ISVTX))  		return 0; -	if (current_user_ns() != inode_userns(inode)) -		goto other_userns; -	if (inode->i_uid == fsuid) +	if (uid_eq(inode->i_uid, fsuid))  		return 0; -	if (dir->i_uid == fsuid) +	if (uid_eq(dir->i_uid, fsuid))  		return 0; - -other_userns: -	return !ns_capable(inode_userns(inode), CAP_FOWNER); +	return !inode_capable(inode, CAP_FOWNER);  }  /* @@ -2534,8 +2526,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)  	if (error)  		return error; -	if ((S_ISCHR(mode) || S_ISBLK(mode)) && -	    !ns_capable(inode_userns(dir), CAP_MKNOD)) +	if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))  		return -EPERM;  	if (!dir->i_op->mknod) diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 79717a40dab..204438cc914 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -1,6 +1,7 @@  /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */  #include <linux/sched.h> +#include <linux/user_namespace.h>  #include "nfsd.h"  #include "auth.h" @@ -56,8 +57,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)  			goto oom;  		for (i = 0; i < rqgi->ngroups; i++) { -			if (!GROUP_AT(rqgi, i)) -				GROUP_AT(gi, i) = exp->ex_anon_gid; +			if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i))) +				GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid);  			else  				GROUP_AT(gi, i) = GROUP_AT(rqgi, i);  		} diff --git a/fs/open.c b/fs/open.c index 5eccdcea2d1..d54301219d0 100644 --- a/fs/open.c +++ b/fs/open.c @@ -316,7 +316,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)  	if (!issecure(SECURE_NO_SETUID_FIXUP)) {  		/* Clear the capabilities if we switch to a non-root user */ -		if (override_cred->uid) +		kuid_t root_uid = make_kuid(override_cred->user_ns, 0); +		if (!uid_eq(override_cred->uid, root_uid))  			cap_clear(override_cred->cap_effective);  		else  			override_cred->cap_effective = @@ -505,15 +506,24 @@ static int chown_common(struct path *path, uid_t user, gid_t group)  	struct inode *inode = path->dentry->d_inode;  	int error;  	struct iattr newattrs; +	kuid_t uid; +	kgid_t gid; + +	uid = make_kuid(current_user_ns(), user); +	gid = make_kgid(current_user_ns(), group);  	newattrs.ia_valid =  ATTR_CTIME;  	if (user != (uid_t) -1) { +		if (!uid_valid(uid)) +			return -EINVAL;  		newattrs.ia_valid |= ATTR_UID; -		newattrs.ia_uid = user; +		newattrs.ia_uid = uid;  	}  	if (group != (gid_t) -1) { +		if (!gid_valid(gid)) +			return -EINVAL;  		newattrs.ia_valid |= ATTR_GID; -		newattrs.ia_gid = group; +		newattrs.ia_gid = gid;  	}  	if (!S_ISDIR(inode->i_mode))  		newattrs.ia_valid |= diff --git a/fs/proc/array.c b/fs/proc/array.c index f9bd395b347..dc4c5a7b9ec 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -81,6 +81,7 @@  #include <linux/pid_namespace.h>  #include <linux/ptrace.h>  #include <linux/tracehook.h> +#include <linux/user_namespace.h>  #include <asm/pgtable.h>  #include <asm/processor.h> @@ -161,6 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk)  static inline void task_state(struct seq_file *m, struct pid_namespace *ns,  				struct pid *pid, struct task_struct *p)  { +	struct user_namespace *user_ns = current_user_ns();  	struct group_info *group_info;  	int g;  	struct fdtable *fdt = NULL; @@ -189,8 +191,14 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,  		task_tgid_nr_ns(p, ns),  		pid_nr_ns(pid, ns),  		ppid, tpid, -		cred->uid, cred->euid, cred->suid, cred->fsuid, -		cred->gid, cred->egid, cred->sgid, cred->fsgid); +		from_kuid_munged(user_ns, cred->uid), +		from_kuid_munged(user_ns, cred->euid), +		from_kuid_munged(user_ns, cred->suid), +		from_kuid_munged(user_ns, cred->fsuid), +		from_kgid_munged(user_ns, cred->gid), +		from_kgid_munged(user_ns, cred->egid), +		from_kgid_munged(user_ns, cred->sgid), +		from_kgid_munged(user_ns, cred->fsgid));  	task_lock(p);  	if (p->files) @@ -205,7 +213,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,  	task_unlock(p);  	for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) -		seq_printf(m, "%d ", GROUP_AT(group_info, g)); +		seq_printf(m, "%d ", +			   from_kgid_munged(user_ns, GROUP_AT(group_info, g)));  	put_cred(cred);  	seq_putc(m, '\n'); diff --git a/fs/proc/base.c b/fs/proc/base.c index 57b8159f26f..d2d3108a611 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -81,6 +81,7 @@  #include <linux/oom.h>  #include <linux/elf.h>  #include <linux/pid_namespace.h> +#include <linux/user_namespace.h>  #include <linux/fs_struct.h>  #include <linux/slab.h>  #include <linux/flex_array.h> @@ -1561,8 +1562,8 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)  	generic_fillattr(inode, stat);  	rcu_read_lock(); -	stat->uid = 0; -	stat->gid = 0; +	stat->uid = GLOBAL_ROOT_UID; +	stat->gid = GLOBAL_ROOT_GID;  	task = pid_task(proc_pid(inode), PIDTYPE_PID);  	if (task) {  		if (!has_pid_permissions(pid, task, 2)) { @@ -1622,8 +1623,8 @@ int pid_revalidate(struct dentry *dentry, struct nameidata *nd)  			inode->i_gid = cred->egid;  			rcu_read_unlock();  		} else { -			inode->i_uid = 0; -			inode->i_gid = 0; +			inode->i_uid = GLOBAL_ROOT_UID; +			inode->i_gid = GLOBAL_ROOT_GID;  		}  		inode->i_mode &= ~(S_ISUID | S_ISGID);  		security_task_to_inode(task, inode); @@ -1815,8 +1816,8 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)  					inode->i_gid = cred->egid;  					rcu_read_unlock();  				} else { -					inode->i_uid = 0; -					inode->i_gid = 0; +					inode->i_uid = GLOBAL_ROOT_UID; +					inode->i_gid = GLOBAL_ROOT_GID;  				}  				i_mode = S_IFLNK; @@ -2045,8 +2046,8 @@ static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)  			inode->i_gid = cred->egid;  			rcu_read_unlock();  		} else { -			inode->i_uid = 0; -			inode->i_gid = 0; +			inode->i_uid = GLOBAL_ROOT_UID; +			inode->i_gid = GLOBAL_ROOT_GID;  		}  		security_task_to_inode(task, inode);  		status = 1; @@ -2924,6 +2925,74 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)  }  #endif /* CONFIG_TASK_IO_ACCOUNTING */ +#ifdef CONFIG_USER_NS +static int proc_id_map_open(struct inode *inode, struct file *file, +	struct seq_operations *seq_ops) +{ +	struct user_namespace *ns = NULL; +	struct task_struct *task; +	struct seq_file *seq; +	int ret = -EINVAL; + +	task = get_proc_task(inode); +	if (task) { +		rcu_read_lock(); +		ns = get_user_ns(task_cred_xxx(task, user_ns)); +		rcu_read_unlock(); +		put_task_struct(task); +	} +	if (!ns) +		goto err; + +	ret = seq_open(file, seq_ops); +	if (ret) +		goto err_put_ns; + +	seq = file->private_data; +	seq->private = ns; + +	return 0; +err_put_ns: +	put_user_ns(ns); +err: +	return ret; +} + +static int proc_id_map_release(struct inode *inode, struct file *file) +{ +	struct seq_file *seq = file->private_data; +	struct user_namespace *ns = seq->private; +	put_user_ns(ns); +	return seq_release(inode, file); +} + +static int proc_uid_map_open(struct inode *inode, struct file *file) +{ +	return proc_id_map_open(inode, file, &proc_uid_seq_operations); +} + +static int proc_gid_map_open(struct inode *inode, struct file *file) +{ +	return proc_id_map_open(inode, file, &proc_gid_seq_operations); +} + +static const struct file_operations proc_uid_map_operations = { +	.open		= proc_uid_map_open, +	.write		= proc_uid_map_write, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= proc_id_map_release, +}; + +static const struct file_operations proc_gid_map_operations = { +	.open		= proc_gid_map_open, +	.write		= proc_gid_map_write, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= proc_id_map_release, +}; +#endif /* CONFIG_USER_NS */ +  static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,  				struct pid *pid, struct task_struct *task)  { @@ -3026,6 +3095,10 @@ static const struct pid_entry tgid_base_stuff[] = {  #ifdef CONFIG_HARDWALL  	INF("hardwall",   S_IRUGO, proc_pid_hardwall),  #endif +#ifdef CONFIG_USER_NS +	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations), +	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations), +#endif  };  static int proc_tgid_base_readdir(struct file * filp, @@ -3381,6 +3454,10 @@ static const struct pid_entry tid_base_stuff[] = {  #ifdef CONFIG_HARDWALL  	INF("hardwall",   S_IRUGO, proc_pid_hardwall),  #endif +#ifdef CONFIG_USER_NS +	REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations), +	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations), +#endif  };  static int proc_tid_base_readdir(struct file * filp, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 205c9228083..554ecc54799 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -108,8 +108,8 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)  	struct super_block *sb = root->d_sb;  	struct pid_namespace *pid = sb->s_fs_info; -	if (pid->pid_gid) -		seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid); +	if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) +		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));  	if (pid->hide_pid != 0)  		seq_printf(seq, ",hidepid=%u", pid->hide_pid); diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 21d836f4029..3476bca8f7a 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -371,9 +371,9 @@ void register_sysctl_root(struct ctl_table_root *root)  static int test_perm(int mode, int op)  { -	if (!current_euid()) +	if (uid_eq(current_euid(), GLOBAL_ROOT_UID))  		mode >>= 6; -	else if (in_egroup_p(0)) +	else if (in_egroup_p(GLOBAL_ROOT_GID))  		mode >>= 3;  	if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)  		return 0; diff --git a/fs/proc/root.c b/fs/proc/root.c index eed44bfc85d..7c30fce037c 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -67,7 +67,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid)  		case Opt_gid:  			if (match_int(&args[0], &option))  				return 0; -			pid->pid_gid = option; +			pid->pid_gid = make_kgid(current_user_ns(), option);  			break;  		case Opt_hidepid:  			if (match_int(&args[0], &option)) diff --git a/fs/stat.c b/fs/stat.c index 0cef3366a91..b6ff11825fc 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -138,8 +138,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta  	tmp.st_nlink = stat->nlink;  	if (tmp.st_nlink != stat->nlink)  		return -EOVERFLOW; -	SET_UID(tmp.st_uid, stat->uid); -	SET_GID(tmp.st_gid, stat->gid); +	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); +	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));  	tmp.st_rdev = old_encode_dev(stat->rdev);  #if BITS_PER_LONG == 32  	if (stat->size > MAX_NON_LFS) @@ -224,8 +224,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)  	tmp.st_nlink = stat->nlink;  	if (tmp.st_nlink != stat->nlink)  		return -EOVERFLOW; -	SET_UID(tmp.st_uid, stat->uid); -	SET_GID(tmp.st_gid, stat->gid); +	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); +	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));  	tmp.st_rdev = encode_dev(stat->rdev);  	tmp.st_size = stat->size;  	tmp.st_atime = stat->atime.tv_sec; @@ -355,8 +355,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)  #endif  	tmp.st_mode = stat->mode;  	tmp.st_nlink = stat->nlink; -	tmp.st_uid = stat->uid; -	tmp.st_gid = stat->gid; +	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); +	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);  	tmp.st_atime = stat->atime.tv_sec;  	tmp.st_atime_nsec = stat->atime.tv_nsec;  	tmp.st_mtime = stat->mtime.tv_sec; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index feb2d69396c..907c2b3af75 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -62,8 +62,8 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)  	/* assign default attributes */  	iattrs->ia_mode = sd->s_mode; -	iattrs->ia_uid = 0; -	iattrs->ia_gid = 0; +	iattrs->ia_uid = GLOBAL_ROOT_UID; +	iattrs->ia_gid = GLOBAL_ROOT_GID;  	iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME;  	return attrs;  |