Commit 81d6f780 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v7.1-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

 - Fix for two ACL issues (security fix to validate dacloffset better
   and chmod fix)

 - Fix out of bounds reads (in check_wsl_eas and smb2_check_msg for
   symlinks)

 - Two Kerberos fixes including an important one when AES-256 encryption
   chosen

 - Fix open_cached_dir problem when directory leases disabled

* tag 'v7.1-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  smb: client: validate dacloffset before building DACL pointers
  smb/client: fix out-of-bounds read in smb2_compound_op()
  smb/client: fix out-of-bounds read in symlink_data()
  smb: client: Zero-pad short GSS session keys per MS-SMB2
  smb: client: Use FullSessionKey for AES-256 encryption key derivation
  smb: client: use kzalloc to zero-initialize security descriptor buffer
  cifs: abort open_cached_dir if we don't request leases
parents 8bb44576 f98b4815
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -286,6 +286,14 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
			    &rqst[0], &oplock, &oparms, utf16_path);
	if (rc)
		goto oshr_free;

	if (oplock != SMB2_OPLOCK_LEVEL_II) {
		rc = -EINVAL;
		cifs_dbg(FYI, "%s: Oplock level %d not suitable for cached directory\n",
			 __func__, oplock);
		goto oshr_free;
	}

	smb2_set_next_command(tcon, &rqst[0]);

	memset(&qi_iov, 0, sizeof(qi_iov));
+33 −4
Original line number Diff line number Diff line
@@ -1264,6 +1264,17 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl)
	return 0;
}

static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
{
	if (acl_len < sizeof(struct smb_acl))
		return false;

	if (dacloffset < sizeof(struct smb_ntsd))
		return false;

	return dacloffset <= acl_len - sizeof(struct smb_acl);
}


/* Convert CIFS ACL to POSIX form */
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
@@ -1284,7 +1295,6 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
	group_sid_ptr = (struct smb_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));
	dacloffset = le32_to_cpu(pntsd->dacloffset);
	dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
	cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
		 le32_to_cpu(pntsd->gsidoffset),
@@ -1315,11 +1325,18 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
		return rc;
	}

	if (dacloffset)
	if (dacloffset) {
		if (!dacl_offset_valid(acl_len, dacloffset)) {
			cifs_dbg(VFS, "Server returned illegal DACL offset\n");
			return -EINVAL;
		}

		dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
		parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
			   group_sid_ptr, fattr, get_mode_from_special_sid);
	else
	} else {
		cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
	}

	return rc;
}
@@ -1342,6 +1359,11 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,

	dacloffset = le32_to_cpu(pntsd->dacloffset);
	if (dacloffset) {
		if (!dacl_offset_valid(secdesclen, dacloffset)) {
			cifs_dbg(VFS, "Server returned illegal DACL offset\n");
			return -EINVAL;
		}

		dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
		rc = validate_dacl(dacl_ptr, end_of_acl);
		if (rc)
@@ -1710,6 +1732,12 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
		nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
		dacloffset = le32_to_cpu(pntsd->dacloffset);
		if (dacloffset) {
			if (!dacl_offset_valid(secdesclen, dacloffset)) {
				cifs_dbg(VFS, "Server returned illegal DACL offset\n");
				rc = -EINVAL;
				goto id_mode_to_cifs_acl_exit;
			}

			dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
			rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
			if (rc) {
@@ -1732,7 +1760,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
	 * descriptor parameters, and security descriptor itself
	 */
	nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN);
	pnntsd = kmalloc(nsecdesclen, GFP_KERNEL);
	pnntsd = kzalloc(nsecdesclen, GFP_KERNEL);
	if (!pnntsd) {
		kfree(pntsd);
		cifs_put_tlink(tlink);
@@ -1752,6 +1780,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
		rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
		cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
	}
id_mode_to_cifs_acl_exit:
	cifs_put_tlink(tlink);

	kfree(pnntsd);
+1 −1
Original line number Diff line number Diff line
@@ -296,7 +296,7 @@ static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug
		break;
	case SMB2_ENCRYPTION_AES256_CCM:
	case SMB2_ENCRYPTION_AES256_GCM:
		out.session_key_length = CIFS_SESS_KEY_SIZE;
		out.session_key_length = ses->auth_key.len;
		out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE;
		break;
	default:
+8 −4
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
	u32 outlen, next;
	u16 vlen;
	u8 nlen;
	u8 *end;
	u8 *ea_end, *iov_end;

	outlen = le32_to_cpu(rsp->OutputBufferLength);
	if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
@@ -120,15 +120,19 @@ static int check_wsl_eas(struct kvec *rsp_iov)

	ea = (void *)((u8 *)rsp_iov->iov_base +
		      le16_to_cpu(rsp->OutputBufferOffset));
	end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
	ea_end = (u8 *)ea + outlen;
	iov_end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
	if (ea_end > iov_end)
		return -EINVAL;

	for (;;) {
		if ((u8 *)ea > end - sizeof(*ea))
		if ((u8 *)ea > ea_end - sizeof(*ea))
			return -EINVAL;

		nlen = ea->ea_name_length;
		vlen = le16_to_cpu(ea->ea_value_length);
		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
		    (u8 *)ea->ea_data + nlen + 1 + vlen > end)
		    (u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
			return -EINVAL;

		switch (vlen) {
+2 −1
Original line number Diff line number Diff line
@@ -241,7 +241,8 @@ smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
	if (len != calc_len) {
		/* create failed on symlink */
		if (command == SMB2_CREATE_HE &&
		    shdr->Status == STATUS_STOPPED_ON_SYMLINK)
		    shdr->Status == STATUS_STOPPED_ON_SYMLINK &&
		    len > calc_len)
			return 0;
		/* Windows 7 server returns 24 bytes more */
		if (calc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
Loading