diff options
101 files changed, 1058 insertions, 656 deletions
diff --git a/Documentation/namespaces/resource-control.txt b/Documentation/namespaces/resource-control.txt new file mode 100644 index 00000000000..abc13c39473 --- /dev/null +++ b/Documentation/namespaces/resource-control.txt @@ -0,0 +1,14 @@ +There are a lot of kinds of objects in the kernel that don't have +individual limits or that have limits that are ineffective when a set +of processes is allowed to switch user ids.  With user namespaces +enabled in a kernel for people who don't trust their users or their +users programs to play nice this problems becomes more acute. + +Therefore it is recommended that memory control groups be enabled in +kernels that enable user namespaces, and it is further recommended +that userspace configure memory control groups to limit how much +memory user's they don't trust to play nice can use. + +Memory control groups can be configured by installing the libcgroup +package present on most distros editing /etc/cgrules.conf, +/etc/cgconfig.conf and setting up libpam-cgroup. diff --git a/fs/9p/fid.c b/fs/9p/fid.c index da8eefbe830..afd4724b2d9 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -74,19 +74,20 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)   *   */ -static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any) +static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)  {  	struct v9fs_dentry *dent;  	struct p9_fid *fid, *ret;  	p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n", -		 dentry->d_name.name, dentry, uid, any); +		 dentry->d_name.name, dentry, from_kuid(&init_user_ns, uid), +		 any);  	dent = (struct v9fs_dentry *) dentry->d_fsdata;  	ret = NULL;  	if (dent) {  		spin_lock(&dent->lock);  		list_for_each_entry(fid, &dent->fidlist, dlist) { -			if (any || fid->uid == uid) { +			if (any || uid_eq(fid->uid, uid)) {  				ret = fid;  				break;  			} @@ -126,7 +127,7 @@ err_out:  }  static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, -					       uid_t uid, int any) +					       kuid_t uid, int any)  {  	struct dentry *ds;  	char **wnames, *uname; @@ -233,7 +234,7 @@ err_out:  struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)  { -	uid_t uid; +	kuid_t uid;  	int  any, access;  	struct v9fs_session_info *v9ses; @@ -253,7 +254,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)  		break;  	default: -		uid = ~0; +		uid = INVALID_UID;  		any = 0;  		break;  	} @@ -272,7 +273,7 @@ struct p9_fid *v9fs_fid_clone(struct dentry *dentry)  	return ret;  } -static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid) +static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, kuid_t uid)  {  	struct p9_fid *fid, *ret; @@ -289,7 +290,7 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)  	int err;  	struct p9_fid *fid; -	fid = v9fs_fid_clone_with_uid(dentry, 0); +	fid = v9fs_fid_clone_with_uid(dentry, GLOBAL_ROOT_UID);  	if (IS_ERR(fid))  		goto error_out;  	/* diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index d934f04e773..58e6cbce415 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -161,7 +161,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)  				ret = r;  				continue;  			} -			v9ses->dfltuid = option; +			v9ses->dfltuid = make_kuid(current_user_ns(), option); +			if (!uid_valid(v9ses->dfltuid)) { +				p9_debug(P9_DEBUG_ERROR, +					 "uid field, but not a uid?\n"); +				ret = -EINVAL; +				continue; +			}  			break;  		case Opt_dfltgid:  			r = match_int(&args[0], &option); @@ -171,7 +177,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)  				ret = r;  				continue;  			} -			v9ses->dfltgid = option; +			v9ses->dfltgid = make_kgid(current_user_ns(), option); +			if (!gid_valid(v9ses->dfltgid)) { +				p9_debug(P9_DEBUG_ERROR, +					 "gid field, but not a gid?\n"); +				ret = -EINVAL; +				continue; +			}  			break;  		case Opt_afid:  			r = match_int(&args[0], &option); @@ -248,8 +260,9 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)  			else if (strcmp(s, "client") == 0) {  				v9ses->flags |= V9FS_ACCESS_CLIENT;  			} else { +				uid_t uid;  				v9ses->flags |= V9FS_ACCESS_SINGLE; -				v9ses->uid = simple_strtoul(s, &e, 10); +				uid = simple_strtoul(s, &e, 10);  				if (*e != '\0') {  					ret = -EINVAL;  					pr_info("Unknown access argument %s\n", @@ -257,6 +270,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)  					kfree(s);  					goto free_and_return;  				} +				v9ses->uid = make_kuid(current_user_ns(), uid); +				if (!uid_valid(v9ses->uid)) { +					ret = -EINVAL; +					pr_info("Uknown uid %s\n", s); +					kfree(s); +					goto free_and_return; +				}  			}  			kfree(s); @@ -319,7 +339,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,  	list_add(&v9ses->slist, &v9fs_sessionlist);  	spin_unlock(&v9fs_sessionlist_lock); -	v9ses->uid = ~0; +	v9ses->uid = INVALID_UID;  	v9ses->dfltuid = V9FS_DEFUID;  	v9ses->dfltgid = V9FS_DEFGID; @@ -364,7 +384,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,  		v9ses->flags &= ~V9FS_ACCESS_MASK;  		v9ses->flags |= V9FS_ACCESS_ANY; -		v9ses->uid = ~0; +		v9ses->uid = INVALID_UID;  	}  	if (!v9fs_proto_dotl(v9ses) ||  		!((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) { @@ -375,7 +395,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,  		v9ses->flags &= ~V9FS_ACL_MASK;  	} -	fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0, +	fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, INVALID_UID,  							v9ses->aname);  	if (IS_ERR(fid)) {  		retval = PTR_ERR(fid); @@ -387,7 +407,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,  	if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)  		fid->uid = v9ses->uid;  	else -		fid->uid = ~0; +		fid->uid = INVALID_UID;  #ifdef CONFIG_9P_FSCACHE  	/* register the session for caching */ diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 34c59f14a1c..a8e127c8962 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -109,9 +109,9 @@ struct v9fs_session_info {  	char *uname;		/* user name to mount as */  	char *aname;		/* name of remote hierarchy being mounted */  	unsigned int maxdata;	/* max data for client interface */ -	unsigned int dfltuid;	/* default uid/muid for legacy support */ -	unsigned int dfltgid;	/* default gid for legacy support */ -	u32 uid;		/* if ACCESS_SINGLE, the uid that has access */ +	kuid_t dfltuid;		/* default uid/muid for legacy support */ +	kgid_t dfltgid;		/* default gid for legacy support */ +	kuid_t uid;		/* if ACCESS_SINGLE, the uid that has access */  	struct p9_client *clnt;	/* 9p client */  	struct list_head slist; /* list of sessions registered with v9fs */  	struct backing_dev_info bdi; @@ -165,8 +165,8 @@ extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,  #define V9FS_PORT	564  #define V9FS_DEFUSER	"nobody"  #define V9FS_DEFANAME	"" -#define V9FS_DEFUID	(-2) -#define V9FS_DEFGID	(-2) +#define V9FS_DEFUID	KUIDT_INIT(-2) +#define V9FS_DEFGID	KGIDT_INIT(-2)  static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)  { diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 57d017ac68e..b5340c829de 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -225,9 +225,9 @@ v9fs_blank_wstat(struct p9_wstat *wstat)  	wstat->uid = NULL;  	wstat->gid = NULL;  	wstat->muid = NULL; -	wstat->n_uid = ~0; -	wstat->n_gid = ~0; -	wstat->n_muid = ~0; +	wstat->n_uid = INVALID_UID; +	wstat->n_gid = INVALID_GID; +	wstat->n_muid = INVALID_UID;  	wstat->extension = NULL;  } diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 8d24ad66dfb..07f409288d1 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -57,7 +57,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,   * group of the new file system object.   */ -static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode) +static kgid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)  {  	BUG_ON(dir_inode == NULL); @@ -245,7 +245,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,  			  int *opened)  {  	int err = 0; -	gid_t gid; +	kgid_t gid;  	umode_t mode;  	char *name = NULL;  	struct p9_qid qid; @@ -396,7 +396,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,  	int err;  	struct v9fs_session_info *v9ses;  	struct p9_fid *fid = NULL, *dfid = NULL; -	gid_t gid; +	kgid_t gid;  	char *name;  	umode_t mode;  	struct inode *inode; @@ -697,7 +697,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,  		const char *symname)  {  	int err; -	gid_t gid; +	kgid_t gid;  	char *name;  	struct p9_qid qid;  	struct inode *inode; @@ -837,7 +837,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,  		dev_t rdev)  {  	int err; -	gid_t gid; +	kgid_t gid;  	char *name;  	umode_t mode;  	struct v9fs_session_info *v9ses; diff --git a/fs/afs/afs.h b/fs/afs/afs.h index c548aa346f0..3c462ff6db6 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h @@ -119,8 +119,8 @@ struct afs_file_status {  	u64			size;		/* file size */  	afs_dataversion_t	data_version;	/* current data version */  	u32			author;		/* author ID */ -	u32			owner;		/* owner ID */ -	u32			group;		/* group ID */ +	kuid_t			owner;		/* owner ID */ +	kgid_t			group;		/* group ID */  	afs_access_t		caller_access;	/* access rights for authenticated caller */  	afs_access_t		anon_access;	/* access rights for unauthenticated caller */  	umode_t			mode;		/* UNIX mode */ @@ -133,13 +133,6 @@ struct afs_file_status {  /*   * AFS file status change request   */ -struct afs_store_status { -	u32			mask;		/* which bits of the struct are set */ -	u32			mtime_client;	/* last time client changed data */ -	u32			owner;		/* owner ID */ -	u32			group;		/* group ID */ -	umode_t			mode;		/* UNIX mode */ -};  #define AFS_SET_MTIME		0x01		/* set the mtime */  #define AFS_SET_OWNER		0x02		/* set the owner ID */ diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index b960ff05ea0..c2e930ec288 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -42,6 +42,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  	umode_t mode;  	u64 data_version, size;  	u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ +	kuid_t owner; +	kgid_t group;  #define EXTRACT(DST)				\  	do {					\ @@ -56,7 +58,9 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  	size = ntohl(*bp++);  	data_version = ntohl(*bp++);  	EXTRACT(status->author); -	EXTRACT(status->owner); +	owner = make_kuid(&init_user_ns, ntohl(*bp++)); +	changed |= !uid_eq(owner, status->owner); +	status->owner = owner;  	EXTRACT(status->caller_access); /* call ticket dependent */  	EXTRACT(status->anon_access);  	EXTRACT(status->mode); @@ -65,7 +69,9 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  	bp++; /* seg size */  	status->mtime_client = ntohl(*bp++);  	status->mtime_server = ntohl(*bp++); -	EXTRACT(status->group); +	group = make_kgid(&init_user_ns, ntohl(*bp++)); +	changed |= !gid_eq(group, status->group); +	status->group = group;  	bp++; /* sync counter */  	data_version |= (u64) ntohl(*bp++) << 32;  	EXTRACT(status->lock_count); @@ -181,12 +187,12 @@ static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)  	if (attr->ia_valid & ATTR_UID) {  		mask |= AFS_SET_OWNER; -		owner = attr->ia_uid; +		owner = from_kuid(&init_user_ns, attr->ia_uid);  	}  	if (attr->ia_valid & ATTR_GID) {  		mask |= AFS_SET_GROUP; -		group = attr->ia_gid; +		group = from_kgid(&init_user_ns, attr->ia_gid);  	}  	if (attr->ia_valid & ATTR_MODE) { diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 95cffd38239..789bc253b5f 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -69,7 +69,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)  	set_nlink(inode, vnode->status.nlink);  	inode->i_uid		= vnode->status.owner; -	inode->i_gid		= 0; +	inode->i_gid		= GLOBAL_ROOT_GID;  	inode->i_size		= vnode->status.size;  	inode->i_ctime.tv_sec	= vnode->status.mtime_server;  	inode->i_ctime.tv_nsec	= 0; @@ -175,8 +175,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,  	inode->i_mode		= S_IFDIR | S_IRUGO | S_IXUGO;  	inode->i_op		= &afs_autocell_inode_operations;  	set_nlink(inode, 2); -	inode->i_uid		= 0; -	inode->i_gid		= 0; +	inode->i_uid		= GLOBAL_ROOT_UID; +	inode->i_gid		= GLOBAL_ROOT_GID;  	inode->i_ctime.tv_sec	= get_seconds();  	inode->i_ctime.tv_nsec	= 0;  	inode->i_atime		= inode->i_mtime = inode->i_ctime; diff --git a/fs/afs/super.c b/fs/afs/super.c index 43165009428..7c31ec39957 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -24,6 +24,8 @@  #include <linux/parser.h>  #include <linux/statfs.h>  #include <linux/sched.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h>  #include "internal.h"  #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ @@ -363,6 +365,10 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  	memset(¶ms, 0, sizeof(params)); +	ret = -EINVAL; +	if (current->nsproxy->net_ns != &init_net) +		goto error; +  	/* parse the options and device name */  	if (options) {  		ret = afs_parse_options(¶ms, options, &dev_name); diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index a1d9bb30c1b..ae2be696eb5 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -930,7 +930,7 @@ static int send_cap_msg(struct ceph_mds_session *session,  			u64 size, u64 max_size,  			struct timespec *mtime, struct timespec *atime,  			u64 time_warp_seq, -			uid_t uid, gid_t gid, umode_t mode, +			kuid_t uid, kgid_t gid, umode_t mode,  			u64 xattr_version,  			struct ceph_buffer *xattrs_buf,  			u64 follows) @@ -974,8 +974,8 @@ static int send_cap_msg(struct ceph_mds_session *session,  		ceph_encode_timespec(&fc->atime, atime);  	fc->time_warp_seq = cpu_to_le32(time_warp_seq); -	fc->uid = cpu_to_le32(uid); -	fc->gid = cpu_to_le32(gid); +	fc->uid = cpu_to_le32(from_kuid(&init_user_ns, uid)); +	fc->gid = cpu_to_le32(from_kgid(&init_user_ns, gid));  	fc->mode = cpu_to_le32(mode);  	fc->xattr_version = cpu_to_le64(xattr_version); @@ -1081,8 +1081,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,  	struct timespec mtime, atime;  	int wake = 0;  	umode_t mode; -	uid_t uid; -	gid_t gid; +	kuid_t uid; +	kgid_t gid;  	struct ceph_mds_session *session;  	u64 xattr_version = 0;  	struct ceph_buffer *xattr_blob = NULL; @@ -2359,10 +2359,11 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,  	if ((issued & CEPH_CAP_AUTH_EXCL) == 0) {  		inode->i_mode = le32_to_cpu(grant->mode); -		inode->i_uid = le32_to_cpu(grant->uid); -		inode->i_gid = le32_to_cpu(grant->gid); +		inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); +		inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid));  		dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, -		     inode->i_uid, inode->i_gid); +		     from_kuid(&init_user_ns, inode->i_uid), +		     from_kgid(&init_user_ns, inode->i_gid));  	}  	if ((issued & CEPH_CAP_LINK_EXCL) == 0) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 2971eaa65cd..d45895f4a04 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -612,10 +612,11 @@ static int fill_inode(struct inode *inode,  	if ((issued & CEPH_CAP_AUTH_EXCL) == 0) {  		inode->i_mode = le32_to_cpu(info->mode); -		inode->i_uid = le32_to_cpu(info->uid); -		inode->i_gid = le32_to_cpu(info->gid); +		inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(info->uid)); +		inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(info->gid));  		dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, -		     inode->i_uid, inode->i_gid); +		     from_kuid(&init_user_ns, inode->i_uid), +		     from_kgid(&init_user_ns, inode->i_gid));  	}  	if ((issued & CEPH_CAP_LINK_EXCL) == 0) @@ -1565,26 +1566,30 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)  	if (ia_valid & ATTR_UID) {  		dout("setattr %p uid %d -> %d\n", inode, -		     inode->i_uid, attr->ia_uid); +		     from_kuid(&init_user_ns, inode->i_uid), +		     from_kuid(&init_user_ns, attr->ia_uid));  		if (issued & CEPH_CAP_AUTH_EXCL) {  			inode->i_uid = attr->ia_uid;  			dirtied |= CEPH_CAP_AUTH_EXCL;  		} else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 || -			   attr->ia_uid != inode->i_uid) { -			req->r_args.setattr.uid = cpu_to_le32(attr->ia_uid); +			   !uid_eq(attr->ia_uid, inode->i_uid)) { +			req->r_args.setattr.uid = cpu_to_le32( +				from_kuid(&init_user_ns, attr->ia_uid));  			mask |= CEPH_SETATTR_UID;  			release |= CEPH_CAP_AUTH_SHARED;  		}  	}  	if (ia_valid & ATTR_GID) {  		dout("setattr %p gid %d -> %d\n", inode, -		     inode->i_gid, attr->ia_gid); +		     from_kgid(&init_user_ns, inode->i_gid), +		     from_kgid(&init_user_ns, attr->ia_gid));  		if (issued & CEPH_CAP_AUTH_EXCL) {  			inode->i_gid = attr->ia_gid;  			dirtied |= CEPH_CAP_AUTH_EXCL;  		} else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 || -			   attr->ia_gid != inode->i_gid) { -			req->r_args.setattr.gid = cpu_to_le32(attr->ia_gid); +			   !gid_eq(attr->ia_gid, inode->i_gid)) { +			req->r_args.setattr.gid = cpu_to_le32( +				from_kgid(&init_user_ns, attr->ia_gid));  			mask |= CEPH_SETATTR_GID;  			release |= CEPH_CAP_AUTH_SHARED;  		} diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 9165eb8309e..7a3dfe0a9a8 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1658,8 +1658,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,  	head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch);  	head->op = cpu_to_le32(req->r_op); -	head->caller_uid = cpu_to_le32(req->r_uid); -	head->caller_gid = cpu_to_le32(req->r_gid); +	head->caller_uid = cpu_to_le32(from_kuid(&init_user_ns, req->r_uid)); +	head->caller_gid = cpu_to_le32(from_kgid(&init_user_ns, req->r_gid));  	head->args = req->r_args;  	ceph_encode_filepath(&p, end, ino1, path1); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index dd26846dd71..ff4188bf619 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -184,8 +184,8 @@ struct ceph_mds_request {  	union ceph_mds_request_args r_args;  	int r_fmode;        /* file mode, if expecting cap */ -	uid_t r_uid; -	gid_t r_gid; +	kuid_t r_uid; +	kgid_t r_gid;  	/* for choosing which mds to send this request to */  	int r_direct_mode; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 66ebe720e40..f053bbd1886 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -138,8 +138,8 @@ struct ceph_cap_snap {  	struct ceph_snap_context *context;  	umode_t mode; -	uid_t uid; -	gid_t gid; +	kuid_t uid; +	kgid_t gid;  	struct ceph_buffer *xattr_blob;  	u64 xattr_version; diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index c865bfdfe81..37e4a72a7d1 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -55,10 +55,10 @@ struct cifs_sb_info {  	unsigned int wsize;  	unsigned long actimeo; /* attribute cache timeout (jiffies) */  	atomic_t active; -	uid_t	mnt_uid; -	gid_t	mnt_gid; -	uid_t	mnt_backupuid; -	gid_t	mnt_backupgid; +	kuid_t	mnt_uid; +	kgid_t	mnt_gid; +	kuid_t	mnt_backupuid; +	kgid_t	mnt_backupgid;  	umode_t	mnt_file_mode;  	umode_t	mnt_dir_mode;  	unsigned int mnt_cifs_flags; diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 086f381d648..10e77476129 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -149,10 +149,12 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)  		goto out;  	dp = description + strlen(description); -	sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); +	sprintf(dp, ";uid=0x%x", +		from_kuid_munged(&init_user_ns, sesInfo->linux_uid));  	dp = description + strlen(description); -	sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); +	sprintf(dp, ";creduid=0x%x", +		from_kuid_munged(&init_user_ns, sesInfo->cred_uid));  	if (sesInfo->user_name) {  		dp = description + strlen(description); diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 5cbd00e7406..f1e3f25fe00 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -266,8 +266,8 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,  	struct key *sidkey;  	char *sidstr;  	const struct cred *saved_cred; -	uid_t fuid = cifs_sb->mnt_uid; -	gid_t fgid = cifs_sb->mnt_gid; +	kuid_t fuid = cifs_sb->mnt_uid; +	kgid_t fgid = cifs_sb->mnt_gid;  	/*  	 * If we have too many subauthorities, then something is really wrong. @@ -297,6 +297,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,  	 * probably a safe assumption but might be better to check based on  	 * sidtype.  	 */ +	BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));  	if (sidkey->datalen != sizeof(uid_t)) {  		rc = -EIO;  		cFYI(1, "%s: Downcall contained malformed key " @@ -305,10 +306,21 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,  		goto out_key_put;  	} -	if (sidtype == SIDOWNER) -		memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t)); -	else -		memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t)); +	if (sidtype == SIDOWNER) { +		kuid_t uid; +		uid_t id; +		memcpy(&id, &sidkey->payload.value, sizeof(uid_t)); +		uid = make_kuid(&init_user_ns, id); +		if (uid_valid(uid)) +			fuid = uid; +	} else { +		kgid_t gid; +		gid_t id; +		memcpy(&id, &sidkey->payload.value, sizeof(gid_t)); +		gid = make_kgid(&init_user_ns, id); +		if (gid_valid(gid)) +			fgid = gid; +	}  out_key_put:  	key_put(sidkey); @@ -346,7 +358,8 @@ init_cifs_idmap(void)  	if (!cred)  		return -ENOMEM; -	keyring = keyring_alloc(".cifs_idmap", 0, 0, cred, +	keyring = keyring_alloc(".cifs_idmap", +				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |  				KEY_USR_VIEW | KEY_USR_READ,  				KEY_ALLOC_NOT_IN_QUOTA, NULL); @@ -774,7 +787,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,  /* Convert permission bits from mode to equivalent CIFS ACL */  static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, -	__u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag) +	__u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)  {  	int rc = 0;  	__u32 dacloffset; @@ -806,17 +819,19 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,  		*aclflag = CIFS_ACL_DACL;  	} else {  		memcpy(pnntsd, pntsd, secdesclen); -		if (uid != NO_CHANGE_32) { /* chown */ +		if (uid_valid(uid)) { /* chown */ +			uid_t id;  			owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +  					le32_to_cpu(pnntsd->osidoffset));  			nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),  								GFP_KERNEL);  			if (!nowner_sid_ptr)  				return -ENOMEM; -			rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr); +			id = from_kuid(&init_user_ns, uid); +			rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);  			if (rc) {  				cFYI(1, "%s: Mapping error %d for owner id %d", -						__func__, rc, uid); +						__func__, rc, id);  				kfree(nowner_sid_ptr);  				return rc;  			} @@ -824,17 +839,19 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,  			kfree(nowner_sid_ptr);  			*aclflag = CIFS_ACL_OWNER;  		} -		if (gid != NO_CHANGE_32) { /* chgrp */ +		if (gid_valid(gid)) { /* chgrp */ +			gid_t id;  			group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +  					le32_to_cpu(pnntsd->gsidoffset));  			ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),  								GFP_KERNEL);  			if (!ngroup_sid_ptr)  				return -ENOMEM; -			rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr); +			id = from_kgid(&init_user_ns, gid); +			rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);  			if (rc) {  				cFYI(1, "%s: Mapping error %d for group id %d", -						__func__, rc, gid); +						__func__, rc, id);  				kfree(ngroup_sid_ptr);  				return rc;  			} @@ -1002,7 +1019,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,  /* Convert mode bits to an ACL so we can update the ACL on the server */  int  id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, -			uid_t uid, gid_t gid) +			kuid_t uid, kgid_t gid)  {  	int rc = 0;  	int aclflag = CIFS_ACL_DACL; /* default flag to set */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index de7f9168a11..9be09b21b4e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -375,13 +375,15 @@ cifs_show_options(struct seq_file *s, struct dentry *root)  				   (int)(srcaddr->sa_family));  	} -	seq_printf(s, ",uid=%u", cifs_sb->mnt_uid); +	seq_printf(s, ",uid=%u", +		   from_kuid_munged(&init_user_ns, cifs_sb->mnt_uid));  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)  		seq_printf(s, ",forceuid");  	else  		seq_printf(s, ",noforceuid"); -	seq_printf(s, ",gid=%u", cifs_sb->mnt_gid); +	seq_printf(s, ",gid=%u", +		   from_kgid_munged(&init_user_ns, cifs_sb->mnt_gid));  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)  		seq_printf(s, ",forcegid");  	else @@ -436,9 +438,13 @@ cifs_show_options(struct seq_file *s, struct dentry *root)  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)  		seq_printf(s, ",noperm");  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) -		seq_printf(s, ",backupuid=%u", cifs_sb->mnt_backupuid); +		seq_printf(s, ",backupuid=%u", +			   from_kuid_munged(&init_user_ns, +					    cifs_sb->mnt_backupuid));  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) -		seq_printf(s, ",backupgid=%u", cifs_sb->mnt_backupgid); +		seq_printf(s, ",backupgid=%u", +			   from_kgid_munged(&init_user_ns, +					    cifs_sb->mnt_backupgid));  	seq_printf(s, ",rsize=%u", cifs_sb->rsize);  	seq_printf(s, ",wsize=%u", cifs_sb->wsize); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e6899cea1c3..4f07f6fbe49 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -400,11 +400,11 @@ struct smb_vol {  	char *iocharset;  /* local code page for mapping to and from Unicode */  	char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */  	char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ -	uid_t cred_uid; -	uid_t linux_uid; -	gid_t linux_gid; -	uid_t backupuid; -	gid_t backupgid; +	kuid_t cred_uid; +	kuid_t linux_uid; +	kgid_t linux_gid; +	kuid_t backupuid; +	kgid_t backupgid;  	umode_t file_mode;  	umode_t dir_mode;  	unsigned secFlg; @@ -703,8 +703,8 @@ struct cifs_ses {  	char *serverNOS;	/* name of network operating system of server */  	char *serverDomain;	/* security realm of server */  	__u64 Suid;		/* remote smb uid  */ -	uid_t linux_uid;        /* overriding owner of files on the mount */ -	uid_t cred_uid;		/* owner of credentials */ +	kuid_t linux_uid;	/* overriding owner of files on the mount */ +	kuid_t cred_uid;	/* owner of credentials */  	unsigned int capabilities;  	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for  				TCP names - will ipv6 and sctp addresses fit? */ @@ -838,7 +838,7 @@ struct cifs_tcon {   */  struct tcon_link {  	struct rb_node		tl_rbnode; -	uid_t			tl_uid; +	kuid_t			tl_uid;  	unsigned long		tl_flags;  #define TCON_LINK_MASTER	0  #define TCON_LINK_PENDING	1 @@ -931,7 +931,7 @@ struct cifsFileInfo {  	struct list_head tlist;	/* pointer to next fid owned by tcon */  	struct list_head flist;	/* next fid (file instance) for this inode */  	struct cifs_fid_locks *llist;	/* brlocks held by this fid */ -	unsigned int uid;	/* allows finding which FileInfo structure */ +	kuid_t uid;		/* allows finding which FileInfo structure */  	__u32 pid;		/* process id who opened file */  	struct cifs_fid fid;	/* file id from remote */  	/* BB add lock scope info here if needed */ ; @@ -1245,8 +1245,8 @@ struct cifs_fattr {  	u64		cf_eof;  	u64		cf_bytes;  	u64		cf_createtime; -	uid_t		cf_uid; -	gid_t		cf_gid; +	kuid_t		cf_uid; +	kgid_t		cf_gid;  	umode_t		cf_mode;  	dev_t		cf_rdev;  	unsigned int	cf_nlink; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b9d59a948a2..e996ff6b26d 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -277,7 +277,6 @@  #define CIFS_NO_HANDLE        0xFFFF  #define NO_CHANGE_64          0xFFFFFFFFFFFFFFFFULL -#define NO_CHANGE_32          0xFFFFFFFFUL  /* IPC$ in ASCII */  #define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1988c1baa22..f450f0683dd 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -46,7 +46,8 @@ extern void _free_xid(unsigned int);  ({								\  	unsigned int __xid = _get_xid();				\  	cFYI(1, "CIFS VFS: in %s as Xid: %u with uid: %d",	\ -	     __func__, __xid, current_fsuid());			\ +	     __func__, __xid,					\ +	     from_kuid(&init_user_ns, current_fsuid()));	\  	__xid;							\  }) @@ -161,7 +162,7 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,  			      struct cifs_fattr *fattr, struct inode *inode,  			      const char *path, const __u16 *pfid);  extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64, -					uid_t, gid_t); +					kuid_t, kgid_t);  extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,  					const char *, u32 *);  extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, @@ -304,8 +305,8 @@ struct cifs_unix_set_info_args {  	__u64	atime;  	__u64	mtime;  	__u64	mode; -	__u64	uid; -	__u64	gid; +	kuid_t	uid; +	kgid_t	gid;  	dev_t	device;  }; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 76d0d299885..00e12f2d626 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -5819,8 +5819,14 @@ static void  cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,  			const struct cifs_unix_set_info_args *args)  { +	u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;  	u64 mode = args->mode; +	if (uid_valid(args->uid)) +		uid = from_kuid(&init_user_ns, args->uid); +	if (gid_valid(args->gid)) +		gid = from_kgid(&init_user_ns, args->gid); +  	/*  	 * Samba server ignores set of file size to zero due to bugs in some  	 * older clients, but we should be precise - we use SetFileSize to @@ -5833,8 +5839,8 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,  	data_offset->LastStatusChange = cpu_to_le64(args->ctime);  	data_offset->LastAccessTime = cpu_to_le64(args->atime);  	data_offset->LastModificationTime = cpu_to_le64(args->mtime); -	data_offset->Uid = cpu_to_le64(args->uid); -	data_offset->Gid = cpu_to_le64(args->gid); +	data_offset->Uid = cpu_to_le64(uid); +	data_offset->Gid = cpu_to_le64(gid);  	/* better to leave device as zero when it is  */  	data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));  	data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 12b3da39733..4474a57f30a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -987,6 +987,41 @@ static int get_option_ul(substring_t args[], unsigned long *option)  	return rc;  } +static int get_option_uid(substring_t args[], kuid_t *result) +{ +	unsigned long value; +	kuid_t uid; +	int rc; + +	rc = get_option_ul(args, &value); +	if (rc) +		return rc; + +	uid = make_kuid(current_user_ns(), value); +	if (!uid_valid(uid)) +		return -EINVAL; + +	*result = uid; +	return 0; +} + +static int get_option_gid(substring_t args[], kgid_t *result) +{ +	unsigned long value; +	kgid_t gid; +	int rc; + +	rc = get_option_ul(args, &value); +	if (rc) +		return rc; + +	gid = make_kgid(current_user_ns(), value); +	if (!gid_valid(gid)) +		return -EINVAL; + +	*result = gid; +	return 0; +}  static int cifs_parse_security_flavors(char *value,  				       struct smb_vol *vol) @@ -1424,47 +1459,42 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,  		/* Numeric Values */  		case Opt_backupuid: -			if (get_option_ul(args, &option)) { +			if (get_option_uid(args, &vol->backupuid)) {  				cERROR(1, "%s: Invalid backupuid value",  					__func__);  				goto cifs_parse_mount_err;  			} -			vol->backupuid = option;  			vol->backupuid_specified = true;  			break;  		case Opt_backupgid: -			if (get_option_ul(args, &option)) { +			if (get_option_gid(args, &vol->backupgid)) {  				cERROR(1, "%s: Invalid backupgid value",  					__func__);  				goto cifs_parse_mount_err;  			} -			vol->backupgid = option;  			vol->backupgid_specified = true;  			break;  		case Opt_uid: -			if (get_option_ul(args, &option)) { +			if (get_option_uid(args, &vol->linux_uid)) {  				cERROR(1, "%s: Invalid uid value",  					__func__);  				goto cifs_parse_mount_err;  			} -			vol->linux_uid = option;  			uid_specified = true;  			break;  		case Opt_cruid: -			if (get_option_ul(args, &option)) { +			if (get_option_uid(args, &vol->cred_uid)) {  				cERROR(1, "%s: Invalid cruid value",  					__func__);  				goto cifs_parse_mount_err;  			} -			vol->cred_uid = option;  			break;  		case Opt_gid: -			if (get_option_ul(args, &option)) { +			if (get_option_gid(args, &vol->linux_gid)) {  				cERROR(1, "%s: Invalid gid value",  						__func__);  				goto cifs_parse_mount_err;  			} -			vol->linux_gid = option;  			gid_specified = true;  			break;  		case Opt_file_mode: @@ -2241,7 +2271,7 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol)  {  	switch (ses->server->secType) {  	case Kerberos: -		if (vol->cred_uid != ses->cred_uid) +		if (!uid_eq(vol->cred_uid, ses->cred_uid))  			return 0;  		break;  	default: @@ -2713,7 +2743,7 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)  	if (new->rsize && new->rsize < old->rsize)  		return 0; -	if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid) +	if (!uid_eq(old->mnt_uid, new->mnt_uid) || !gid_eq(old->mnt_gid, new->mnt_gid))  		return 0;  	if (old->mnt_file_mode != new->mnt_file_mode || @@ -3919,7 +3949,7 @@ cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)  }  static struct cifs_tcon * -cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) +cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)  {  	int rc;  	struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); @@ -3989,7 +4019,7 @@ cifs_sb_tcon_pending_wait(void *unused)  /* find and return a tlink with given uid */  static struct tcon_link * -tlink_rb_search(struct rb_root *root, uid_t uid) +tlink_rb_search(struct rb_root *root, kuid_t uid)  {  	struct rb_node *node = root->rb_node;  	struct tcon_link *tlink; @@ -3997,9 +4027,9 @@ tlink_rb_search(struct rb_root *root, uid_t uid)  	while (node) {  		tlink = rb_entry(node, struct tcon_link, tl_rbnode); -		if (tlink->tl_uid > uid) +		if (uid_gt(tlink->tl_uid, uid))  			node = node->rb_left; -		else if (tlink->tl_uid < uid) +		else if (uid_lt(tlink->tl_uid, uid))  			node = node->rb_right;  		else  			return tlink; @@ -4018,7 +4048,7 @@ tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)  		tlink = rb_entry(*new, struct tcon_link, tl_rbnode);  		parent = *new; -		if (tlink->tl_uid > new_tlink->tl_uid) +		if (uid_gt(tlink->tl_uid, new_tlink->tl_uid))  			new = &((*new)->rb_left);  		else  			new = &((*new)->rb_right); @@ -4048,7 +4078,7 @@ struct tcon_link *  cifs_sb_tlink(struct cifs_sb_info *cifs_sb)  {  	int ret; -	uid_t fsuid = current_fsuid(); +	kuid_t fsuid = current_fsuid();  	struct tcon_link *tlink, *newtlink;  	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 8719bbe0dcc..1cd01621744 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -342,14 +342,14 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,  		*created |= FILE_CREATED;  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { -			args.uid = (__u64) current_fsuid(); +			args.uid = current_fsuid();  			if (inode->i_mode & S_ISGID) -				args.gid = (__u64) inode->i_gid; +				args.gid = inode->i_gid;  			else -				args.gid = (__u64) current_fsgid(); +				args.gid = current_fsgid();  		} else { -			args.uid = NO_CHANGE_64; -			args.gid = NO_CHANGE_64; +			args.uid = INVALID_UID; /* no change */ +			args.gid = INVALID_GID; /* no change */  		}  		CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid,  				       current->tgid); @@ -588,11 +588,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,  			.device	= device_number,  		};  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { -			args.uid = (__u64) current_fsuid(); -			args.gid = (__u64) current_fsgid(); +			args.uid = current_fsuid(); +			args.gid = current_fsgid();  		} else { -			args.uid = NO_CHANGE_64; -			args.gid = NO_CHANGE_64; +			args.uid = INVALID_UID; /* no change */ +			args.gid = INVALID_GID; /* no change */  		}  		rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,  					    cifs_sb->local_nls, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8ea6ca50a66..a8d8b589ee0 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -515,8 +515,8 @@ int cifs_open(struct inode *inode, struct file *file)  		 */  		struct cifs_unix_set_info_args args = {  			.mode	= inode->i_mode, -			.uid	= NO_CHANGE_64, -			.gid	= NO_CHANGE_64, +			.uid	= INVALID_UID, /* no change */ +			.gid	= INVALID_GID, /* no change */  			.ctime	= NO_CHANGE_64,  			.atime	= NO_CHANGE_64,  			.mtime	= NO_CHANGE_64, @@ -1693,7 +1693,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,  	   are always at the end of the list but since the first entry might  	   have a close pending, we go through the whole list */  	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { -		if (fsuid_only && open_file->uid != current_fsuid()) +		if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))  			continue;  		if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {  			if (!open_file->invalidHandle) { @@ -1746,7 +1746,7 @@ refind_writable:  	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {  		if (!any_available && open_file->pid != current->tgid)  			continue; -		if (fsuid_only && open_file->uid != current_fsuid()) +		if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))  			continue;  		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {  			if (!open_file->invalidHandle) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ed6208ff85a..9638233964f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -244,15 +244,25 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,  		break;  	} -	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) -		fattr->cf_uid = cifs_sb->mnt_uid; -	else -		fattr->cf_uid = le64_to_cpu(info->Uid); - -	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) -		fattr->cf_gid = cifs_sb->mnt_gid; -	else -		fattr->cf_gid = le64_to_cpu(info->Gid); +	fattr->cf_uid = cifs_sb->mnt_uid; +	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) { +		u64 id = le64_to_cpu(info->Uid); +		if (id < ((uid_t)-1)) { +			kuid_t uid = make_kuid(&init_user_ns, id); +			if (uid_valid(uid)) +				fattr->cf_uid = uid; +		} +	} +	 +	fattr->cf_gid = cifs_sb->mnt_gid; +	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { +		u64 id = le64_to_cpu(info->Gid); +		if (id < ((gid_t)-1)) { +			kgid_t gid = make_kgid(&init_user_ns, id); +			if (gid_valid(gid)) +				fattr->cf_gid = gid; +		} +	}  	fattr->cf_nlink = le64_to_cpu(info->Nlinks);  } @@ -1245,14 +1255,14 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,  			.device	= 0,  		};  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { -			args.uid = (__u64)current_fsuid(); +			args.uid = current_fsuid();  			if (parent->i_mode & S_ISGID) -				args.gid = (__u64)parent->i_gid; +				args.gid = parent->i_gid;  			else -				args.gid = (__u64)current_fsgid(); +				args.gid = current_fsgid();  		} else { -			args.uid = NO_CHANGE_64; -			args.gid = NO_CHANGE_64; +			args.uid = INVALID_UID; /* no change */ +			args.gid = INVALID_GID; /* no change */  		}  		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,  				       cifs_sb->local_nls, @@ -2013,12 +2023,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)  	if (attrs->ia_valid & ATTR_UID)  		args->uid = attrs->ia_uid;  	else -		args->uid = NO_CHANGE_64; +		args->uid = INVALID_UID; /* no change */  	if (attrs->ia_valid & ATTR_GID)  		args->gid = attrs->ia_gid;  	else -		args->gid = NO_CHANGE_64; +		args->gid = INVALID_GID; /* no change */  	if (attrs->ia_valid & ATTR_ATIME)  		args->atime = cifs_UnixTimeToNT(attrs->ia_atime); @@ -2086,8 +2096,8 @@ static int  cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)  {  	unsigned int xid; -	uid_t uid = NO_CHANGE_32; -	gid_t gid = NO_CHANGE_32; +	kuid_t uid = INVALID_UID; +	kgid_t gid = INVALID_GID;  	struct inode *inode = direntry->d_inode;  	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);  	struct cifsInodeInfo *cifsInode = CIFS_I(inode); @@ -2146,7 +2156,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)  #ifdef CONFIG_CIFS_ACL  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { -		if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) { +		if (uid_valid(uid) || gid_valid(gid)) {  			rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,  							uid, gid);  			if (rc) { @@ -2170,7 +2180,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)  #ifdef CONFIG_CIFS_ACL  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {  			rc = id_mode_to_cifs_acl(inode, full_path, mode, -						NO_CHANGE_32, NO_CHANGE_32); +						INVALID_UID, INVALID_GID);  			if (rc) {  				cFYI(1, "%s: Setting ACL failed with error: %d",  					__func__, rc); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 3a00c0d0cea..1b15bf839f3 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -569,7 +569,7 @@ bool  backup_cred(struct cifs_sb_info *cifs_sb)  {  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) { -		if (cifs_sb->mnt_backupuid == current_fsuid()) +		if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid()))  			return true;  	}  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) { diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 958ae0e0ff8..1da168c61d3 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -33,7 +33,7 @@ void coda_cache_enter(struct inode *inode, int mask)  	spin_lock(&cii->c_lock);  	cii->c_cached_epoch = atomic_read(&permission_epoch); -	if (cii->c_uid != current_fsuid()) { +	if (!uid_eq(cii->c_uid, current_fsuid())) {  		cii->c_uid = current_fsuid();                  cii->c_cached_perm = mask;          } else @@ -65,7 +65,7 @@ int coda_cache_check(struct inode *inode, int mask)  	spin_lock(&cii->c_lock);  	hit = (mask & cii->c_cached_perm) == mask && -	    cii->c_uid == current_fsuid() && +	    uid_eq(cii->c_uid, current_fsuid()) &&  	    cii->c_cached_epoch == atomic_read(&permission_epoch);  	spin_unlock(&cii->c_lock); diff --git a/fs/coda/coda_fs_i.h b/fs/coda/coda_fs_i.h index b24fdfd8a3f..c6407521321 100644 --- a/fs/coda/coda_fs_i.h +++ b/fs/coda/coda_fs_i.h @@ -25,7 +25,7 @@ struct coda_inode_info {  	u_short	           c_flags;     /* flags (see below) */  	unsigned int	   c_mapcount;  /* nr of times this inode is mapped */  	unsigned int	   c_cached_epoch; /* epoch for cached permissions */ -	vuid_t		   c_uid;	/* fsuid for cached permissions */ +	kuid_t		   c_uid;	/* fsuid for cached permissions */  	unsigned int       c_cached_perm; /* cached access permissions */  	spinlock_t	   c_lock;  	struct inode	   vfs_inode; diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index 854ace71268..2849f41e72a 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c @@ -100,9 +100,9 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)  	if (attr->va_mode != (u_short) -1)  	        inode->i_mode = attr->va_mode | inode_type;          if (attr->va_uid != -1)  -	        inode->i_uid = (uid_t) attr->va_uid; +	        inode->i_uid = make_kuid(&init_user_ns, (uid_t) attr->va_uid);          if (attr->va_gid != -1) -	        inode->i_gid = (gid_t) attr->va_gid; +	        inode->i_gid = make_kgid(&init_user_ns, (gid_t) attr->va_gid);  	if (attr->va_nlink != -1)  		set_nlink(inode, attr->va_nlink);  	if (attr->va_size != -1) @@ -171,10 +171,10 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)                  vattr->va_mode = iattr->ia_mode;  	}          if ( valid & ATTR_UID ) { -                vattr->va_uid = (vuid_t) iattr->ia_uid; +                vattr->va_uid = (vuid_t) from_kuid(&init_user_ns, iattr->ia_uid);  	}          if ( valid & ATTR_GID ) { -                vattr->va_gid = (vgid_t) iattr->ia_gid; +                vattr->va_gid = (vgid_t) from_kgid(&init_user_ns, iattr->ia_gid);  	}          if ( valid & ATTR_SIZE ) {                  vattr->va_size = iattr->ia_size; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index be2aa490948..cf674e9179a 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -20,6 +20,7 @@  #include <linux/file.h>  #include <linux/vfs.h>  #include <linux/slab.h> +#include <linux/pid_namespace.h>  #include <asm/uaccess.h> @@ -48,7 +49,7 @@ static struct inode *coda_alloc_inode(struct super_block *sb)  		return NULL;  	memset(&ei->c_fid, 0, sizeof(struct CodaFid));  	ei->c_flags = 0; -	ei->c_uid = 0; +	ei->c_uid = GLOBAL_ROOT_UID;  	ei->c_cached_perm = 0;  	spin_lock_init(&ei->c_lock);  	return &ei->vfs_inode; @@ -157,6 +158,9 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)  	int error;  	int idx; +	if (task_active_pid_ns(current) != &init_pid_ns) +		return -EINVAL; +  	idx = get_device_index((struct coda_mount_data *) data);  	/* Ignore errors in data, for backward compatibility */ diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 761d5b31b18..ebc2bae6c28 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -37,6 +37,7 @@  #include <linux/list.h>  #include <linux/mutex.h>  #include <linux/device.h> +#include <linux/pid_namespace.h>  #include <asm/io.h>  #include <asm/poll.h>  #include <asm/uaccess.h> @@ -266,6 +267,12 @@ static int coda_psdev_open(struct inode * inode, struct file * file)  	struct venus_comm *vcp;  	int idx, err; +	if (task_active_pid_ns(current) != &init_pid_ns) +		return -EINVAL; + +	if (current_user_ns() != &init_user_ns) +		return -EINVAL; +  	idx = iminor(inode);  	if (idx < 0 || idx >= MAX_CODADEVS)  		return -ENODEV; diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 0c68fd31fbf..3a731976dc5 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -50,9 +50,9 @@ static void *alloc_upcall(int opcode, int size)  		return ERR_PTR(-ENOMEM);          inp->ih.opcode = opcode; -	inp->ih.pid = current->pid; -	inp->ih.pgid = task_pgrp_nr(current); -	inp->ih.uid = current_fsuid(); +	inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns); +	inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns); +	inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());  	return (void*)inp;  } @@ -157,7 +157,7 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid,  }  int venus_close(struct super_block *sb, struct CodaFid *fid, int flags, -		vuid_t uid) +		kuid_t uid)  {  	union inputArgs *inp;  	union outputArgs *outp; @@ -166,7 +166,7 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,  	insize = SIZE(release);  	UPARG(CODA_CLOSE); -	inp->ih.uid = uid; +	inp->ih.uid = from_kuid(&init_user_ns, uid);          inp->coda_close.VFid = *fid;          inp->coda_close.flags = flags; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 472e6befc54..073d30b9d1a 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -243,6 +243,13 @@ static int mknod_ptmx(struct super_block *sb)  	struct dentry *root = sb->s_root;  	struct pts_fs_info *fsi = DEVPTS_SB(sb);  	struct pts_mount_opts *opts = &fsi->mount_opts; +	kuid_t root_uid; +	kgid_t root_gid; + +	root_uid = make_kuid(current_user_ns(), 0); +	root_gid = make_kgid(current_user_ns(), 0); +	if (!uid_valid(root_uid) || !gid_valid(root_gid)) +		return -EINVAL;  	mutex_lock(&root->d_inode->i_mutex); @@ -273,6 +280,8 @@ static int mknod_ptmx(struct super_block *sb)  	mode = S_IFCHR|opts->ptmxmode;  	init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2)); +	inode->i_uid = root_uid; +	inode->i_gid = root_gid;  	d_add(dentry, inode); @@ -438,6 +447,12 @@ static struct dentry *devpts_mount(struct file_system_type *fs_type,  	if (error)  		return ERR_PTR(error); +	/* Require newinstance for all user namespace mounts to ensure +	 * the mount options are not changed. +	 */ +	if ((current_user_ns() != &init_user_ns) && !opts.newinstance) +		return ERR_PTR(-EINVAL); +  	if (opts.newinstance)  		s = sget(fs_type, NULL, set_anon_super, flags, NULL);  	else @@ -491,6 +506,9 @@ static struct file_system_type devpts_fs_type = {  	.name		= "devpts",  	.mount		= devpts_mount,  	.kill_sb	= devpts_kill_sb, +#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES +	.fs_flags	= FS_USERNS_MOUNT | FS_USERNS_DEV_MOUNT, +#endif  };  /* diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index f850020ad90..f69ac0af549 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -237,7 +237,7 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,  		return -EINVAL;  	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))  		return value ? -EACCES : 0; -	if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER)) +	if (!uid_eq(current_fsuid(), inode->i_uid) && !capable(CAP_FOWNER))  		return -EPERM;  	if (S_ISLNK(inode->i_mode))  		return -EOPNOTSUPP; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index df686d13a7d..5e83657f046 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1099,7 +1099,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)  	if (error)  		return error; -	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	error = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (error)  		return error; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 7179478e5a2..c3e82bd2317 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1849,7 +1849,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,  	if (!ht)  		return -ENOMEM; -	error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	error = gfs2_quota_hold(dip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (error)  		goto out; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 78d4184ffc7..444b6503ebc 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -322,8 +322,8 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)  		break;  	}; -	ip->i_inode.i_uid = be32_to_cpu(str->di_uid); -	ip->i_inode.i_gid = be32_to_cpu(str->di_gid); +	i_uid_write(&ip->i_inode, be32_to_cpu(str->di_uid)); +	i_gid_write(&ip->i_inode, be32_to_cpu(str->di_gid));  	gfs2_set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink));  	i_size_write(&ip->i_inode, be64_to_cpu(str->di_size));  	gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e2601ba38ef..156e42ec84e 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -392,7 +392,6 @@ struct gfs2_revoke_replay {  };  enum { -	QDF_USER		= 0,  	QDF_CHANGE		= 1,  	QDF_LOCKED		= 2,  	QDF_REFRESH		= 3, @@ -404,7 +403,7 @@ struct gfs2_quota_data {  	atomic_t qd_count; -	u32 qd_id; +	struct kqid qd_id;  	unsigned long qd_flags;		/* QDF_... */  	s64 qd_change; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index db048a8ab6a..cc00bd1d1f8 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -368,10 +368,11 @@ static void munge_mode_uid_gid(const struct gfs2_inode *dip,  			       struct inode *inode)  {  	if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && -	    (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { +	    (dip->i_inode.i_mode & S_ISUID) && +	    !uid_eq(dip->i_inode.i_uid, GLOBAL_ROOT_UID)) {  		if (S_ISDIR(inode->i_mode))  			inode->i_mode |= S_ISUID; -		else if (dip->i_inode.i_uid != current_fsuid()) +		else if (!uid_eq(dip->i_inode.i_uid, current_fsuid()))  			inode->i_mode &= ~07111;  		inode->i_uid = dip->i_inode.i_uid;  	} else @@ -455,8 +456,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,  	di->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino);  	di->di_num.no_addr = cpu_to_be64(ip->i_no_addr);  	di->di_mode = cpu_to_be32(ip->i_inode.i_mode); -	di->di_uid = cpu_to_be32(ip->i_inode.i_uid); -	di->di_gid = cpu_to_be32(ip->i_inode.i_gid); +	di->di_uid = cpu_to_be32(i_uid_read(&ip->i_inode)); +	di->di_gid = cpu_to_be32(i_gid_read(&ip->i_inode));  	di->di_nlink = 0;  	di->di_size = cpu_to_be64(ip->i_inode.i_size);  	di->di_blocks = cpu_to_be64(1); @@ -548,7 +549,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,  	if (error)  		return error; -	error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	error = gfs2_quota_lock(dip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (error)  		goto fail; @@ -978,8 +979,8 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,  		return -EPERM;  	if ((dip->i_inode.i_mode & S_ISVTX) && -	    dip->i_inode.i_uid != current_fsuid() && -	    ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER)) +	    !uid_eq(dip->i_inode.i_uid, current_fsuid()) && +	    !uid_eq(ip->i_inode.i_uid, current_fsuid()) && !capable(CAP_FOWNER))  		return -EPERM;  	if (IS_APPEND(&dip->i_inode)) @@ -1580,7 +1581,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)  {  	struct gfs2_inode *ip = GFS2_I(inode);  	struct gfs2_sbd *sdp = GFS2_SB(inode); -	u32 ouid, ogid, nuid, ngid; +	kuid_t ouid, nuid; +	kgid_t ogid, ngid;  	int error;  	ouid = inode->i_uid; @@ -1588,16 +1590,17 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)  	nuid = attr->ia_uid;  	ngid = attr->ia_gid; -	if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) -		ouid = nuid = NO_QUOTA_CHANGE; -	if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) -		ogid = ngid = NO_QUOTA_CHANGE; +	if (!(attr->ia_valid & ATTR_UID) || uid_eq(ouid, nuid)) +		ouid = nuid = NO_UID_QUOTA_CHANGE; +	if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid)) +		ogid = ngid = NO_GID_QUOTA_CHANGE;  	error = gfs2_quota_lock(ip, nuid, ngid);  	if (error)  		return error; -	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { +	if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || +	    !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {  		error = gfs2_quota_check(ip, nuid, ngid);  		if (error)  			goto out_gunlock_q; @@ -1611,7 +1614,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)  	if (error)  		goto out_end_trans; -	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { +	if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || +	    !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {  		u64 blocks = gfs2_get_inode_blocks(&ip->i_inode);  		gfs2_quota_change(ip, -blocks, ouid, ogid);  		gfs2_quota_change(ip, blocks, nuid, ngid); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 06122d09c0d..c7c840e916f 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -65,13 +65,10 @@  #include "inode.h"  #include "util.h" -#define QUOTA_USER 1 -#define QUOTA_GROUP 0 -  struct gfs2_quota_change_host {  	u64 qc_change;  	u32 qc_flags; /* GFS2_QCF_... */ -	u32 qc_id; +	struct kqid qc_id;  };  static LIST_HEAD(qd_lru_list); @@ -120,17 +117,24 @@ out:  	return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100;  } +static u64 qd2index(struct gfs2_quota_data *qd) +{ +	struct kqid qid = qd->qd_id; +	return (2 * (u64)from_kqid(&init_user_ns, qid)) + +		(qid.type == USRQUOTA) ? 0 : 1; +} +  static u64 qd2offset(struct gfs2_quota_data *qd)  {  	u64 offset; -	offset = 2 * (u64)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags); +	offset = qd2index(qd);  	offset *= sizeof(struct gfs2_quota);  	return offset;  } -static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, +static int qd_alloc(struct gfs2_sbd *sdp, struct kqid qid,  		    struct gfs2_quota_data **qdp)  {  	struct gfs2_quota_data *qd; @@ -141,13 +145,11 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id,  		return -ENOMEM;  	atomic_set(&qd->qd_count, 1); -	qd->qd_id = id; -	if (user) -		set_bit(QDF_USER, &qd->qd_flags); +	qd->qd_id = qid;  	qd->qd_slot = -1;  	INIT_LIST_HEAD(&qd->qd_reclaim); -	error = gfs2_glock_get(sdp, 2 * (u64)id + !user, +	error = gfs2_glock_get(sdp, qd2index(qd),  			      &gfs2_quota_glops, CREATE, &qd->qd_gl);  	if (error)  		goto fail; @@ -161,7 +163,7 @@ fail:  	return error;  } -static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, +static int qd_get(struct gfs2_sbd *sdp, struct kqid qid,  		  struct gfs2_quota_data **qdp)  {  	struct gfs2_quota_data *qd = NULL, *new_qd = NULL; @@ -173,8 +175,7 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id,  		found = 0;  		spin_lock(&qd_lru_lock);  		list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { -			if (qd->qd_id == id && -			    !test_bit(QDF_USER, &qd->qd_flags) == !user) { +			if (qid_eq(qd->qd_id, qid)) {  				if (!atomic_read(&qd->qd_count) &&  				    !list_empty(&qd->qd_reclaim)) {  					/* Remove it from reclaim list */ @@ -208,7 +209,7 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id,  			return 0;  		} -		error = qd_alloc(sdp, user, id, &new_qd); +		error = qd_alloc(sdp, qid, &new_qd);  		if (error)  			return error;  	} @@ -458,12 +459,12 @@ static void qd_unlock(struct gfs2_quota_data *qd)  	qd_put(qd);  } -static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, +static int qdsb_get(struct gfs2_sbd *sdp, struct kqid qid,  		    struct gfs2_quota_data **qdp)  {  	int error; -	error = qd_get(sdp, user, id, qdp); +	error = qd_get(sdp, qid, qdp);  	if (error)  		return error; @@ -491,7 +492,7 @@ static void qdsb_put(struct gfs2_quota_data *qd)  	qd_put(qd);  } -int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) +int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)  {  	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);  	struct gfs2_quota_data **qd; @@ -512,28 +513,30 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)  		return 0; -	error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, qd); +	error = qdsb_get(sdp, make_kqid_uid(ip->i_inode.i_uid), qd);  	if (error)  		goto out;  	ip->i_res->rs_qa_qd_num++;  	qd++; -	error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, qd); +	error = qdsb_get(sdp, make_kqid_gid(ip->i_inode.i_gid), qd);  	if (error)  		goto out;  	ip->i_res->rs_qa_qd_num++;  	qd++; -	if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) { -		error = qdsb_get(sdp, QUOTA_USER, uid, qd); +	if (!uid_eq(uid, NO_UID_QUOTA_CHANGE) && +	    !uid_eq(uid, ip->i_inode.i_uid)) { +		error = qdsb_get(sdp, make_kqid_uid(uid), qd);  		if (error)  			goto out;  		ip->i_res->rs_qa_qd_num++;  		qd++;  	} -	if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) { -		error = qdsb_get(sdp, QUOTA_GROUP, gid, qd); +	if (!gid_eq(gid, NO_GID_QUOTA_CHANGE) && +	    !gid_eq(gid, ip->i_inode.i_gid)) { +		error = qdsb_get(sdp, make_kqid_gid(gid), qd);  		if (error)  			goto out;  		ip->i_res->rs_qa_qd_num++; @@ -567,18 +570,10 @@ static int sort_qd(const void *a, const void *b)  	const struct gfs2_quota_data *qd_a = *(const struct gfs2_quota_data **)a;  	const struct gfs2_quota_data *qd_b = *(const struct gfs2_quota_data **)b; -	if (!test_bit(QDF_USER, &qd_a->qd_flags) != -	    !test_bit(QDF_USER, &qd_b->qd_flags)) { -		if (test_bit(QDF_USER, &qd_a->qd_flags)) -			return -1; -		else -			return 1; -	} -	if (qd_a->qd_id < qd_b->qd_id) +	if (qid_lt(qd_a->qd_id, qd_b->qd_id))  		return -1; -	if (qd_a->qd_id > qd_b->qd_id) +	if (qid_lt(qd_b->qd_id, qd_a->qd_id))  		return 1; -  	return 0;  } @@ -595,9 +590,9 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)  	if (!test_bit(QDF_CHANGE, &qd->qd_flags)) {  		qc->qc_change = 0;  		qc->qc_flags = 0; -		if (test_bit(QDF_USER, &qd->qd_flags)) +		if (qd->qd_id.type == USRQUOTA)  			qc->qc_flags = cpu_to_be32(GFS2_QCF_USER); -		qc->qc_id = cpu_to_be32(qd->qd_id); +		qc->qc_id = cpu_to_be32(from_kqid(&init_user_ns, qd->qd_id));  	}  	x = be64_to_cpu(qc->qc_change) + change; @@ -925,7 +920,7 @@ fail:  	return error;  } -int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) +int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)  {  	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);  	struct gfs2_quota_data *qd; @@ -1040,13 +1035,13 @@ static int print_message(struct gfs2_quota_data *qd, char *type)  	printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\n",  	       sdp->sd_fsname, type, -	       (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", -	       qd->qd_id); +	       (qd->qd_id.type == USRQUOTA) ? "user" : "group", +	       from_kqid(&init_user_ns, qd->qd_id));  	return 0;  } -int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) +int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)  {  	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);  	struct gfs2_quota_data *qd; @@ -1063,8 +1058,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)  	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {  		qd = ip->i_res->rs_qa_qd[x]; -		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || -		      (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags)))) +		if (!(qid_eq(qd->qd_id, make_kqid_uid(uid)) || +		      qid_eq(qd->qd_id, make_kqid_gid(gid))))  			continue;  		value = (s64)be64_to_cpu(qd->qd_qb.qb_value); @@ -1074,10 +1069,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)  		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {  			print_message(qd, "exceeded"); -			quota_send_warning(make_kqid(&init_user_ns, -						     test_bit(QDF_USER, &qd->qd_flags) ? -						     USRQUOTA : GRPQUOTA, -						     qd->qd_id), +			quota_send_warning(qd->qd_id,  					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);  			error = -EDQUOT; @@ -1087,10 +1079,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)  			   time_after_eq(jiffies, qd->qd_last_warn +  					 gfs2_tune_get(sdp,  						gt_quota_warn_period) * HZ)) { -			quota_send_warning(make_kqid(&init_user_ns, -						     test_bit(QDF_USER, &qd->qd_flags) ? -						     USRQUOTA : GRPQUOTA, -						     qd->qd_id), +			quota_send_warning(qd->qd_id,  					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);  			error = print_message(qd, "warning");  			qd->qd_last_warn = jiffies; @@ -1101,7 +1090,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)  }  void gfs2_quota_change(struct gfs2_inode *ip, s64 change, -		       u32 uid, u32 gid) +		       kuid_t uid, kgid_t gid)  {  	struct gfs2_quota_data *qd;  	unsigned int x; @@ -1114,8 +1103,8 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,  	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {  		qd = ip->i_res->rs_qa_qd[x]; -		if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || -		    (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) { +		if (qid_eq(qd->qd_id, make_kqid_uid(uid)) || +		    qid_eq(qd->qd_id, make_kqid_gid(gid))) {  			do_qc(qd, change);  		}  	} @@ -1170,13 +1159,13 @@ static int gfs2_quota_sync_timeo(struct super_block *sb, int type)  	return gfs2_quota_sync(sb, type);  } -int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) +int gfs2_quota_refresh(struct gfs2_sbd *sdp, struct kqid qid)  {  	struct gfs2_quota_data *qd;  	struct gfs2_holder q_gh;  	int error; -	error = qd_get(sdp, user, id, &qd); +	error = qd_get(sdp, qid, &qd);  	if (error)  		return error; @@ -1194,7 +1183,9 @@ static void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void *  	qc->qc_change = be64_to_cpu(str->qc_change);  	qc->qc_flags = be32_to_cpu(str->qc_flags); -	qc->qc_id = be32_to_cpu(str->qc_id); +	qc->qc_id = make_kqid(&init_user_ns, +			      (qc->qc_flags & GFS2_QCF_USER)?USRQUOTA:GRPQUOTA, +			      be32_to_cpu(str->qc_id));  }  int gfs2_quota_init(struct gfs2_sbd *sdp) @@ -1257,8 +1248,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)  			if (!qc.qc_change)  				continue; -			error = qd_alloc(sdp, (qc.qc_flags & GFS2_QCF_USER), -					 qc.qc_id, &qd); +			error = qd_alloc(sdp, qc.qc_id, &qd);  			if (error) {  				brelse(bh);  				goto fail; @@ -1485,21 +1475,17 @@ static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,  	struct gfs2_quota_data *qd;  	struct gfs2_holder q_gh;  	int error; -	int type;  	memset(fdq, 0, sizeof(struct fs_disk_quota));  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)  		return -ESRCH; /* Crazy XFS error code */ -	if (qid.type == USRQUOTA) -		type = QUOTA_USER; -	else if (qid.type == GRPQUOTA) -		type = QUOTA_GROUP; -	else +	if ((qid.type != USRQUOTA) && +	    (qid.type != GRPQUOTA))  		return -EINVAL; -	error = qd_get(sdp, type, from_kqid(&init_user_ns, qid), &qd); +	error = qd_get(sdp, qid, &qd);  	if (error)  		return error;  	error = do_glock(qd, FORCE, &q_gh); @@ -1508,8 +1494,8 @@ static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,  	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;  	fdq->d_version = FS_DQUOT_VERSION; -	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA; -	fdq->d_id = from_kqid(&init_user_ns, qid); +	fdq->d_flags = (qid.type == USRQUOTA) ? FS_USER_QUOTA : FS_GROUP_QUOTA; +	fdq->d_id = from_kqid_munged(current_user_ns(), qid);  	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;  	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;  	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift; @@ -1535,32 +1521,18 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,  	int alloc_required;  	loff_t offset;  	int error; -	int type;  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)  		return -ESRCH; /* Crazy XFS error code */ -	switch(qid.type) { -	case USRQUOTA: -		type = QUOTA_USER; -		if (fdq->d_flags != FS_USER_QUOTA) -			return -EINVAL; -		break; -	case GRPQUOTA: -		type = QUOTA_GROUP; -		if (fdq->d_flags != FS_GROUP_QUOTA) -			return -EINVAL; -		break; -	default: +	if ((qid.type != USRQUOTA) && +	    (qid.type != GRPQUOTA))  		return -EINVAL; -	}  	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)  		return -EINVAL; -	if (fdq->d_id != from_kqid(&init_user_ns, qid)) -		return -EINVAL; -	error = qd_get(sdp, type, from_kqid(&init_user_ns, qid), &qd); +	error = qd_get(sdp, qid, &qd);  	if (error)  		return error; diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index f25d98b8790..4f5e6e44ed8 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -14,20 +14,21 @@ struct gfs2_inode;  struct gfs2_sbd;  struct shrink_control; -#define NO_QUOTA_CHANGE ((u32)-1) +#define NO_UID_QUOTA_CHANGE INVALID_UID +#define NO_GID_QUOTA_CHANGE INVALID_GID -extern int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid); +extern int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);  extern void gfs2_quota_unhold(struct gfs2_inode *ip); -extern int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid); +extern int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);  extern void gfs2_quota_unlock(struct gfs2_inode *ip); -extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid); +extern int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);  extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, -			      u32 uid, u32 gid); +			      kuid_t uid, kgid_t gid);  extern int gfs2_quota_sync(struct super_block *sb, int type); -extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id); +extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, struct kqid qid);  extern int gfs2_quota_init(struct gfs2_sbd *sdp);  extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp); @@ -41,7 +42,7 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)  	int ret;  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)  		return 0; -	ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (ret)  		return ret;  	if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index a3b40eeaa6e..cab77b8ba84 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -673,8 +673,8 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf)  	str->di_num.no_addr = cpu_to_be64(ip->i_no_addr);  	str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino);  	str->di_mode = cpu_to_be32(ip->i_inode.i_mode); -	str->di_uid = cpu_to_be32(ip->i_inode.i_uid); -	str->di_gid = cpu_to_be32(ip->i_inode.i_gid); +	str->di_uid = cpu_to_be32(i_uid_read(&ip->i_inode)); +	str->di_gid = cpu_to_be32(i_gid_read(&ip->i_inode));  	str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink);  	str->di_size = cpu_to_be64(i_size_read(&ip->i_inode));  	str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); @@ -1376,7 +1376,7 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)  	if (error)  		return error; -	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	error = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (error)  		return error; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 4fb9ad80d26..597a612834d 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -173,6 +173,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,  static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,  					size_t len)  { +	struct kqid qid;  	int error;  	u32 id; @@ -181,13 +182,18 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,  	id = simple_strtoul(buf, NULL, 0); -	error = gfs2_quota_refresh(sdp, 1, id); +	qid = make_kqid(current_user_ns(), USRQUOTA, id); +	if (!qid_valid(qid)) +		return -EINVAL; + +	error = gfs2_quota_refresh(sdp, qid);  	return error ? error : len;  }  static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,  					 size_t len)  { +	struct kqid qid;  	int error;  	u32 id; @@ -196,7 +202,11 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,  	id = simple_strtoul(buf, NULL, 0); -	error = gfs2_quota_refresh(sdp, 0, id); +	qid = make_kqid(current_user_ns(), GRPQUOTA, id); +	if (!qid_valid(qid)) +		return -EINVAL; + +	error = gfs2_quota_refresh(sdp, qid);  	return error ? error : len;  } diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index cbb46c2baa6..ecd37f30ab9 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -331,7 +331,7 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,  	if (error)  		return error; -	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	error = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (error)  		goto out_alloc; @@ -1461,7 +1461,7 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)  	if (error)  		return error; -	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); +	error = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);  	if (error)  		return error; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 1acdad7fcec..e2be336d1c2 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -331,12 +331,15 @@ static int  ncp_show_options(struct seq_file *seq, struct dentry *root)  	struct ncp_server *server = NCP_SBP(root->d_sb);  	unsigned int tmp; -	if (server->m.uid != 0) -		seq_printf(seq, ",uid=%u", server->m.uid); -	if (server->m.gid != 0) -		seq_printf(seq, ",gid=%u", server->m.gid); -	if (server->m.mounted_uid != 0) -		seq_printf(seq, ",owner=%u", server->m.mounted_uid); +	if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID)) +		seq_printf(seq, ",uid=%u", +			   from_kuid_munged(&init_user_ns, server->m.uid)); +	if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID)) +		seq_printf(seq, ",gid=%u", +			   from_kgid_munged(&init_user_ns, server->m.gid)); +	if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID)) +		seq_printf(seq, ",owner=%u", +			   from_kuid_munged(&init_user_ns, server->m.mounted_uid));  	tmp = server->m.file_mode & S_IALLUGO;  	if (tmp != NCP_DEFAULT_FILE_MODE)  		seq_printf(seq, ",mode=0%o", tmp); @@ -381,13 +384,13 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)  	data->flags = 0;  	data->int_flags = 0; -	data->mounted_uid = 0; +	data->mounted_uid = GLOBAL_ROOT_UID;  	data->wdog_pid = NULL;  	data->ncp_fd = ~0;  	data->time_out = NCP_DEFAULT_TIME_OUT;  	data->retry_count = NCP_DEFAULT_RETRY_COUNT; -	data->uid = 0; -	data->gid = 0; +	data->uid = GLOBAL_ROOT_UID; +	data->gid = GLOBAL_ROOT_GID;  	data->file_mode = NCP_DEFAULT_FILE_MODE;  	data->dir_mode = NCP_DEFAULT_DIR_MODE;  	data->info_fd = -1; @@ -399,13 +402,19 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)  			goto err;  		switch (optval) {  			case 'u': -				data->uid = optint; +				data->uid = make_kuid(current_user_ns(), optint); +				if (!uid_valid(data->uid)) +					goto err;  				break;  			case 'g': -				data->gid = optint; +				data->gid = make_kgid(current_user_ns(), optint); +				if (!gid_valid(data->gid)) +					goto err;  				break;  			case 'o': -				data->mounted_uid = optint; +				data->mounted_uid = make_kuid(current_user_ns(), optint); +				if (!uid_valid(data->mounted_uid)) +					goto err;  				break;  			case 'm':  				data->file_mode = optint; @@ -480,13 +489,13 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  				data.flags = md->flags;  				data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE; -				data.mounted_uid = md->mounted_uid; +				data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);  				data.wdog_pid = find_get_pid(md->wdog_pid);  				data.ncp_fd = md->ncp_fd;  				data.time_out = md->time_out;  				data.retry_count = md->retry_count; -				data.uid = md->uid; -				data.gid = md->gid; +				data.uid = make_kuid(current_user_ns(), md->uid); +				data.gid = make_kgid(current_user_ns(), md->gid);  				data.file_mode = md->file_mode;  				data.dir_mode = md->dir_mode;  				data.info_fd = -1; @@ -499,13 +508,13 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  				struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;  				data.flags = md->flags; -				data.mounted_uid = md->mounted_uid; +				data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);  				data.wdog_pid = find_get_pid(md->wdog_pid);  				data.ncp_fd = md->ncp_fd;  				data.time_out = md->time_out;  				data.retry_count = md->retry_count; -				data.uid = md->uid; -				data.gid = md->gid; +				data.uid = make_kuid(current_user_ns(), md->uid); +				data.gid = make_kgid(current_user_ns(), md->gid);  				data.file_mode = md->file_mode;  				data.dir_mode = md->dir_mode;  				data.info_fd = -1; @@ -520,6 +529,10 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  				goto out;  			break;  	} +	error = -EINVAL; +	if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) || +	    !gid_valid(data.gid)) +		goto out;  	error = -EBADF;  	ncp_filp = fget(data.ncp_fd);  	if (!ncp_filp) @@ -886,12 +899,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  		goto out;  	result = -EPERM; -	if (((attr->ia_valid & ATTR_UID) && -	     (attr->ia_uid != server->m.uid))) +	if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))  		goto out; -	if (((attr->ia_valid & ATTR_GID) && -	     (attr->ia_gid != server->m.gid))) +	if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))  		goto out;  	if (((attr->ia_valid & ATTR_MODE) && diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 6958adfaff0..d44318d2750 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -45,7 +45,7 @@ ncp_get_fs_info(struct ncp_server * server, struct inode *inode,  		return -EINVAL;  	}  	/* TODO: info.addr = server->m.serv_addr; */ -	SET_UID(info.mounted_uid, server->m.mounted_uid); +	SET_UID(info.mounted_uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));  	info.connection		= server->connection;  	info.buffer_size	= server->buffer_size;  	info.volume_number	= NCP_FINFO(inode)->volNumber; @@ -69,7 +69,7 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode,  		DPRINTK("info.version invalid: %d\n", info2.version);  		return -EINVAL;  	} -	info2.mounted_uid   = server->m.mounted_uid; +	info2.mounted_uid   = from_kuid_munged(current_user_ns(), server->m.mounted_uid);  	info2.connection    = server->connection;  	info2.buffer_size   = server->buffer_size;  	info2.volume_number = NCP_FINFO(inode)->volNumber; @@ -135,7 +135,7 @@ ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode,  		DPRINTK("info.version invalid: %d\n", info2.version);  		return -EINVAL;  	} -	info2.mounted_uid   = server->m.mounted_uid; +	info2.mounted_uid   = from_kuid_munged(current_user_ns(), server->m.mounted_uid);  	info2.connection    = server->connection;  	info2.buffer_size   = server->buffer_size;  	info2.volume_number = NCP_FINFO(inode)->volNumber; @@ -348,22 +348,25 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg  		{  			u16 uid; -			SET_UID(uid, server->m.mounted_uid); +			SET_UID(uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));  			if (put_user(uid, (u16 __user *)argp))  				return -EFAULT;  			return 0;  		}  	case NCP_IOC_GETMOUNTUID32: -		if (put_user(server->m.mounted_uid, -			     (u32 __user *)argp)) +	{ +		uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid); +		if (put_user(uid, (u32 __user *)argp))  			return -EFAULT;  		return 0; +	}  	case NCP_IOC_GETMOUNTUID64: -		if (put_user(server->m.mounted_uid, -			     (u64 __user *)argp)) +	{ +		uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid); +		if (put_user(uid, (u64 __user *)argp))  			return -EFAULT;  		return 0; - +	}  	case NCP_IOC_GETROOT:  		{  			struct ncp_setroot_ioctl sr; @@ -810,7 +813,7 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  {  	struct inode *inode = filp->f_dentry->d_inode;  	struct ncp_server *server = NCP_SERVER(inode); -	uid_t uid = current_uid(); +	kuid_t uid = current_uid();  	int need_drop_write = 0;  	long ret; @@ -824,7 +827,7 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		}  		break;  	} -	if (server->m.mounted_uid != uid) { +	if (!uid_eq(server->m.mounted_uid, uid)) {  		switch (cmd) {  		/*  		 * Only mount owner can issue these ioctls.  Information diff --git a/fs/ncpfs/ncp_fs_sb.h b/fs/ncpfs/ncp_fs_sb.h index 54cc0cdb3dc..c51b2c54353 100644 --- a/fs/ncpfs/ncp_fs_sb.h +++ b/fs/ncpfs/ncp_fs_sb.h @@ -23,15 +23,15 @@ struct ncp_mount_data_kernel {  	unsigned long    flags;		/* NCP_MOUNT_* flags */  	unsigned int	 int_flags;	/* internal flags */  #define NCP_IMOUNT_LOGGEDIN_POSSIBLE	0x0001 -	uid_t		 mounted_uid;	/* Who may umount() this filesystem? */ +	kuid_t		 mounted_uid;	/* Who may umount() this filesystem? */  	struct pid      *wdog_pid;	/* Who cares for our watchdog packets? */  	unsigned int     ncp_fd;	/* The socket to the ncp port */  	unsigned int     time_out;	/* How long should I wait after  					   sending a NCP request? */  	unsigned int     retry_count;	/* And how often should I retry? */  	unsigned char	 mounted_vol[NCP_VOLNAME_LEN + 1]; -	uid_t		 uid; -	gid_t		 gid; +	kuid_t		 uid; +	kgid_t		 gid;  	umode_t		 file_mode;  	umode_t		 dir_mode;  	int		 info_fd; diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index bc3968fa81e..b9623d19d59 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -97,7 +97,7 @@ static void nfs_fattr_free_group_name(struct nfs_fattr *fattr)  static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr)  {  	struct nfs4_string *owner = fattr->owner_name; -	__u32 uid; +	kuid_t uid;  	if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))  		return false; @@ -111,7 +111,7 @@ static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr  static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr)  {  	struct nfs4_string *group = fattr->group_name; -	__u32 gid; +	kgid_t gid;  	if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))  		return false; @@ -193,7 +193,8 @@ static int nfs_idmap_init_keyring(void)  	if (!cred)  		return -ENOMEM; -	keyring = keyring_alloc(".id_resolver", 0, 0, cred, +	keyring = keyring_alloc(".id_resolver", +				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |  				KEY_USR_VIEW | KEY_USR_READ,  				KEY_ALLOC_NOT_IN_QUOTA, NULL); @@ -836,43 +837,61 @@ idmap_release_pipe(struct inode *inode)  	nfs_idmap_abort_pipe_upcall(idmap, -EPIPE);  } -int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) +int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, kuid_t *uid)  {  	struct idmap *idmap = server->nfs_client->cl_idmap; +	__u32 id = -1; +	int ret = 0; -	if (nfs_map_string_to_numeric(name, namelen, uid)) -		return 0; -	return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap); +	if (!nfs_map_string_to_numeric(name, namelen, &id)) +		ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap); +	if (ret == 0) { +		*uid = make_kuid(&init_user_ns, id); +		if (!uid_valid(*uid)) +			ret = -ERANGE; +	} +	return ret;  } -int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) +int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, kgid_t *gid)  {  	struct idmap *idmap = server->nfs_client->cl_idmap; +	__u32 id = -1; +	int ret = 0; -	if (nfs_map_string_to_numeric(name, namelen, gid)) -		return 0; -	return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap); +	if (!nfs_map_string_to_numeric(name, namelen, &id)) +		ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap); +	if (ret == 0) { +		*gid = make_kgid(&init_user_ns, id); +		if (!gid_valid(*gid)) +			ret = -ERANGE; +	} +	return ret;  } -int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) +int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf, size_t buflen)  {  	struct idmap *idmap = server->nfs_client->cl_idmap;  	int ret = -EINVAL; +	__u32 id; +	id = from_kuid(&init_user_ns, uid);  	if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) -		ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap); +		ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);  	if (ret < 0) -		ret = nfs_map_numeric_to_string(uid, buf, buflen); +		ret = nfs_map_numeric_to_string(id, buf, buflen);  	return ret;  } -int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen) +int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen)  {  	struct idmap *idmap = server->nfs_client->cl_idmap;  	int ret = -EINVAL; +	__u32 id; +	id = from_kgid(&init_user_ns, gid);  	if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) -		ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap); +		ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);  	if (ret < 0) -		ret = nfs_map_numeric_to_string(gid, buf, buflen); +		ret = nfs_map_numeric_to_string(id, buf, buflen);  	return ret;  } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6acc73c80d7..468ba8bf0f5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -332,8 +332,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)  		inode->i_version = 0;  		inode->i_size = 0;  		clear_nlink(inode); -		inode->i_uid = -2; -		inode->i_gid = -2; +		inode->i_uid = make_kuid(&init_user_ns, -2); +		inode->i_gid = make_kgid(&init_user_ns, -2);  		inode->i_blocks = 0;  		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));  		nfsi->write_io = 0; @@ -1006,9 +1006,9 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat  	/* Have any file permissions changed? */  	if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))  		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; -	if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid) +	if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && !uid_eq(inode->i_uid, fattr->uid))  		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; -	if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid) +	if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && !gid_eq(inode->i_gid, fattr->gid))  		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;  	/* Has the link count changed? */ @@ -1437,7 +1437,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)  				| NFS_INO_REVAL_FORCED);  	if (fattr->valid & NFS_ATTR_FATTR_OWNER) { -		if (inode->i_uid != fattr->uid) { +		if (!uid_eq(inode->i_uid, fattr->uid)) {  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;  			inode->i_uid = fattr->uid;  		} @@ -1448,7 +1448,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)  				| NFS_INO_REVAL_FORCED);  	if (fattr->valid & NFS_ATTR_FATTR_GROUP) { -		if (inode->i_gid != fattr->gid) { +		if (!gid_eq(inode->i_gid, fattr->gid)) {  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;  			inode->i_gid = fattr->gid;  		} diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 06b9df49f7f..62db136339e 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -290,8 +290,13 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)  	fattr->mode = be32_to_cpup(p++);  	fattr->nlink = be32_to_cpup(p++); -	fattr->uid = be32_to_cpup(p++); -	fattr->gid = be32_to_cpup(p++); +	fattr->uid = make_kuid(&init_user_ns, be32_to_cpup(p++)); +	if (!uid_valid(fattr->uid)) +		goto out_uid; +	fattr->gid = make_kgid(&init_user_ns, be32_to_cpup(p++)); +	if (!gid_valid(fattr->gid)) +		goto out_gid; +		  	fattr->size = be32_to_cpup(p++);  	fattr->du.nfs2.blocksize = be32_to_cpup(p++); @@ -313,6 +318,12 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)  	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);  	return 0; +out_uid: +	dprintk("NFS: returned invalid uid\n"); +	return -EINVAL; +out_gid: +	dprintk("NFS: returned invalid gid\n"); +	return -EINVAL;  out_overflow:  	print_overflow_msg(__func__, xdr);  	return -EIO; @@ -351,11 +362,11 @@ static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)  	else  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);  	if (attr->ia_valid & ATTR_UID) -		*p++ = cpu_to_be32(attr->ia_uid); +		*p++ = cpu_to_be32(from_kuid(&init_user_ns, attr->ia_uid));  	else  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);  	if (attr->ia_valid & ATTR_GID) -		*p++ = cpu_to_be32(attr->ia_gid); +		*p++ = cpu_to_be32(from_kgid(&init_user_ns, attr->ia_gid));  	else  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);  	if (attr->ia_valid & ATTR_SIZE) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index bffc32406fb..fa6d72131c1 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -592,13 +592,13 @@ static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)  	if (attr->ia_valid & ATTR_UID) {  		*p++ = xdr_one; -		*p++ = cpu_to_be32(attr->ia_uid); +		*p++ = cpu_to_be32(from_kuid(&init_user_ns, attr->ia_uid));  	} else  		*p++ = xdr_zero;  	if (attr->ia_valid & ATTR_GID) {  		*p++ = xdr_one; -		*p++ = cpu_to_be32(attr->ia_gid); +		*p++ = cpu_to_be32(from_kgid(&init_user_ns, attr->ia_gid));  	} else  		*p++ = xdr_zero; @@ -657,8 +657,12 @@ static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)  	fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;  	fattr->nlink = be32_to_cpup(p++); -	fattr->uid = be32_to_cpup(p++); -	fattr->gid = be32_to_cpup(p++); +	fattr->uid = make_kuid(&init_user_ns, be32_to_cpup(p++)); +	if (!uid_valid(fattr->uid)) +		goto out_uid; +	fattr->gid = make_kgid(&init_user_ns, be32_to_cpup(p++)); +	if (!gid_valid(fattr->gid)) +		goto out_gid;  	p = xdr_decode_size3(p, &fattr->size);  	p = xdr_decode_size3(p, &fattr->du.nfs3.used); @@ -675,6 +679,12 @@ static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)  	fattr->valid |= NFS_ATTR_FATTR_V3;  	return 0; +out_uid: +	dprintk("NFS: returned invalid uid\n"); +	return -EINVAL; +out_gid: +	dprintk("NFS: returned invalid gid\n"); +	return -EINVAL;  out_overflow:  	print_overflow_msg(__func__, xdr);  	return -EIO; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 26b14392043..e3edda554ac 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1002,7 +1002,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const  		owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);  		if (owner_namelen < 0) {  			dprintk("nfs: couldn't resolve uid %d to string\n", -					iap->ia_uid); +					from_kuid(&init_user_ns, iap->ia_uid));  			/* XXX */  			strcpy(owner_name, "nobody");  			owner_namelen = sizeof("nobody") - 1; @@ -1014,7 +1014,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const  		owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);  		if (owner_grouplen < 0) {  			dprintk("nfs: couldn't resolve gid %d to string\n", -					iap->ia_gid); +					from_kgid(&init_user_ns, iap->ia_gid));  			strcpy(owner_group, "nobody");  			owner_grouplen = sizeof("nobody") - 1;  			/* goto out; */ @@ -3778,14 +3778,14 @@ out_overflow:  }  static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, -		const struct nfs_server *server, uint32_t *uid, +		const struct nfs_server *server, kuid_t *uid,  		struct nfs4_string *owner_name)  {  	uint32_t len;  	__be32 *p;  	int ret = 0; -	*uid = -2; +	*uid = make_kuid(&init_user_ns, -2);  	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))  		return -EIO;  	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { @@ -3813,7 +3813,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,  					__func__, len);  		bitmap[1] &= ~FATTR4_WORD1_OWNER;  	} -	dprintk("%s: uid=%d\n", __func__, (int)*uid); +	dprintk("%s: uid=%d\n", __func__, (int)from_kuid(&init_user_ns, *uid));  	return ret;  out_overflow:  	print_overflow_msg(__func__, xdr); @@ -3821,14 +3821,14 @@ out_overflow:  }  static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, -		const struct nfs_server *server, uint32_t *gid, +		const struct nfs_server *server, kgid_t *gid,  		struct nfs4_string *group_name)  {  	uint32_t len;  	__be32 *p;  	int ret = 0; -	*gid = -2; +	*gid = make_kgid(&init_user_ns, -2);  	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))  		return -EIO;  	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { @@ -3856,7 +3856,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,  					__func__, len);  		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;  	} -	dprintk("%s: gid=%d\n", __func__, (int)*gid); +	dprintk("%s: gid=%d\n", __func__, (int)from_kgid(&init_user_ns, *gid));  	return ret;  out_overflow:  	print_overflow_msg(__func__, xdr); diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index 6940439bd60..ed628f71274 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c @@ -38,8 +38,8 @@ struct nfsacl_encode_desc {  	unsigned int count;  	struct posix_acl *acl;  	int typeflag; -	uid_t uid; -	gid_t gid; +	kuid_t uid; +	kgid_t gid;  };  struct nfsacl_simple_acl { @@ -60,14 +60,16 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)  	*p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);  	switch(entry->e_tag) {  		case ACL_USER_OBJ: -			*p++ = htonl(nfsacl_desc->uid); +			*p++ = htonl(from_kuid(&init_user_ns, nfsacl_desc->uid));  			break;  		case ACL_GROUP_OBJ: -			*p++ = htonl(nfsacl_desc->gid); +			*p++ = htonl(from_kgid(&init_user_ns, nfsacl_desc->gid));  			break;  		case ACL_USER: +			*p++ = htonl(from_kuid(&init_user_ns, entry->e_uid)); +			break;  		case ACL_GROUP: -			*p++ = htonl(entry->e_id); +			*p++ = htonl(from_kgid(&init_user_ns, entry->e_gid));  			break;  		default:  /* Solaris depends on that! */  			*p++ = 0; @@ -148,6 +150,7 @@ xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)  		(struct nfsacl_decode_desc *) desc;  	__be32 *p = elem;  	struct posix_acl_entry *entry; +	unsigned int id;  	if (!nfsacl_desc->acl) {  		if (desc->array_len > NFS_ACL_MAX_ENTRIES) @@ -160,14 +163,22 @@ xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)  	entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];  	entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT; -	entry->e_id = ntohl(*p++); +	id = ntohl(*p++);  	entry->e_perm = ntohl(*p++);  	switch(entry->e_tag) { -		case ACL_USER_OBJ:  		case ACL_USER: -		case ACL_GROUP_OBJ: +			entry->e_uid = make_kuid(&init_user_ns, id); +			if (!uid_valid(entry->e_uid)) +				return -EINVAL; +			break;  		case ACL_GROUP: +			entry->e_gid = make_kgid(&init_user_ns, id); +			if (!gid_valid(entry->e_gid)) +				return -EINVAL; +			break; +		case ACL_USER_OBJ: +		case ACL_GROUP_OBJ:  		case ACL_OTHER:  			if (entry->e_perm & ~S_IRWXO)  				return -EINVAL; @@ -190,9 +201,13 @@ cmp_acl_entry(const void *x, const void *y)  	if (a->e_tag != b->e_tag)  		return a->e_tag - b->e_tag; -	else if (a->e_id > b->e_id) +	else if ((a->e_tag == ACL_USER) && uid_gt(a->e_uid, b->e_uid)) +		return 1; +	else if ((a->e_tag == ACL_USER) && uid_lt(a->e_uid, b->e_uid)) +		return -1; +	else if ((a->e_tag == ACL_GROUP) && gid_gt(a->e_gid, b->e_gid))  		return 1; -	else if (a->e_id < b->e_id) +	else if ((a->e_tag == ACL_GROUP) && gid_lt(a->e_gid, b->e_gid))  		return -1;  	else  		return 0; @@ -213,22 +228,18 @@ posix_acl_from_nfsacl(struct posix_acl *acl)  	sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),  	     cmp_acl_entry, NULL); -	/* Clear undefined identifier fields and find the ACL_GROUP_OBJ -	   and ACL_MASK entries. */ +	/* Find the ACL_GROUP_OBJ and ACL_MASK entries. */  	FOREACH_ACL_ENTRY(pa, acl, pe) {  		switch(pa->e_tag) {  			case ACL_USER_OBJ: -				pa->e_id = ACL_UNDEFINED_ID;  				break;  			case ACL_GROUP_OBJ: -				pa->e_id = ACL_UNDEFINED_ID;  				group_obj = pa;  				break;  			case ACL_MASK:  				mask = pa;  				/* fall through */  			case ACL_OTHER: -				pa->e_id = ACL_UNDEFINED_ID;  				break;  		}  	} diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h index 34e5c40af5e..8b186a4955c 100644 --- a/fs/nfsd/acl.h +++ b/fs/nfsd/acl.h @@ -44,8 +44,6 @@  struct nfs4_acl *nfs4_acl_new(int);  int nfs4_acl_get_whotype(char *, u32);  int nfs4_acl_write_who(int who, char *p); -int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group, -		                        uid_t who, u32 mask);  #define NFS4_ACL_TYPE_DEFAULT	0x01  #define NFS4_ACL_DIR		0x02 diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 34a10d78b83..06cddd57226 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -47,9 +47,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)  		if (!gi)  			goto oom;  	} else if (flags & NFSEXP_ROOTSQUASH) { -		if (!new->fsuid) +		if (uid_eq(new->fsuid, GLOBAL_ROOT_UID))  			new->fsuid = exp->ex_anon_uid; -		if (!new->fsgid) +		if (gid_eq(new->fsgid, GLOBAL_ROOT_GID))  			new->fsgid = exp->ex_anon_gid;  		gi = groups_alloc(rqgi->ngroups); @@ -58,7 +58,7 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)  		for (i = 0; i < rqgi->ngroups; i++) {  			if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i))) -				GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid); +				GROUP_AT(gi, i) = exp->ex_anon_gid;  			else  				GROUP_AT(gi, i) = GROUP_AT(rqgi, i);  		} @@ -66,9 +66,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)  		gi = get_group_info(rqgi);  	} -	if (new->fsuid == (uid_t) -1) +	if (uid_eq(new->fsuid, INVALID_UID))  		new->fsuid = exp->ex_anon_uid; -	if (new->fsgid == (gid_t) -1) +	if (gid_eq(new->fsgid, INVALID_GID))  		new->fsgid = exp->ex_anon_gid;  	ret = set_groups(new, gi); @@ -76,7 +76,7 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)  	if (ret < 0)  		goto error; -	if (new->fsuid) +	if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID))  		new->cap_effective = cap_drop_nfsd_set(new->cap_effective);  	else  		new->cap_effective = cap_raise_nfsd_set(new->cap_effective, diff --git a/fs/nfsd/auth.h b/fs/nfsd/auth.h index 78b3c0e9382..53325a12ba6 100644 --- a/fs/nfsd/auth.h +++ b/fs/nfsd/auth.h @@ -1,6 +1,5 @@  /*   * nfsd-specific authentication stuff. - * uid/gid mapping not yet implemented.   *   * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>   */ @@ -8,11 +7,6 @@  #ifndef LINUX_NFSD_AUTH_H  #define LINUX_NFSD_AUTH_H -#define nfsd_luid(rq, uid)	((u32)(uid)) -#define nfsd_lgid(rq, gid)	((u32)(gid)) -#define nfsd_ruid(rq, uid)	((u32)(uid)) -#define nfsd_rgid(rq, gid)	((u32)(gid)) -  /*   * Set the current process's fsuid/fsgid etc to those of the NFS   * client user diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index a3946cf13fc..5681c5906f0 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -544,13 +544,17 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)  		err = get_int(&mesg, &an_int);  		if (err)  			goto out3; -		exp.ex_anon_uid= an_int; +		exp.ex_anon_uid= make_kuid(&init_user_ns, an_int); +		if (!uid_valid(exp.ex_anon_uid)) +			goto out3;  		/* anon gid */  		err = get_int(&mesg, &an_int);  		if (err)  			goto out3; -		exp.ex_anon_gid= an_int; +		exp.ex_anon_gid= make_kgid(&init_user_ns, an_int); +		if (!gid_valid(exp.ex_anon_gid)) +			goto out3;  		/* fsid */  		err = get_int(&mesg, &an_int); @@ -613,7 +617,7 @@ out:  }  static void exp_flags(struct seq_file *m, int flag, int fsid, -		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); +		kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);  static void show_secinfo(struct seq_file *m, struct svc_export *exp);  static int svc_export_show(struct seq_file *m, @@ -1179,15 +1183,17 @@ static void show_secinfo(struct seq_file *m, struct svc_export *exp)  }  static void exp_flags(struct seq_file *m, int flag, int fsid, -		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) +		kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)  {  	show_expflags(m, flag, NFSEXP_ALLFLAGS);  	if (flag & NFSEXP_FSID)  		seq_printf(m, ",fsid=%d", fsid); -	if (anonu != (uid_t)-2 && anonu != (0x10000-2)) -		seq_printf(m, ",anonuid=%u", anonu); -	if (anong != (gid_t)-2 && anong != (0x10000-2)) -		seq_printf(m, ",anongid=%u", anong); +	if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) && +	    !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2))) +		seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu)); +	if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) && +	    !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2))) +		seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));  	if (fsloc && fsloc->locations_count > 0) {  		char *loctype = (fsloc->migrated) ? "refer" : "replicas";  		int i; diff --git a/fs/nfsd/idmap.h b/fs/nfsd/idmap.h index 9d513efc01b..bf95f6b817a 100644 --- a/fs/nfsd/idmap.h +++ b/fs/nfsd/idmap.h @@ -54,9 +54,9 @@ static inline void nfsd_idmap_shutdown(struct net *net)  }  #endif -__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *); -__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *); -int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *); -int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *); +__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, kuid_t *); +__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, kgid_t *); +int nfsd_map_uid_to_name(struct svc_rqst *, kuid_t, char *); +int nfsd_map_gid_to_name(struct svc_rqst *, kgid_t, char *);  #endif /* LINUX_NFSD_IDMAP_H */ diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 324c0baf7cd..925c944bc0b 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -105,12 +105,14 @@ decode_sattr3(__be32 *p, struct iattr *iap)  		iap->ia_mode = ntohl(*p++);  	}  	if (*p++) { -		iap->ia_valid |= ATTR_UID; -		iap->ia_uid = ntohl(*p++); +		iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++)); +		if (uid_valid(iap->ia_uid)) +			iap->ia_valid |= ATTR_UID;  	}  	if (*p++) { -		iap->ia_valid |= ATTR_GID; -		iap->ia_gid = ntohl(*p++); +		iap->ia_gid = make_kgid(&init_user_ns, ntohl(*p++)); +		if (gid_valid(iap->ia_gid)) +			iap->ia_valid |= ATTR_GID;  	}  	if (*p++) {  		u64	newsize; @@ -167,8 +169,8 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,  	*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);  	*p++ = htonl((u32) stat->mode);  	*p++ = htonl((u32) stat->nlink); -	*p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); -	*p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); +	*p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid)); +	*p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));  	if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {  		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);  	} else { diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 9c51aff02ae..8a50b3c1809 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -264,7 +264,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,  			ace->flag = eflag;  			ace->access_mask = deny_mask_from_posix(deny, flags);  			ace->whotype = NFS4_ACL_WHO_NAMED; -			ace->who = pa->e_id; +			ace->who_uid = pa->e_uid;  			ace++;  			acl->naces++;  		} @@ -273,7 +273,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,  		ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,  						   flags);  		ace->whotype = NFS4_ACL_WHO_NAMED; -		ace->who = pa->e_id; +		ace->who_uid = pa->e_uid;  		ace++;  		acl->naces++;  		pa++; @@ -300,7 +300,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,  		ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,  						   flags);  		ace->whotype = NFS4_ACL_WHO_NAMED; -		ace->who = pa->e_id; +		ace->who_gid = pa->e_gid;  		ace++;  		acl->naces++;  		pa++; @@ -329,7 +329,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,  			ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;  			ace->access_mask = deny_mask_from_posix(deny, flags);  			ace->whotype = NFS4_ACL_WHO_NAMED; -			ace->who = pa->e_id; +			ace->who_gid = pa->e_gid;  			ace++;  			acl->naces++;  		} @@ -345,6 +345,18 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,  	acl->naces++;  } +static bool +pace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2) +{ +	if (pace1->e_tag != pace2->e_tag) +		return pace1->e_tag > pace2->e_tag; +	if (pace1->e_tag == ACL_USER) +		return uid_gt(pace1->e_uid, pace2->e_uid); +	if (pace1->e_tag == ACL_GROUP) +		return gid_gt(pace1->e_gid, pace2->e_gid); +	return false; +} +  static void  sort_pacl_range(struct posix_acl *pacl, int start, int end) {  	int sorted = 0, i; @@ -355,8 +367,8 @@ sort_pacl_range(struct posix_acl *pacl, int start, int end) {  	while (!sorted) {  		sorted = 1;  		for (i = start; i < end; i++) { -			if (pacl->a_entries[i].e_id -					> pacl->a_entries[i+1].e_id) { +			if (pace_gt(&pacl->a_entries[i], +				    &pacl->a_entries[i+1])) {  				sorted = 0;  				tmp = pacl->a_entries[i];  				pacl->a_entries[i] = pacl->a_entries[i+1]; @@ -398,7 +410,10 @@ struct posix_ace_state {  };  struct posix_user_ace_state { -	uid_t uid; +	union { +		kuid_t uid; +		kgid_t gid; +	};  	struct posix_ace_state perms;  }; @@ -521,7 +536,6 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)  	if (error)  		goto out_err;  	low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); -	pace->e_id = ACL_UNDEFINED_ID;  	for (i=0; i < state->users->n; i++) {  		pace++; @@ -531,7 +545,7 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)  			goto out_err;  		low_mode_from_nfs4(state->users->aces[i].perms.allow,  					&pace->e_perm, flags); -		pace->e_id = state->users->aces[i].uid; +		pace->e_uid = state->users->aces[i].uid;  		add_to_mask(state, &state->users->aces[i].perms);  	} @@ -541,7 +555,6 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)  	if (error)  		goto out_err;  	low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); -	pace->e_id = ACL_UNDEFINED_ID;  	add_to_mask(state, &state->group);  	for (i=0; i < state->groups->n; i++) { @@ -552,14 +565,13 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)  			goto out_err;  		low_mode_from_nfs4(state->groups->aces[i].perms.allow,  					&pace->e_perm, flags); -		pace->e_id = state->groups->aces[i].uid; +		pace->e_gid = state->groups->aces[i].gid;  		add_to_mask(state, &state->groups->aces[i].perms);  	}  	pace++;  	pace->e_tag = ACL_MASK;  	low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); -	pace->e_id = ACL_UNDEFINED_ID;  	pace++;  	pace->e_tag = ACL_OTHER; @@ -567,7 +579,6 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)  	if (error)  		goto out_err;  	low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); -	pace->e_id = ACL_UNDEFINED_ID;  	return pacl;  out_err: @@ -587,12 +598,13 @@ static inline void deny_bits(struct posix_ace_state *astate, u32 mask)  	astate->deny |= mask & ~astate->allow;  } -static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid) +static int find_uid(struct posix_acl_state *state, kuid_t uid)  { +	struct posix_ace_state_array *a = state->users;  	int i;  	for (i = 0; i < a->n; i++) -		if (a->aces[i].uid == uid) +		if (uid_eq(a->aces[i].uid, uid))  			return i;  	/* Not found: */  	a->n++; @@ -603,6 +615,23 @@ static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array  	return i;  } +static int find_gid(struct posix_acl_state *state, kgid_t gid) +{ +	struct posix_ace_state_array *a = state->groups; +	int i; + +	for (i = 0; i < a->n; i++) +		if (gid_eq(a->aces[i].gid, gid)) +			return i; +	/* Not found: */ +	a->n++; +	a->aces[i].gid = gid; +	a->aces[i].perms.allow = state->everyone.allow; +	a->aces[i].perms.deny  = state->everyone.deny; + +	return i; +} +  static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)  {  	int i; @@ -636,7 +665,7 @@ static void process_one_v4_ace(struct posix_acl_state *state,  		}  		break;  	case ACL_USER: -		i = find_uid(state, state->users, ace->who); +		i = find_uid(state, ace->who_uid);  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {  			allow_bits(&state->users->aces[i].perms, mask);  		} else { @@ -658,7 +687,7 @@ static void process_one_v4_ace(struct posix_acl_state *state,  		}  		break;  	case ACL_GROUP: -		i = find_uid(state, state->groups, ace->who); +		i = find_gid(state, ace->who_gid);  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {  			allow_bits(&state->groups->aces[i].perms, mask);  		} else { diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index a1f10c0a625..0ce12346df9 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -65,7 +65,7 @@ MODULE_PARM_DESC(nfs4_disable_idmapping,  struct ent {  	struct cache_head h;  	int               type;		       /* User / Group */ -	uid_t             id; +	u32               id;  	char              name[IDMAP_NAMESZ];  	char              authname[IDMAP_NAMESZ];  }; @@ -540,7 +540,7 @@ rqst_authname(struct svc_rqst *rqstp)  static __be32  idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, -		uid_t *id) +		u32 *id)  {  	struct ent *item, key = {  		.type = type, @@ -564,7 +564,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen  }  static int -idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) +idmap_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name)  {  	struct ent *item, key = {  		.id = id, @@ -587,7 +587,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)  }  static bool -numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) +numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id)  {  	int ret;  	char buf[11]; @@ -603,7 +603,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel  }  static __be32 -do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) +do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id)  {  	if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)  		if (numeric_name_to_id(rqstp, type, name, namelen, id)) @@ -616,7 +616,7 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u  }  static int -do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) +do_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name)  {  	if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)  		return sprintf(name, "%u", id); @@ -625,26 +625,40 @@ do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)  __be32  nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, -		__u32 *id) +		kuid_t *uid)  { -	return do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); +	__be32 status; +	u32 id = -1; +	status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id); +	*uid = make_kuid(&init_user_ns, id); +	if (!uid_valid(*uid)) +		status = nfserr_badowner; +	return status;  }  __be32  nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, -		__u32 *id) +		kgid_t *gid)  { -	return do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id); +	__be32 status; +	u32 id = -1; +	status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id); +	*gid = make_kgid(&init_user_ns, id); +	if (!gid_valid(*gid)) +		status = nfserr_badowner; +	return status;  }  int -nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) +nfsd_map_uid_to_name(struct svc_rqst *rqstp, kuid_t uid, char *name)  { +	u32 id = from_kuid(&init_user_ns, uid);  	return do_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);  }  int -nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) +nfsd_map_gid_to_name(struct svc_rqst *rqstp, kgid_t gid, char *name)  { +	u32 id = from_kgid(&init_user_ns, gid);  	return do_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);  } diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index ba6fdd4a045..4914af4a817 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -73,8 +73,8 @@ nfs4_save_creds(const struct cred **original_creds)  	if (!new)  		return -ENOMEM; -	new->fsuid = 0; -	new->fsgid = 0; +	new->fsuid = GLOBAL_ROOT_UID; +	new->fsgid = GLOBAL_ROOT_GID;  	*original_creds = override_creds(new);  	put_cred(new);  	return 0; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 499e957510e..9e7103b6e0a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1202,7 +1202,7 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2)  	if (g1->ngroups != g2->ngroups)  		return false;  	for (i=0; i<g1->ngroups; i++) -		if (GROUP_AT(g1, i) != GROUP_AT(g2, i)) +		if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))  			return false;  	return true;  } @@ -1227,8 +1227,8 @@ static bool  same_creds(struct svc_cred *cr1, struct svc_cred *cr2)  {  	if ((is_gss_cred(cr1) != is_gss_cred(cr2)) -		|| (cr1->cr_uid != cr2->cr_uid) -		|| (cr1->cr_gid != cr2->cr_gid) +		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid)) +		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))  		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))  		return false;  	if (cr1->cr_principal == cr2->cr_principal) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0dc11586682..2d1d06bae3a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -293,13 +293,13 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,  			ace->whotype = nfs4_acl_get_whotype(buf, dummy32);  			status = nfs_ok;  			if (ace->whotype != NFS4_ACL_WHO_NAMED) -				ace->who = 0; +				;  			else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)  				status = nfsd_map_name_to_gid(argp->rqstp, -						buf, dummy32, &ace->who); +						buf, dummy32, &ace->who_gid);  			else  				status = nfsd_map_name_to_uid(argp->rqstp, -						buf, dummy32, &ace->who); +						buf, dummy32, &ace->who_uid);  			if (status)  				return status;  		} @@ -464,9 +464,16 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_  			READ32(dummy);  			READ_BUF(dummy * 4);  			if (cbs->flavor == (u32)(-1)) { -				cbs->uid = uid; -				cbs->gid = gid; -				cbs->flavor = RPC_AUTH_UNIX; +				kuid_t kuid = make_kuid(&init_user_ns, uid); +				kgid_t kgid = make_kgid(&init_user_ns, gid); +				if (uid_valid(kuid) && gid_valid(kgid)) { +					cbs->uid = kuid; +					cbs->gid = kgid; +					cbs->flavor = RPC_AUTH_UNIX; +				} else { +					dprintk("RPC_AUTH_UNIX with invalid" +						"uid or gid ignoring!\n"); +				}  			}  			break;  		case RPC_AUTH_GSS: @@ -1926,7 +1933,7 @@ static u32 nfs4_file_type(umode_t mode)  }  static __be32 -nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, +nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, kuid_t uid, kgid_t gid,  			__be32 **p, int *buflen)  {  	int status; @@ -1935,10 +1942,10 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,  		return nfserr_resource;  	if (whotype != NFS4_ACL_WHO_NAMED)  		status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1)); -	else if (group) -		status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1)); +	else if (gid_valid(gid)) +		status = nfsd_map_gid_to_name(rqstp, gid, (u8 *)(*p + 1));  	else -		status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1)); +		status = nfsd_map_uid_to_name(rqstp, uid, (u8 *)(*p + 1));  	if (status < 0)  		return nfserrno(status);  	*p = xdr_encode_opaque(*p, NULL, status); @@ -1948,22 +1955,33 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,  }  static inline __be32 -nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) +nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t user, __be32 **p, int *buflen)  { -	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); +	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, user, INVALID_GID, +				 p, buflen);  }  static inline __be32 -nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) +nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t group, __be32 **p, int *buflen)  { -	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); +	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, INVALID_UID, group, +				 p, buflen);  }  static inline __be32 -nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, +nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,  		__be32 **p, int *buflen)  { -	return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); +	kuid_t uid = INVALID_UID; +	kgid_t gid = INVALID_GID; + +	if (ace->whotype == NFS4_ACL_WHO_NAMED) { +		if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) +			gid = ace->who_gid; +		else +			uid = ace->who_uid; +	} +	return nfsd4_encode_name(rqstp, ace->whotype, uid, gid, p, buflen);  }  #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ @@ -2224,9 +2242,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,  			WRITE32(ace->type);  			WRITE32(ace->flag);  			WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL); -			status = nfsd4_encode_aclname(rqstp, ace->whotype, -				ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP, -				&p, &buflen); +			status = nfsd4_encode_aclname(rqstp, ace, &p, &buflen);  			if (status == nfserr_resource)  				goto out_resource;  			if (status) diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 979b4210697..4201ede0ec9 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -100,12 +100,14 @@ decode_sattr(__be32 *p, struct iattr *iap)  		iap->ia_mode = tmp;  	}  	if ((tmp = ntohl(*p++)) != (u32)-1) { -		iap->ia_valid |= ATTR_UID; -		iap->ia_uid = tmp; +		iap->ia_uid = make_kuid(&init_user_ns, tmp); +		if (uid_valid(iap->ia_uid)) +			iap->ia_valid |= ATTR_UID;  	}  	if ((tmp = ntohl(*p++)) != (u32)-1) { -		iap->ia_valid |= ATTR_GID; -		iap->ia_gid = tmp; +		iap->ia_gid = make_kgid(&init_user_ns, tmp); +		if (gid_valid(iap->ia_gid)) +			iap->ia_valid |= ATTR_GID;  	}  	if ((tmp = ntohl(*p++)) != (u32)-1) {  		iap->ia_valid |= ATTR_SIZE; @@ -151,8 +153,8 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,  	*p++ = htonl(nfs_ftypes[type >> 12]);  	*p++ = htonl((u32) stat->mode);  	*p++ = htonl((u32) stat->nlink); -	*p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); -	*p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); +	*p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid)); +	*p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));  	if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {  		*p++ = htonl(NFS_MAXPATHLEN); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index d1c229feed5..1a8c7391f7a 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -152,8 +152,8 @@ struct nfsd4_channel_attrs {  struct nfsd4_cb_sec {  	u32	flavor; /* (u32)(-1) used to mean "no valid flavor" */ -	u32	uid; -	u32	gid; +	kuid_t	uid; +	kgid_t	gid;  };  struct nfsd4_create_session { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d586117fa94..31ff1d642e3 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -401,8 +401,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,  	/* Revoke setuid/setgid on chown */  	if (!S_ISDIR(inode->i_mode) && -	    (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) || -	     ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid))) { +	    (((iap->ia_valid & ATTR_UID) && !uid_eq(iap->ia_uid, inode->i_uid)) || +	     ((iap->ia_valid & ATTR_GID) && !gid_eq(iap->ia_gid, inode->i_gid)))) {  		iap->ia_valid |= ATTR_KILL_PRIV;  		if (iap->ia_valid & ATTR_MODE) {  			/* we're setting mode too, just clear the s*id bits */ @@ -1205,7 +1205,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,  	 * send along the gid on create when it tries to implement  	 * setgid directories via NFS:  	 */ -	if (current_fsuid() != 0) +	if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID))  		iap->ia_valid &= ~(ATTR_UID|ATTR_GID);  	if (iap->ia_valid)  		return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); @@ -2150,7 +2150,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,  	 * with NFSv3.  	 */  	if ((acc & NFSD_MAY_OWNER_OVERRIDE) && -	    inode->i_uid == current_fsuid()) +	    uid_eq(inode->i_uid, current_fsuid()))  		return 0;  	/* This assumes  NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 260b16281fc..8a404576fb2 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -65,7 +65,20 @@ static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)  		acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);  		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); -		acl->a_entries[n].e_id   = le32_to_cpu(entry->e_id); +		switch(acl->a_entries[n].e_tag) { +		case ACL_USER: +			acl->a_entries[n].e_uid = +				make_kuid(&init_user_ns, +					  le32_to_cpu(entry->e_id)); +			break; +		case ACL_GROUP: +			acl->a_entries[n].e_gid = +				make_kgid(&init_user_ns, +					  le32_to_cpu(entry->e_id)); +			break; +		default: +			break; +		}  		value += sizeof(struct posix_acl_entry);  	} @@ -91,7 +104,21 @@ static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)  	for (n = 0; n < acl->a_count; n++, entry++) {  		entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);  		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); -		entry->e_id   = cpu_to_le32(acl->a_entries[n].e_id); +		switch(acl->a_entries[n].e_tag) { +		case ACL_USER: +			entry->e_id = cpu_to_le32( +				from_kuid(&init_user_ns, +					  acl->a_entries[n].e_uid)); +			break; +		case ACL_GROUP: +			entry->e_id = cpu_to_le32( +				from_kgid(&init_user_ns, +					  acl->a_entries[n].e_gid)); +			break; +		default: +			entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); +			break; +		}  	}  	return ocfs2_acl;  } diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 88577eb5d71..12ae194ac94 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -2045,8 +2045,8 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)  	lvb->lvb_version   = OCFS2_LVB_VERSION;  	lvb->lvb_isize	   = cpu_to_be64(i_size_read(inode));  	lvb->lvb_iclusters = cpu_to_be32(oi->ip_clusters); -	lvb->lvb_iuid      = cpu_to_be32(inode->i_uid); -	lvb->lvb_igid      = cpu_to_be32(inode->i_gid); +	lvb->lvb_iuid      = cpu_to_be32(i_uid_read(inode)); +	lvb->lvb_igid      = cpu_to_be32(i_gid_read(inode));  	lvb->lvb_imode     = cpu_to_be16(inode->i_mode);  	lvb->lvb_inlink    = cpu_to_be16(inode->i_nlink);  	lvb->lvb_iatime_packed  = @@ -2095,8 +2095,8 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)  	else  		inode->i_blocks = ocfs2_inode_sector_count(inode); -	inode->i_uid     = be32_to_cpu(lvb->lvb_iuid); -	inode->i_gid     = be32_to_cpu(lvb->lvb_igid); +	i_uid_write(inode, be32_to_cpu(lvb->lvb_iuid)); +	i_gid_write(inode, be32_to_cpu(lvb->lvb_igid));  	inode->i_mode    = be16_to_cpu(lvb->lvb_imode);  	set_nlink(inode, be16_to_cpu(lvb->lvb_inlink));  	ocfs2_unpack_timespec(&inode->i_atime, diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 37d313ede15..0a2924a2d9e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1116,7 +1116,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)  			    (unsigned long long)OCFS2_I(inode)->ip_blkno,  			    dentry->d_name.len, dentry->d_name.name,  			    attr->ia_valid, attr->ia_mode, -			    attr->ia_uid, attr->ia_gid); +			    from_kuid(&init_user_ns, attr->ia_uid), +			    from_kgid(&init_user_ns, attr->ia_gid));  	/* ensuring we don't even attempt to truncate a symlink */  	if (S_ISLNK(inode->i_mode)) @@ -1174,14 +1175,14 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)  		}  	} -	if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -	    (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { +	if ((attr->ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || +	    (attr->ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {  		/*  		 * Gather pointers to quota structures so that allocation /  		 * freeing of quota structures happens here and not inside  		 * dquot_transfer() where we have problems with lock ordering  		 */ -		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid +		if (attr->ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,  		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {  			transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid)); @@ -1190,7 +1191,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)  				goto bail_unlock;  			}  		} -		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid +		if (attr->ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid)  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,  		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {  			transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid)); diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index d89e08a81ed..f87f9bd1edf 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -269,8 +269,8 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,  	inode->i_generation = le32_to_cpu(fe->i_generation);  	inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev));  	inode->i_mode = le16_to_cpu(fe->i_mode); -	inode->i_uid = le32_to_cpu(fe->i_uid); -	inode->i_gid = le32_to_cpu(fe->i_gid); +	i_uid_write(inode, le32_to_cpu(fe->i_uid)); +	i_gid_write(inode, le32_to_cpu(fe->i_gid));  	/* Fast symlinks will have i_size but no allocated clusters. */  	if (S_ISLNK(inode->i_mode) && !fe->i_clusters) { @@ -1259,8 +1259,8 @@ int ocfs2_mark_inode_dirty(handle_t *handle,  	fe->i_size = cpu_to_le64(i_size_read(inode));  	ocfs2_set_links_count(fe, inode->i_nlink); -	fe->i_uid = cpu_to_le32(inode->i_uid); -	fe->i_gid = cpu_to_le32(inode->i_gid); +	fe->i_uid = cpu_to_le32(i_uid_read(inode)); +	fe->i_gid = cpu_to_le32(i_gid_read(inode));  	fe->i_mode = cpu_to_le16(inode->i_mode);  	fe->i_atime = cpu_to_le64(inode->i_atime.tv_sec);  	fe->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); @@ -1290,8 +1290,8 @@ void ocfs2_refresh_inode(struct inode *inode,  	ocfs2_set_inode_flags(inode);  	i_size_write(inode, le64_to_cpu(fe->i_size));  	set_nlink(inode, ocfs2_read_links_count(fe)); -	inode->i_uid = le32_to_cpu(fe->i_uid); -	inode->i_gid = le32_to_cpu(fe->i_gid); +	i_uid_write(inode, le32_to_cpu(fe->i_uid)); +	i_gid_write(inode, le32_to_cpu(fe->i_gid));  	inode->i_mode = le16_to_cpu(fe->i_mode);  	if (S_ISLNK(inode->i_mode) && le32_to_cpu(fe->i_clusters) == 0)  		inode->i_blocks = 0; diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index f1fd0741162..04ee1b57c24 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -512,8 +512,8 @@ static int __ocfs2_mknod_locked(struct inode *dir,  	fe->i_suballoc_loc = cpu_to_le64(suballoc_loc);  	fe->i_suballoc_bit = cpu_to_le16(suballoc_bit);  	fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot); -	fe->i_uid = cpu_to_le32(inode->i_uid); -	fe->i_gid = cpu_to_le32(inode->i_gid); +	fe->i_uid = cpu_to_le32(i_uid_read(inode)); +	fe->i_gid = cpu_to_le32(i_gid_read(inode));  	fe->i_mode = cpu_to_le16(inode->i_mode);  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))  		fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev)); diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 30a055049e1..934a4ac3e7f 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4407,7 +4407,7 @@ static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,  	 * rights to do so.  	 */  	if (preserve) { -		if ((current_fsuid() != inode->i_uid) && !capable(CAP_CHOWN)) +		if (!uid_eq(current_fsuid(), inode->i_uid) && !capable(CAP_CHOWN))  			return -EPERM;  		if (!in_group_p(inode->i_gid) && !capable(CAP_CHOWN))  			return -EPERM; diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index eab8c09d380..c24f1e10b94 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -260,6 +260,7 @@ static struct file_system_type ramfs_fs_type = {  	.name		= "ramfs",  	.mount		= ramfs_mount,  	.kill_sb	= ramfs_kill_sb, +	.fs_flags	= FS_USERNS_MOUNT,  };  static struct file_system_type rootfs_fs_type = {  	.name		= "rootfs", diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index 8031d6eef10..5b8721efa94 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -34,7 +34,7 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid,  		 const char *name, int length, int *type,   		 struct CodaFid *resfid);  int venus_close(struct super_block *sb, struct CodaFid *fid, int flags, -		vuid_t uid); +		kuid_t uid);  int venus_open(struct super_block *sb, struct CodaFid *fid, int flags,  	       struct file **f);  int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,  diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e111fa419a4..7b8fc73810a 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -13,6 +13,7 @@  #define _LINUX_NFS4_H  #include <linux/list.h> +#include <linux/uidgid.h>  #include <uapi/linux/nfs4.h>  struct nfs4_ace { @@ -20,7 +21,10 @@ struct nfs4_ace {  	uint32_t	flag;  	uint32_t	access_mask;  	int		whotype; -	uid_t		who; +	union { +		kuid_t	who_uid; +		kgid_t	who_gid; +	};  };  struct nfs4_acl { diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h index 2dcef3ab58b..0f4b79da658 100644 --- a/include/linux/nfs_idmap.h +++ b/include/linux/nfs_idmap.h @@ -36,6 +36,7 @@  #ifndef NFS_IDMAP_H  #define NFS_IDMAP_H +#include <linux/uidgid.h>  #include <uapi/linux/nfs_idmap.h> @@ -67,10 +68,10 @@ void nfs_fattr_init_names(struct nfs_fattr *fattr,  void nfs_fattr_free_names(struct nfs_fattr *);  void nfs_fattr_map_and_free_names(struct nfs_server *, struct nfs_fattr *); -int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, __u32 *); -int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, __u32 *); -int nfs_map_uid_to_name(const struct nfs_server *, __u32, char *, size_t); -int nfs_map_gid_to_group(const struct nfs_server *, __u32, char *, size_t); +int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, kuid_t *); +int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, kgid_t *); +int nfs_map_uid_to_name(const struct nfs_server *, kuid_t, char *, size_t); +int nfs_map_gid_to_group(const struct nfs_server *, kgid_t, char *, size_t);  extern unsigned int nfs_idmap_cache_timeout;  #endif /* NFS_IDMAP_H */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 29adb12c7ec..13441ddac33 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -48,8 +48,8 @@ struct nfs_fattr {  	unsigned int		valid;		/* which fields are valid */  	umode_t			mode;  	__u32			nlink; -	__u32			uid; -	__u32			gid; +	kuid_t			uid; +	kgid_t			gid;  	dev_t			rdev;  	__u64			size;  	union { diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 24c139288db..7898c997dfe 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -49,8 +49,8 @@ struct svc_export {  	struct auth_domain *	ex_client;  	int			ex_flags;  	struct path		ex_path; -	uid_t			ex_anon_uid; -	gid_t			ex_anon_gid; +	kuid_t			ex_anon_uid; +	kgid_t			ex_anon_gid;  	int			ex_fsid;  	unsigned char *		ex_uuid; /* 16 byte fsid */  	struct nfsd4_fs_locations ex_fslocs; diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index f25ba922baa..58fda1c3c78 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -17,14 +17,15 @@  #include <linux/atomic.h>  #include <linux/rcupdate.h> +#include <linux/uidgid.h>  /* size of the nodename buffer */  #define UNX_MAXNODENAME	32  /* Work around the lack of a VFS credential */  struct auth_cred { -	uid_t	uid; -	gid_t	gid; +	kuid_t	uid; +	kgid_t	gid;  	struct group_info *group_info;  	const char *principal;  	unsigned char machine_cred : 1; @@ -48,7 +49,7 @@ struct rpc_cred {  	unsigned long		cr_flags;	/* various flags */  	atomic_t		cr_count;	/* ref count */ -	uid_t			cr_uid; +	kuid_t			cr_uid;  	/* per-flavor data */  }; diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index dd74084a979..ff374ab3083 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -18,8 +18,8 @@  #include <linux/cred.h>  struct svc_cred { -	uid_t			cr_uid; -	gid_t			cr_gid; +	kuid_t			cr_uid; +	kgid_t			cr_gid;  	struct group_info	*cr_group_info;  	u32			cr_flavor; /* pseudoflavor */  	char			*cr_principal; /* for gss */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index b9bd2e6c73c..4ce00932493 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -21,7 +21,7 @@ struct user_namespace {  	struct uid_gid_map	uid_map;  	struct uid_gid_map	gid_map;  	struct uid_gid_map	projid_map; -	struct kref		kref; +	atomic_t		count;  	struct user_namespace	*parent;  	kuid_t			owner;  	kgid_t			group; @@ -35,18 +35,18 @@ extern struct user_namespace init_user_ns;  static inline struct user_namespace *get_user_ns(struct user_namespace *ns)  {  	if (ns) -		kref_get(&ns->kref); +		atomic_inc(&ns->count);  	return ns;  }  extern int create_user_ns(struct cred *new);  extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred); -extern void free_user_ns(struct kref *kref); +extern void free_user_ns(struct user_namespace *ns);  static inline void put_user_ns(struct user_namespace *ns)  { -	if (ns) -		kref_put(&ns->kref, free_user_ns); +	if (ns && atomic_dec_and_test(&ns->count)) +		free_user_ns(ns);  }  struct seq_operations; diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 7184853ca36..27dfe85772b 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -407,17 +407,17 @@ struct p9_wstat {  	char *gid;  	char *muid;  	char *extension;	/* 9p2000.u extensions */ -	u32 n_uid;		/* 9p2000.u extensions */ -	u32 n_gid;		/* 9p2000.u extensions */ -	u32 n_muid;		/* 9p2000.u extensions */ +	kuid_t n_uid;		/* 9p2000.u extensions */ +	kgid_t n_gid;		/* 9p2000.u extensions */ +	kuid_t n_muid;		/* 9p2000.u extensions */  };  struct p9_stat_dotl {  	u64 st_result_mask;  	struct p9_qid qid;  	u32 st_mode; -	u32 st_uid; -	u32 st_gid; +	kuid_t st_uid; +	kgid_t st_gid;  	u64 st_nlink;  	u64 st_rdev;  	u64 st_size; @@ -471,8 +471,8 @@ struct p9_stat_dotl {  struct p9_iattr_dotl {  	u32 valid;  	u32 mode; -	u32 uid; -	u32 gid; +	kuid_t uid; +	kgid_t gid;  	u64 size;  	u64 atime_sec;  	u64 atime_nsec; diff --git a/include/net/9p/client.h b/include/net/9p/client.h index fc9b90b0c05..5ff70f433e8 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -187,7 +187,7 @@ struct p9_fid {  	int mode;  	struct p9_qid qid;  	u32 iounit; -	uid_t uid; +	kuid_t uid;  	void *rdir; @@ -220,17 +220,17 @@ void p9_client_destroy(struct p9_client *clnt);  void p9_client_disconnect(struct p9_client *clnt);  void p9_client_begin_disconnect(struct p9_client *clnt);  struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, -					char *uname, u32 n_uname, char *aname); +				char *uname, kuid_t n_uname, char *aname);  struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,  		char **wnames, int clone);  int p9_client_open(struct p9_fid *fid, int mode);  int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,  							char *extension);  int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); -int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, +int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, kgid_t gid,  							struct p9_qid *qid);  int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, -		gid_t gid, struct p9_qid *qid); +		kgid_t gid, struct p9_qid *qid);  int p9_client_clunk(struct p9_fid *fid);  int p9_client_fsync(struct p9_fid *fid, int datasync);  int p9_client_remove(struct p9_fid *fid); @@ -250,9 +250,9 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,  							u64 request_mask);  int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode, -			dev_t rdev, gid_t gid, struct p9_qid *); +			dev_t rdev, kgid_t gid, struct p9_qid *);  int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, -				gid_t gid, struct p9_qid *); +				kgid_t gid, struct p9_qid *);  int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);  int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);  struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); diff --git a/init/Kconfig b/init/Kconfig index 968c539f0ac..0a5e80fb9ba 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1032,6 +1032,13 @@ config USER_NS  	help  	  This allows containers, i.e. vservers, to use user namespaces  	  to provide different user info for different servers. + +	  When user namespaces are enabled in the kernel it is +	  recommended that the MEMCG and MEMCG_KMEM options also be +	  enabled and that user-space use the memory control groups to +	  limit the amount of memory a memory unprivileged users can +	  use. +  	  If unsure, say N.  config PID_NS @@ -1060,20 +1067,7 @@ config UIDGID_CONVERTED  	bool  	default y -	# Networking -	depends on NET_9P = n -  	# Filesystems -	depends on 9P_FS = n -	depends on AFS_FS = n -	depends on CEPH_FS = n -	depends on CIFS = n -	depends on CODA_FS = n -	depends on GFS2_FS = n -	depends on NCP_FS = n -	depends on NFSD = n -	depends on NFS_FS = n -	depends on OCFS2_FS = n  	depends on XFS_FS = n  config UIDGID_STRICT_TYPE_CHECKS diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 71a3ca18c87..023c9867ff4 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1383,6 +1383,7 @@ static struct file_system_type mqueue_fs_type = {  	.name = "mqueue",  	.mount = mqueue_mount,  	.kill_sb = kill_litter_super, +	.fs_flags = FS_USERNS_MOUNT,  };  int mq_init_ns(struct ipc_namespace *ns) diff --git a/kernel/sys.c b/kernel/sys.c index 840cfdad7bf..2e18d33ca77 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -434,11 +434,12 @@ static DEFINE_MUTEX(reboot_mutex);  SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,  		void __user *, arg)  { +	struct pid_namespace *pid_ns = task_active_pid_ns(current);  	char buffer[256];  	int ret = 0;  	/* We only trust the superuser with rebooting the system. */ -	if (!capable(CAP_SYS_BOOT)) +	if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))  		return -EPERM;  	/* For safety, we require "magic" arguments. */ @@ -454,7 +455,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,  	 * pid_namespace, the command is handled by reboot_pid_ns() which will  	 * call do_exit().  	 */ -	ret = reboot_pid_ns(task_active_pid_ns(current), cmd); +	ret = reboot_pid_ns(pid_ns, cmd);  	if (ret)  		return ret; diff --git a/kernel/user.c b/kernel/user.c index 33acb5e53a5..57ebfd42023 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -47,9 +47,7 @@ struct user_namespace init_user_ns = {  			.count = 4294967295U,  		},  	}, -	.kref = { -		.refcount	= ATOMIC_INIT(3), -	}, +	.count = ATOMIC_INIT(3),  	.owner = GLOBAL_ROOT_UID,  	.group = GLOBAL_ROOT_GID,  	.proc_inum = PROC_USER_INIT_INO, diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 2b042c42fbc..8b650837083 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -78,7 +78,7 @@ int create_user_ns(struct cred *new)  		return ret;  	} -	kref_init(&ns->kref); +	atomic_set(&ns->count, 1);  	/* Leave the new->user_ns reference with the new user namespace. */  	ns->parent = parent_ns;  	ns->owner = owner; @@ -104,15 +104,16 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)  	return create_user_ns(cred);  } -void free_user_ns(struct kref *kref) +void free_user_ns(struct user_namespace *ns)  { -	struct user_namespace *parent, *ns = -		container_of(kref, struct user_namespace, kref); +	struct user_namespace *parent; -	parent = ns->parent; -	proc_free_inum(ns->proc_inum); -	kmem_cache_free(user_ns_cachep, ns); -	put_user_ns(parent); +	do { +		parent = ns->parent; +		proc_free_inum(ns->proc_inum); +		kmem_cache_free(user_ns_cachep, ns); +		ns = parent; +	} while (atomic_dec_and_test(&parent->count));  }  EXPORT_SYMBOL(free_user_ns); @@ -519,6 +520,42 @@ struct seq_operations proc_projid_seq_operations = {  	.show = projid_m_show,  }; +static bool mappings_overlap(struct uid_gid_map *new_map, struct uid_gid_extent *extent) +{ +	u32 upper_first, lower_first, upper_last, lower_last; +	unsigned idx; + +	upper_first = extent->first; +	lower_first = extent->lower_first; +	upper_last = upper_first + extent->count - 1; +	lower_last = lower_first + extent->count - 1; + +	for (idx = 0; idx < new_map->nr_extents; idx++) { +		u32 prev_upper_first, prev_lower_first; +		u32 prev_upper_last, prev_lower_last; +		struct uid_gid_extent *prev; + +		prev = &new_map->extent[idx]; + +		prev_upper_first = prev->first; +		prev_lower_first = prev->lower_first; +		prev_upper_last = prev_upper_first + prev->count - 1; +		prev_lower_last = prev_lower_first + prev->count - 1; + +		/* Does the upper range intersect a previous extent? */ +		if ((prev_upper_first <= upper_last) && +		    (prev_upper_last >= upper_first)) +			return true; + +		/* Does the lower range intersect a previous extent? */ +		if ((prev_lower_first <= lower_last) && +		    (prev_lower_last >= lower_first)) +			return true; +	} +	return false; +} + +  static DEFINE_MUTEX(id_map_mutex);  static ssize_t map_write(struct file *file, const char __user *buf, @@ -531,7 +568,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,  	struct user_namespace *ns = seq->private;  	struct uid_gid_map new_map;  	unsigned idx; -	struct uid_gid_extent *extent, *last = NULL; +	struct uid_gid_extent *extent = NULL;  	unsigned long page = 0;  	char *kbuf, *pos, *next_line;  	ssize_t ret = -EINVAL; @@ -634,14 +671,11 @@ static ssize_t map_write(struct file *file, const char __user *buf,  		if ((extent->lower_first + extent->count) <= extent->lower_first)  			goto out; -		/* For now only accept extents that are strictly in order */ -		if (last && -		    (((last->first + last->count) > extent->first) || -		     ((last->lower_first + last->count) > extent->lower_first))) +		/* Do the ranges in extent overlap any previous extents? */ +		if (mappings_overlap(&new_map, extent))  			goto out;  		new_map.nr_extents++; -		last = extent;  		/* Fail if the file contains too many extents */  		if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) && diff --git a/mm/shmem.c b/mm/shmem.c index 1ad79243cb7..39de1d6a077 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2778,6 +2778,7 @@ static struct file_system_type shmem_fs_type = {  	.name		= "tmpfs",  	.mount		= shmem_mount,  	.kill_sb	= kill_litter_super, +	.fs_flags	= FS_USERNS_MOUNT,  };  int __init shmem_init(void) @@ -2835,6 +2836,7 @@ static struct file_system_type shmem_fs_type = {  	.name		= "tmpfs",  	.mount		= ramfs_mount,  	.kill_sb	= kill_litter_super, +	.fs_flags	= FS_USERNS_MOUNT,  };  int __init shmem_init(void) diff --git a/net/9p/client.c b/net/9p/client.c index 34d41767093..8eb75425e6e 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1100,7 +1100,7 @@ void p9_client_begin_disconnect(struct p9_client *clnt)  EXPORT_SYMBOL(p9_client_begin_disconnect);  struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, -	char *uname, u32 n_uname, char *aname) +	char *uname, kuid_t n_uname, char *aname)  {  	int err = 0;  	struct p9_req_t *req; @@ -1117,7 +1117,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,  		goto error;  	} -	req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, +	req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid,  			afid ? afid->fid : P9_NOFID, uname, aname, n_uname);  	if (IS_ERR(req)) {  		err = PTR_ERR(req); @@ -1270,7 +1270,7 @@ error:  EXPORT_SYMBOL(p9_client_open);  int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, -		gid_t gid, struct p9_qid *qid) +		kgid_t gid, struct p9_qid *qid)  {  	int err = 0;  	struct p9_client *clnt; @@ -1279,13 +1279,14 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,  	p9_debug(P9_DEBUG_9P,  			">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n", -			ofid->fid, name, flags, mode, gid); +			ofid->fid, name, flags, mode, +		 	from_kgid(&init_user_ns, gid));  	clnt = ofid->clnt;  	if (ofid->mode != -1)  		return -EINVAL; -	req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags, +	req = p9_client_rpc(clnt, P9_TLCREATE, "dsddg", ofid->fid, name, flags,  			mode, gid);  	if (IS_ERR(req)) {  		err = PTR_ERR(req); @@ -1358,7 +1359,7 @@ error:  }  EXPORT_SYMBOL(p9_client_fcreate); -int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, +int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, kgid_t gid,  		struct p9_qid *qid)  {  	int err = 0; @@ -1369,7 +1370,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,  			dfid->fid, name, symtgt);  	clnt = dfid->clnt; -	req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt, +	req = p9_client_rpc(clnt, P9_TSYMLINK, "dssg", dfid->fid, name, symtgt,  			gid);  	if (IS_ERR(req)) {  		err = PTR_ERR(req); @@ -1710,7 +1711,9 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)  		(unsigned long long)ret->qid.path, ret->qid.version, ret->mode,  		ret->atime, ret->mtime, (unsigned long long)ret->length,  		ret->name, ret->uid, ret->gid, ret->muid, ret->extension, -		ret->n_uid, ret->n_gid, ret->n_muid); +		from_kuid(&init_user_ns, ret->n_uid), +		from_kgid(&init_user_ns, ret->n_gid), +		from_kuid(&init_user_ns, ret->n_muid));  	p9_free_req(clnt, req);  	return ret; @@ -1764,8 +1767,10 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,  		"<<< st_btime_sec=%lld st_btime_nsec=%lld\n"  		"<<< st_gen=%lld st_data_version=%lld",  		ret->st_result_mask, ret->qid.type, ret->qid.path, -		ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid, -		ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize, +		ret->qid.version, ret->st_mode, ret->st_nlink, +		from_kuid(&init_user_ns, ret->st_uid), +		from_kgid(&init_user_ns, ret->st_gid), +		ret->st_rdev, ret->st_size, ret->st_blksize,  		ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec,  		ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec,  		ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec, @@ -1828,7 +1833,9 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)  		(unsigned long long)wst->qid.path, wst->qid.version, wst->mode,  		wst->atime, wst->mtime, (unsigned long long)wst->length,  		wst->name, wst->uid, wst->gid, wst->muid, wst->extension, -		wst->n_uid, wst->n_gid, wst->n_muid); +		from_kuid(&init_user_ns, wst->n_uid), +		from_kgid(&init_user_ns, wst->n_gid), +		from_kuid(&init_user_ns, wst->n_muid));  	req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst);  	if (IS_ERR(req)) { @@ -1857,7 +1864,9 @@ int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)  		"    valid=%x mode=%x uid=%d gid=%d size=%lld\n"  		"    atime_sec=%lld atime_nsec=%lld\n"  		"    mtime_sec=%lld mtime_nsec=%lld\n", -		p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid, +		p9attr->valid, p9attr->mode, +		from_kuid(&init_user_ns, p9attr->uid), +		from_kgid(&init_user_ns, p9attr->gid),  		p9attr->size, p9attr->atime_sec, p9attr->atime_nsec,  		p9attr->mtime_sec, p9attr->mtime_nsec); @@ -2106,7 +2115,7 @@ error:  EXPORT_SYMBOL(p9_client_readdir);  int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, -			dev_t rdev, gid_t gid, struct p9_qid *qid) +			dev_t rdev, kgid_t gid, struct p9_qid *qid)  {  	int err;  	struct p9_client *clnt; @@ -2116,7 +2125,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,  	clnt = fid->clnt;  	p9_debug(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "  		"minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev)); -	req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode, +	req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddg", fid->fid, name, mode,  		MAJOR(rdev), MINOR(rdev), gid);  	if (IS_ERR(req))  		return PTR_ERR(req); @@ -2137,7 +2146,7 @@ error:  EXPORT_SYMBOL(p9_client_mknod_dotl);  int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, -				gid_t gid, struct p9_qid *qid) +				kgid_t gid, struct p9_qid *qid)  {  	int err;  	struct p9_client *clnt; @@ -2146,8 +2155,8 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,  	err = 0;  	clnt = fid->clnt;  	p9_debug(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n", -		 fid->fid, name, mode, gid); -	req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode, +		 fid->fid, name, mode, from_kgid(&init_user_ns, gid)); +	req = p9_client_rpc(clnt, P9_TMKDIR, "dsdg", fid->fid, name, mode,  		gid);  	if (IS_ERR(req))  		return PTR_ERR(req); diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 3d33ecf1332..ab9127ec5b7 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -85,6 +85,8 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)  	d - int32_t  	q - int64_t  	s - string +	u - numeric uid +	g - numeric gid  	S - stat  	Q - qid  	D - data blob (int32_t size followed by void *, results are not freed) @@ -163,6 +165,26 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  					(*sptr)[len] = 0;  			}  			break; +		case 'u': { +				kuid_t *uid = va_arg(ap, kuid_t *); +				__le32 le_val; +				if (pdu_read(pdu, &le_val, sizeof(le_val))) { +					errcode = -EFAULT; +					break; +				} +				*uid = make_kuid(&init_user_ns, +						 le32_to_cpu(le_val)); +			} break; +		case 'g': { +				kgid_t *gid = va_arg(ap, kgid_t *); +				__le32 le_val; +				if (pdu_read(pdu, &le_val, sizeof(le_val))) { +					errcode = -EFAULT; +					break; +				} +				*gid = make_kgid(&init_user_ns, +						 le32_to_cpu(le_val)); +			} break;  		case 'Q':{  				struct p9_qid *qid =  				    va_arg(ap, struct p9_qid *); @@ -177,11 +199,12 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  				    va_arg(ap, struct p9_wstat *);  				memset(stbuf, 0, sizeof(struct p9_wstat)); -				stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -									-1; +				stbuf->n_uid = stbuf->n_muid = INVALID_UID; +				stbuf->n_gid = INVALID_GID; +  				errcode =  				    p9pdu_readf(pdu, proto_version, -						"wwdQdddqssss?sddd", +						"wwdQdddqssss?sugu",  						&stbuf->size, &stbuf->type,  						&stbuf->dev, &stbuf->qid,  						&stbuf->mode, &stbuf->atime, @@ -294,7 +317,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  				memset(stbuf, 0, sizeof(struct p9_stat_dotl));  				errcode =  				    p9pdu_readf(pdu, proto_version, -					"qQdddqqqqqqqqqqqqqqq", +					"qQdugqqqqqqqqqqqqqqq",  					&stbuf->st_result_mask,  					&stbuf->qid,  					&stbuf->st_mode, @@ -377,6 +400,20 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  					errcode = -EFAULT;  			}  			break; +		case 'u': { +				kuid_t uid = va_arg(ap, kuid_t); +				__le32 val = cpu_to_le32( +						from_kuid(&init_user_ns, uid)); +				if (pdu_write(pdu, &val, sizeof(val))) +					errcode = -EFAULT; +			} break; +		case 'g': { +				kgid_t gid = va_arg(ap, kgid_t); +				__le32 val = cpu_to_le32( +						from_kgid(&init_user_ns, gid)); +				if (pdu_write(pdu, &val, sizeof(val))) +					errcode = -EFAULT; +			} break;  		case 'Q':{  				const struct p9_qid *qid =  				    va_arg(ap, const struct p9_qid *); @@ -390,7 +427,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  				    va_arg(ap, const struct p9_wstat *);  				errcode =  				    p9pdu_writef(pdu, proto_version, -						 "wwdQdddqssss?sddd", +						 "wwdQdddqssss?sugu",  						 stbuf->size, stbuf->type,  						 stbuf->dev, &stbuf->qid,  						 stbuf->mode, stbuf->atime, @@ -468,7 +505,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  							struct p9_iattr_dotl *);  				errcode = p9pdu_writef(pdu, proto_version, -							"ddddqqqqq", +							"ddugqqqqq",  							p9attr->valid,  							p9attr->mode,  							p9attr->uid, diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index ee71ea26777..1deb29af82f 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -15,6 +15,8 @@  #include <linux/slab.h>  #include <linux/statfs.h>  #include <linux/string.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h>  #include <linux/ceph/ceph_features.h> @@ -292,6 +294,9 @@ ceph_parse_options(char *options, const char *dev_name,  	int err = -ENOMEM;  	substring_t argstr[MAX_OPT_ARGS]; +	if (current->nsproxy->net_ns != &init_net) +		return ERR_PTR(-EINVAL); +  	opt = kzalloc(sizeof(*opt), GFP_KERNEL);  	if (!opt)  		return ERR_PTR(-ENOMEM); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index b5c067bccc4..392adc41e2e 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -412,7 +412,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,  			*entry, *new;  	unsigned int nr; -	nr = hash_long(acred->uid, cache->hashbits); +	nr = hash_long(from_kuid(&init_user_ns, acred->uid), cache->hashbits);  	rcu_read_lock();  	hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { @@ -519,8 +519,8 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)  {  	struct rpc_auth *auth = task->tk_client->cl_auth;  	struct auth_cred acred = { -		.uid = 0, -		.gid = 0, +		.uid = GLOBAL_ROOT_UID, +		.gid = GLOBAL_ROOT_GID,  	};  	dprintk("RPC: %5u looking up %s cred\n", diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index 6ed6f201b02..b6badafc649 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c @@ -18,8 +18,8 @@  # define RPCDBG_FACILITY	RPCDBG_AUTH  #endif -#define RPC_MACHINE_CRED_USERID		((uid_t)0) -#define RPC_MACHINE_CRED_GROUPID	((gid_t)0) +#define RPC_MACHINE_CRED_USERID		GLOBAL_ROOT_UID +#define RPC_MACHINE_CRED_GROUPID	GLOBAL_ROOT_GID  struct generic_cred {  	struct rpc_cred gc_base; @@ -96,7 +96,9 @@ generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)  	dprintk("RPC:       allocated %s cred %p for uid %d gid %d\n",  			gcred->acred.machine_cred ? "machine" : "generic", -			gcred, acred->uid, acred->gid); +			gcred, +			from_kuid(&init_user_ns, acred->uid), +			from_kgid(&init_user_ns, acred->gid));  	return &gcred->gc_base;  } @@ -129,8 +131,8 @@ machine_cred_match(struct auth_cred *acred, struct generic_cred *gcred, int flag  {  	if (!gcred->acred.machine_cred ||  	    gcred->acred.principal != acred->principal || -	    gcred->acred.uid != acred->uid || -	    gcred->acred.gid != acred->gid) +	    !uid_eq(gcred->acred.uid, acred->uid) || +	    !gid_eq(gcred->acred.gid, acred->gid))  		return 0;  	return 1;  } @@ -147,8 +149,8 @@ generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)  	if (acred->machine_cred)  		return machine_cred_match(acred, gcred, flags); -	if (gcred->acred.uid != acred->uid || -	    gcred->acred.gid != acred->gid || +	if (!uid_eq(gcred->acred.uid, acred->uid) || +	    !gid_eq(gcred->acred.gid, acred->gid) ||  	    gcred->acred.machine_cred != 0)  		goto out_nomatch; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 911ef008b70..6ea29f4ed6c 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -255,7 +255,7 @@ err:  struct gss_upcall_msg {  	atomic_t count; -	uid_t	uid; +	kuid_t	uid;  	struct rpc_pipe_msg msg;  	struct list_head list;  	struct gss_auth *auth; @@ -302,11 +302,11 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)  }  static struct gss_upcall_msg * -__gss_find_upcall(struct rpc_pipe *pipe, uid_t uid) +__gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid)  {  	struct gss_upcall_msg *pos;  	list_for_each_entry(pos, &pipe->in_downcall, list) { -		if (pos->uid != uid) +		if (!uid_eq(pos->uid, uid))  			continue;  		atomic_inc(&pos->count);  		dprintk("RPC:       %s found msg %p\n", __func__, pos); @@ -394,8 +394,11 @@ gss_upcall_callback(struct rpc_task *task)  static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)  { -	gss_msg->msg.data = &gss_msg->uid; -	gss_msg->msg.len = sizeof(gss_msg->uid); +	uid_t uid = from_kuid(&init_user_ns, gss_msg->uid); +	memcpy(gss_msg->databuf, &uid, sizeof(uid)); +	gss_msg->msg.data = gss_msg->databuf; +	gss_msg->msg.len = sizeof(uid); +	BUG_ON(sizeof(uid) > UPCALL_BUF_LEN);  }  static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, @@ -408,7 +411,7 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,  	gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ",  				   mech->gm_name, -				   gss_msg->uid); +				   from_kuid(&init_user_ns, gss_msg->uid));  	p += gss_msg->msg.len;  	if (clnt->cl_principal) {  		len = sprintf(p, "target=%s ", clnt->cl_principal); @@ -444,7 +447,7 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg,  static struct gss_upcall_msg *  gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, -		uid_t uid, const char *service_name) +		kuid_t uid, const char *service_name)  {  	struct gss_upcall_msg *gss_msg;  	int vers; @@ -474,7 +477,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr  	struct gss_cred *gss_cred = container_of(cred,  			struct gss_cred, gc_base);  	struct gss_upcall_msg *gss_new, *gss_msg; -	uid_t uid = cred->cr_uid; +	kuid_t uid = cred->cr_uid;  	gss_new = gss_alloc_msg(gss_auth, clnt, uid, gss_cred->gc_principal);  	if (IS_ERR(gss_new)) @@ -516,7 +519,7 @@ gss_refresh_upcall(struct rpc_task *task)  	int err = 0;  	dprintk("RPC: %5u %s for uid %u\n", -		task->tk_pid, __func__, cred->cr_uid); +		task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_uid));  	gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);  	if (PTR_ERR(gss_msg) == -EAGAIN) {  		/* XXX: warning on the first, under the assumption we @@ -548,7 +551,8 @@ gss_refresh_upcall(struct rpc_task *task)  	gss_release_msg(gss_msg);  out:  	dprintk("RPC: %5u %s for uid %u result %d\n", -		task->tk_pid, __func__, cred->cr_uid, err); +		task->tk_pid, __func__, +		from_kuid(&init_user_ns, cred->cr_uid),	err);  	return err;  } @@ -561,7 +565,8 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)  	DEFINE_WAIT(wait);  	int err = 0; -	dprintk("RPC:       %s for uid %u\n", __func__, cred->cr_uid); +	dprintk("RPC:       %s for uid %u\n", +		__func__, from_kuid(&init_user_ns, cred->cr_uid));  retry:  	gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);  	if (PTR_ERR(gss_msg) == -EAGAIN) { @@ -603,7 +608,7 @@ out_intr:  	gss_release_msg(gss_msg);  out:  	dprintk("RPC:       %s for uid %u result %d\n", -		__func__, cred->cr_uid, err); +		__func__, from_kuid(&init_user_ns, cred->cr_uid), err);  	return err;  } @@ -617,7 +622,8 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)  	struct gss_upcall_msg *gss_msg;  	struct rpc_pipe *pipe = RPC_I(filp->f_dentry->d_inode)->pipe;  	struct gss_cl_ctx *ctx; -	uid_t uid; +	uid_t id; +	kuid_t uid;  	ssize_t err = -EFBIG;  	if (mlen > MSG_BUF_MAXSIZE) @@ -632,12 +638,18 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)  		goto err;  	end = (const void *)((char *)buf + mlen); -	p = simple_get_bytes(buf, end, &uid, sizeof(uid)); +	p = simple_get_bytes(buf, end, &id, sizeof(id));  	if (IS_ERR(p)) {  		err = PTR_ERR(p);  		goto err;  	} +	uid = make_kuid(&init_user_ns, id); +	if (!uid_valid(uid)) { +		err = -EINVAL; +		goto err; +	} +  	err = -ENOMEM;  	ctx = gss_alloc_context();  	if (ctx == NULL) @@ -1058,7 +1070,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)  	int err = -ENOMEM;  	dprintk("RPC:       %s for uid %d, flavor %d\n", -		__func__, acred->uid, auth->au_flavor); +		__func__, from_kuid(&init_user_ns, acred->uid), +		auth->au_flavor);  	if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))  		goto out_err; @@ -1114,7 +1127,7 @@ out:  	}  	if (gss_cred->gc_principal != NULL)  		return 0; -	return rc->cr_uid == acred->uid; +	return uid_eq(rc->cr_uid, acred->uid);  }  /* diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 73e95738660..ecd1d58bf61 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -418,6 +418,7 @@ static int rsc_parse(struct cache_detail *cd,  {  	/* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */  	char *buf = mesg; +	int id;  	int len, rv;  	struct rsc rsci, *rscp = NULL;  	time_t expiry; @@ -444,7 +445,7 @@ static int rsc_parse(struct cache_detail *cd,  		goto out;  	/* uid, or NEGATIVE */ -	rv = get_int(&mesg, &rsci.cred.cr_uid); +	rv = get_int(&mesg, &id);  	if (rv == -EINVAL)  		goto out;  	if (rv == -ENOENT) @@ -452,8 +453,16 @@ static int rsc_parse(struct cache_detail *cd,  	else {  		int N, i; +		/* uid */ +		rsci.cred.cr_uid = make_kuid(&init_user_ns, id); +		if (!uid_valid(rsci.cred.cr_uid)) +			goto out; +  		/* gid */ -		if (get_int(&mesg, &rsci.cred.cr_gid)) +		if (get_int(&mesg, &id)) +			goto out; +		rsci.cred.cr_gid = make_kgid(&init_user_ns, id); +		if (!gid_valid(rsci.cred.cr_gid))  			goto out;  		/* number of additional gid's */ @@ -467,11 +476,10 @@ static int rsc_parse(struct cache_detail *cd,  		/* gid's */  		status = -EINVAL;  		for (i=0; i<N; i++) { -			gid_t gid;  			kgid_t kgid; -			if (get_int(&mesg, &gid)) +			if (get_int(&mesg, &id))  				goto out; -			kgid = make_kgid(&init_user_ns, gid); +			kgid = make_kgid(&init_user_ns, id);  			if (!gid_valid(kgid))  				goto out;  			GROUP_AT(rsci.cred.cr_group_info, i) = kgid; diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 52c5abdee21..dc37021fc3e 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -18,8 +18,8 @@  struct unx_cred {  	struct rpc_cred		uc_base; -	gid_t			uc_gid; -	gid_t			uc_gids[NFS_NGROUPS]; +	kgid_t			uc_gid; +	kgid_t			uc_gids[NFS_NGROUPS];  };  #define uc_uid			uc_base.cr_uid @@ -65,7 +65,8 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)  	unsigned int i;  	dprintk("RPC:       allocating UNIX cred for uid %d gid %d\n", -			acred->uid, acred->gid); +			from_kuid(&init_user_ns, acred->uid), +			from_kgid(&init_user_ns, acred->gid));  	if (!(cred = kmalloc(sizeof(*cred), GFP_NOFS)))  		return ERR_PTR(-ENOMEM); @@ -79,13 +80,10 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)  		groups = NFS_NGROUPS;  	cred->uc_gid = acred->gid; -	for (i = 0; i < groups; i++) { -		gid_t gid; -		gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); -		cred->uc_gids[i] = gid; -	} +	for (i = 0; i < groups; i++) +		cred->uc_gids[i] = GROUP_AT(acred->group_info, i);  	if (i < NFS_NGROUPS) -		cred->uc_gids[i] = NOGROUP; +		cred->uc_gids[i] = INVALID_GID;  	return &cred->uc_base;  } @@ -123,21 +121,17 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)  	unsigned int i; -	if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid) +	if (!uid_eq(cred->uc_uid, acred->uid) || !gid_eq(cred->uc_gid, acred->gid))  		return 0;  	if (acred->group_info != NULL)  		groups = acred->group_info->ngroups;  	if (groups > NFS_NGROUPS)  		groups = NFS_NGROUPS; -	for (i = 0; i < groups ; i++) { -		gid_t gid; -		gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); -		if (cred->uc_gids[i] != gid) +	for (i = 0; i < groups ; i++) +		if (!gid_eq(cred->uc_gids[i], GROUP_AT(acred->group_info, i)))  			return 0; -	} -	if (groups < NFS_NGROUPS && -	    cred->uc_gids[groups] != NOGROUP) +	if (groups < NFS_NGROUPS && gid_valid(cred->uc_gids[groups]))  		return 0;  	return 1;  } @@ -163,11 +157,11 @@ unx_marshal(struct rpc_task *task, __be32 *p)  	 */  	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); -	*p++ = htonl((u32) cred->uc_uid); -	*p++ = htonl((u32) cred->uc_gid); +	*p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid)); +	*p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid));  	hold = p++; -	for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++) -		*p++ = htonl((u32) cred->uc_gids[i]); +	for (i = 0; i < 16 && gid_valid(cred->uc_gids[i]); i++) +		*p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i]));  	*hold = htonl(p - hold - 1);		/* gid array length */  	*base = htonl((p - base - 1) << 2);	/* cred length */ diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 4d012920373..a1852e19ed0 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -415,10 +415,15 @@ svcauth_unix_info_release(struct svc_xprt *xpt)  struct unix_gid {  	struct cache_head	h; -	uid_t			uid; +	kuid_t			uid;  	struct group_info	*gi;  }; +static int unix_gid_hash(kuid_t uid) +{ +	return hash_long(from_kuid(&init_user_ns, uid), GID_HASHBITS); +} +  static void unix_gid_put(struct kref *kref)  {  	struct cache_head *item = container_of(kref, struct cache_head, ref); @@ -433,7 +438,7 @@ static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew)  {  	struct unix_gid *orig = container_of(corig, struct unix_gid, h);  	struct unix_gid *new = container_of(cnew, struct unix_gid, h); -	return orig->uid == new->uid; +	return uid_eq(orig->uid, new->uid);  }  static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem)  { @@ -465,7 +470,7 @@ static void unix_gid_request(struct cache_detail *cd,  	char tuid[20];  	struct unix_gid *ug = container_of(h, struct unix_gid, h); -	snprintf(tuid, 20, "%u", ug->uid); +	snprintf(tuid, 20, "%u", from_kuid(&init_user_ns, ug->uid));  	qword_add(bpp, blen, tuid);  	(*bpp)[-1] = '\n';  } @@ -475,13 +480,14 @@ static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h)  	return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request);  } -static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid); +static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid);  static int unix_gid_parse(struct cache_detail *cd,  			char *mesg, int mlen)  {  	/* uid expiry Ngid gid0 gid1 ... gidN-1 */ -	int uid; +	int id; +	kuid_t uid;  	int gids;  	int rv;  	int i; @@ -493,9 +499,12 @@ static int unix_gid_parse(struct cache_detail *cd,  		return -EINVAL;  	mesg[mlen-1] = 0; -	rv = get_int(&mesg, &uid); +	rv = get_int(&mesg, &id);  	if (rv)  		return -EINVAL; +	uid = make_kuid(&init_user_ns, id); +	if (!uid_valid(uid)) +		return -EINVAL;  	ug.uid = uid;  	expiry = get_expiry(&mesg); @@ -530,7 +539,7 @@ static int unix_gid_parse(struct cache_detail *cd,  		ug.h.expiry_time = expiry;  		ch = sunrpc_cache_update(cd,  					 &ug.h, &ugp->h, -					 hash_long(uid, GID_HASHBITS)); +					 unix_gid_hash(uid));  		if (!ch)  			err = -ENOMEM;  		else { @@ -549,7 +558,7 @@ static int unix_gid_show(struct seq_file *m,  			 struct cache_detail *cd,  			 struct cache_head *h)  { -	struct user_namespace *user_ns = current_user_ns(); +	struct user_namespace *user_ns = &init_user_ns;  	struct unix_gid *ug;  	int i;  	int glen; @@ -565,7 +574,7 @@ static int unix_gid_show(struct seq_file *m,  	else  		glen = 0; -	seq_printf(m, "%u %d:", ug->uid, glen); +	seq_printf(m, "%u %d:", from_kuid_munged(user_ns, ug->uid), glen);  	for (i = 0; i < glen; i++)  		seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i)));  	seq_printf(m, "\n"); @@ -615,20 +624,20 @@ void unix_gid_cache_destroy(struct net *net)  	cache_destroy_net(cd, net);  } -static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid) +static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid)  {  	struct unix_gid ug;  	struct cache_head *ch;  	ug.uid = uid; -	ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS)); +	ch = sunrpc_cache_lookup(cd, &ug.h, unix_gid_hash(uid));  	if (ch)  		return container_of(ch, struct unix_gid, h);  	else  		return NULL;  } -static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) +static struct group_info *unix_gid_find(kuid_t uid, struct svc_rqst *rqstp)  {  	struct unix_gid *ug;  	struct group_info *gi; @@ -750,8 +759,8 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)  	}  	/* Signal that mapping to nobody uid/gid is required */ -	cred->cr_uid = (uid_t) -1; -	cred->cr_gid = (gid_t) -1; +	cred->cr_uid = INVALID_UID; +	cred->cr_gid = INVALID_GID;  	cred->cr_group_info = groups_alloc(0);  	if (cred->cr_group_info == NULL)  		return SVC_CLOSE; /* kmalloc failure - client must retry */ @@ -812,8 +821,10 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)  	argv->iov_base = (void*)((__be32*)argv->iov_base + slen);	/* skip machname */  	argv->iov_len -= slen*4; -	cred->cr_uid = svc_getnl(argv);		/* uid */ -	cred->cr_gid = svc_getnl(argv);		/* gid */ +	cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */ +	cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */ +	if (!uid_valid(cred->cr_uid) || !gid_valid(cred->cr_gid)) +		goto badcred;  	slen = svc_getnl(argv);			/* gids length */  	if (slen > 16 || (len -= (slen + 2)*4) < 0)  		goto badcred;  |