Commit 2912d799 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'firewire-fixes-6.19-rc8' of...

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 b5725cfa ("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
parents 28307372 20e01bba
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -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: