Commit 8abf2775 authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

cifs: Use kuids and kgids SID to uid/gid mapping



Update id_mode_to_cifs_acl to take a kuid_t and a kgid_t.

Replace NO_CHANGE_32 with INVALID_UID and INVALID_GID, and tests for
NO_CHANGE_32 with uid_valid and gid_valid.

Carefully unpack the value returned from request_key.  memcpy the
value into the expected type.  The convert the uid/gid into a
kuid/kgid.  And then only if the result is a valid kuid or kgid update
fuid/fgid.

Cc: Steve French <smfrench@gmail.com>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 8e3028b9
Loading
Loading
Loading
Loading
+29 −14
Original line number Diff line number Diff line
@@ -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.
@@ -306,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);
@@ -776,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;
@@ -808,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;
			}
@@ -826,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;
			}
@@ -1004,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 */
+0 −1
Original line number Diff line number Diff line
@@ -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"
+1 −1
Original line number Diff line number Diff line
@@ -161,7 +161,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 *,
+4 −4
Original line number Diff line number Diff line
@@ -2090,8 +2090,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);
@@ -2150,7 +2150,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) {
@@ -2174,7 +2174,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);