]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: validate response sizes in ipc_validate_msg()
authorMichael Bommarito <michael.bommarito@gmail.com>
Wed, 15 Apr 2026 11:25:00 +0000 (07:25 -0400)
committerSteve French <stfrench@microsoft.com>
Sat, 18 Apr 2026 17:19:59 +0000 (12:19 -0500)
ipc_validate_msg() computes the expected message size for each
response type by adding (or multiplying) attacker-controlled fields
from the daemon response to a fixed struct size in unsigned int
arithmetic.  Three cases can overflow:

  KSMBD_EVENT_RPC_REQUEST:
      msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
  KSMBD_EVENT_SHARE_CONFIG_REQUEST:
      msg_sz = sizeof(struct ksmbd_share_config_response) +
               resp->payload_sz;
  KSMBD_EVENT_LOGIN_REQUEST_EXT:
      msg_sz = sizeof(struct ksmbd_login_response_ext) +
               resp->ngroups * sizeof(gid_t);

resp->payload_sz is __u32 and resp->ngroups is __s32.  Each addition
can wrap in unsigned int; the multiplication by sizeof(gid_t) mixes
signed and size_t, so a negative ngroups is converted to SIZE_MAX
before the multiply.  A wrapped value of msg_sz that happens to
equal entry->msg_sz bypasses the size check on the next line, and
downstream consumers (smb2pdu.c:6742 memcpy using rpc_resp->payload_sz,
kmemdup in ksmbd_alloc_user using resp_ext->ngroups) then trust the
unverified length.

Use check_add_overflow() on the RPC_REQUEST and SHARE_CONFIG_REQUEST
paths to detect integer overflow without constraining functional
payload size; userspace ksmbd-tools grows NDR responses in 4096-byte
chunks for calls like NetShareEnumAll, so a hard transport cap is
unworkable on the response side.  For LOGIN_REQUEST_EXT, reject
resp->ngroups outside the signed [0, NGROUPS_MAX] range up front and
report the error from ipc_validate_msg() so it fires at the IPC
boundary; with that bound the subsequent multiplication and addition
stay well below UINT_MAX.  The now-redundant ngroups check and
pr_err in ksmbd_alloc_user() are removed.

This is the response-side analogue of aab98e2dbd64 ("ksmbd: fix
integer overflows on 32 bit systems"), which hardened the request
side.

Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
Fixes: a77e0e02af1c ("ksmbd: add support for supplementary groups")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
Assisted-by: Codex:gpt-5-4
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/mgmt/user_config.c
fs/smb/server/transport_ipc.c

index a3183fe5c5365f3508dd939b9ffc17efff07ae60..cf45841d9d1b994295d2511f5fee89834fcd6056 100644 (file)
@@ -56,12 +56,6 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
                goto err_free;
 
        if (resp_ext) {
-               if (resp_ext->ngroups > NGROUPS_MAX) {
-                       pr_err("ngroups(%u) from login response exceeds max groups(%d)\n",
-                                       resp_ext->ngroups, NGROUPS_MAX);
-                       goto err_free;
-               }
-
                user->sgid = kmemdup(resp_ext->____payload,
                                     resp_ext->ngroups * sizeof(gid_t),
                                     KSMBD_DEFAULT_GFP);
index f7aa427a06fe2cc21df9e760c1ec85d60ac2c1eb..0c581b9624d3e0bee688b43d64745715de147533 100644 (file)
@@ -13,6 +13,7 @@
 #include <net/genetlink.h>
 #include <linux/socket.h>
 #include <linux/workqueue.h>
+#include <linux/overflow.h>
 
 #include "vfs_cache.h"
 #include "transport_ipc.h"
@@ -496,7 +497,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
        {
                struct ksmbd_rpc_command *resp = entry->response;
 
-               msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
+               if (check_add_overflow(sizeof(struct ksmbd_rpc_command),
+                                      resp->payload_sz, &msg_sz))
+                       return -EINVAL;
                break;
        }
        case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST:
@@ -515,8 +518,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
                        if (resp->payload_sz < resp->veto_list_sz)
                                return -EINVAL;
 
-                       msg_sz = sizeof(struct ksmbd_share_config_response) +
-                                       resp->payload_sz;
+                       if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
+                                              resp->payload_sz, &msg_sz))
+                               return -EINVAL;
                }
                break;
        }
@@ -525,6 +529,12 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
                struct ksmbd_login_response_ext *resp = entry->response;
 
                if (resp->ngroups) {
+                       if (resp->ngroups < 0 ||
+                           resp->ngroups > NGROUPS_MAX) {
+                               pr_err("ngroups(%d) from login response exceeds max groups(%d)\n",
+                                      resp->ngroups, NGROUPS_MAX);
+                               return -EINVAL;
+                       }
                        msg_sz = sizeof(struct ksmbd_login_response_ext) +
                                        resp->ngroups * sizeof(gid_t);
                }