mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
ksmbd: fix partial file information responses
Variable-length file information handlers use the client output length while constructing the response. FILE_ALL_INFORMATION can consequently return -EINVAL before the common buffer check, while stream information can stop building the complete result too early. Build the complete response within the available server response buffer and apply the client output length only when selecting the final status and transmitted length. Use the protocol-defined fixed sizes for all, alternate-name, and stream information to distinguish STATUS_INFO_LENGTH_MISMATCH from STATUS_BUFFER_OVERFLOW. This fixes smb2.getinfo.qfile_buffercheck. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
d40c24634f
commit
6b8b79226b
|
|
@ -5486,7 +5486,6 @@ static int get_file_all_info(struct ksmbd_work *work,
|
|||
char *filename;
|
||||
u64 time;
|
||||
int ret, buf_free_len, filename_len;
|
||||
struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
|
||||
|
||||
if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
|
||||
ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n",
|
||||
|
|
@ -5499,10 +5498,9 @@ static int get_file_all_info(struct ksmbd_work *work,
|
|||
return PTR_ERR(filename);
|
||||
|
||||
filename_len = strlen(filename);
|
||||
buf_free_len = smb2_calc_max_out_buf_len(work,
|
||||
buf_free_len = smb2_resp_buf_len(work,
|
||||
offsetof(struct smb2_query_info_rsp, Buffer) +
|
||||
offsetof(struct smb2_file_all_info, FileName),
|
||||
le32_to_cpu(req->OutputBufferLength));
|
||||
offsetof(struct smb2_file_all_info, FileName));
|
||||
if (buf_free_len < (filename_len + 1) * 2) {
|
||||
kfree(filename);
|
||||
return -EINVAL;
|
||||
|
|
@ -5593,7 +5591,6 @@ static int get_file_stream_info(struct ksmbd_work *work,
|
|||
ssize_t xattr_list_len;
|
||||
int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
|
||||
int buf_free_len;
|
||||
struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
|
||||
int ret;
|
||||
|
||||
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
|
||||
|
|
@ -5603,10 +5600,8 @@ static int get_file_stream_info(struct ksmbd_work *work,
|
|||
|
||||
file_info = (struct smb2_file_stream_info *)rsp->Buffer;
|
||||
|
||||
buf_free_len =
|
||||
smb2_calc_max_out_buf_len(work,
|
||||
offsetof(struct smb2_query_info_rsp, Buffer),
|
||||
le32_to_cpu(req->OutputBufferLength));
|
||||
buf_free_len = smb2_resp_buf_len(work,
|
||||
offsetof(struct smb2_query_info_rsp, Buffer));
|
||||
if (buf_free_len < 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -5919,6 +5914,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
|
|||
struct ksmbd_file *fp;
|
||||
int fileinfoclass = 0;
|
||||
int rc = 0;
|
||||
unsigned int fixed_len;
|
||||
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
|
||||
|
||||
if (test_share_config_flag(work->tcon->share_conf,
|
||||
|
|
@ -6022,10 +6018,23 @@ static int smb2_get_info_file(struct ksmbd_work *work,
|
|||
fileinfoclass);
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
fixed_len = le32_to_cpu(rsp->OutputBufferLength);
|
||||
switch (fileinfoclass) {
|
||||
case FILE_ALL_INFORMATION:
|
||||
fixed_len = FILE_ALL_INFORMATION_SIZE;
|
||||
break;
|
||||
case FILE_ALTERNATE_NAME_INFORMATION:
|
||||
fixed_len = FILE_ALTERNATE_NAME_INFORMATION_SIZE;
|
||||
break;
|
||||
case FILE_STREAM_INFORMATION:
|
||||
fixed_len = FILE_STREAM_INFORMATION_SIZE;
|
||||
break;
|
||||
}
|
||||
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
fixed_len,
|
||||
rsp, work->response_buf);
|
||||
}
|
||||
ksmbd_fd_put(work, fp);
|
||||
|
||||
iov_pin_out:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user