three ksmbd server fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmoh6iQACgkQiiy9cAdy
 T1HZagv+PVKZ5Djru4YzKQH19sYHkiav7FLzwZZy+bTmGlApWci6m/7aBojZOeac
 t5vaFURjrrGSAY5QQGjtr7rFgsQsQkU6AuSo8BnaGXRdzf9HoMkI0TI/OOGfuELX
 BCD10yoX8m8SwnrXIPaqHoyfn0uhUHRZk8okWPtPzv19VZK3t84XkQjLjR+IYHwb
 UZWhmGanjqw2yS5kTuWr6M3+POLnDqrdEzNj8R1ugcQ5aH/s1vfVEUi1vXKnGSBa
 ZPldxXRUpbEUMwrk1PyXd4Hb/OKpQrAoj3kl6sBXLNvLHtiw4i8+NkpGDg00eXYE
 xOqAdADNFpWx1lIJVJ845Enn5twaGM8y7KlXr+lEGfVU7iCKahs4d0RkjQON5aTo
 1HTx+nov4cP0nojvnPONU0li576E66ryqWzpBqsfEN93ROi+x7snuT9vB6QCjGHH
 lDv0UgsGF9TGWw2sBBQXhgYBXiFs2e1YSvdfT6KAd2x2SEJOIZ8yM6+ZNLzS1zTP
 XGjnnZ7S
 =7kge
 -----END PGP SIGNATURE-----

Merge tag 'v7.1-rc7-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix use after free in SMB2_CANCEL

 - Fix race in ksmbd_reopen_durable_fd

 - Fix oplock and lease break potential NULL-dref

* tag 'v7.1-rc7-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: fix use-after-free of a deferred file_lock on double SMB2_CANCEL
  ksmbd: fix durable reconnect double-bind race in ksmbd_reopen_durable_fd
  ksmbd: fix NULL-deref of opinfo->conn in oplock/lease break notifiers
This commit is contained in:
Linus Torvalds 2026-06-05 08:23:02 -07:00
commit e4a9638a0b
3 changed files with 32 additions and 6 deletions

View file

@ -711,11 +711,16 @@ out:
*/
static int smb2_oplock_break_noti(struct oplock_info *opinfo)
{
struct ksmbd_conn *conn = opinfo->conn;
struct ksmbd_conn *conn;
struct oplock_break_info *br_info;
int ret = 0;
struct ksmbd_work *work = ksmbd_alloc_work_struct();
struct ksmbd_work *work;
conn = READ_ONCE(opinfo->conn);
if (!conn)
return 0;
work = ksmbd_alloc_work_struct();
if (!work)
return -ENOMEM;
@ -815,11 +820,15 @@ out:
*/
static int smb2_lease_break_noti(struct oplock_info *opinfo)
{
struct ksmbd_conn *conn = opinfo->conn;
struct ksmbd_conn *conn;
struct ksmbd_work *work;
struct lease_break_info *br_info;
struct lease *lease = opinfo->o_lease;
conn = READ_ONCE(opinfo->conn);
if (!conn)
return 0;
work = ksmbd_alloc_work_struct();
if (!work)
return -ENOMEM;

View file

@ -7322,6 +7322,17 @@ int smb2_cancel(struct ksmbd_work *work)
le64_to_cpu(hdr->Id.AsyncId))
continue;
/*
* A cancelled deferred byte-range lock frees its
* file_lock and takes the smb2_lock() early-exit that
* skips release_async_work(), so the work stays on
* conn->async_requests with a live cancel_fn pointing
* at the freed file_lock. Re-firing it on a second
* SMB2_CANCEL is a use-after-free.
*/
if (iter->state == KSMBD_WORK_CANCELLED)
break;
ksmbd_debug(SMB,
"smb2 with AsyncId %llu cancelled command = 0x%x\n",
le64_to_cpu(hdr->Id.AsyncId),

View file

@ -1390,19 +1390,19 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
struct ksmbd_lock *smb_lock;
unsigned int old_f_state;
write_lock(&global_ft.lock);
if (!fp->is_durable || fp->conn || fp->tcon) {
write_unlock(&global_ft.lock);
pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon);
return -EBADF;
}
if (has_file_id(fp->volatile_id)) {
write_unlock(&global_ft.lock);
pr_err("Still in use durable fd: %llu\n", fp->volatile_id);
return -EBADF;
}
old_f_state = fp->f_state;
fp->f_state = FP_NEW;
/*
* Initialize fp's connection binding before publishing fp into the
* session's file table. If __open_id() is ordered first, a
@ -1413,11 +1413,17 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
*/
fp->conn = ksmbd_conn_get(conn);
fp->tcon = work->tcon;
write_unlock(&global_ft.lock);
old_f_state = fp->f_state;
fp->f_state = FP_NEW;
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
if (!has_file_id(fp->volatile_id)) {
write_lock(&global_ft.lock);
fp->conn = NULL;
fp->tcon = NULL;
write_unlock(&global_ft.lock);
ksmbd_conn_put(conn);
fp->f_state = old_f_state;
return -EBADF;