On 2020/05/29 22:26, Tetsuo Handa wrote:
>     By the way, I do worry that people forget to perform these steps when 
> they do
>     their tests without asking syzbot...

Here is a draft of boot-time switching. Since kconfig can handle string 
variable up to
2048 characters, we could hold the content of the "your-config" file inside 
.config file
in order to avoid relying on external file in "syzkaller tree". But since only 
one kconfig
option is used, basically the way to temporarily include/exclude specific 
options (under
automated testing by syzbot) seems to remain directly patching 
apply_twist_flags(), for
https://github.com/google/syzkaller/blob/master/dashboard/config/util.sh will 
automatically
overwrite CONFIG_DEFAULT_TWIST_FLAGS settings. If each twist flag were using 
independent
kconfig option, the way to temporarily include/exclude specific options will 
become directly
patching Kconfig file.

 drivers/tty/vt/keyboard.c |    2 ++
 include/linux/kernel.h    |    8 ++++++++
 init/main.c               |   30 ++++++++++++++++++++++++++++++
 kernel/reboot.c           |   36 ++++++++++++++++++++++++++++++++++++
 lib/Kconfig.debug         |    5 +++++
 5 files changed, 81 insertions(+)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 568b2171f335..ae0b7cd69249 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -637,6 +637,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, 
char up_flag)
             kbd->kbdmode == VC_OFF) &&
             value != KVAL(K_SAK))
                return;         /* SAK is allowed even in raw mode */
+       if (twist_flags.disable_kbd_k_spec_handler)
+               return;
        fn_handler[value](vc);
 }
 
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 82d91547d122..78fdbb4f17b1 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1038,4 +1038,12 @@ static inline void ftrace_dump(enum ftrace_dump_mode 
oops_dump_mode) { }
         /* OTHER_WRITABLE?  Generally considered a bad idea. */                
\
         BUILD_BUG_ON_ZERO((perms) & 2) +                                       
\
         (perms))
+
+/* Flags for twisting kernel behavior. */
+struct twist_flags {
+       bool disable_kbd_k_spec_handler;
+       bool disable_reboot_request;
+};
+extern struct twist_flags twist_flags;
+
 #endif
diff --git a/init/main.c b/init/main.c
index 0ead83e86b5a..15eecd253b61 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1531,3 +1531,33 @@ static noinline void __init kernel_init_freeable(void)
 
        integrity_load_keys();
 }
