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: <1458564569-19672-4-git-send-email-prarit@redhat.com>
Date:	Mon, 21 Mar 2016 08:49:29 -0400
From:	Prarit Bhargava <prarit@...hat.com>
To:	linux-kernel@...r.kernel.org
Cc:	Prarit Bhargava <prarit@...hat.com>
Subject: [PATCH 3/3] cpuidle, Prevent users from enabling cstates that are disabled in Hardware

The current codebase allows a user to enable a cstate even though the
hardware has disabled it.  This patch adds state checking and prevents
userspace from setting a hardware disabled cstate to enabled.

Signed-off-by: Prarit Bhargava <prarit@...hat.com>
---
 drivers/cpuidle/governors/ladder.c |    3 +++
 drivers/cpuidle/governors/menu.c   |    4 ++++
 drivers/cpuidle/sysfs.c            |   34 ++++++++++++++++++++++++++++++++--
 drivers/idle/intel_idle.c          |    6 ++++--
 include/linux/cpuidle.h            |   10 ++++++++--
 5 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 63bd5a4..680e5ee 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -144,6 +144,9 @@ static int ladder_enable_device(struct cpuidle_driver *drv,
 		state = &drv->states[i];
 		lstate = &ldev->states[i];
 
+		/* Some states may be disabled by hardware */
+		dev->states_usage[i].disable = drv->states[i].disabled;
+
 		lstate->stats.promotion_count = 0;
 		lstate->stats.demotion_count = 0;
 
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 0742b32..7351e0d 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -466,6 +466,10 @@ static int menu_enable_device(struct cpuidle_driver *drv,
 	for(i = 0; i < BUCKETS; i++)
 		data->correction_factor[i] = RESOLUTION * DECAY;
 
+	/* Some states may be disabled by hardware */
+	for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
+		dev->states_usage[i].disable = drv->states[i].disabled;
+
 	return 0;
 }
 
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 832a2c3..313d1aa 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -274,6 +274,38 @@ static ssize_t store_state_##_name(struct cpuidle_state *state, \
 	return size; \
 }
 
+static ssize_t store_state_disable(struct cpuidle_state *state,
+				   struct cpuidle_state_usage *state_usage,
+				   const char *buf, size_t size)
+{
+	unsigned long long value;
+	int err;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (state_usage->disable == CPUIDLE_STATE_HW_DISABLE) {
+		pr_info("cpuidle: state %s is disabled by hardware.\n",
+			state->name);
+		return -EINVAL;
+	}
+
+	err = kstrtoull(buf, 0, &value);
+	if (err)
+		return err;
+	if (value)
+		state_usage->disable = CPUIDLE_STATE_DISABLE;
+	else
+		state_usage->disable = CPUIDLE_STATE_ENABLE;
+	return size;
+}
+
+static ssize_t show_state_disable(struct cpuidle_state *state,
+				  struct cpuidle_state_usage *state_usage,
+				  char *buf)
+{
+	return sprintf(buf, "%u\n", !!state_usage->disable);
+}
+
 #define define_show_state_ull_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
 				  struct cpuidle_state_usage *state_usage, \
@@ -299,8 +331,6 @@ define_show_state_ull_function(usage)
 define_show_state_ull_function(time)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
-define_show_state_ull_function(disable)
-define_store_state_ull_function(disable)
 
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 58bc913..f23d0f6 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -1142,10 +1142,12 @@ static int __init intel_idle_cpuidle_driver_init(void)
 
 		/* Has this state been disabled in hardware? */
 		if (limit < cpuidle_state_table[cstate].limit) {
-			cpuidle_state_table[cstate].disabled = 1;
-			pr_debug(PREFIX "state %s (0x%x) is disabled.  Max Package limit is 0x%x.\n",
+			cpuidle_state_table[cstate].disabled =
+						       CPUIDLE_STATE_HW_DISABLE;
+			pr_debug(PREFIX "state %s (0x%x) is disabled and set to %d.  Max Package limit is 0x%x.\n",
 				 cpuidle_state_table[cstate].name,
 				 cpuidle_state_table[cstate].limit,
+				 cpuidle_state_table[cstate].disabled,
 				 limit);
 
 		}
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 8bcfabb..0e59e17 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -29,8 +29,14 @@ struct cpuidle_driver;
  * CPUIDLE DEVICE INTERFACE *
  ****************************/
 
+enum cpuidle_state_disable {
+	CPUIDLE_STATE_ENABLE = 0,
+	CPUIDLE_STATE_DISABLE = 1,
+	CPUIDLE_STATE_HW_DISABLE = 2,
+};
+
 struct cpuidle_state_usage {
-	unsigned long long	disable;
+	enum cpuidle_state_disable disable;
 	unsigned long long	usage;
 	unsigned long long	time; /* in US */
 };
@@ -44,7 +50,7 @@ struct cpuidle_state {
 	unsigned int	exit_latency; /* in US */
 	int		power_usage; /* in mW */
 	unsigned int	target_residency; /* in US */
-	bool		disabled; /* disabled on all CPUs */
+	enum cpuidle_state_disable	disabled; /* disabled on all CPUs */
 
 	int (*enter)	(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
-- 
1.7.9.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