ksmbd: safely discard unregistered deferred locks

When vfs_lock_file() defers a lock, smb2_lock() puts its ksmbd_lock on
rollback_list before allocating and registering the asynchronous work.
If either operation fails, rollback assumes that smb_lock->conn is
initialized and dereferences NULL. The deferred file_lock also remains
linked into the VFS blocked-lock state while it is freed.

Keep the lock off rollback_list until async setup succeeds. On setup
failures, explicitly unblock and wake the deferred lock before freeing it
and its ksmbd wrapper.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Namjae Jeon 2026-07-29 21:25:35 +09:00
parent 5ce5227cd6
commit 054bcca4cd

View File

@ -9169,6 +9169,13 @@ static void smb2_remove_blocked_lock(void **argv)
locks_wake_up(flock);
}
static void smb2_free_blocked_lock(struct file_lock *flock)
{
ksmbd_vfs_posix_lock_unblock(flock);
locks_wake_up(flock);
locks_free_lock(flock);
}
static inline bool lock_defer_pending(struct file_lock *fl)
{
/* check pending lock waiters */
@ -9428,11 +9435,12 @@ int smb2_lock(struct ksmbd_work *work)
ksmbd_debug(SMB,
"would have to wait for getting lock\n");
list_add(&smb_lock->llist, &rollback_list);
argv = kmalloc(sizeof(void *), KSMBD_DEFAULT_GFP);
if (!argv) {
err = -ENOMEM;
smb2_free_blocked_lock(flock);
kfree(smb_lock);
goto out;
}
argv[0] = flock;
@ -9443,8 +9451,11 @@ int smb2_lock(struct ksmbd_work *work)
if (rc) {
kfree(argv);
err = -ENOMEM;
smb2_free_blocked_lock(flock);
kfree(smb_lock);
goto out;
}
list_add(&smb_lock->llist, &rollback_list);
spin_lock(&fp->f_lock);
list_add(&work->fp_entry, &fp->blocked_works);
spin_unlock(&fp->f_lock);