[PATCH] ksmbd: fix heap out-of-bounds write in SMB2_CREATE context stacking

From: Henry Martin

Date: Thu Oct 08 2026 - 13:06:01 EST


smb2_open() appends up to six create contexts (lease, mxac, disk_id,
durable, posix, aapl) back-to-back without checking the total length
against work->response_sz. A non-compound SMB2_CREATE only gets the
448-byte small response buffer, which also carries the 4-byte rfc1002
length word, leaving 292 bytes for contexts. The AAPL response alone
occupies 128 fixed bytes, so a client stacking contexts (up to 416)
overruns the kmalloc-512 object into the adjacent allocation with a
deterministic zero-fill.

Compute the worst-case context total from the per-dialect
conn->vals->create_*_size table and grow the response buffer to fit
before writing any context, so legitimate requests keep working
unchanged.

This vulnerability was discovered by Tencent CodeBuddy Security.

Fixes: 8f1b796ff1135 ("ksmbd: add AAPL kAAPL_SERVER_QUERY create context support")
Signed-off-by: Henry Martin <bsdhenrymartin@xxxxxxxxx>
---
fs/smb/server/smb2pdu.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 6b8809f67b926..e18e6b630f757 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -5162,6 +5162,52 @@ int smb2_open(struct ksmbd_work *work)
rsp->CreateContextsLength = 0;
iov_len = offsetof(struct smb2_create_rsp, Buffer);

+ /*
+ * The create contexts below are appended back-to-back with no
+ * length check, while a non-compound CREATE only gets the 448-byte
+ * small response buffer; a client stacking lease+mxac+disk_id+
+ * durable+posix+AAPL contexts overruns it (the AAPL response alone
+ * memsets 128 fixed bytes). Compute the worst-case total and grow
+ * the buffer before writing any context. Note that response_buf
+ * also carries the 4-byte rfc1002 length word before the SMB2
+ * header.
+ */
+ {
+ size_t ctx_max = 0;
+ size_t need;
+ void *nbuf;
+
+ if (opinfo && opinfo->is_lease)
+ ctx_max += conn->vals->create_lease_size;
+ if (maximal_access_ctxt)
+ ctx_max += conn->vals->create_mxac_size;
+ if (query_disk_id)
+ ctx_max += conn->vals->create_disk_id_size;
+ if (durable_rsp && dh_info.type == DURABLE_REQ_V2)
+ ctx_max += conn->vals->create_durable_v2_size;
+ else if (durable_rsp && dh_info.type == DURABLE_REQ)
+ ctx_max += conn->vals->create_durable_size;
+ if (posix_ctxt)
+ ctx_max += conn->vals->create_posix_size;
+ if (aapl_ctxt)
+ ctx_max += conn->vals->create_aapl_size;
+
+ need = 4 + offsetof(struct smb2_create_rsp, Buffer) + ctx_max;
+ if (need > work->response_sz) {
+ nbuf = kvzalloc(need, KSMBD_DEFAULT_GFP);
+ if (!nbuf) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ memcpy(nbuf, work->response_buf,
+ 4 + offsetof(struct smb2_create_rsp, Buffer));
+ kvfree(work->response_buf);
+ work->response_buf = nbuf;
+ work->response_sz = need;
+ rsp = smb_get_msg(work->response_buf);
+ }
+ }
+
/* If lease is request send lease context response */
if (opinfo && opinfo->is_lease) {
struct create_context *lease_ccontext;
--
2.43.7