diff options
Diffstat (limited to 'fs/smb/server/smb2pdu.c')
| -rw-r--r-- | fs/smb/server/smb2pdu.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index b73167785e87..bec692bca1ca 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -1689,7 +1689,7 @@ static int ntlm_authenticate(struct ksmbd_work *work, struct ksmbd_conn *conn = work->conn; struct ksmbd_session *sess = work->sess; struct ksmbd_user *user; - char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {}; + char channel_key[CIFS_KEY_SIZE] = {}; char *auth_key = conn->binding ? channel_key : sess->sess_key; u64 prev_id; bool binding = conn->binding; @@ -1826,7 +1826,7 @@ static int krb5_authenticate(struct ksmbd_work *work, struct ksmbd_conn *conn = work->conn; struct ksmbd_session *sess = work->sess; char *in_blob, *out_blob; - char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {}; + char channel_key[CIFS_KEY_SIZE] = {}; char *auth_key = conn->binding ? channel_key : sess->sess_key; u64 prev_sess_id; bool binding = conn->binding; @@ -6597,9 +6597,8 @@ static int smb2_rename(struct ksmbd_work *work, pr_err("failed to store stream name in xattr: %d\n", rc); rc = -EINVAL; - goto out; } - + kfree(xattr_stream_name); goto out; } @@ -6781,6 +6780,7 @@ static int set_file_allocation_info(struct ksmbd_work *work, */ loff_t alloc_blks; + u64 alloc_size; struct inode *inode; struct kstat stat; int rc; @@ -6796,7 +6796,19 @@ static int set_file_allocation_info(struct ksmbd_work *work, if (rc) return rc; - alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9; + /* + * AllocationSize is fully client-controlled (the caller only + * validates the fixed 8-byte buffer length). Reject values that + * would overflow the "round up to 512-byte blocks" conversion + * below instead of silently wrapping it to a tiny block count, + * which would truncate the file to a size the client never + * asked for. + */ + alloc_size = le64_to_cpu(file_alloc_info->AllocationSize); + if (alloc_size > MAX_LFS_FILESIZE - 511) + return -EINVAL; + + alloc_blks = (alloc_size + 511) >> 9; inode = file_inode(fp->filp); if (alloc_blks > stat.blocks) { @@ -7433,6 +7445,15 @@ int smb2_read(struct ksmbd_work *work) goto out; } + /* + * ksmbd_vfs_read() fills only nbytes; the [nbytes, ALIGN(nbytes, 8)) + * tail of the un-zeroed buffer is transmitted as compound-response + * alignment padding, leaking uninitialized kernel memory to the + * client. Zero just that tail. + */ + if (nbytes & 7) + memset(aux_payload_buf + nbytes, 0, ALIGN(nbytes, 8) - nbytes); + if ((nbytes == 0 && length != 0) || nbytes < mincount) { kvfree(aux_payload_buf); rsp->hdr.Status = STATUS_END_OF_FILE; @@ -9787,22 +9808,21 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work) } if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) { - __u8 *hash_value; + ksmbd_conn_lock(conn); if (conn->binding) { struct preauth_session *preauth_sess; preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); - if (!preauth_sess) - return; - hash_value = preauth_sess->Preauth_HashValue; - } else { - hash_value = sess->Preauth_HashValue; - if (!hash_value) - return; + if (preauth_sess) + ksmbd_gen_preauth_integrity_hash(conn, + work->response_buf, + preauth_sess->Preauth_HashValue); + } else if (sess->Preauth_HashValue) { + ksmbd_gen_preauth_integrity_hash(conn, work->response_buf, + sess->Preauth_HashValue); } - ksmbd_gen_preauth_integrity_hash(conn, work->response_buf, - hash_value); + ksmbd_conn_unlock(conn); } } |