@@ -61,7 +61,18 @@ static bool __read_mostly sysrq_always_enabled;
static bool sysrq_on(void)
{
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ /*
+ * In CRASH_ONLY mode, sysrq is considered "on" only for the purpose
+ * of allowing the crash command. The actual check for individual
+ * commands happens in sysrq_on_mask().
+ * For general "is sysrq on?" queries (like for input handler reg),
+ * it should reflect that at least something (crash) is possible.
+ */
+ return true;
+#else
return sysrq_enabled || sysrq_always_enabled;
+#endif
}
/**
@@ -82,9 +93,19 @@ EXPORT_SYMBOL_GPL(sysrq_mask);
*/
static bool sysrq_on_mask(int mask)
{
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ /*
+ * If CRASH_ONLY is set, only allow operations that have the
+ * SYSRQ_ENABLE_DUMP mask (which sysrq_crash_op uses).
+ * This makes sysrq_enabled and sysrq_always_enabled irrelevant
+ * for other operations.
+ */
+ return mask == SYSRQ_ENABLE_DUMP;
+#else
return sysrq_always_enabled ||
sysrq_enabled == 1 ||
(sysrq_enabled & mask);
+#endif
}
static int __init sysrq_always_enabled_setup(char *str)
@@ -557,6 +578,21 @@ static int sysrq_key_table_key2index(u8 key)
}
}
+/*
+ * Initialize the sysrq_key_table at boot time if CRASH_ONLY is set.
+ * This ensures only the crash handler is active.
+ */
+static void __init sysrq_init_crash_only_table(void)
+{
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ int i;
+ const struct sysrq_key_op *crash_op = &sysrq_crash_op;
+ for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++)
+ sysrq_key_table[i] = NULL;
+ sysrq_key_table[sysrq_key_table_key2index('c')] = crash_op;
+#endif
+};
+
/*
* get and put functions for the table, exposed to modules.
*/
@@ -584,7 +620,6 @@ void __handle_sysrq(u8 key, bool check_mask)
{
const struct sysrq_key_op *op_p;
int orig_suppress_printk;
- int i;
orig_suppress_printk = suppress_printk;
suppress_printk = 0;
@@ -599,7 +634,15 @@ void __handle_sysrq(u8 key, bool check_mask)
*/
printk_force_console_enter();
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ if (key != 'c') { /* In CRASH_ONLY mode, only 'c' is considered */
+ op_p = NULL;
+ } else {
+ op_p = __sysrq_get_key_op(key);
+ }
+#else
op_p = __sysrq_get_key_op(key);
+#endif
if (op_p) {
/*
* Should we check for enabled operations (/proc/sysrq-trigger
@@ -615,6 +658,15 @@ void __handle_sysrq(u8 key, bool check_mask)
}
} else {
pr_info("HELP : ");
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ /* Check if the crash op is actually in the table and is the crash_op. */
+ if (sysrq_key_table_key2index('c') != -1 &&
+ sysrq_key_table[sysrq_key_table_key2index('c')] == &sysrq_crash_op)
+ pr_cont("%s ", sysrq_crash_op.help_msg);
+ else /* Should not happen if table is defined correctly */
+ pr_cont("[Crash command not available] ");
+#else
+ int i;
/* Only print the help msg once per handler */
for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
if (sysrq_key_table[i]) {
@@ -628,6 +680,7 @@ void __handle_sysrq(u8 key, bool check_mask)
pr_cont("%s ", sysrq_key_table[i]->help_msg);
}
}
+#endif
pr_cont("\n");
printk_force_console_exit();
}
@@ -1104,6 +1157,10 @@ static inline void sysrq_unregister_handler(void)
int sysrq_toggle_support(int enable_mask)
{
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ pr_warn("SysRq: CONFIG_MAGIC_SYSRQ_CRASH_ONLY is set. Runtime toggle is not allowed.\n");
+ return -EPERM;
+#else
bool was_enabled = sysrq_on();
sysrq_enabled = enable_mask;
@@ -1116,6 +1173,7 @@ int sysrq_toggle_support(int enable_mask)
}
return 0;
+#endif
}
EXPORT_SYMBOL_GPL(sysrq_toggle_support);
@@ -1145,12 +1203,30 @@ static int __sysrq_swap_key_ops(u8 key, const struct sysrq_key_op *insert_op_p,
int register_sysrq_key(u8 key, const struct sysrq_key_op *op_p)
{
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ /*
+ * In CRASH_ONLY mode, do not allow registering new SysRq ops.
+ */
+ pr_warn("SysRq: CONFIG_MAGIC_SYSRQ_CRASH_ONLY is set. Cannot register new SysRq key '%c'.\n", key);
+ return -EPERM;
+#endif
return __sysrq_swap_key_ops(key, op_p, NULL);
}
EXPORT_SYMBOL(register_sysrq_key);
int unregister_sysrq_key(u8 key, const struct sysrq_key_op *op_p)
{
+#ifdef CONFIG_MAGIC_SYSRQ_CRASH_ONLY
+ /*
+ * In CRASH_ONLY mode, do not allow unregistering the crash op.
+ * Other ops should be NULL anyway due to sysrq_init_crash_only_table.
+ */
+ if (op_p == &sysrq_crash_op) {
+ pr_warn("SysRq: CONFIG_MAGIC_SYSRQ_CRASH_ONLY is set. Cannot unregister the crash SysRq key '%c'.\n", key);
+ return -EPERM;
+ }
+ return -EPERM; /* Attempt to unregister anything else is also an error */
+#endif
return __sysrq_swap_key_ops(key, NULL, op_p);
}
EXPORT_SYMBOL(unregister_sysrq_key);
@@ -1209,6 +1285,7 @@ static inline void sysrq_init_procfs(void)
static int __init sysrq_init(void)
{
sysrq_init_procfs();
+ sysrq_init_crash_only_table();
if (sysrq_on())
sysrq_register_handler();
@@ -640,6 +640,19 @@ config MAGIC_SYSRQ_DEFAULT_ENABLE
This may be set to 1 or 0 to enable or disable them all, or
to a bitmask as described in Documentation/admin-guide/sysrq.rst.
+config MAGIC_SYSRQ_CRASH_ONLY
+ bool "Restrict Magic SysRq to crash command only"
+ depends on MAGIC_SYSRQ
+ default n
+ help
+ If you say Y here, the Magic SysRq key functionality will be
+ severely restricted at compile time. Only the 'c' command (trigger
+ a system crash) will be available. All other SysRq commands will be
+ disabled, and no new SysRq commands can be registered at runtime.
+ The /proc/sys/kernel/sysrq setting will be ineffective for
+ non-crash commands, and attempts to change it may be blocked.
+ This is a security hardening option.
+
config MAGIC_SYSRQ_SERIAL
bool "Enable magic SysRq key over serial"
depends on MAGIC_SYSRQ
This commit introduces a new Kconfig option, CONFIG_MAGIC_SYSRQ_CRASH_ONLY, which allows for a significant hardening of the system by restricting the Magic SysRq functionality at compile time. Security Impact: - Reduces attack surface by disabling non-essential SysRq commands - Maintains critical crash-dump capability required for debugging - Eliminates runtime configuration vulnerabilities When CONFIG_MAGIC_SYSRQ_CRASH_ONLY is enabled: 1. Restricted Commands: Only the 'c' (trigger a system crash/dump) SysRq command remains operational. All other built-in SysRq commands (e.g., reboot, sync, show-memory, SAK) are disabled. 2. Runtime Registration Disabled: The kernel will no longer allow the registration of new SysRq key operations at runtime via register_sysrq_key(). Attempts to do so will return -EPERM and a warning will be logged. 3. Crash Command Unregistration Prevented: The 'c' (crash) command cannot be unregistered at runtime if this Kconfig option is active. 4. Proc Interface Hardening: The /proc/sys/kernel/sysrq interface, which normally allows runtime enabling/disabling of SysRq features, is effectively neutered for non-crash commands. - Writing to /proc/sys/kernel/sysrq to enable features other than the crash dump will be blocked (returns -EPERM with a warning). - The sysrq_on_mask() function, which checks if a specific SysRq operation is permitted, will only return true for the crash dump operation, regardless of the /proc/sys/kernel/sysrq bitmask or the sysrq_always_enabled kernel command line parameter. 5. Restricted Help Output: When an invalid SysRq key is pressed, the help message printed to the console will only list the 'c' (crash) command, reflecting the restricted functionality. 6. Compile-Time Table Modification: The sysrq_key_table is initialized at boot time by sysrq_init_crash_only_table() to contain only the sysrq_crash_op for the 'c' key. All other entries are set to NULL. This feature provides a strong compile-time mechanism to reduce the attack surface associated with the Magic SysRq key, limiting its use to critical crash dump generation for debugging purposes, which is often essential even in highly secure environments. The sysrq_on() function is modified to always return true when CONFIG_MAGIC_SYSRQ_CRASH_ONLY is set. This ensures that the SysRq input handler is registered, allowing the Alt+SysRq+C key combination to be processed, while the actual command filtering occurs deeper within the SysRq logic. Usage Recommendation: For systems requiring: 1. Guaranteed crash-dump capability 2. Elimination of debug backdoors 3. Compliance with strict security requirements Affected files: lib/Kconfig.debug: Added CONFIG_MAGIC_SYSRQ_CRASH_ONLY. drivers/tty/sysrq.c: Implemented the conditional logic for restricted mode. Signed-off-by: Marwan Seliem <marwanmhks@gmail.com> --- drivers/tty/sysrq.c | 79 ++++++++++++++++++++++++++++++++++++++++++++- lib/Kconfig.debug | 13 ++++++++ 2 files changed, 91 insertions(+), 1 deletion(-)