| CVE |
Vendors |
Products |
Updated |
CVSS v3.1 |
| In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: ISO: Reject concurrent BIS listener setup
iso_sock_listen() drops the socket lock before calling iso_listen_bis()
to preserve the hdev->lock ordering. Two concurrent listen() calls on
the same broadcast socket can therefore both observe BT_BOUND. Caller
A can attach connA and release the locks, then caller B can acquire
them and attach connB before A publishes BT_LISTEN.
__iso_chan_add() checks whether connB already has a socket, but not
whether the socket already has a connection. The second attachment
overwrites iso_pi(sk)->conn, leaking the connA reference and leaving
connA->sk intact. Socket teardown follows connB, so later events on
connA can cause a stale socket access.
Recheck BT_BOUND and require iso_pi(sk)->conn to be NULL after taking
both the HCI device and socket locks in iso_listen_bis(). The connection
check also covers the interval between attachment and publication of
BT_LISTEN. Reject a competing setup with -EBADFD through the existing
unlock path before allocating another connection.
A recorded KASAN report from an instrumented kernel shows:
BUG: KASAN: slab-use-after-free in iso_sock_hold+0x119/0x1f0
Call Trace:
iso_sock_hold+0x119/0x1f0
iso_conn_del+0xe4/0x270
hci_disconn_complete_evt+0x351/0x8c0
hci_event_packet+0x71b/0xb20
hci_rx_work+0x293/0x730
Allocated by task 93:
sk_prot_alloc+0x113/0x220
sk_alloc+0x2b/0x6d0
bt_sock_alloc+0x29/0x370
iso_sock_alloc.constprop.0+0x19/0x300
iso_sock_create+0x94/0x100
Freed by task 93:
kfree+0x121/0x3c0
__sk_destruct+0x42b/0x540
iso_sock_release+0x29d/0x340
__sock_release+0xa1/0x260
sock_close+0x10/0x20 |
| In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: ISO: Serialize concurrent connect calls
iso_sock_connect() checks the socket state before taking the socket lock
and drops the lock again before setting up a connection. Two callers can
both pass the admission check while the socket is open or bound.
Caller A can copy its destination for route selection, then caller B can
replace the socket destination before A binds or connects the CIS. A
then uses B's destination with the route selected for its own request.
B can also proceed after A attaches a connection and sets BT_CONNECT.
For deferred BIS setup, B can bind a second BIS and overwrite
iso_pi(sk)->conn, leaving the first connection's reference and conn->sk
back-pointer stranded. Concurrent CIS connects can likewise replace the
socket's connection. Later teardown only detaches the current connection,
so a callback on the old connection can race with socket release and
access a freed socket.
KASAN reported:
BUG: KASAN: slab-use-after-free in iso_sock_hold+0xf7/0x1b0
Call Trace:
iso_sock_hold+0xf7/0x1b0
iso_conn_del+0x7b/0x1d0
iso_connect_cfm+0x186/0x16a0
hci_conn_failed+0x154/0x280
hci_abort_conn_sync+0x3dc/0x7d0
hci_cmd_sync_work+0x173/0x300
Allocated by task 121:
sk_alloc+0x2b/0x6d0
bt_sock_alloc+0x29/0x370
iso_sock_alloc.constprop.0+0x19/0x300
iso_sock_create+0x94/0x100
Freed by task 121:
kfree+0x121/0x3c0
__sk_destruct+0x42b/0x540
iso_sock_release+0x29d/0x340
__sock_release+0xa1/0x260
Check admission under the socket lock and mark the connect operation in
progress before publishing its destination. Keep that flag set across
route lookup and connection setup, rejecting another connect with
-EBADFD before it can change the destination or attach a connection.
Clear the flag after either helper returns, including on failure, so a
failed setup can be retried.
A separate flag is needed because the socket lock must be released before
acquiring the HCI device lock, while BT_CONNECT requires an attached
connection. Keep the existing state transitions and the deferred CIS
completion through iso_sock_recvmsg().
Reject an existing socket attachment in __iso_chan_add() before taking
a new reference or publishing either pointer, so every caller preserves
the connection association. Keep the same-socket, same-connection success
case for deferred CIS setup. Reject an attached socket before BIS setup
so a reusable BIS is not claimed before the attachment is rejected.
In CIS setup, reject a different HCI connection before iso_conn_add()
and drop the per-attempt HCI hold directly. An unowned iso_conn may still
carry another reference after detachment, so its destruction cannot be
relied on to release that hold.
iso_listen_bis() creates a fresh PA HCI/ISO pair under the device lock,
so the temporary iso_conn_put() frees the ISO candidate and drops its
HCI hold on rejection. iso_conn_ready() uses a freshly allocated,
unpublished child with no connection, making the socket-side rejection
unreachable. |
| In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: SCO: serialise sco_conn lifetime against sco_recv_scodata()
sco_recv_scodata() upgrades the weak hcon->sco_data back-pointer to a
strong reference under hdev->lock:
hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
...
conn = sco_conn_hold_unless_zero(hcon->sco_data);
hci_dev_unlock(hdev);
but the pointer is cleared from the other side without that lock. When
the last sco_conn reference is dropped, sco_conn_free() ran
conn->hcon->sco_data = NULL;
with no hdev->lock held, so the RX path could read hcon->sco_data and
call kref_get_unless_zero() on an sco_conn that was concurrently freed:
BUG: KASAN: slab-use-after-free in sco_conn_hold_unless_zero+0xbe/0x160
Write of size 4 by task kworker/u17:0
Workqueue: hci0 hci_rx_work
Call Trace:
sco_conn_hold_unless_zero+0xbe/0x160
sco_recv_scodata+0x13f/0x490
hci_rx_work+0x3af/0x730
kref_get_unless_zero() only guards against a zero refcount, not against
the backing memory already being freed.
Give hcon->sco_data an actual reference on the sco_conn it points to, so
the object cannot be freed while the pointer is still installed, and only
clear and drop it from sco_conn_del(), which runs under hdev->lock (its
callers, sco_connect_cfm() and sco_disconn_cfm(), hold it). The reader in
sco_recv_scodata() also takes hdev->lock, so the store and the read are
now serialised: the RX path either observes NULL or a reference that is
guaranteed to stay valid until it drops its own.
sco_conn_add() no longer hands its kref_init() reference to the caller as
the connection's only reference; that initial reference is the one owned
by hcon->sco_data, and callers get their own via sco_conn_hold().
Because the sco_conn can now outlive the socket (the association keeps it
alive until the link goes down), the hci_conn can no longer be dropped
from sco_conn_free() without regressing socket close: closing a connected
SCO socket must still tear the link down. Move hci_conn ownership to the
socket instead: __sco_chan_add() takes an hci_conn reference and it is
released from sco_chan_del() and sco_sock_destruct(), exactly once. The
sco_conn no longer owns an hci_conn reference, so sco_conn_add() stops
consuming one and sco_connect() drops the hci_connect_sco() reference on
every path; sco_connect_cfm() no longer needs its hci_conn_hold() dance. |
| In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: RFCOMM: free the skb when the DLC has no owner
rfcomm_recv_data() hands the skb to d->data_ready() and returns 0
without freeing it, so the callback owns the skb from that point on.
The tty implementation frees it when the DLC has been detached from its
device:
static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc,
struct sk_buff *skb)
{
struct rfcomm_dev *dev = dlc->owner;
if (!dev) {
kfree_skb(skb);
return;
}
The socket implementation returns without freeing it, and the skb is
leaked.
A connected DLC can have no owner: rfcomm_sock_destruct() clears
d->owner, while the DLC itself stays on the session until it is closed.
Data frames that arrive in that window still find d->state ==
BT_CONNECTED in rfcomm_recv_data() and are handed to the callback, one
leaked skb each.
The leak does not stop on its own either. The remote runs out of
credits only once RFCOMM_RX_THROTTLED is set, and for a socket the only
place that sets it is rfcomm_sk_data_ready() itself, below the return.
rfcomm_process_dlcs() keeps granting credits, so the remote keeps
sending and the leak keeps growing.
Free the skb, as the tty side does. |
| In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
An RFCOMM connect() issued while a BR/EDR link is being authenticated
makes lockdep report a circular dependency, and the reported cycle is a
real AB/BA between rfcomm_mutex and hdev->lock.
rfcomm_security_cfm() is called from the HCI event path, which already
holds hdev->lock:
hci_rx_work()
hci_event_packet()
hci_cc_read_enc_key_size() [hdev->lock]
hci_encrypt_cfm() [hci_cb_list_lock]
rfcomm_security_cfm() [rfcomm_mutex]
while an RFCOMM connect() from userspace takes the same two locks the
other way round:
rfcomm_sock_connect()
rfcomm_dlc_open() [rfcomm_mutex]
__rfcomm_dlc_open()
rfcomm_session_create()
kernel_connect()
l2cap_sock_connect()
l2cap_chan_connect() [hdev->lock]
WARNING: possible circular locking dependency detected
kworker/u131:1/1128 is trying to acquire lock:
rfcomm_mutex, at: rfcomm_security_cfm+0x31/0x3e0 [rfcomm]
but task is already holding lock:
hci_cb_list_lock, at: hci_cc_read_enc_key_size+0x1d2/0xcc0
Chain exists of:
rfcomm_mutex --> &hdev->lock --> hci_cb_list_lock
hci_auth_complete_evt() and hci_encrypt_change_evt() reach the callback
the same way.
Both orders have to be seen in the same boot, which is why a BR/EDR
connection alone is not enough to show it: a session set up by the
remote side is created by rfcomm_accept_connection() in krfcommd, which
calls kernel_accept() and never takes hdev->lock under rfcomm_mutex.
Connecting a device that authenticates and encrypts the link and then
calling connect() on an RFCOMM socket towards any address - the connect
does not have to succeed, the order is recorded before the page timeout
- reports it every time.
Only the session socket has to be connected with the lock held, and it
does not: nothing else can see the socket before it is put on the
session list. So connect it first and take rfcomm_mutex afterwards,
which removes the rfcomm_mutex -> hdev->lock order for good, rather
than keeping the HCI event path out of rfcomm_mutex.
rfcomm_session_create() becomes rfcomm_session_connect(), which returns
the connected socket without touching the session list, and
rfcomm_dlc_open() adds the session once it holds the lock again. If
another opener added a session for the same pair while this socket was
connecting, that session is used and this socket is dropped.
__rfcomm_dlc_open() now takes the session it should use, and its state
check runs after the lock is re-acquired, so a DLC that was opened or
closed in the meantime is still handled.
Over an existing ACL link the connection can complete before the
session reaches the list, and the wakeup from the socket callback is
then lost, so krfcommd is woken once the session is visible.
Connecting without the lock opens a window in which the socket can be
closed. The DLC is not on a session yet, so rfcomm_dlc_close() finds
nothing to do and returns without touching it, and rfcomm_dlc_open()
would then attach a DLC whose owner is gone. rfcomm_dlc_close() now
marks such a DLC with RFCOMM_CLOSED, and rfcomm_dlc_open() checks the
mark once it holds rfcomm_mutex again and drops the socket instead of
attaching the DLC. The mark is cleared when an open starts, so a DLC
that is reused is not affected. This covers both callers of
rfcomm_dlc_open(), the socket and the tty layer. |
| In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: RFCOMM: Fix NULL tty_dev dereference in rfcomm_dev_shutdown
syzbot hit a NULL pointer dereference in rfcomm_dev_shutdown() when an
RFCOMM tty is closed.
rfcomm_dev_add() puts the new device on rfcomm_dev_list first and only
then registers the tty device and saves it in dev->tty_dev. If that
registration fails, dev->tty_dev is never set at all. The device can be
looked up in the meantime, so an open() of /dev/rfcommN gets through
rfcomm_tty_install() and attaches to it. When that tty is closed again,
rfcomm_dev_shutdown() uses dev->tty_dev without checking it:
Oops: general protection fault, probably for non-canonical address
KASAN: null-ptr-deref in range [0x0000000000000040-0x0000000000000047]
RIP: 0010:rfcomm_dev_shutdown+0x48/0xb0 net/bluetooth/rfcomm/tty.c:131
Call Trace:
tty_port_shutdown+0x1bf/0x220 drivers/tty/tty_port.c:372
tty_port_close+0x4e/0x150 drivers/tty/tty_port.c:705
tty_release+0x359/0x1670 drivers/tty/tty_io.c:1718
__fput+0x418/0xa50 fs/file_table.c:512
rfcomm_dev_destruct() already copes with a NULL dev->tty_dev. Add the
same check to rfcomm_dev_shutdown(), so the tty device is only moved
when it was actually registered. |
| In the Linux kernel, the following vulnerability has been resolved:
drm/fb-helper: defer setup when fbdev_probe() fails, not just on -EAGAIN
__drm_fb_helper_initial_config_and_unlock() calls
drm_client_modeset_probe() first, which already fills in each
mode_set->mode/num_connectors for every connected output, and only
afterwards calls drm_fb_helper_single_fb_probe() to create
fb_helper->fb and wire it into those mode_sets via
drm_setup_crtcs_fb().
If drm_fb_helper_single_fb_probe() fails with anything other than
-EAGAIN (e.g. dev->driver->fbdev_probe() itself fails), the function
bails out before drm_setup_crtcs_fb() runs and before setting
fb_helper->deferred_setup. The client is left with mode_sets that
have a mode and connectors but mode_set->fb == NULL, and nothing
marks this fb_helper as needing a retry.
__drm_fb_helper_restore_fbdev_mode_unlocked() only skips committing
when fb_helper->deferred_setup is set, so a later .restore() call
(drm_lastclose() on process exit, in this report) commits the stale
mode_set through drm_client_modeset_commit() ->
drm_client_modeset_commit_atomic() -> __drm_atomic_helper_set_config(),
which hits WARN_ON(!set->fb).
Mark fb_helper->deferred_setup on any drm_fb_helper_single_fb_probe()
failure, not just -EAGAIN, so restore keeps skipping the commit until
a later hotplug event successfully re-probes and re-populates
mode_set->fb. The real error code is still returned to the caller
unchanged. |
| In the Linux kernel, the following vulnerability has been resolved:
drm/i915/gem: Prevent overstepping exec array boundary
It is possible for eb_relocate_parse_slow() to call kvfree() on
entries outside the original exec array during following
scenario inside eb_relocate_parse_slow():
1) eb_copy_relocations() allocates as many as eb->buffer_count
copies for exec entries;
2) eb_parse() appends up to two VMAs, right after incrementing
eb->buffer_count;
3) cleanup under "out" label uses this incremented buffer_count
to release relocation pointers from exec array via kvfree(),
not from VMA array.
To amend this problem, ensure that relocation cleanup uses the
original exec object count, excluding the VMAs appended by the
command parser.
(cherry picked from commit 2a0158925fb943c7ba8f3216e2734952128defc9) |
| In the Linux kernel, the following vulnerability has been resolved:
drm/i915/gt: Unmask interrupts only when ACTIVE is true
There is a small race window between intel_rps_boost() reading
a stale ACTIVE state and queuing rps->work, where ACTIVE may be
changed via asynchronous calls triggered by wakeref drop.
This means that rps_work() could be triggered after the GT has
been parked, so unmasking RPS PM interrupts would happen without
holding PM wakelock. This sequence of events may be observed
during live_rc6_ctx_wa() selftest:
1) live_rc6_ctx_wa()
-> intel_engine_pm_put()
-> wakeref_put()
ASYNC1) wakeref_put() callback
-> __engine_park()
-> intel_gt_pm_put_async()
-> intel_gt_pm_put_async_untracked()
-> intel_wakeref_put_async()
ASYNC2) wakeref_put_async() callback
-> __gt_park()
-> intel_rps_park()
-> intel_rps_clear_active() [clear ACTIVE]
WITH INTERRUPTS:
-> rps_disable_interrupts()
-> cancel_work_sync(rps->work)
-> rps_reset_interrupts() [rps->pm_iir = 0]
WITHOUT INTERRUPTS (TIMER mode):
-> rps_stop_timer()
-> cancel_work_sync(rps->work)
2) live_rc6_ctx_wa()
-> intel_gt_wait_for_idle()
-> intel_gt_retire_requests_timeout()
-> dma_fence_wait_timeout()
-> ops->wait() [i915_fence_wait()]
-> i915_request_wait_timeout()
-> intel_rps_boost()
-> intel_rps_is_active() [check ACTIVE]
[OPEN RACE WINDOW]
-> queue_work(rps->work)
-> retire_requests()
-> i915_request_retire()
-> intel_rps_dec_waiters() [from 1 to 0]
If ASYNC1 and ASYNC2 would execute during [OPEN RACE WINDOW],
then:
3) rps_work() executes from the workqueue and may satisfy
"(!pm_iir && !client_boost)" test (in TIMER mode rps->pm_iir
is zeroed by an earlier rps_work() call or never gets a new
value after previous intel_rps_unpark() event), so it jumps
to "out" label, bypassing intel_rps_is_active() guard and
executes gen6_gt_pm_unmask_irq();
4) GT is parked and runtime PM wakelock is dropped, so only
a raw reference in __gt_park() ->
intel_display_power_put_async() remains for 100ms, then the
MMIO write in gen6_gt_pm_unmask_irq() detects missing
wakelock via assert_rpm_wakelock_held() and emits
"RPM wakelock ref not held during HW access" tainting kernel.
Commit 3e7abf814193 ("drm/i915: Extract GT render power state management")
dropped the "if (rps->interrupts_enabled)" guard that
gen6_pm_rps_work() had around this unmask in i915_irq.c.
INTEL_RPS_ACTIVE brackets the same window, since it is set in
intel_rps_unpark() before rps_enable_interrupts() and
rps_start_timer() and cleared in intel_rps_park() before
rps_stop_timer() and rps_disable_interrupts().
Skip unmasking when RPS is no longer active (reaching unmask
operation is independent of INTERRUPT mode). This does not
prevent RPS operation from resuming on the next unpark.
In interrupt mode, intel_rps_unpark() calls
rps_enable_interrupts(), which enables and unmasks the PM
interrupts. In timer mode, it calls rps_start_timer(),
restarting periodic engine-busyness evaluation. The timer
generates software RPS events and queues rps_work() directly,
independently of PM interrupt delivery. Neither mode requires
the late worker to unmask interrupts while the GT is parked
(cherry picked from commit ca4a6deadad15b91ee083afe445fa6bdbfb68206) |
| In the Linux kernel, the following vulnerability has been resolved:
drm/imagination: Size page table preallocation by device address
Commit 0a8224058a58 ("drm/imagination: Fix page count for page table for
map() interface") passed the device address to
pvr_mmu_op_context_create(), but the preallocation is still sized from
device_addr + sgt_offset with an exclusive end. The offset into the
object's pages has no place in a device-virtual range, and the exclusive
end allocates one table too many when the range ends on a table
boundary.
Count the tables from device_addr and the inclusive end of the range.
The new calculation does not take page table indices into account. This
fixes another issue with the previous implementation, where the
difference between start and end indices could underflow when a mapping
crossed a page table boundary. This would lead to the driver
preallocating a huge number of MMU pages, exhausting system memory and
triggering an out of memory panic.
[Alessio: add paragraph to point out OOM bug being fixed, cc stable] |
| In the Linux kernel, the following vulnerability has been resolved:
drm/panthor: validate userspace queue count against initialized firmware slot count
In panthor_drv.c:panthor_ioctl_group_create(),
the queue count is validated against the hardcoded maximum:
if (!args->queues.count || args->queues.count > MAX_CS_PER_CSG)
return -EINVAL;
However, if the firmware reports fewer slots than MAX_CS_PER_CSG,
panthor_fw_init_ifaces() will only initialize that smaller number of
stream interfaces.
If unprivileged userspace requests more queues than the firmware reported
(but no more than MAX_CS_PER_CSG), cs_slot_prog_locked() fetches an
uninitialized stream interface and may crash when dereferencing
cs_iface->input->ringbuf_base. |
| In the Linux kernel, the following vulnerability has been resolved:
drm/vmwgfx: validate pitch coming from userspace
Validate the pitch, alongside the box dimensions before trying
to copy data from the underlying surface. Fixes possible
out of bounds reads with cursor snooping. |
| In the Linux kernel, the following vulnerability has been resolved:
drm/xe/i2c: cancel the client work on remove
xe_i2c_notifier() stores the DesignWare adapter in i2c->adapter and
schedules i2c->work when the adapter is registered under the xe I2C
platform device, and xe_i2c_client_work() then instantiates the AMC
client device on that adapter.
xe_i2c_remove() tears down the AMC, unregisters the client devices,
the bus notifier and the adapter platform device, but it never drains
i2c->work. A work item that is still queued or running when the
adapter is unregistered dereferences i2c->adapter in
i2c_new_client_device() after platform_device_unregister() has
released the adapter. The work item is also embedded in the
devm-allocated struct xe_i2c, so a work item still queued after the
drm device devm unwind frees that allocation runs its callback on
freed memory.
The bus notifier is the only thing that schedules this work, and it is
unregistered after the client devices. An instance that is still queued
when the teardown runs can therefore write
i2c->client[XE_I2C_CLIENT_AMC] while the loop is unregistering and
clearing the same array, and an AMC client it instantiates late is only
cleaned up by the adapter's own child sweep in i2c_del_adapter().
Move bus_unregister_notifier() in front of the client teardown loop
and cancel the work right after it, so no new instance can be
scheduled and a queued instance is drained before the client array is
touched. A running instance still finds a live adapter, since the
adapter is unregistered later.
(cherry picked from commit a23f27d5ec11c3f418c5e5531eea34ccda2b5b20) |
| In the Linux kernel, the following vulnerability has been resolved:
drm/xe: Fix shrinker accounting double-subtraction on nested external pins
xe_bo_pin_external() and xe_bo_unpin_external() support nested pins,
since the underlying ttm_bo_pin()/ttm_bo_unpin() maintain a pin_count
refcount rather than a boolean. However, the shrinker accounting calls
xe_ttm_tt_account_subtract() and xe_ttm_tt_account_add() are invoked
unconditionally on every pin_external()/unpin_external() call, instead
of only on the transition into and out of the pinned state.
An external BO (dma-buf) can be pinned more than once while already
pinned, for example when it has multiple attachments/importers, each
independently calling xe_bo_pin_external(). Each such nested pin
subtracts the BO's pages from the shrinker's accounting again, even
though the BO's pages were already removed from consideration by the
first pin. Symmetrically, each nested unpin adds them back again
before the BO is actually unpinned. This desynchronizes the
shrinker's page and object counts from reality, and since they are
declared as signed long but interpreted as unsigned long in
xe_shrinker_count(), the underflow can turn into an enormous
shrinkable/purgeable page count, causing the shrinker to be invoked
excessively under memory pressure.
Guard the accounting calls with the same pin-count transition checks
already used to guard the pinned_link list maintenance, so accounting
is only updated on the outermost pin and the final unpin.
While centralizing this logic into xe_bo_account_pin()/
xe_bo_account_unpin(), also close a second, related accounting gap
affecting imported dma-bufs. For an imported bo's ttm_tt, xe's
ttm_tt_populate hook (xe_ttm_tt_populate()) early-returns without
calling xe_ttm_tt_account_add(), since TTM_TT_FLAG_EXTERNAL is set
without TTM_TT_FLAG_EXTERNAL_MAPPABLE. However, TTM core's
ttm_tt_populate() wrapper unconditionally marks the tt as populated
on driver-hook success, so ttm_tt_is_populated() still reports true
for it. xe_bo_account_pin()/xe_bo_account_unpin() trusted
ttm_tt_is_populated() as a proxy for "these pages are accounted for
by the shrinker", and would subtract/add pages for such a tt that
were never added in the first place, again underflowing the
shrinker's counts. This is reachable today via xe_bo_pin_external(),
and would have become newly reachable via the fb-pin path once this
patch routes __xe_pin_fb_vma() through xe_bo_pin_account() below, so
fix it here rather than in a later patch, to avoid a commit in this
series that introduces the regression before fixing it. Skip the
accounting for imported bos, using the same EXTERNAL &&
!EXTERNAL_MAPPABLE test xe_ttm_tt_populate()/xe_ttm_tt_unpopulate()
use to decide whether to act, via a new xe_ttm_bo_is_imported()
helper (hoisted up from its only prior use site).
v2:
- Fix the critical issue caught by Sashiko AI review: the pin-count
transition check introduced here was still bypassed by the fb-pin
path (__xe_pin_fb_vma()/__xe_unpin_fb_vma()), which could leave a
stale pinned_link entry and a permanent shrinker accounting leak
when the fb-unpin performed the true last unpin. Addressed in a
separate follow-up patch in this series rather than folded in here,
since it is a distinct bug with its own Fixes: tag.
- Drop the unneeded local "last_unpin" variable in
xe_bo_unpin_external(), restoring the original inline
bo->ttm.pin_count == 1 check; it was a no-op rename not used by any
of the new accounting helpers, and was going to be deleted again by
the follow-up patch anyway.
v3:
- Exclude imported dma-bufs from the pin/unpin shrinker accounting,
fixing another underflow caught by Sashiko AI review.
- Add a short comment on the backup-object pin site noting it's
already populated/accounted at pin time, addressing (as a
false-positive clarification, no code fix needed) a separate
Medium-severity accounting-leak concern also caught by Sashiko AI
---truncated--- |
| In the Linux kernel, the following vulnerability has been resolved:
drm/xe: Fix stale pinned_link entry when fb-pin performs the final unpin
xe_bo_pin_external() and xe_bo_unpin_external() maintain the bo's
pinned_link list membership in xe->pinned.late.external, based on
whether the current call is the outermost pin or the final unpin.
However, the same external bo's pin_count can also be raised and
lowered directly by __xe_pin_fb_vma()/__xe_unpin_fb_vma(), which pin
the bo as a display scanout buffer without going through
xe_bo_pin_external()/xe_bo_unpin_external() at all, and have no
notion of, or ownership over, pinned_link.
If a bo is pinned both externally (e.g. dma-buf export) and as an fb,
and the external unpin happens first, xe_bo_unpin_external() correctly
observes pin_count > 1 and leaves the bo on pinned_link. When the fb
unpin later performs the true last unpin (pin_count 1 -> 0), it never
touches pinned_link, leaving the bo linked on xe->pinned.late.external
indefinitely. Once the bo is subsequently freed, this stale list entry
points into freed memory, corrupting the list and risking a
use-after-free the next time the list is walked or spliced.
The backup object pin/unpin sites in xe_bo_notifier_prepare_pinned()/
xe_bo_notifier_unprepare_pinned() have the same bypass characteristic,
though they never add their bo to a pinned list, so are not affected
by this particular list-corruption issue.
Move the pinned_link removal into xe_bo_account_unpin(), which already
runs on every unpin path (kernel, external, framebuffer, backup
object) right before the true 1 -> 0 pin_count transition. Since
list_del_init() only operates on the node itself, this removal is
list-agnostic and safe to perform regardless of which list (external
or kernel_bo_present) the bo happens to be linked on, or which code
path is performing the final unpin. Drop the now-redundant explicit
list_del_init() calls in xe_bo_unpin_external() and xe_bo_unpin().
v2:
- New patch
v3:
- Rebased on changes to previous patch.
(cherry picked from commit ca58d36a1f93af586ee93b340c9f9fd81312cc01) |
| In the Linux kernel, the following vulnerability has been resolved:
drm/bridge: th1520-dw-hdmi: Fix remove() callback
This driver stores struct th1520_hdmi * in platform drvdata, but
th1520_dw_hdmi_remove() was reading it back as struct dw_hdmi *
and passing it to dw_hdmi_remove(), so teardown runs on the wrong
pointer.
Retrieve struct th1520_hdmi * from platform drvdata and pass
hdmi->dw_hdmi to dw_hdmi_remove(). |
| In the Linux kernel, the following vulnerability has been resolved:
drm/amdgpu/userq: only accept doorbell BOs as queue doorbell
amdgpu_userq_get_doorbell_index() pins any BO passed as doorbell_handle
into the doorbell domain. For a regular BO, TTM moves it with
ttm_bo_move_null() and its contents are lost. Since an importer on the
same device gets the exporter's GEM object, a client can do this to a
buffer another client shared with it.
Reject BOs that were not created in the doorbell domain.
v2: drop the error message, use a local abo variable (Christian)
(cherry picked from commit f7497bbc19db4821c62b9d97b31c9086feb2d917) |
| In the Linux kernel, the following vulnerability has been resolved:
fs: don't silently unmount busy mounts
The propagate_mount_busy() helper exists to decide whether a synchronous
can suceed. It does that by looking at the copies of the victims in the
mounts its parent propagates to. One of those functions from propagation
hell.
It skips a copy that has child mounts except for the case of a single
child mount covering the copy's root. That algorithm used to be exact.
It isn't anymore.
Originally only childless copies were unmounted during propagation.
And 1064f874abc0 ("mnt: Tuck mounts under others instead of creating
shadow/side mounts.") ended up adding covered mounts to both sides in
one go.
Along came 99b19d16471e ("mnt: In propgate_umount handle visiting mounts
in any order") and that started to unmount more than before:
[1]: A copy of a mount is unmounted when each of its children is either
its overmount or a copy of the victim itself. In the former case
the overmount gets reparented. In the latter case the copy of the
victim will end up being unmounted.
So propagate_umount() ended up being rewritten without adjusting
propagate_mount_busy(). And currently propagate_mount_busy() doesn't
look at copies of the victim that have two or more children nor a single
child that is not the overmount.
So any such copy in [1] is not checked for
references. The result is that a synchronous unmount succeeds, pulling
out a mount that is still in use.
A container can run into this with its own mounts. The host shares a
tree with the container and the host has a mount in that tree:
mount -t tmpfs none /mnt
mount --make-shared /mnt
mount -t tmpfs none /mnt/a
The container's /mnt is a slave copy of the host mount. The container
now takes a detached copy of the tree and mounts that copy beneath its
propagated copy of /mnt/a and keeps the file descriptor to the tree
open:
unshare -m --propagation unchanged
mount --make-rslave /
fd = open_tree(AT_FDCWD, "/mnt", OPEN_TREE_CLONE | AT_RECURSIVE)
move_mount(fd, "", AT_FDCWD, "/mnt/a", MOVE_MOUNT_BENEATH)
grep /mnt /proc/self/mountinfo
775 355 ... /mnt ... master:646
777 775 ... /mnt/a ... master:646
776 777 ... /mnt/a ... master:647
778 777 ... /mnt/a/a ... master:647
The now attached tree (777) is now mounted beneath the container's copy
of /mnt/a. That's also where the host mount sits (as seen from the host
mount namespace). So the propagated copy (776) of the host's mount is on
top of its root and the copy of that (778) is inside it. Now the host
runs:
umount /mnt/a
and it succeeds. The moved tree tree and the copy inside of it are gone
from the container. Now only the propagated copy is left and it got
reparented to where it was before:
grep /mnt /proc/self/mountinfo
775 355 ... /mnt ... master:646
776 775 ... /mnt/a ...
But the file descriptor still refers to the moved tree. So a synchronous
umount detached a mount that is still in use.
Teach propagate_mount_busy() the same checks that propagate_umount()
does. It now checks for a single victim mount without children
for which it can assume that MNT_LOCKED is cleared on every copy like
propagate_umount() does. The copies form chains. IOW, when a copy itself
receives propagation from the victim's parent then the mount at the same
mountpoint inside that copy is a copy as well. Whether a mount receives
propagation from the victim's can simply be checked by walking its
masters. Walk each chain once from its top so we are sure that nested
copies stay linear. Check every reference once of every copy that gets
unmounted. |
| In the Linux kernel, the following vulnerability has been resolved:
namespace: reset the old parent's ->overmount in mnt_change_mountpoint()
__umount_mnt() resets ->overmount of the parent when it unmounts the
mount that overmounts it. mnt_change_mountpoint() doesn't. It moves the
mount to its new parent and leaves the old one pointing at it.
For a mount that is moved beneath in attach_recursive_mnt() that doesn't
matter. The new mount has already reset ->overmount of the old parent by
the time the old top mount is moved onto it.
It matters for reparent() though. propagate_umount() moves a surviving
overmount onto the first ancestor that isn't going to be unmounted. The
mount it was taken from is unmounted immediately afterwards. If a file
descriptor keeps that unmounted mount alive ->overmount points at the
moved mount. That's a dangling pointer and UAF as the moved mount is
unmounted and freed.
do_lock_mount() follows ->overmount from the target path under
mount_lock. With a file descriptor on such a mount as the target of a
mount beneath topmost_overmount() walks into the freed mount and
do_lock_mount() takes references on whatever it finds there.
So reset ->overmount of the old parent in mnt_change_mountpoint() the
same way __umount_mnt() does. A mount's ->overmount is then always a
mount that is attached to it. |
| In the Linux kernel, the following vulnerability has been resolved:
statmount: read the parent of an unmounted mount under mount_lock
statmount_mnt_basic() reads the ids of the parent through m->mnt_parent
with namespace_sem held for reading. That's fine for a mount that is
in a namespace. Everything above it is pinned by that namespace.
STATMOUNT_BY_FD also accepts a file descriptor on a mount that has
been unmounted on purpose and that only the file descriptor keeps alive.
If that mount stayed attached to its parent when it was unmounted the
parent is unmounted as well and nothing pins it for the child.
The final mntput() unmounts the children under mount_lock alone and
frees the parent afterwards. Concurrently, statmount_mnt_basic() reads
m->mnt_parent twice while that can happen and can easily dereference a
mount that's already gone.
Read the parent of an unmounted mount under mount_lock. The parent
can't be put while it is held and both ids come from the same mount. A
mounted mount's parent is pinned by the namespace and a mount can't
leave its namespace while namespace_sem is held, so the common case
takes no global lock. |