lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250416-for-upstream-spd5118-spd-write-prot-detect-v1-2-8b3bcafe9dad@canonical.com>
Date: Wed, 16 Apr 2025 14:46:27 +0800
From: "Yo-Jung (Leo) Lin" <leo.lin@...onical.com>
To: Jean Delvare <jdelvare@...e.com>, Guenter Roeck <linux@...ck-us.net>
Cc: linux-hwmon@...r.kernel.org, linux-kernel@...r.kernel.org, 
 "Yo-Jung Lin (Leo)" <leo.lin@...onical.com>
Subject: [PATCH 2/2] hwmon: (spd5118) restrict writes under SPD write
 protection

On some platforms, SPD Write Protection for the SMBus controller may be
enabled. For the i801 family, this will forbid writing data to devices
residing on addresses from 0x50 to 0x57. This may lead to the following
issues:

  1) Writes to the sensor hwmon sysfs attributes will always result in
     ENXIO.

  2) System-wide resume will encounter errors during regcache sync back,
     resulting in the following messages during resume:

     kernel: spd5118 1-0050: Failed to write b = 0: -6
     kernel: spd5118 1-0050: PM: dpm_run_callback(): spd5118_resume [spd5118] returns -6
     kernel: spd5118 1-0050: PM: failed to resume async: error -6

To address this, check if the sensor can be written to at probe, and bypass
write-related functions if writing to the sensor is not possible.

Signed-off-by: Yo-Jung (Leo) Lin <leo.lin@...onical.com>
---
 drivers/hwmon/spd5118.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/spd5118.c b/drivers/hwmon/spd5118.c
index 3cb2eb2e0227..9dd5342c31dd 100644
--- a/drivers/hwmon/spd5118.c
+++ b/drivers/hwmon/spd5118.c
@@ -75,6 +75,7 @@ static const unsigned short normal_i2c[] = {
 struct spd5118_data {
 	struct regmap *regmap;
 	struct mutex nvmem_lock;
+	bool write_protected;
 };
 
 /* hwmon */
@@ -284,7 +285,7 @@ static umode_t spd5118_is_visible(const void *_data, enum hwmon_sensor_types typ
 	case hwmon_temp_lcrit:
 	case hwmon_temp_crit:
 	case hwmon_temp_enable:
-		return 0644;
+		return data->write_protected ? 0444 : 0644;
 	case hwmon_temp_min_alarm:
 	case hwmon_temp_max_alarm:
 	case hwmon_temp_crit_alarm:
@@ -499,7 +500,7 @@ static const struct regmap_range_cfg spd5118_regmap_range_cfg[] = {
 	},
 };
 
-static const struct regmap_config spd5118_regmap_config = {
+static struct regmap_config spd5118_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 	.max_register = 0x7ff,
@@ -563,6 +564,21 @@ static int spd5118_init(struct i2c_client *client)
 	return 0;
 }
 
+static bool spd5118_write_protected(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	int mode = 0;
+	int err = 0;
+
+	mode = i2c_smbus_read_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE);
+	if (mode < 0)
+		dev_warn(dev, "Failed to read MR11: %d", mode);
+
+	err = i2c_smbus_write_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE, mode);
+
+	return (err < 0);
+}
+
 static int spd5118_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@@ -580,6 +596,11 @@ static int spd5118_probe(struct i2c_client *client)
 	if (!data)
 		return -ENOMEM;
 
+	if (spd5118_write_protected(client)) {
+		data->write_protected = true;
+		spd5118_regmap_config.cache_type = REGCACHE_NONE;
+	}
+
 	regmap = devm_regmap_init_i2c(client, &spd5118_regmap_config);
 	if (IS_ERR(regmap))
 		return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n");
@@ -638,6 +659,9 @@ static int spd5118_suspend(struct device *dev)
 	u32 regval;
 	int err;
 
+	if (data->write_protected)
+		return 0;
+
 	/*
 	 * Make sure the configuration register in the regmap cache is current
 	 * before bypassing it.
@@ -662,6 +686,9 @@ static int spd5118_resume(struct device *dev)
 	struct spd5118_data *data = dev_get_drvdata(dev);
 	struct regmap *regmap = data->regmap;
 
+	if (data->write_protected)
+		return 0;
+
 	regcache_cache_only(regmap, false);
 	return regcache_sync(regmap);
 }

-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