[PATCH] ksmbd: reject foreign RPC pipe handles on IPC$ read and write

From: Mohammed

Date: Tue Oct 20 2026 - 14:19:06 EST


Hi Namjae,

Patch attached for the IPC$ pipe-handle issue I reported. Tested
locally. Thanks!

Best regards,
Mohammed Alquraini
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
Date: Mon, 20 Oct 2026 20:30:00 +0300
Subject: [PATCH] ksmbd: reject foreign RPC pipe handles on IPC$ read and write

RPC pipe handles on IPC$ are allocated from a single server-global IDA,
and ksmbd.mountd looks a pipe up by handle alone, with no session
information. smb2_read_pipe() and smb2_write_pipe() take the handle
straight from the client request (VolatileFileId) and pass it to the
daemon without checking that the requesting session opened it. An
authenticated user can therefore issue an SMB2 READ or WRITE on IPC$
with another session's handle and receive that session's in-flight
DCERPC response, or write attacker-chosen bytes into its pipe stream.
A tree connect to IPC$, which every RPC client already has, is the only
requirement.

Validate ownership before the transfer, the way the sibling pipe paths
already do: under sess->rpc_lock, ksmbd_session_rpc_method() returns 0
for a handle the session did not open. smb2_get_info_file_pipe() and
the FSCTL_PIPE_TRANSCEIVE ioctl already reject such handles; read and
write were the remaining gap. Reject them with STATUS_FILE_CLOSED, as
the ioctl path does.

Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Assisted-by: LLM
Signed-off-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
---
fs/smb/server/smb2pdu.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 40af35c0a..5cda343e1 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -9233,6 +9233,16 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)

id = req->VolatileFileId;

+ lockdep_assert_not_held(&work->sess->rpc_lock);
+ down_read(&work->sess->rpc_lock);
+ if (!ksmbd_session_rpc_method(work->sess, id)) {
+ up_read(&work->sess->rpc_lock);
+ rsp->hdr.Status = STATUS_FILE_CLOSED;
+ smb2_set_err_rsp(work);
+ return -ENOENT;
+ }
+ up_read(&work->sess->rpc_lock);
+
rpc_resp = ksmbd_rpc_read(work->sess, id);
if (rpc_resp) {
void *aux_payload_buf;
@@ -9863,6 +9873,16 @@ static noinline int smb2_write_pipe(struct ksmbd_work *work)
goto out;
}

+ lockdep_assert_not_held(&work->sess->rpc_lock);
+ down_read(&work->sess->rpc_lock);
+ if (!ksmbd_session_rpc_method(work->sess, id)) {
+ up_read(&work->sess->rpc_lock);
+ rsp->hdr.Status = STATUS_FILE_CLOSED;
+ smb2_set_err_rsp(work);
+ return -ENOENT;
+ }
+ up_read(&work->sess->rpc_lock);
+
data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
data_offset);

--
2.43.0