From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Hans de Goede <hdegoede@redhat.com>,
Bob Moore <robert.moore@intel.com>,
Erik Kaneda <erik.kaneda@intel.com>,
"Rafael J . Wysocki" <rafael.j.wysocki@intel.com>,
Sasha Levin <sashal@kernel.org>,
linux-acpi@vger.kernel.org, devel@acpica.org
Subject: [PATCH AUTOSEL 5.10 25/47] ACPICA: Fix race in generic_serial_bus (I2C) and GPIO op_region parameter handling
Date: Tue, 2 Mar 2021 06:56:24 -0500 [thread overview]
Message-ID: <20210302115646.62291-25-sashal@kernel.org> (raw)
In-Reply-To: <20210302115646.62291-1-sashal@kernel.org>
From: Hans de Goede <hdegoede@redhat.com>
[ Upstream commit c27f3d011b08540e68233cf56274fdc34bebb9b5 ]
ACPICA commit c9e0116952363b0fa815143dca7e9a2eb4fefa61
The handling of the generic_serial_bus (I2C) and GPIO op_regions in
acpi_ev_address_space_dispatch() passes a number of extra parameters
to the address-space handler through the address-space Context pointer
(instead of using more function parameters).
The Context is shared between threads, so if multiple threads try to
call the handler for the same address-space at the same time, then
a second thread could change the parameters of a first thread while
the handler is running for the first thread.
An example of this race hitting is the Lenovo Yoga Tablet2 1015L,
where there are both attrib_bytes accesses and attrib_byte accesses
to the same address-space. The attrib_bytes access stores the number
of bytes to transfer in Context->access_length. Where as for the
attrib_byte access the number of bytes to transfer is always 1 and
field_obj->Field.access_length is unused (so 0). Both types of
accesses racing from different threads leads to the following problem:
1. Thread a. starts an attrib_bytes access, stores a non 0 value
from field_obj->Field.access_length in Context->access_length
2. Thread b. starts an attrib_byte access, stores 0 in
Context->access_length
3. Thread a. calls i2c_acpi_space_handler() (under Linux). Which
sees that the access-type is ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE
and calls acpi_gsb_i2c_read_bytes(..., Context->access_length)
4. At this point Context->access_length is 0 (set by thread b.)
rather then the field_obj->Field.access_length value from thread a.
This 0 length reads leads to the following errors being logged:
i2c i2c-0: adapter quirk: no zero length (addr 0x0078, size 0, read)
i2c i2c-0: i2c read 0 bytes from client@0x78 starting at reg 0x0 failed, error: -95
Note this is just an example of the problems which this race can cause.
There are likely many more (sporadic) problems caused by this race.
This commit adds a new context_mutex to struct acpi_object_addr_handler
and makes acpi_ev_address_space_dispatch() take that mutex when
using the shared Context to pass extra parameters to an address-space
handler, fixing this race.
Note the new mutex must be taken *after* exiting the interpreter,
therefor the existing acpi_ex_exit_interpreter() call is moved to above
the code which stores the extra parameters in the Context.
Link: https://github.com/acpica/acpica/commit/c9e01169
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Erik Kaneda <erik.kaneda@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/acpi/acpica/acobject.h | 1 +
drivers/acpi/acpica/evhandler.c | 7 ++++
drivers/acpi/acpica/evregion.c | 64 ++++++++++++++++++++++++---------
drivers/acpi/acpica/evxfregn.c | 2 ++
4 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 9f0219a8cb98..dd7efafcb103 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -284,6 +284,7 @@ struct acpi_object_addr_handler {
acpi_adr_space_handler handler;
struct acpi_namespace_node *node; /* Parent device */
void *context;
+ acpi_mutex context_mutex;
acpi_adr_space_setup setup;
union acpi_operand_object *region_list; /* Regions using this handler */
union acpi_operand_object *next;
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
index 5884eba047f7..3438dc187efb 100644
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -489,6 +489,13 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node,
/* Init handler obj */
+ status =
+ acpi_os_create_mutex(&handler_obj->address_space.context_mutex);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(handler_obj);
+ goto unlock_and_exit;
+ }
+
handler_obj->address_space.space_id = (u8)space_id;
handler_obj->address_space.handler_flags = flags;
handler_obj->address_space.region_list = NULL;
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 738d4b231f34..980efc9bd5ee 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -111,6 +111,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
union acpi_operand_object *region_obj2;
void *region_context = NULL;
struct acpi_connection_info *context;
+ acpi_mutex context_mutex;
+ u8 context_locked;
acpi_physical_address address;
ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
@@ -135,6 +137,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
}
context = handler_desc->address_space.context;
+ context_mutex = handler_desc->address_space.context_mutex;
+ context_locked = FALSE;
/*
* It may be the case that the region has never been initialized.
@@ -203,6 +207,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
handler = handler_desc->address_space.handler;
address = (region_obj->region.address + region_offset);
+ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+ "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
+ ®ion_obj->region.handler->address_space, handler,
+ ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(region_obj->region.
+ space_id)));
+
+ if (!(handler_desc->address_space.handler_flags &
+ ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /*
+ * For handlers other than the default (supplied) handlers, we must
+ * exit the interpreter because the handler *might* block -- we don't
+ * know what it will do, so we can't hold the lock on the interpreter.
+ */
+ acpi_ex_exit_interpreter();
+ }
+
/*
* Special handling for generic_serial_bus and general_purpose_io:
* There are three extra parameters that must be passed to the
@@ -211,6 +232,11 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* 2) Length of the above buffer
* 3) Actual access length from the access_as() op
*
+ * Since we pass these extra parameters via the context, which is
+ * shared between threads, we must lock the context to avoid these
+ * parameters being changed from another thread before the handler
+ * has completed running.
+ *
* In addition, for general_purpose_io, the Address and bit_width fields
* are defined as follows:
* 1) Address is the pin number index of the field (bit offset from
@@ -220,6 +246,14 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
context && field_obj) {
+ status =
+ acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ goto re_enter_interpreter;
+ }
+
+ context_locked = TRUE;
+
/* Get the Connection (resource_template) buffer */
context->connection = field_obj->field.resource_buffer;
@@ -229,6 +263,14 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
context && field_obj) {
+ status =
+ acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ goto re_enter_interpreter;
+ }
+
+ context_locked = TRUE;
+
/* Get the Connection (resource_template) buffer */
context->connection = field_obj->field.resource_buffer;
@@ -238,28 +280,15 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
bit_width = field_obj->field.bit_length;
}
- ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
- "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
- ®ion_obj->region.handler->address_space, handler,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(region_obj->region.
- space_id)));
-
- if (!(handler_desc->address_space.handler_flags &
- ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
- /*
- * For handlers other than the default (supplied) handlers, we must
- * exit the interpreter because the handler *might* block -- we don't
- * know what it will do, so we can't hold the lock on the interpreter.
- */
- acpi_ex_exit_interpreter();
- }
-
/* Call the handler */
status = handler(function, address, bit_width, value, context,
region_obj2->extra.region_context);
+ if (context_locked) {
+ acpi_os_release_mutex(context_mutex);
+ }
+
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
acpi_ut_get_region_name(region_obj->region.
@@ -276,6 +305,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
}
}
+re_enter_interpreter:
if (!(handler_desc->address_space.handler_flags &
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
/*
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index da97fd0c6b51..3bb06f17a18b 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -201,6 +201,8 @@ acpi_remove_address_space_handler(acpi_handle device,
/* Now we can delete the handler object */
+ acpi_os_release_mutex(handler_obj->address_space.
+ context_mutex);
acpi_ut_remove_reference(handler_obj);
goto unlock_and_exit;
}
--
2.30.1
next prev parent reply other threads:[~2021-03-03 0:21 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-02 11:56 [PATCH AUTOSEL 5.10 01/47] i2c: rcar: faster irq code to minimize HW race condition Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 02/47] i2c: rcar: optimize cacheline " Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 03/47] scsi: ufs: Add a quirk to permit overriding UniPro defaults Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 04/47] scsi: ufs: WB is only available on LUN #0 to #7 Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 05/47] scsi: ufs: Introduce a quirk to allow only page-aligned sg entries Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 06/47] udf: fix silent AED tagLocation corruption Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 07/47] iommu/vt-d: Clear PRQ overflow only when PRQ is empty Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 08/47] mmc: mxs-mmc: Fix a resource leak in an error handling path in 'mxs_mmc_probe()' Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 09/47] mmc: sdhci-of-dwcmshc: set SDHCI_QUIRK2_PRESET_VALUE_BROKEN Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 10/47] mmc: mediatek: fix race condition between msdc_request_timeout and irq Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 11/47] mmc: sdhci-iproc: Add ACPI bindings for the RPi Sasha Levin
2021-03-02 16:16 ` Jeremy Linton
2021-03-12 22:12 ` Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 12/47] Platform: OLPC: Fix probe error handling Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 13/47] powerpc/pci: Add ppc_md.discover_phbs() Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 14/47] HID: i2c-hid: Add I2C_HID_QUIRK_NO_IRQ_AFTER_RESET for ITE8568 EC on Voyo Winpad A15 Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 15/47] spi: stm32: make spurious and overrun interrupts visible Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 16/47] powerpc: improve handling of unrecoverable system reset Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 17/47] powerpc/perf: Record counter overflow always if SAMPLE_IP is unset Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 18/47] kunit: tool: fix unit test cleanup handling Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 19/47] HID: logitech-dj: add support for the new lightspeed connection iteration Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 20/47] powerpc/64: Fix stack trace not displaying final frame Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 21/47] iommu/amd: Fix performance counter initialization Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 22/47] clk: qcom: gdsc: Implement NO_RET_PERIPH flag Sasha Levin
2021-03-02 23:04 ` Stephen Boyd
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 23/47] sparc32: Limit memblock allocation to low memory Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 24/47] sparc64: Use arch_validate_flags() to validate ADI flag Sasha Levin
2021-03-02 11:56 ` Sasha Levin [this message]
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 26/47] Input: applespi - don't wait for responses to commands indefinitely Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 27/47] x86, build: use objtool mcount Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 28/47] PCI: xgene-msi: Fix race in installing chained irq handler Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 29/47] misc: eeprom_93xx46: Add quirk to support Microchip 93LC46B eeprom Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 30/47] PCI: mediatek: Add missing of_node_put() to fix reference leak Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 31/47] drivers/base: build kunit tests without structleak plugin Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 32/47] drm/msm/a5xx: Remove overwriting A5XX_PC_DBG_ECO_CNTL register Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 33/47] PCI/LINK: Remove bandwidth notification Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 34/47] ext4: don't try to processed freed blocks until mballoc is initialized Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 35/47] PCI: cadence: Retrain Link to work around Gen2 training defect Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 36/47] kbuild: clamp SUBLEVEL to 255 Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 37/47] PCI: Fix pci_register_io_range() memory leak Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 38/47] i40e: Fix memory leak in i40e_probe Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 39/47] kasan: fix memory corruption in kasan_bitops_tags test Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 40/47] riscv: Get rid of MAX_EARLY_MAPPING_SIZE Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 41/47] s390/smp: __smp_rescan_cpus() - move cpumask away from stack Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 42/47] drivers/base/memory: don't store phys_device in memory blocks Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 43/47] sysctl.c: fix underflow value setting risk in vm_table Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 44/47] scsi: libiscsi: Fix iscsi_prep_scsi_cmd_pdu() error handling Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 45/47] nbd: handle device refs for DESTROY_ON_DISCONNECT properly Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 46/47] scsi: target: core: Add cmd length set before cmd complete Sasha Levin
2021-03-02 11:56 ` [PATCH AUTOSEL 5.10 47/47] scsi: target: core: Prevent underflow for service actions Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210302115646.62291-25-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=devel@acpica.org \
--cc=erik.kaneda@intel.com \
--cc=hdegoede@redhat.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rafael.j.wysocki@intel.com \
--cc=robert.moore@intel.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).