mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 17:10:13 +00:00
ACPI support fix for 6.19-rc5
Fix the ACPI/PCI legacy interrupts (INTx) parsing in the cases when the ACPI Global System Interrupt (GSI) value is a 32-bit one with the MSB set that is interpreted as a negative integer and causes acpi_pci_link_allocate_irq() to fail and acpi_irq_get_penalty() to trigger an out-of-bounds array dereference (Lorenzo Pieralisi) -----BEGIN PGP SIGNATURE----- iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmlhHEMSHHJqd0Byand5 c29ja2kubmV0AAoJEO5fvZ0v1OO1sSIIAK1NeCVdGg9YpInOmVSneDENsaWReo9c ZxJBKISVPkiwG+8jEbPgIJJcwAXGBgzYBOA/l2S8TkFjj3h6yRidKI2PUabW49KA LN0k1Xkts/W4EVvY4d2J5WdNCwzzPi+cxG5fDuL5izZNP4yKJxiOvEybUAmA6i9g EqKXnAme/qSGSfZKFltjKDu9OcV+Nq1MSezl5h4JffChIXyJ1vX5tGmM3ENxzwXN gBUMk3BKD1TnnmjVO8Cz1WV8oDszOY3Y2+8MBGkbB5P/6Kwkdf2Wh79voddozi3D i+kJxdAJBqsUFODprhIYmgYR5duvi8XOj6p94hLzu8yJvvStYcqudRs= =v1UK -----END PGP SIGNATURE----- Merge tag 'acpi-6.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull ACPI support fix from Rafael Wysocki: "This fixes the ACPI/PCI legacy interrupts (INTx) parsing in the case when the ACPI Global System Interrupt (GSI) value is a 32-bit one with the MSB set. That was interpreted as a negative integer and caused acpi_pci_link_allocate_irq() to fail and acpi_irq_get_penalty() to trigger an out-of-bounds array dereference (Lorenzo Pieralisi)" * tag 'acpi-6.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI: PCI: IRQ: Fix INTx GSIs signedness
This commit is contained in:
commit
553410fcb9
@ -188,7 +188,7 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
|
|||||||
* the IRQ value, which is hardwired to specific interrupt inputs on
|
* the IRQ value, which is hardwired to specific interrupt inputs on
|
||||||
* the interrupt controller.
|
* the interrupt controller.
|
||||||
*/
|
*/
|
||||||
pr_debug("%04x:%02x:%02x[%c] -> %s[%d]\n",
|
pr_debug("%04x:%02x:%02x[%c] -> %s[%u]\n",
|
||||||
entry->id.segment, entry->id.bus, entry->id.device,
|
entry->id.segment, entry->id.bus, entry->id.device,
|
||||||
pin_name(entry->pin), prt->source, entry->index);
|
pin_name(entry->pin), prt->source, entry->index);
|
||||||
|
|
||||||
@ -384,7 +384,7 @@ static inline bool acpi_pci_irq_valid(struct pci_dev *dev, u8 pin)
|
|||||||
int acpi_pci_irq_enable(struct pci_dev *dev)
|
int acpi_pci_irq_enable(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct acpi_prt_entry *entry;
|
struct acpi_prt_entry *entry;
|
||||||
int gsi;
|
u32 gsi;
|
||||||
u8 pin;
|
u8 pin;
|
||||||
int triggering = ACPI_LEVEL_SENSITIVE;
|
int triggering = ACPI_LEVEL_SENSITIVE;
|
||||||
/*
|
/*
|
||||||
@ -422,18 +422,21 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = -ENODEV;
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
if (entry->link)
|
if (entry->link)
|
||||||
gsi = acpi_pci_link_allocate_irq(entry->link,
|
rc = acpi_pci_link_allocate_irq(entry->link,
|
||||||
entry->index,
|
entry->index,
|
||||||
&triggering, &polarity,
|
&triggering, &polarity,
|
||||||
&link);
|
&link, &gsi);
|
||||||
else
|
else {
|
||||||
gsi = entry->index;
|
gsi = entry->index;
|
||||||
} else
|
rc = 0;
|
||||||
gsi = -1;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (gsi < 0) {
|
if (rc < 0) {
|
||||||
/*
|
/*
|
||||||
* No IRQ known to the ACPI subsystem - maybe the BIOS /
|
* No IRQ known to the ACPI subsystem - maybe the BIOS /
|
||||||
* driver reported one, then use it. Exit in any case.
|
* driver reported one, then use it. Exit in any case.
|
||||||
|
|||||||
@ -448,7 +448,7 @@ static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
|
|||||||
/* >IRQ15 */
|
/* >IRQ15 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int acpi_irq_pci_sharing_penalty(int irq)
|
static int acpi_irq_pci_sharing_penalty(u32 irq)
|
||||||
{
|
{
|
||||||
struct acpi_pci_link *link;
|
struct acpi_pci_link *link;
|
||||||
int penalty = 0;
|
int penalty = 0;
|
||||||
@ -474,7 +474,7 @@ static int acpi_irq_pci_sharing_penalty(int irq)
|
|||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acpi_irq_get_penalty(int irq)
|
static int acpi_irq_get_penalty(u32 irq)
|
||||||
{
|
{
|
||||||
int penalty = 0;
|
int penalty = 0;
|
||||||
|
|
||||||
@ -528,7 +528,7 @@ static int acpi_irq_balance = -1; /* 0: static, 1: balance */
|
|||||||
static int acpi_pci_link_allocate(struct acpi_pci_link *link)
|
static int acpi_pci_link_allocate(struct acpi_pci_link *link)
|
||||||
{
|
{
|
||||||
acpi_handle handle = link->device->handle;
|
acpi_handle handle = link->device->handle;
|
||||||
int irq;
|
u32 irq;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (link->irq.initialized) {
|
if (link->irq.initialized) {
|
||||||
@ -598,44 +598,53 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* acpi_pci_link_allocate_irq
|
* acpi_pci_link_allocate_irq(): Retrieve a link device GSI
|
||||||
* success: return IRQ >= 0
|
*
|
||||||
* failure: return -1
|
* @handle: Handle for the link device
|
||||||
|
* @index: GSI index
|
||||||
|
* @triggering: pointer to store the GSI trigger
|
||||||
|
* @polarity: pointer to store GSI polarity
|
||||||
|
* @name: pointer to store link device name
|
||||||
|
* @gsi: pointer to store GSI number
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success with @triggering, @polarity, @name, @gsi initialized.
|
||||||
|
* -ENODEV on failure
|
||||||
*/
|
*/
|
||||||
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
|
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
|
||||||
int *polarity, char **name)
|
int *polarity, char **name, u32 *gsi)
|
||||||
{
|
{
|
||||||
struct acpi_device *device = acpi_fetch_acpi_dev(handle);
|
struct acpi_device *device = acpi_fetch_acpi_dev(handle);
|
||||||
struct acpi_pci_link *link;
|
struct acpi_pci_link *link;
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
acpi_handle_err(handle, "Invalid link device\n");
|
acpi_handle_err(handle, "Invalid link device\n");
|
||||||
return -1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
link = acpi_driver_data(device);
|
link = acpi_driver_data(device);
|
||||||
if (!link) {
|
if (!link) {
|
||||||
acpi_handle_err(handle, "Invalid link context\n");
|
acpi_handle_err(handle, "Invalid link context\n");
|
||||||
return -1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TBD: Support multiple index (IRQ) entries per Link Device */
|
/* TBD: Support multiple index (IRQ) entries per Link Device */
|
||||||
if (index) {
|
if (index) {
|
||||||
acpi_handle_err(handle, "Invalid index %d\n", index);
|
acpi_handle_err(handle, "Invalid index %d\n", index);
|
||||||
return -1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&acpi_link_lock);
|
mutex_lock(&acpi_link_lock);
|
||||||
if (acpi_pci_link_allocate(link)) {
|
if (acpi_pci_link_allocate(link)) {
|
||||||
mutex_unlock(&acpi_link_lock);
|
mutex_unlock(&acpi_link_lock);
|
||||||
return -1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!link->irq.active) {
|
if (!link->irq.active) {
|
||||||
mutex_unlock(&acpi_link_lock);
|
mutex_unlock(&acpi_link_lock);
|
||||||
acpi_handle_err(handle, "Link active IRQ is 0!\n");
|
acpi_handle_err(handle, "Link active IRQ is 0!\n");
|
||||||
return -1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
link->refcnt++;
|
link->refcnt++;
|
||||||
mutex_unlock(&acpi_link_lock);
|
mutex_unlock(&acpi_link_lock);
|
||||||
@ -647,7 +656,9 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
|
|||||||
if (name)
|
if (name)
|
||||||
*name = acpi_device_bid(link->device);
|
*name = acpi_device_bid(link->device);
|
||||||
acpi_handle_debug(handle, "Link is referenced\n");
|
acpi_handle_debug(handle, "Link is referenced\n");
|
||||||
return link->irq.active;
|
*gsi = link->irq.active;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -89,11 +89,11 @@ int xen_acpi_get_gsi_info(struct pci_dev *dev,
|
|||||||
int *trigger_out,
|
int *trigger_out,
|
||||||
int *polarity_out)
|
int *polarity_out)
|
||||||
{
|
{
|
||||||
int gsi;
|
u32 gsi;
|
||||||
u8 pin;
|
u8 pin;
|
||||||
struct acpi_prt_entry *entry;
|
struct acpi_prt_entry *entry;
|
||||||
int trigger = ACPI_LEVEL_SENSITIVE;
|
int trigger = ACPI_LEVEL_SENSITIVE;
|
||||||
int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ?
|
int ret, polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ?
|
||||||
ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW;
|
ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW;
|
||||||
|
|
||||||
if (!dev || !gsi_out || !trigger_out || !polarity_out)
|
if (!dev || !gsi_out || !trigger_out || !polarity_out)
|
||||||
@ -105,17 +105,18 @@ int xen_acpi_get_gsi_info(struct pci_dev *dev,
|
|||||||
|
|
||||||
entry = acpi_pci_irq_lookup(dev, pin);
|
entry = acpi_pci_irq_lookup(dev, pin);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
|
ret = 0;
|
||||||
if (entry->link)
|
if (entry->link)
|
||||||
gsi = acpi_pci_link_allocate_irq(entry->link,
|
ret = acpi_pci_link_allocate_irq(entry->link,
|
||||||
entry->index,
|
entry->index,
|
||||||
&trigger, &polarity,
|
&trigger, &polarity,
|
||||||
NULL);
|
NULL, &gsi);
|
||||||
else
|
else
|
||||||
gsi = entry->index;
|
gsi = entry->index;
|
||||||
} else
|
} else
|
||||||
gsi = -1;
|
ret = -ENODEV;
|
||||||
|
|
||||||
if (gsi < 0)
|
if (ret < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*gsi_out = gsi;
|
*gsi_out = gsi;
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
int acpi_irq_penalty_init(void);
|
int acpi_irq_penalty_init(void);
|
||||||
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
|
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
|
||||||
int *polarity, char **name);
|
int *polarity, char **name, u32 *gsi);
|
||||||
int acpi_pci_link_free_irq(acpi_handle handle);
|
int acpi_pci_link_free_irq(acpi_handle handle);
|
||||||
|
|
||||||
/* ACPI PCI Device Binding */
|
/* ACPI PCI Device Binding */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user