Received: by 2002:a05:6a10:9848:0:0:0:0 with SMTP id x8csp240105pxf; Wed, 10 Mar 2021 05:26:02 -0800 (PST) X-Google-Smtp-Source: ABdhPJzz9gAAuMaCIXZrn4BkB7dcq3z10juyAQHMLIUK2W8lh1mCTIiSR8Aszw1Ug+2GdS/77YML X-Received: by 2002:aa7:db51:: with SMTP id n17mr3362561edt.259.1615382761833; Wed, 10 Mar 2021 05:26:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1615382761; cv=none; d=google.com; s=arc-20160816; b=FD2KBgYnW+NNyMn/7XzdjleEBNOz3XwtGj5a86HZY4ThcLdnomdbGKb/axiqUD6Z8T M2jTK6IHOyRcQBbxHor3exCXyUPzuoP5ogjv38UpvmwLwBbo1QLQnvISiVnxxa7P+wwn w7XDaHWfR/gFrsmL8KMexMGXkprCoIiBslF0T6HR6593Fxb8FgmsdpACVUBUgoVxR9dB aPPEWsFXhC6UQwF0v3aF3ZEV3LXrsIOTbqkJXtgewY21/XYVIV1gROCiuU/1OhQpphf/ GjF5ywfHrCMB/t3d8H+U4hMvJOig3AJPQe3xSf9H14DRZJh2gw6T1qMLxH1ddwQfx0Sm //GA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=7hbRXGz9zey4mo6PPoubz9i6LfoYZ+e7lfq1lGqptpU=; b=mPR9GLPf9n/wiRuR8TkNbnLpz9HYYF11zNqHnRpVcLt+Q9EAFz91nmBLn0uHgRjDpN aLSYK9srIAMAfBNsVh3m7vvZbO+UOTtGx9srbhvQnKjpMGroK/mcqm7V0aM9cpsGtWmx dbpRhoUUok+ccN9t339T8HM/OBInWQeUjIZMQzcLsoco22uPEYP0KbvIwLas1IpIEcTN rjcPJEAGxkEPPLjS3VLM3QcjitUUuPIHJWMpx4lWSdv9KxjF8oqLrb7cRGubfHqPJZKA kL4AiB4TOc1DdDSCD7lrwqNPw2bbNFo6KAmSYK4cmHxl1O48F29jQUa3IX5TjIsg7b6I wtoA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=aHwqjs50; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id i23si11408696ejv.110.2021.03.10.05.25.38; Wed, 10 Mar 2021 05:26:01 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=aHwqjs50; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232985AbhCJNYo (ORCPT + 99 others); Wed, 10 Mar 2021 08:24:44 -0500 Received: from mail.kernel.org ([198.145.29.99]:45382 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232295AbhCJNYI (ORCPT ); Wed, 10 Mar 2021 08:24:08 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5C4F164FE8; Wed, 10 Mar 2021 13:24:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1615382648; bh=Vv9UikeIutpoj7/MdU8rfR2YotWONpE5xLJ2Iw50AaA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aHwqjs50Nt5GUvkq688UUaLNxH0tw0vQEKavoKYcITJauwR9Zu9sPWB9V4+034yH5 57f1V7ExK3+2BeA2w11W0toGKiMSzbgWGZLO2aIRJOp5a1F3PUAr3qOjaLXcHGPCGj mlLtBQ6JTs3WXCMl2BwLgP1ult92sSGi5ronYVIc= From: gregkh@linuxfoundation.org To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Hans de Goede , Bob Moore , Erik Kaneda , "Rafael J. Wysocki" Subject: [PATCH 5.10 01/49] ACPICA: Fix race in generic_serial_bus (I2C) and GPIO op_region parameter handling Date: Wed, 10 Mar 2021 14:23:12 +0100 Message-Id: <20210310132321.997043366@linuxfoundation.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210310132321.948258062@linuxfoundation.org> References: <20210310132321.948258062@linuxfoundation.org> User-Agent: quilt/0.66 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Greg Kroah-Hartman From: Hans de Goede 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 Signed-off-by: Bob Moore Signed-off-by: Erik Kaneda Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- 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 @@ -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; --- 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", + ®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 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", - ®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 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; }