mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
seven client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmn+DfMACgkQiiy9cAdy T1FlwQv/bOScs7kYk5M5cCUf8kvA3kHBBmXcewSXYVzEaspJFd49IOrbejh07UXR KmfJ4zgX3usbFNzXkmm8AKrax9ZJd8vmdey7/+ELxuBoYiyyDTATZ/VG+yDae0Cu zU7pZNv99LppFkkxQM+7hpBtbazRUTZu3VYprFZ+UCWPupKZs/fQm9huBzJPf2bn dMkojp/AAOGmhuRok3DWA1fu/BvFgslXPk4QohIfWxd0zRGVXQLRkOXvVI34bhR2 IOLH1PohkFsajqWClEyikCaFjhW8ZpmmHVl2t+NZer/wYoq2Mp2Ad9NkILmfrWR1 w4NSxh73emsllZpDkXYULlM9voxnjIXpvg/wPP+DA4yhuThwluJyCgsEkoInMw6X mLM8JiD4EMQhxKiZwtrO4gd/TshSBhm01ly0a6VwvV2p1mvW2cJH2VAZyoC+xN8d CabEmVnJuiwh4SPwKwsJN3bePwvjp30j1oVRspQthTQRrunyY4hkXr3z2Hpo6TNb tMudF/Qh =A8aI -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
81d6f78075
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1713,17 +1713,30 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
|
|||
is_binding = (ses->ses_status == SES_GOOD);
|
||||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
/*
|
||||
* Per MS-SMB2 3.2.5.3, Session.SessionKey is the first 16 bytes of the
|
||||
* GSS cryptographic key, right-padded with zero bytes if shorter.
|
||||
* Allocate at least SMB2_NTLMV2_SESSKEY_SIZE bytes (zeroed) so the KDF
|
||||
* input buffer is always valid for HMAC-SHA256 even with deprecated
|
||||
* Kerberos enctypes that return a short session key.
|
||||
*/
|
||||
if (unlikely(msg->sesskey_len < SMB2_NTLMV2_SESSKEY_SIZE))
|
||||
cifs_dbg(VFS,
|
||||
"short GSS session key (%u bytes); zero-padding per MS-SMB2 3.2.5.3\n",
|
||||
msg->sesskey_len);
|
||||
|
||||
kfree_sensitive(ses->auth_key.response);
|
||||
ses->auth_key.response = kmemdup(msg->data,
|
||||
msg->sesskey_len,
|
||||
GFP_KERNEL);
|
||||
ses->auth_key.len = max_t(unsigned int, msg->sesskey_len,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
|
||||
if (!ses->auth_key.response) {
|
||||
cifs_dbg(VFS, "%s: can't allocate (%u bytes) memory\n",
|
||||
__func__, msg->sesskey_len);
|
||||
__func__, ses->auth_key.len);
|
||||
ses->auth_key.len = 0;
|
||||
rc = -ENOMEM;
|
||||
goto out_put_spnego_key;
|
||||
}
|
||||
ses->auth_key.len = msg->sesskey_len;
|
||||
memcpy(ses->auth_key.response, msg->data, msg->sesskey_len);
|
||||
|
||||
sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
|
||||
sess_data->iov[1].iov_len = msg->secblob_len;
|
||||
|
|
|
|||
|
|
@ -251,7 +251,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
}
|
||||
|
||||
static void generate_key(struct cifs_ses *ses, struct kvec label,
|
||||
struct kvec context, __u8 *key, unsigned int key_size)
|
||||
struct kvec context, __u8 *key, unsigned int key_size,
|
||||
unsigned int full_key_size)
|
||||
{
|
||||
unsigned char zero = 0x0;
|
||||
__u8 i[4] = {0, 0, 0, 1};
|
||||
|
|
@ -265,7 +266,7 @@ static void generate_key(struct cifs_ses *ses, struct kvec label,
|
|||
memset(key, 0x0, key_size);
|
||||
|
||||
hmac_sha256_init_usingrawkey(&hmac_ctx, ses->auth_key.response,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
full_key_size);
|
||||
hmac_sha256_update(&hmac_ctx, i, 4);
|
||||
hmac_sha256_update(&hmac_ctx, label.iov_base, label.iov_len);
|
||||
hmac_sha256_update(&hmac_ctx, &zero, 1);
|
||||
|
|
@ -298,6 +299,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
|||
struct TCP_Server_Info *server,
|
||||
const struct derivation_triplet *ptriplet)
|
||||
{
|
||||
unsigned int full_key_size = SMB2_NTLMV2_SESSKEY_SIZE;
|
||||
bool is_binding = false;
|
||||
int chan_index = 0;
|
||||
|
||||
|
|
@ -330,12 +332,24 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
|||
if (is_binding) {
|
||||
generate_key(ses, ptriplet->signing.label,
|
||||
ptriplet->signing.context,
|
||||
ses->chans[chan_index].signkey,
|
||||
SMB3_SIGN_KEY_SIZE);
|
||||
ses->chans[chan_index].signkey, SMB3_SIGN_KEY_SIZE,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
} else {
|
||||
generate_key(ses, ptriplet->signing.label,
|
||||
ptriplet->signing.context,
|
||||
ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
|
||||
ptriplet->signing.context, ses->smb3signingkey,
|
||||
SMB3_SIGN_KEY_SIZE, SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
|
||||
/*
|
||||
* Per MS-SMB2 3.2.5.3.1, signing key always uses Session.SessionKey
|
||||
* (first 16 bytes). Encryption/decryption keys use
|
||||
* Session.FullSessionKey when dialect is 3.1.1 and cipher is
|
||||
* AES-256-CCM or AES-256-GCM, otherwise Session.SessionKey.
|
||||
*/
|
||||
|
||||
if (server->dialect == SMB311_PROT_ID &&
|
||||
(server->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
|
||||
server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
||||
full_key_size = ses->auth_key.len;
|
||||
|
||||
/* safe to access primary channel, since it will never go away */
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
|
@ -345,10 +359,13 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
|||
|
||||
generate_key(ses, ptriplet->encryption.label,
|
||||
ptriplet->encryption.context,
|
||||
ses->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE);
|
||||
ses->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE,
|
||||
full_key_size);
|
||||
|
||||
generate_key(ses, ptriplet->decryption.label,
|
||||
ptriplet->decryption.context,
|
||||
ses->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
|
||||
ses->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE,
|
||||
full_key_size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
|
||||
|
|
@ -361,7 +378,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
|||
&ses->Suid);
|
||||
cifs_dbg(VFS, "Cipher type %d\n", server->cipher_type);
|
||||
cifs_dbg(VFS, "Session Key %*ph\n",
|
||||
SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response);
|
||||
(int)ses->auth_key.len, ses->auth_key.response);
|
||||
cifs_dbg(VFS, "Signing Key %*ph\n",
|
||||
SMB3_SIGN_KEY_SIZE, ses->smb3signingkey);
|
||||
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user