Information disclosure (kernel memory leakage via GPIO short-read in ADM1266 GPIO accessors)

HIGH
torvalds/linux
Commit: a7232f68c43c
Affected: v7.0-rc6 and earlier (up to this patch)
2026-05-25 23:28 UTC

Description

The commit fixes an information disclosure vulnerability in ADM1266 GPIO accessors under hwmon/pmbus. Previously adm1266_gpio_get() and adm1266_gpio_get_multiple() performed a 2-byte block read and combined read_buf[0] and read_buf[1] without ensuring two bytes were actually returned. If the I2C device returned 0 or 1 bytes (short block-read), read_buf[1] could be uninitialized stack memory, and the resulting pins_status/status value would leak kernel stack bits to userspace via gpiolib (sysfs or ioctls). The patch adds a check for ret < 2 and returns -EIO, preventing use of potentially garbage data and eliminating the leak.

Proof of Concept

PoC (proof-of-concept) is provided conceptually, showing how an attacker with a vulnerable kernel could trigger a short I2C block read and observe leaked kernel data via GPIO status reporting. The PoC relies on an I2C device that returns 0 or 1 byte for a GPIO_STATUS/PDIO_STATUS block read on the ADM1266 interface. On a vulnerable kernel, the code path would compose pins_status from read_buf[0] and read_buf[1], where read_buf[1] contains uninitialized stack data, leaking bits to userspace. The following simple demonstration illustrates the exploit using a user-space I2C interface (requires a device/emulator that returns only 1 byte for the GPIO_STATUS read or a stub device that reports a short read). Python PoC (conceptual, requires a vulnerable kernel and a short-read-capable I2C device): from smbus2 import SMBus DEVICE_ADDR = 0x5A # ADM1266 GPIO/Status device address (example) GPIO_STATUS = 0x10 # ADM1266 GPIO_STATUS command (example) with SMBus(1) as bus: # Attempt to read 2 bytes from the GPIO_STATUS; a vulnerable kernel may return only 0 or 1 byte data = bus.read_i2c_block_data(DEVICE_ADDR, GPIO_STATUS, 2) pins_status = data[0] + (data[1] << 8) print("pins_status:", pins_status) Notes: - On a vulnerable kernel (pre-fix), data[1] could be uninitialized and contain stack garbage, causing information disclosure via the reported pins_status value. - On the fixed kernel, the driver returns -EIO when ret < 2, so this PoC would fail with an error rather than leaking memory. - The exact I2C device address and GPIO_STATUS command are hardware-dependent and are used here as illustrative placeholders. A real PoC would use an I2C stub or emulator that returns only 0 or 1 byte for the block read.

Commit Details

Author: Abdurrahman Hussain

Date: 2026-05-19 00:52 UTC

Message:

hwmon: (pmbus/adm1266) reject short block-read responses in the GPIO accessors adm1266_gpio_get() and adm1266_gpio_get_multiple() both compose the pin-status word as pins_status = read_buf[0] + (read_buf[1] << 8); right after i2c_smbus_read_block_data(), guarding only against an error return. A well-behaved device returns 2 bytes for GPIO_STATUS/PDIO_STATUS, but the helper happily reports a 0- or 1-byte response too. If the device returns 0 bytes, both read_buf slots are uninitialized stack memory; if it returns 1 byte, read_buf[1] is. The composed value then flows through set_bit() into the caller's *bits in adm1266_gpio_get_multiple(), or into the return value of adm1266_gpio_get(), and ends up in userspace via gpiolib (sysfs and the char-dev ioctls). That leaks a few bits of kernel stack per request on any device whose firmware glitch, bus error, or hostile slave produces a short block-read response. Add the missing length check to both call sites and surface a short response as -EIO. Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") Cc: stable@vger.kernel.org Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-3-e425e4f88139@nexthop.ai Signed-off-by: Guenter Roeck <linux@roeck-us.net>

Triage Assessment

Vulnerability Type: Information disclosure

Confidence: HIGH

Reasoning:

The patch adds a check for short I2C block reads (ret < 2) and returns -EIO, preventing the code from using potentially uninitialized read_buf data to form GPIO status. Without this, a faulty/short response could leak kernel stack bits to userspace via gpiolib, constituting an information disclosure vulnerability. The fix is a targeted security fix rather than a general refactor or feature change.

Verification Assessment

Vulnerability Type: Information disclosure (kernel memory leakage via GPIO short-read in ADM1266 GPIO accessors)

Confidence: HIGH

Affected Versions: v7.0-rc6 and earlier (up to this patch)

Code Diff

diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index 3bf512df30cdb4..6f904a5a8ea6b3 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -176,6 +176,8 @@ static int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset) ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); if (ret < 0) return ret; + if (ret < 2) + return -EIO; pins_status = read_buf[0] + (read_buf[1] << 8); if (offset < ADM1266_GPIO_NR) @@ -196,6 +198,8 @@ static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); if (ret < 0) return ret; + if (ret < 2) + return -EIO; status = read_buf[0] + (read_buf[1] << 8); @@ -208,6 +212,8 @@ static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf); if (ret < 0) return ret; + if (ret < 2) + return -EIO; status = read_buf[0] + (read_buf[1] << 8);
← Back to Alerts View on GitHub →