All of lore.kernel.org
 help / color / mirror / Atom feed
From: gregkh@linuxfoundation.org
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, 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>
Subject: [PATCH 5.4 05/24] ACPICA: Fix race in generic_serial_bus (I2C) and GPIO op_region parameter handling
Date: Wed, 10 Mar 2021 14:24:17 +0100	[thread overview]
Message-ID: <20210310132320.712391524@linuxfoundation.org> (raw)
In-Reply-To: <20210310132320.550932445@linuxfoundation.org>

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

From: Hans de Goede <hdegoede@redhat.com>

commit c27f3d011b08540e68233cf56274fdc34bebb9b5 upstream.

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: Greg Kroah-Hartman <gregkh@linuxfoundation.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(-)

--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -283,6 +283,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;
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -489,6 +489,13 @@ acpi_ev_install_space_handler(struct acp
 
 	/* 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;
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -111,6 +111,8 @@ acpi_ev_address_space_dispatch(union acp
 	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 acp
 	}
 
 	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 acp
 	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",
+			  &region_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 acp
 	 *   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 acp
 	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 acp
 	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 acp
 		bit_width = field_obj->field.bit_length;
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
-			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
-			  &region_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 acp
 		}
 	}
 
+re_enter_interpreter:
 	if (!(handler_desc->address_space.handler_flags &
 	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
 		/*
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -201,6 +201,8 @@ acpi_remove_address_space_handler(acpi_h
 
 			/* 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;
 		}



  parent reply	other threads:[~2021-03-10 13:26 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-10 13:24 [PATCH 5.4 00/24] 5.4.105-rc1 review gregkh
2021-03-10 13:24 ` [PATCH 5.4 01/24] net: dsa: add GRO support via gro_cells gregkh
2021-03-10 13:24 ` [PATCH 5.4 02/24] dm table: fix iterate_devices based device capability checks gregkh
2021-03-10 13:24 ` [PATCH 5.4 03/24] dm table: fix DAX " gregkh
2021-03-10 13:24 ` [PATCH 5.4 04/24] dm table: fix zoned " gregkh
2021-03-10 13:24 ` gregkh [this message]
2021-03-10 13:24 ` [PATCH 5.4 06/24] iommu/amd: Fix sleeping in atomic in increase_address_space() gregkh
2021-03-10 13:24 ` [PATCH 5.4 07/24] mwifiex: pcie: skip cancel_work_sync() on reset failure path gregkh
2021-03-10 13:24 ` [PATCH 5.4 08/24] platform/x86: acer-wmi: Cleanup ACER_CAP_FOO defines gregkh
2021-03-10 13:24 ` [PATCH 5.4 09/24] platform/x86: acer-wmi: Cleanup accelerometer device handling gregkh
2021-03-10 13:24 ` [PATCH 5.4 10/24] platform/x86: acer-wmi: Add new force_caps module parameter gregkh
2021-03-10 13:24 ` [PATCH 5.4 11/24] platform/x86: acer-wmi: Add ACER_CAP_SET_FUNCTION_MODE capability flag gregkh
2021-03-10 13:24 ` [PATCH 5.4 12/24] platform/x86: acer-wmi: Add support for SW_TABLET_MODE on Switch devices gregkh
2021-03-10 13:24 ` [PATCH 5.4 13/24] platform/x86: acer-wmi: Add ACER_CAP_KBD_DOCK quirk for the Aspire Switch 10E SW3-016 gregkh
2021-03-10 13:24 ` [PATCH 5.4 14/24] HID: mf: add support for 0079:1846 Mayflash/Dragonrise USB Gamecube Adapter gregkh
2021-03-10 13:24 ` [PATCH 5.4 15/24] media: cx23885: add more quirks for reset DMA on some AMD IOMMU gregkh
2021-03-10 13:24 ` [PATCH 5.4 16/24] ACPI: video: Add DMI quirk for GIGABYTE GB-BXBT-2807 gregkh
2021-03-10 13:24 ` [PATCH 5.4 17/24] ASoC: Intel: bytcr_rt5640: Add quirk for ARCHOS Cesium 140 gregkh
2021-03-10 13:24 ` [PATCH 5.4 18/24] PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller gregkh
2021-03-10 13:24 ` [PATCH 5.4 19/24] misc: eeprom_93xx46: Add quirk to support Microchip 93LC46B eeprom gregkh
2021-03-10 13:24 ` [PATCH 5.4 20/24] drm/msm/a5xx: Remove overwriting A5XX_PC_DBG_ECO_CNTL register gregkh
2021-03-10 13:24 ` [PATCH 5.4 21/24] mmc: sdhci-of-dwcmshc: set SDHCI_QUIRK2_PRESET_VALUE_BROKEN gregkh
2021-03-10 13:24 ` [PATCH 5.4 22/24] HID: i2c-hid: Add I2C_HID_QUIRK_NO_IRQ_AFTER_RESET for ITE8568 EC on Voyo Winpad A15 gregkh
2021-03-10 13:24 ` [PATCH 5.4 23/24] nvme-pci: mark Seagate Nytro XM1440 as QUIRK_NO_NS_DESC_LIST gregkh
2021-03-10 13:24 ` [PATCH 5.4 24/24] nvme-pci: add quirks for Lexar 256GB SSD gregkh
2021-03-10 22:00 ` [PATCH 5.4 00/24] 5.4.105-rc1 review Shuah Khan
2021-03-10 23:52 ` Guenter Roeck
2021-03-11  4:05 ` Ross Schmidt
2021-03-11  4:19 ` Florian Fainelli
2021-03-11 13:08   ` Greg KH
2021-03-11 17:23     ` Florian Fainelli
2021-03-11 17:40       ` Greg KH
2021-03-11 17:41         ` Florian Fainelli
2021-03-12 12:54           ` Alexander Lobakin
2021-03-15  9:50             ` Pali Rohár
2021-03-23 17:20               ` Florian Fainelli
2021-03-23 23:32                 ` Pali Rohár
2021-03-24 10:26                 ` Greg KH
2021-03-12 22:55           ` Florian Fainelli
2021-03-13 13:42             ` Greg KH
2021-03-13 22:30               ` Pavel Machek
2021-03-11  7:34 ` Naresh Kamboju
2021-03-11  7:59 ` Jon Hunter
2021-03-11  9:42 ` Samuel Zou

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=20210310132320.712391524@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=erik.kaneda@intel.com \
    --cc=hdegoede@redhat.com \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.