firewire fixes for 6.19-rc8

Fix a race condition introduced in v6.18. Andreas Persson discovered this
 issue while working with Focusrite Saffire Pro 40 (TCD33070). The fw_card
 instance maintains a linked list of pending transactions, which must be
 protected against concurrent access. However, a commit b5725cfa41
 ("firewire: core: use spin lock specific to timer for split transaction")
 unintentionally allowed concurrent accesses to this list. Fix this by
 adjusting the relevant critical sections to properly serialize access.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQE66IEYNDXNBPeGKSsLtaWM8LwEwUCaX00QAAKCRCsLtaWM8Lw
 E0G/AP9PAE2Una4WBWNMw24zgyMYJyODekEQEZLr72ksPHMDGQD9GZNKylKogQdi
 OquDPN4J93mw4/9DGtCbF8ZEQLAxdwA=
 =7hNC
 -----END PGP SIGNATURE-----

Merge tag 'firewire-fixes-6.19-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394

Pull firewire fix from Takashi Sakamoto:
 "Fix a race condition introduced in v6.18.

  Andreas Persson discovered this issue while working with Focusrite
  Saffire Pro 40 (TCD33070). The fw_card instance maintains a linked
  list of pending transactions, which must be protected against
  concurrent access.

  However, a commit b5725cfa41 ("firewire: core: use spin lock
  specific to timer for split transaction") unintentionally allowed
  concurrent accesses to this list.

  Fix this by adjusting the relevant critical sections to properly
  serialize access"

* tag 'firewire-fixes-6.19-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
  firewire: core: fix race condition against transaction list
This commit is contained in:
Linus Torvalds 2026-01-30 17:07:45 -08:00
commit 2912d799e5

View File

@ -173,20 +173,14 @@ static void split_transaction_timeout_callback(struct timer_list *timer)
}
}
static void start_split_transaction_timeout(struct fw_transaction *t,
struct fw_card *card)
// card->transactions.lock should be acquired in advance for the linked list.
static void start_split_transaction_timeout(struct fw_transaction *t, unsigned int delta)
{
unsigned long delta;
if (list_empty(&t->link) || WARN_ON(t->is_split_transaction))
return;
t->is_split_transaction = true;
// NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for
// local destination never runs in any type of IRQ context.
scoped_guard(spinlock_irqsave, &card->split_timeout.lock)
delta = card->split_timeout.jiffies;
mod_timer(&t->split_timeout_timer, jiffies + delta);
}
@ -207,13 +201,20 @@ static void transmit_complete_callback(struct fw_packet *packet,
break;
case ACK_PENDING:
{
unsigned int delta;
// NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for
// local destination never runs in any type of IRQ context.
scoped_guard(spinlock_irqsave, &card->split_timeout.lock) {
t->split_timeout_cycle =
compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
delta = card->split_timeout.jiffies;
}
start_split_transaction_timeout(t, card);
// NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for
// local destination never runs in any type of IRQ context.
scoped_guard(spinlock_irqsave, &card->transactions.lock)
start_split_transaction_timeout(t, delta);
break;
}
case ACK_BUSY_X: