Skip to contentSkip to conversation

smb/server: prevent file publication after tree disconnect

PATCH Superseded Weiming Shi 2 participants 3 messages Oct 20 – Oct 21

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 smb/server: prevent file publication after tree disconnect

TREE_DISCONNECT closes the tree's published file handles before marking and removing the tree connection. A concurrent CREATE that already holds a tree reference can therefore publish its file after the close pass. When CREATE drops its reference, the tree can be freed while the published file still points to it.

Mark and remove the tree connection before closing its files, and serialize both new-open and durable-reconnect volatile ID publication with that state transition. An opener is then either published in time for the close pass or rejected after disconnect with STATUS_NETWORK_NAME_DELETED.

Keep a tree reference while a file carries its tree pointer. This protects asynchronous users that can defer the file's final destruction past tree disconnect.

The close pass can race the successful FP_NEW to FP_INITED transition. Take the opening request's file reference atomically with that transition. This keeps the file alive until request completion even if teardown removes the ID immediately.

  BUG: KASAN: slab-use-after-free in proc_show_files (fs/smb/server/vfs_cache.c:126)
  Read of size 4 at addr ff11000101540f80 by task poc/153

  Call Trace:
    proc_show_files (fs/smb/server/vfs_cache.c:126)
    seq_read_iter (fs/seq_file.c:231)
    proc_reg_read_iter (fs/proc/inode.c:299)
    vfs_read (fs/read_write.c:574)
    ksys_read (fs/read_write.c:716)
    do_syscall_64 (arch/x86/entry/syscall_64.c:84)
    entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)

Allocated by:

    ksmbd_tree_conn_connect (fs/smb/server/mgmt/tree_connect.c:35)
    smb2_tree_connect (fs/smb/server/smb2pdu.c:2819)
    handle_ksmbd_work (fs/smb/server/server.c:368)

Freed by:

    kfree (mm/slub.c:6801)
    handle_ksmbd_work (fs/smb/server/server.c:332)
Fixes f44158485826 ("cifsd: add file operations")
Assisted-by LLM
---
 fs/smb/server/mgmt/tree_connect.c |  7 ++++
 fs/smb/server/mgmt/tree_connect.h |  2 +
 fs/smb/server/smb2pdu.c           | 37 ++++++++++++++----
 fs/smb/server/vfs_cache.c         | 65 +++++++++++++++++++++----------
 4 files changed, 83 insertions(+), 28 deletions(-)
fs/smb/server/mgmt/tree_connect.c +7 -0
index dd1db3554cae..837175ac5ce8 100644
@@ -103,6 +103,13 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
 	return status;
 }
 
+struct ksmbd_tree_connect *
+ksmbd_tree_connect_get(struct ksmbd_tree_connect *tcon)
+{
+	atomic_inc(&tcon->refcount);
+	return tcon;
+}
+
 void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
 {
 	if (atomic_dec_and_test(&tcon->refcount)) {
fs/smb/server/mgmt/tree_connect.h +2 -0
index f0023d86716f..82891ff9b7b9 100644
@@ -51,6 +51,8 @@ struct ksmbd_session;
 
 struct ksmbd_tree_conn_status
 ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name);
+struct ksmbd_tree_connect *
+ksmbd_tree_connect_get(struct ksmbd_tree_connect *tcon);
 void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon);
 
 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
fs/smb/server/smb2pdu.c +29 -8
index b7ce67094626..d4d8840a92b1 100644
@@ -3041,9 +3041,10 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
 		goto err_out;
 	}
 
+	err = ksmbd_tree_conn_disconnect(sess, tcon);
+
 	ksmbd_close_tree_conn_fds(work);
 
-	err = ksmbd_tree_conn_disconnect(sess, tcon);
 	if (err) {
 		rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
 		goto err_out;
@@ -4280,8 +4281,12 @@ int smb2_open(struct ksmbd_work *work)
 				goto err_out2;
 
 			rc = ksmbd_reopen_durable_fd(work, dh_info.fp);
-			if (rc)
+			if (rc) {
+				if (rc == -ENOTCONN)
+					rsp->hdr.Status =
+						STATUS_NETWORK_NAME_DELETED;
 				goto err_out2;
+			}
 
 			fp = dh_info.fp;
 
@@ -4702,6 +4707,8 @@ int smb2_open(struct ksmbd_work *work)
 	if (IS_ERR(fp)) {
 		fput(filp);
 		rc = PTR_ERR(fp);
+		if (rc == -ENOTCONN)
+			rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
 		fp = NULL;
 		goto err_out;
 	}
@@ -5302,11 +5309,20 @@ int smb2_open(struct ksmbd_work *work)
 
 err_out2:
 	if (!rc) {
-		if (!dh_info.replay)
+		if (!dh_info.replay) {
+			smb2_complete_request_open(work);
 			rc = ksmbd_update_fstate(&work->sess->file_table, fp,
 						 FP_INITED);
-		if (!rc)
+			if (rc == -ENOENT)
+				rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
+			if (!rc) {
+				work->request_open = fp;
+				work->request_open_chseq =
+					smb3_hdr_channel_sequence(&req->hdr);
+			}
+		} else {
 			rc = smb2_set_request_open(work, fp, &req->hdr, false, false);
+		}
 		if (!rc)
 			rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
 	}
@@ -5321,8 +5337,7 @@ int smb2_open(struct ksmbd_work *work)
 				rsp->hdr.Status = STATUS_PRIVILEGE_NOT_HELD;
 			else
 				rsp->hdr.Status = STATUS_ACCESS_DENIED;
-		}
-		else if (rc == -ENOENT)
+		} else if (rc == -ENOENT && !rsp->hdr.Status)
 			rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;
 		else if (rc == -EPERM)
 			rsp->hdr.Status = STATUS_SHARING_VIOLATION;
