summaryrefslogtreecommitdiff
path: root/sys/dev/acpi
diff options
context:
space:
mode:
authormsaitoh <msaitoh@NetBSD.org>2019-08-05 10:12:04 +0000
committermsaitoh <msaitoh@NetBSD.org>2019-08-05 10:12:04 +0000
commit0741fcd81992d5ff88ebbc8e55e899ca10d9f81e (patch)
treed6dc2b4ab33934be9a80cf26364f50d12317cd74 /sys/dev/acpi
parentebc51ba0f02ced4c89c1774591ae3a3fa5b4d994 (diff)
- Fix a bug that acpiec_space_handler() doesn't access more than 64bit
correctly. Found by kUBSan on Thinkpad X220. acpiec0 accessed 128bits from address 0xa0. The error message was: UBSan: Undefined Behavior in ../../../../dev/acpi/acpi_ec.c:672:32, shift exponent 64 is too large for 64-bit type 'long unsigned int' - KNF. The error message was:
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r--sys/dev/acpi/acpi_ec.c79
1 files changed, 44 insertions, 35 deletions
diff --git a/sys/dev/acpi/acpi_ec.c b/sys/dev/acpi/acpi_ec.c
index d4f9de4d551..789142e4abb 100644
--- a/sys/dev/acpi/acpi_ec.c
+++ b/sys/dev/acpi/acpi_ec.c
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_ec.c,v 1.75 2017/03/11 08:26:23 tsutsui Exp $ */
+/* $NetBSD: acpi_ec.c,v 1.76 2019/08/05 10:12:04 msaitoh Exp $ */
/*-
* Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
@@ -59,7 +59,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.75 2017/03/11 08:26:23 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.76 2019/08/05 10:12:04 msaitoh Exp $");
#include <sys/param.h>
#include <sys/callout.h>
@@ -404,6 +404,7 @@ post_data_map:
static bool
acpiec_suspend(device_t dv, const pmf_qual_t *qual)
{
+
acpiec_cold = true;
return true;
@@ -412,6 +413,7 @@ acpiec_suspend(device_t dv, const pmf_qual_t *qual)
static bool
acpiec_resume(device_t dv, const pmf_qual_t *qual)
{
+
acpiec_cold = false;
return true;
@@ -454,9 +456,10 @@ acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle,
ACPI_FREE(p);
return false;
}
-
+
if (p->Package.Count != 2) {
- aprint_error_dev(self, "_GPE package does not contain 2 elements\n");
+ aprint_error_dev(self,
+ "_GPE package does not contain 2 elements\n");
ACPI_FREE(p);
return false;
}
@@ -511,6 +514,7 @@ static ACPI_STATUS
acpiec_space_setup(ACPI_HANDLE region, uint32_t func, void *arg,
void **region_arg)
{
+
if (func == ACPI_REGION_DEACTIVATE)
*region_arg = NULL;
else
@@ -528,9 +532,11 @@ acpiec_lock(device_t dv)
mutex_enter(&sc->sc_access_mtx);
if (sc->sc_need_global_lock) {
- rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->sc_global_lock);
+ rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT,
+ &sc->sc_global_lock);
if (rv != AE_OK) {
- aprint_error_dev(dv, "failed to acquire global lock: %s\n",
+ aprint_error_dev(dv,
+ "failed to acquire global lock: %s\n",
AcpiFormatException(rv));
return;
}
@@ -546,7 +552,8 @@ acpiec_unlock(device_t dv)
if (sc->sc_need_global_lock) {
rv = AcpiReleaseGlobalLock(sc->sc_global_lock);
if (rv != AE_OK) {
- aprint_error_dev(dv, "failed to release global lock: %s\n",
+ aprint_error_dev(dv,
+ "failed to release global lock: %s\n",
AcpiFormatException(rv));
}
}
@@ -587,7 +594,8 @@ acpiec_read(device_t dv, uint8_t addr, uint8_t *val)
} else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) {
mutex_exit(&sc->sc_mtx);
acpiec_unlock(dv);
- aprint_error_dev(dv, "command takes over %d sec...\n", EC_CMD_TIMEOUT);
+ aprint_error_dev(dv,
+ "command takes over %d sec...\n", EC_CMD_TIMEOUT);
return AE_ERROR;
}
@@ -634,7 +642,8 @@ acpiec_write(device_t dv, uint8_t addr, uint8_t val)
} else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) {
mutex_exit(&sc->sc_mtx);
acpiec_unlock(dv);
- aprint_error_dev(dv, "command takes over %d sec...\n", EC_CMD_TIMEOUT);
+ aprint_error_dev(dv,
+ "command takes over %d sec...\n", EC_CMD_TIMEOUT);
return AE_ERROR;
}
@@ -648,43 +657,42 @@ static ACPI_STATUS
acpiec_space_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS paddr,
uint32_t width, ACPI_INTEGER *value, void *arg, void *region_arg)
{
- device_t dv;
+ device_t dv = arg;
ACPI_STATUS rv;
- uint8_t addr, reg;
- unsigned int i;
+ uint8_t addr;
+ uint8_t *reg;
+ if ((func != ACPI_READ) && (func != ACPI_WRITE)) {
+ aprint_error("%s: invalid Address Space function called: %x\n",
+ device_xname(dv), (unsigned int)func);
+ return AE_BAD_PARAMETER;
+ }
if (paddr > 0xff || width % 8 != 0 || value == NULL || arg == NULL ||
paddr + width / 8 > 0x100)
return AE_BAD_PARAMETER;
addr = paddr;
- dv = arg;
+ reg = (uint8_t *)value;
rv = AE_OK;
- switch (func) {
- case ACPI_READ:
+ if (func == ACPI_READ)
*value = 0;
- for (i = 0; i < width; i += 8, ++addr) {
- rv = acpiec_read(dv, addr, &reg);
- if (rv != AE_OK)
- break;
- *value |= (ACPI_INTEGER)reg << i;
- }
- break;
- case ACPI_WRITE:
- for (i = 0; i < width; i += 8, ++addr) {
- reg = (*value >>i) & 0xff;
- rv = acpiec_write(dv, addr, reg);
- if (rv != AE_OK)
- break;
+
+ do {
+ switch (func) {
+ case ACPI_READ:
+ rv = acpiec_read(dv, addr, reg);
+ break;
+ case ACPI_WRITE:
+ rv = acpiec_write(dv, addr, *reg);
+ break;
}
- break;
- default:
- aprint_error("%s: invalid Address Space function called: %x\n",
- device_xname(dv), (unsigned int)func);
- return AE_BAD_PARAMETER;
- }
+ if (rv != AE_OK)
+ break;
+ addr++;
+ reg++;
+ } while (addr < (paddr + width / 8));
return rv;
}
@@ -867,7 +875,8 @@ acpiec_bus_read(device_t dv, u_int addr, ACPI_INTEGER *val, int width)
ACPI_STATUS
acpiec_bus_write(device_t dv, u_int addr, ACPI_INTEGER val, int width)
{
- return acpiec_space_handler(ACPI_WRITE, addr, width * 8, &val, dv, NULL);
+ return acpiec_space_handler(ACPI_WRITE, addr, width * 8, &val, dv,
+ NULL);
}
ACPI_HANDLE