[BUG/RFC] target: PR ALL_TG_PT traversal can dereference freed LUN during removal
From: zhang san
Date: Wed Nov 04 2026 - 05:24:52 EST
Hello,
We found a use-after-free in __core_scsi3_alloc_registration() when a
PR REGISTER AND IGNORE with ALL_TG_PT=1 races a concurrent LUN removal
via configfs.
Problem description:
The function iterates dev->dev_sep_list with
list_for_each_entry_safe() while dropping se_port_lock inside each
iteration body. The current element (lun_tmp) is protected by a
percpu_ref_tryget_live() reference, but the iterator's cached next
pointer is not: if the next se_lun is removed and freed during the
unlocked body, the loop's next iteration dereferences freed memory
through the cached pointer. This manifests as a general protection
fault on a non-canonical address (list poison).
We reproduced this on mainline 6628e7d4c6b2 (v7.4-rc1) with a
KASAN-enabled kernel: a GPF in __core_scsi3_alloc_registration() when
the PR registration races a configfs port deletion. The reproducer
uses controlled timing to expose the interleaving and is available on
request; control runs were clean.
Attempted fix and design question:
We explored taking a percpu_ref_tryget_live() reference on the next
entry before dropping the lock, and releasing it when the iteration
advances. This prevented the observed use-after-free in the tested
interleaving.
However, when the next entry's tryget fails (the LUN is dying and
being removed), there is a functional tradeoff:
- We cannot safely carry that pointer across the lock drop without a
lifetime guarantee.
- We cannot obtain a live reference with tryget in this case.
- Our prototype stops the traversal (break), which may skip later
LUNs that are still valid and should receive ALL_TG_PT registrations.
We therefore do not consider the prototype ready to submit as a fix.
We would appreciate guidance on the correct approach:
1. Is stopping the iteration when a dying LUN is encountered
acceptable under the target core's PR registration semantics?
2. Should the traversal instead restart under se_port_lock, using a
safe way to identify and avoid already processed LUNs?
3. Is there an existing target-core lifetime or traversal mechanism
that should be used instead?
We can provide the prototype patch, KASAN traces, kernel
configuration, and test setup privately if useful. If a fix is
proposed, please CC me so I can test the exact revision and provide a
Tested-by tag if it passes.
This finding comes from an AI-assisted source audit; the source
analysis and injection-assisted tests were reviewed by us.
Best regards,
Yaohan Li
shunsheng1218@xxxxxxxxx