]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: fix credit charge calculation for SMB2 QUERY_INFO
authorNamjae Jeon <linkinjeon@kernel.org>
Fri, 26 Jun 2026 01:51:16 +0000 (10:51 +0900)
committerSteve French <stfrench@microsoft.com>
Wed, 1 Jul 2026 02:29:46 +0000 (21:29 -0500)
smb2_validate_credit_charge() computes the credit charge a request is
allowed to consume from the payload size:

  CreditCharge = (max(SendPayloadSize, ResponsePayloadSize) - 1)/65536 + 1

For SMB2 QUERY_INFO, the server must validate CreditCharge based on the
*maximum* of InputBufferLength and OutputBufferLength. ksmbd instead
summed the two lengths, which overestimates the required charge.

As a result a single-credit QUERY_INFO whose InputBufferLength and
OutputBufferLength each fit in 64KB but whose sum exceeds 64KB is
rejected with STATUS_INVALID_PARAMETER, even though it is a valid
request. IOCTL already uses max() of the request and response sizes;
make QUERY_INFO consistent by feeding InputBufferLength as the request
length and OutputBufferLength as the expected response length so that
smb2_validate_credit_charge() takes their maximum.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/smb2misc.c

index a1ddca21c47bf9617733415ef1af579f13c4d17e..35fba49d27d68019d4002622296fdf70b85dda64 100644 (file)
@@ -261,8 +261,12 @@ calc_size_exit:
 
 static inline int smb2_query_info_req_len(struct smb2_query_info_req *h)
 {
-       return le32_to_cpu(h->InputBufferLength) +
-               le32_to_cpu(h->OutputBufferLength);
+       return le32_to_cpu(h->InputBufferLength);
+}
+
+static inline int smb2_query_info_resp_len(struct smb2_query_info_req *h)
+{
+       return le32_to_cpu(h->OutputBufferLength);
 }
 
 static inline int smb2_set_info_req_len(struct smb2_set_info_req *h)
@@ -308,6 +312,7 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn,
        switch (hdr->Command) {
        case SMB2_QUERY_INFO:
                req_len = smb2_query_info_req_len(__hdr);
+               expect_resp_len = smb2_query_info_resp_len(__hdr);
                break;
        case SMB2_SET_INFO:
                req_len = smb2_set_info_req_len(__hdr);