Skip to content

Commit be6a150

Browse files
dedekindrafaeljw
authored andcommitted
intel_idle: Add C-states validation
Add validation for C-states specified via the "table=" module parameter. Treat this module parameter as untrusted input and validate it thoroughly. Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Link: https://patch.msgid.link/20251216080402.156988-4-dedekind1@gmail.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 111f77a commit be6a150

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

drivers/idle/intel_idle.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <linux/kernel.h>
4646
#include <linux/cpuidle.h>
4747
#include <linux/tick.h>
48+
#include <linux/time64.h>
4849
#include <trace/events/power.h>
4950
#include <linux/sched.h>
5051
#include <linux/sched/smt.h>
@@ -75,6 +76,11 @@ static bool ibrs_off __read_mostly;
7576

7677
/* The maximum allowed length for the 'table' module parameter */
7778
#define MAX_CMDLINE_TABLE_LEN 256
79+
/* Maximum allowed C-state latency */
80+
#define MAX_CMDLINE_LATENCY_US (5 * USEC_PER_MSEC)
81+
/* Maximum allowed C-state target residency */
82+
#define MAX_CMDLINE_RESIDENCY_US (100 * USEC_PER_MSEC)
83+
7884
static char cmdline_table_str[MAX_CMDLINE_TABLE_LEN] __read_mostly;
7985

8086
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
@@ -2434,6 +2440,41 @@ static char *get_cmdline_field(char *args, char **field, char sep)
24342440
return args + i + 1;
24352441
}
24362442

2443+
/**
2444+
* validate_cmdline_cstate - Validate a C-state from cmdline.
2445+
* @state: The C-state to validate.
2446+
* @prev_state: The previous C-state in the table or NULL.
2447+
*
2448+
* Return: 0 if the C-state is valid or -EINVAL otherwise.
2449+
*/
2450+
static int validate_cmdline_cstate(struct cpuidle_state *state,
2451+
struct cpuidle_state *prev_state)
2452+
{
2453+
if (state->exit_latency == 0)
2454+
/* Exit latency 0 can only be used for the POLL state */
2455+
return -EINVAL;
2456+
2457+
if (state->exit_latency > MAX_CMDLINE_LATENCY_US)
2458+
return -EINVAL;
2459+
2460+
if (state->target_residency > MAX_CMDLINE_RESIDENCY_US)
2461+
return -EINVAL;
2462+
2463+
if (state->target_residency < state->exit_latency)
2464+
return -EINVAL;
2465+
2466+
if (!prev_state)
2467+
return 0;
2468+
2469+
if (state->exit_latency <= prev_state->exit_latency)
2470+
return -EINVAL;
2471+
2472+
if (state->target_residency <= prev_state->target_residency)
2473+
return -EINVAL;
2474+
2475+
return 0;
2476+
}
2477+
24372478
/**
24382479
* cmdline_table_adjust - Adjust the C-states table with data from cmdline.
24392480
* @drv: cpuidle driver (assumed to point to intel_idle_driver).
@@ -2532,6 +2573,19 @@ static void __init cmdline_table_adjust(struct cpuidle_driver *drv)
25322573
state->name, state->exit_latency, state->target_residency);
25332574
}
25342575

2576+
/* Validate the adjusted C-states, start with index 1 to skip POLL */
2577+
for (i = 1; i < drv->state_count; i++) {
2578+
struct cpuidle_state *prev_state;
2579+
2580+
state = &cmdline_states[i];
2581+
prev_state = &cmdline_states[i - 1];
2582+
2583+
if (validate_cmdline_cstate(state, prev_state)) {
2584+
pr_err("C-state '%s' validation failed\n", state->name);
2585+
goto error;
2586+
}
2587+
}
2588+
25352589
/* Copy the adjusted C-states table back */
25362590
for (i = 1; i < drv->state_count; i++)
25372591
drv->states[i] = cmdline_states[i];

0 commit comments

Comments
 (0)