Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e183d7a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'hwmon-for-linus-v4.7-rc4' of...

Merge tag 'hwmon-for-linus-v4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:
 "Two stability fixes plus a security fix for the dell-smm driver"

* tag 'hwmon-for-linus-v4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (dell-smm) Disallow fan_type() calls on broken machines
  hwmon: (dell-smm) Restrict fan control and serial number to CAP_SYS_ADMIN by default
  hwmon: (dell-smm) Fail in ioctl I8K_BIOS_VERSION when bios version is not a number
parents 33688abb 2744d2fd
Loading
Loading
Loading
Loading
+42 −18
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/uaccess.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/ctype.h>


#include <linux/i8k.h>
#include <linux/i8k.h>


@@ -66,11 +67,13 @@


static DEFINE_MUTEX(i8k_mutex);
static DEFINE_MUTEX(i8k_mutex);
static char bios_version[4];
static char bios_version[4];
static char bios_machineid[16];
static struct device *i8k_hwmon_dev;
static struct device *i8k_hwmon_dev;
static u32 i8k_hwmon_flags;
static u32 i8k_hwmon_flags;
static uint i8k_fan_mult = I8K_FAN_MULT;
static uint i8k_fan_mult = I8K_FAN_MULT;
static uint i8k_pwm_mult;
static uint i8k_pwm_mult;
static uint i8k_fan_max = I8K_FAN_HIGH;
static uint i8k_fan_max = I8K_FAN_HIGH;
static bool disallow_fan_type_call;


#define I8K_HWMON_HAVE_TEMP1	(1 << 0)
#define I8K_HWMON_HAVE_TEMP1	(1 << 0)
#define I8K_HWMON_HAVE_TEMP2	(1 << 1)
#define I8K_HWMON_HAVE_TEMP2	(1 << 1)
@@ -94,13 +97,13 @@ module_param(ignore_dmi, bool, 0);
MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");


#if IS_ENABLED(CONFIG_I8K)
#if IS_ENABLED(CONFIG_I8K)
static bool restricted;
static bool restricted = true;
module_param(restricted, bool, 0);
module_param(restricted, bool, 0);
MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
MODULE_PARM_DESC(restricted, "Restrict fan control and serial number to CAP_SYS_ADMIN (default: 1)");


static bool power_status;
static bool power_status;
module_param(power_status, bool, 0600);
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k (default: 0)");
#endif
#endif


static uint fan_mult;
static uint fan_mult;
@@ -239,6 +242,9 @@ static int i8k_get_fan_type(int fan)
{
{
	struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
	struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };


	if (disallow_fan_type_call)
		return -EINVAL;

	regs.ebx = fan & 0xff;
	regs.ebx = fan & 0xff;
	return i8k_smm(&regs) ? : regs.eax & 0xff;
	return i8k_smm(&regs) ? : regs.eax & 0xff;
}
}
@@ -387,14 +393,20 @@ i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)


	switch (cmd) {
	switch (cmd) {
	case I8K_BIOS_VERSION:
	case I8K_BIOS_VERSION:
		if (!isdigit(bios_version[0]) || !isdigit(bios_version[1]) ||
		    !isdigit(bios_version[2]))
			return -EINVAL;

		val = (bios_version[0] << 16) |
		val = (bios_version[0] << 16) |
				(bios_version[1] << 8) | bios_version[2];
				(bios_version[1] << 8) | bios_version[2];
		break;
		break;


	case I8K_MACHINE_ID:
	case I8K_MACHINE_ID:
		memset(buff, 0, 16);
		if (restricted && !capable(CAP_SYS_ADMIN))
		strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
			return -EPERM;
			sizeof(buff));

		memset(buff, 0, sizeof(buff));
		strlcpy(buff, bios_machineid, sizeof(buff));
		break;
		break;


	case I8K_FN_STATUS:
	case I8K_FN_STATUS:
@@ -511,7 +523,7 @@ static int i8k_proc_show(struct seq_file *seq, void *offset)
	seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
	seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
		   I8K_PROC_FMT,
		   I8K_PROC_FMT,
		   bios_version,
		   bios_version,
		   i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
		   (restricted && !capable(CAP_SYS_ADMIN)) ? "-1" : bios_machineid,
		   cpu_temp,
		   cpu_temp,
		   left_fan, right_fan, left_speed, right_speed,
		   left_fan, right_fan, left_speed, right_speed,
		   ac_power, fn_key);
		   ac_power, fn_key);
@@ -718,6 +730,9 @@ static struct attribute *i8k_attrs[] = {
static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
			      int index)
			      int index)
{
{
	if (disallow_fan_type_call &&
	    (index == 9 || index == 12))
		return 0;
	if (index >= 0 && index <= 1 &&
	if (index >= 0 && index <= 1 &&
	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
		return 0;
		return 0;
@@ -929,12 +944,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {


MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);


static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
	{
/*
/*
		 * CPU fan speed going up and down on Dell Studio XPS 8000
 * On some machines once I8K_SMM_GET_FAN_TYPE is issued then CPU fan speed
		 * for unknown reasons.
 * randomly going up and down due to bug in Dell SMM or BIOS. Here is blacklist
 * of affected Dell machines for which we disallow I8K_SMM_GET_FAN_TYPE call.
 * See bug: https://bugzilla.kernel.org/show_bug.cgi?id=100121
 */
 */
static struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initdata = {
	{
		.ident = "Dell Studio XPS 8000",
		.ident = "Dell Studio XPS 8000",
		.matches = {
		.matches = {
			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -942,16 +959,19 @@ static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
		},
		},
	},
	},
	{
	{
		/*
		 * CPU fan speed going up and down on Dell Studio XPS 8100
		 * for unknown reasons.
		 */
		.ident = "Dell Studio XPS 8100",
		.ident = "Dell Studio XPS 8100",
		.matches = {
		.matches = {
			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
		},
		},
	},
	},
	{
		.ident = "Dell Inspiron 580",
		.matches = {
			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 580 "),
		},
	},
	{ }
	{ }
};
};


@@ -966,8 +986,7 @@ static int __init i8k_probe(void)
	/*
	/*
	 * Get DMI information
	 * Get DMI information
	 */
	 */
	if (!dmi_check_system(i8k_dmi_table) ||
	if (!dmi_check_system(i8k_dmi_table)) {
	    dmi_check_system(i8k_blacklist_dmi_table)) {
		if (!ignore_dmi && !force)
		if (!ignore_dmi && !force)
			return -ENODEV;
			return -ENODEV;


@@ -978,8 +997,13 @@ static int __init i8k_probe(void)
			i8k_get_dmi_data(DMI_BIOS_VERSION));
			i8k_get_dmi_data(DMI_BIOS_VERSION));
	}
	}


	if (dmi_check_system(i8k_blacklist_fan_type_dmi_table))
		disallow_fan_type_call = true;

	strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION),
	strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION),
		sizeof(bios_version));
		sizeof(bios_version));
	strlcpy(bios_machineid, i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
		sizeof(bios_machineid));


	/*
	/*
	 * Get SMM Dell signature
	 * Get SMM Dell signature