+
+/* Flags for twisting kernel behavior. */
+struct twist_flags twist_flags __ro_after_init;
+EXPORT_SYMBOL(twist_flags);
+static __initdata char default_twist_flags[] __initdata = 
CONFIG_DEFAULT_TWIST_FLAGS;
+static __initdata char *chosen_twist_flags = default_twist_flags;
+
+static int __init overwrite_twist_flags(char *str)
+{
+       chosen_twist_flags = str;
+       return 1;
+}
+__setup("twist_flags=", overwrite_twist_flags);
+
+static int __init apply_twist_flags(void)
+{
+       char *flags = chosen_twist_flags;
+       char *name;
+
+       while ((name = strsep(&flags, ",")) != NULL) {
+               if (!strcmp(name, "kbd-disable-hotkeys"))
+                       twist_flags.disable_kbd_k_spec_handler = true;
+               else if (!strcmp(name, "disable-reboot-request"))
+                       twist_flags.disable_reboot_request = true;
+               else
+                       printk(KERN_INFO "Ignoring unknown twist option 
'%s'.\n", name);
+       }
+       return 0;
+}
+late_initcall(apply_twist_flags);
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 491f1347bf43..63cec97a9e59 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -63,6 +63,8 @@ EXPORT_SYMBOL_GPL(pm_power_off_prepare);
  */
 void emergency_restart(void)
 {
+       if (twist_flags.disable_reboot_request)
+               panic("reboot request is disabled");
        kmsg_dump(KMSG_DUMP_EMERG);
        machine_emergency_restart();
 }
@@ -243,6 +245,8 @@ void migrate_to_reboot_cpu(void)
  */
 void kernel_restart(char *cmd)
 {
+       if (twist_flags.disable_reboot_request)
+               panic("reboot request is disabled");
        kernel_restart_prepare(cmd);
        migrate_to_reboot_cpu();
        syscore_shutdown();
@@ -270,6 +274,8 @@ static void kernel_shutdown_prepare(enum system_states 
state)
  */
 void kernel_halt(void)
 {
+       if (twist_flags.disable_reboot_request)
+               panic("reboot request is disabled");
        kernel_shutdown_prepare(SYSTEM_HALT);
        migrate_to_reboot_cpu();
        syscore_shutdown();
@@ -286,6 +292,8 @@ EXPORT_SYMBOL_GPL(kernel_halt);
  */
 void kernel_power_off(void)
 {
+       if (twist_flags.disable_reboot_request)
+               panic("reboot request is disabled");
        kernel_shutdown_prepare(SYSTEM_POWER_OFF);
        if (pm_power_off_prepare)
                pm_power_off_prepare();
@@ -344,6 +352,10 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
        mutex_lock(&system_transition_mutex);
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:
+               if (twist_flags.disable_reboot_request) {
+                       ret = -EPERM;
+                       break;
+               }
                kernel_restart(NULL);
                break;
 
@@ -356,11 +368,19 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, 
unsigned int, cmd,
                break;
 
        case LINUX_REBOOT_CMD_HALT:
+               if (twist_flags.disable_reboot_request) {
+                       ret = -EPERM;
+                       break;
+               }
                kernel_halt();
                do_exit(0);
                panic("cannot halt");
 
        case LINUX_REBOOT_CMD_POWER_OFF:
+               if (twist_flags.disable_reboot_request) {
+                       ret = -EPERM;
+                       break;
+               }
                kernel_power_off();
                do_exit(0);
                break;
@@ -373,17 +393,29 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, 
unsigned int, cmd,
                }
                buffer[sizeof(buffer) - 1] = '\0';
 
+               if (twist_flags.disable_reboot_request) {
+                       ret = -EPERM;
+                       break;
+               }
                kernel_restart(buffer);
                break;
 
 #ifdef CONFIG_KEXEC_CORE
        case LINUX_REBOOT_CMD_KEXEC:
+               if (twist_flags.disable_reboot_request) {
+                       ret = -EPERM;
+                       break;
+               }
                ret = kernel_kexec();
                break;
 #endif
 
 #ifdef CONFIG_HIBERNATION
        case LINUX_REBOOT_CMD_SW_SUSPEND:
+               if (twist_flags.disable_reboot_request) {
+                       ret = -EPERM;
+                       break;
+               }
                ret = hibernate();
                break;
 #endif
@@ -493,6 +525,8 @@ static DECLARE_WORK(poweroff_work, poweroff_work_func);
  */
 void orderly_poweroff(bool force)
 {
+       if (twist_flags.disable_reboot_request)
+               panic("reboot request is disabled");
        if (force) /* do not override the pending "true" */
                poweroff_force = true;
        schedule_work(&poweroff_work);
@@ -514,6 +548,8 @@ static DECLARE_WORK(reboot_work, reboot_work_func);
  */
 void orderly_reboot(void)
 {
+       if (twist_flags.disable_reboot_request)
+               panic("reboot request is disabled");
        schedule_work(&reboot_work);
 }
 EXPORT_SYMBOL_GPL(orderly_reboot);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 498d344ea53a..41cfabc74ad7 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2338,4 +2338,9 @@ config HYPERV_TESTING
 
 endmenu # "Kernel Testing and Coverage"
 
+menuconfig DEFAULT_TWIST_FLAGS
+       string "Default twist options (DANGEROUS)"
+       help
+         Don't specify anything unless you know what you are doing.
+
 endmenu # Kernel hacking

Reply via email to