mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
ksmbd: return buffer overflow for partial filesystem info
The query-info buffer check returns STATUS_INFO_LENGTH_MISMATCH for every output buffer smaller than the complete response. Variable-length filesystem information instead requires STATUS_BUFFER_OVERFLOW when the fixed portion fits but the complete data does not. Pass the fixed size for each filesystem information class to the buffer checker. Keep INFO_LENGTH_MISMATCH for buffers below that size, and return BUFFER_OVERFLOW with a response truncated to the requested length for larger partial buffers. This fixes smb2.getinfo.qfs_buffercheck. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
8184c425a1
commit
0ecd35fac4
|
|
@ -5115,21 +5115,30 @@ int smb2_query_dir(struct ksmbd_work *work)
|
|||
/**
|
||||
* buffer_check_err() - helper function to check buffer errors
|
||||
* @reqOutputBufferLength: max buffer length expected in command response
|
||||
* @fixed_len: minimum fixed response length
|
||||
* @rsp: query info response buffer contains output buffer length
|
||||
* @rsp_org: base response buffer pointer in case of chained response
|
||||
*
|
||||
* Return: 0 on success, otherwise error
|
||||
*/
|
||||
static int buffer_check_err(int reqOutputBufferLength,
|
||||
unsigned int fixed_len,
|
||||
struct smb2_query_info_rsp *rsp,
|
||||
void *rsp_org)
|
||||
{
|
||||
if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) {
|
||||
unsigned int output_len = le32_to_cpu(rsp->OutputBufferLength);
|
||||
|
||||
if (reqOutputBufferLength < fixed_len) {
|
||||
pr_err("Invalid Buffer Size Requested\n");
|
||||
rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
*(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reqOutputBufferLength < output_len) {
|
||||
rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;
|
||||
rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -5192,11 +5201,13 @@ static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
|
|||
case FILE_STANDARD_INFORMATION:
|
||||
get_standard_info_pipe(rsp, rsp_org);
|
||||
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
rsp, rsp_org);
|
||||
break;
|
||||
case FILE_INTERNAL_INFORMATION:
|
||||
get_internal_info_pipe(rsp, id, rsp_org);
|
||||
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
rsp, rsp_org);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -6013,6 +6024,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
|
|||
}
|
||||
if (!rc)
|
||||
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
rsp, work->response_buf);
|
||||
ksmbd_fd_put(work, fp);
|
||||
|
||||
|
|
@ -6034,6 +6046,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
struct kstatfs stfs;
|
||||
struct path path;
|
||||
int rc = 0, len;
|
||||
unsigned int fixed_len = 0;
|
||||
|
||||
if (!share->path)
|
||||
return -EIO;
|
||||
|
|
@ -6068,6 +6081,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->DeviceCharacteristics |=
|
||||
cpu_to_le32(FILE_READ_ONLY_DEVICE);
|
||||
rsp->OutputBufferLength = cpu_to_le32(8);
|
||||
fixed_len = 8;
|
||||
break;
|
||||
}
|
||||
case FS_ATTRIBUTE_INFORMATION:
|
||||
|
|
@ -6120,6 +6134,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->FileSystemNameLen = cpu_to_le32(len);
|
||||
sz = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + len;
|
||||
rsp->OutputBufferLength = cpu_to_le32(sz);
|
||||
fixed_len = 16;
|
||||
break;
|
||||
}
|
||||
case FS_VOLUME_INFORMATION:
|
||||
|
|
@ -6147,6 +6162,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->SupportsObjects = 0;
|
||||
sz = sizeof(struct filesystem_vol_info) + len;
|
||||
rsp->OutputBufferLength = cpu_to_le32(sz);
|
||||
fixed_len = 24;
|
||||
break;
|
||||
}
|
||||
case FS_SIZE_INFORMATION:
|
||||
|
|
@ -6159,6 +6175,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->SectorsPerAllocationUnit = cpu_to_le32(1);
|
||||
info->BytesPerSector = cpu_to_le32(stfs.f_bsize);
|
||||
rsp->OutputBufferLength = cpu_to_le32(24);
|
||||
fixed_len = 24;
|
||||
break;
|
||||
}
|
||||
case FS_FULL_SIZE_INFORMATION:
|
||||
|
|
@ -6174,6 +6191,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->SectorsPerAllocationUnit = cpu_to_le32(1);
|
||||
info->BytesPerSector = cpu_to_le32(stfs.f_bsize);
|
||||
rsp->OutputBufferLength = cpu_to_le32(32);
|
||||
fixed_len = 32;
|
||||
break;
|
||||
}
|
||||
case FS_OBJECT_ID_INFORMATION:
|
||||
|
|
@ -6194,6 +6212,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->extended_info.rel_date = 0;
|
||||
memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0"));
|
||||
rsp->OutputBufferLength = cpu_to_le32(64);
|
||||
fixed_len = 64;
|
||||
break;
|
||||
}
|
||||
case FS_SECTOR_SIZE_INFORMATION:
|
||||
|
|
@ -6215,6 +6234,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->ByteOffsetForSectorAlignment = 0;
|
||||
info->ByteOffsetForPartitionAlignment = 0;
|
||||
rsp->OutputBufferLength = cpu_to_le32(28);
|
||||
fixed_len = 28;
|
||||
break;
|
||||
}
|
||||
case FS_CONTROL_INFORMATION:
|
||||
|
|
@ -6235,6 +6255,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID);
|
||||
info->Padding = 0;
|
||||
rsp->OutputBufferLength = cpu_to_le32(48);
|
||||
fixed_len = 48;
|
||||
break;
|
||||
}
|
||||
case FS_POSIX_INFORMATION:
|
||||
|
|
@ -6255,6 +6276,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->TotalFileNodes = cpu_to_le64(stfs.f_files);
|
||||
info->FreeFileNodes = cpu_to_le64(stfs.f_ffree);
|
||||
rsp->OutputBufferLength = cpu_to_le32(56);
|
||||
fixed_len = 56;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -6263,6 +6285,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
|
||||
fixed_len,
|
||||
rsp, work->response_buf);
|
||||
path_put(&path);
|
||||
|
||||
|
|
@ -6364,6 +6387,7 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
|
|||
|
||||
rsp->OutputBufferLength = cpu_to_le32(secdesclen);
|
||||
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
rsp, work->response_buf);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user