@@ -5345,8 +5360,14 @@ int smb2_open(struct ksmbd_work *work)
 		if (!rsp->hdr.Status)
 			rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
 
-		if (fp && !dh_info.replay)
-			ksmbd_fd_put(work, fp);
+		if (fp && !dh_info.replay) {
+			if (work->request_open == fp) {
+				ksmbd_close_fd(work, fp->volatile_id);
+				smb2_complete_request_open(work);
+			} else {
+				ksmbd_fd_put(work, fp);
+			}
+		}
 		smb2_set_err_rsp(work);
 		ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status);
 	}
fs/smb/server/vfs_cache.c +45 -20

159 lines not on this page · raw message

Signature · 1 line
2.56.0
maintainer
#1 lore raw
Quoted 39 lines · Weiming Shi

TREE_DISCONNECT closes the tree's published file handles before marking and removing the tree connection. A concurrent CREATE that already holds a tree reference can therefore publish its file after the close pass. When CREATE drops its reference, the tree can be freed while the published file still points to it.

Mark and remove the tree connection before closing its files, and serialize both new-open and durable-reconnect volatile ID publication with that state transition. An opener is then either published in time for the close pass or rejected after disconnect with STATUS_NETWORK_NAME_DELETED.

Keep a tree reference while a file carries its tree pointer. This protects asynchronous users that can defer the file's final destruction past tree disconnect.

The close pass can race the successful FP_NEW to FP_INITED transition. Take the opening request's file reference atomically with that transition. This keeps the file alive until request completion even if teardown removes the ID immediately.

  BUG: KASAN: slab-use-after-free in proc_show_files (fs/smb/server/vfs_cache.c:126)
  Read of size 4 at addr ff11000101540f80 by task poc/153

  Call Trace:
    proc_show_files (fs/smb/server/vfs_cache.c:126)
    seq_read_iter (fs/seq_file.c:231)
    proc_reg_read_iter (fs/proc/inode.c:299)
    vfs_read (fs/read_write.c:574)
    ksys_read (fs/read_write.c:716)
    do_syscall_64 (arch/x86/entry/syscall_64.c:84)
    entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)

Allocated by:

    ksmbd_tree_conn_connect (fs/smb/server/mgmt/tree_connect.c:35)
    smb2_tree_connect (fs/smb/server/smb2pdu.c:2819)
    handle_ksmbd_work (fs/smb/server/server.c:368)

Freed by:

Quoted 8 lines
    kfree (mm/slub.c:6801)
    handle_ksmbd_work (fs/smb/server/server.c:332)
Fixes f44158485826 ("cifsd: add file operations")
Assisted-by LLM

This patch does not apply cleanly to the ksmbd-for-next branch. Could you please rebase it onto that branch and resend it? Thanks!

#2 lore raw
Quoted 44 lines · Namjae Jeon <[email protected]> 于2026年10月21日周三 10:06写道:
Quoted 42 lines · Weiming Shi

TREE_DISCONNECT closes the tree's published file handles before marking and removing the tree connection. A concurrent CREATE that already holds a tree reference can therefore publish its file after the close pass. When CREATE drops its reference, the tree can be freed while the published file still points to it.

Mark and remove the tree connection before closing its files, and serialize both new-open and durable-reconnect volatile ID publication with that state transition. An opener is then either published in time for the close pass or rejected after disconnect with STATUS_NETWORK_NAME_DELETED.

Keep a tree reference while a file carries its tree pointer. This protects asynchronous users that can defer the file's final destruction past tree disconnect.

The close pass can race the successful FP_NEW to FP_INITED transition. Take the opening request's file reference atomically with that transition. This keeps the file alive until request completion even if teardown removes the ID immediately.

  BUG: KASAN: slab-use-after-free in proc_show_files (fs/smb/server/vfs_cache.c:126)
  Read of size 4 at addr ff11000101540f80 by task poc/153

  Call Trace:
    proc_show_files (fs/smb/server/vfs_cache.c:126)
    seq_read_iter (fs/seq_file.c:231)
    proc_reg_read_iter (fs/proc/inode.c:299)
    vfs_read (fs/read_write.c:574)
    ksys_read (fs/read_write.c:716)
    do_syscall_64 (arch/x86/entry/syscall_64.c:84)
    entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)

Allocated by:

    ksmbd_tree_conn_connect (fs/smb/server/mgmt/tree_connect.c:35)
    smb2_tree_connect (fs/smb/server/smb2pdu.c:2819)
    handle_ksmbd_work (fs/smb/server/server.c:368)

Freed by:

    kfree (mm/slub.c:6801)
    handle_ksmbd_work (fs/smb/server/server.c:332)
Quoted 8 lines
Quoted 5 lines
Fixes f44158485826 ("cifsd: add file operations")
Assisted-by LLM

This patch does not apply cleanly to the ksmbd-for-next branch. Could you please rebase it onto that branch and resend it? Thanks!

Thanks for the heads-up. I'll rebase the patch onto the latest ksmbd-for-next branch and resend it shortly.

Best regards,
Weiming Shi