diff -ru kernel-source-2.4.19.orig/include/linux/sysctl.h kernel-source-2.4.19/include/linux/sysctl.h --- kernel-source-2.4.19.orig/include/linux/sysctl.h Sat Aug 3 01:39:46 2002 +++ kernel-source-2.4.19/include/linux/sysctl.h Fri Nov 8 08:54:53 2002 @@ -124,6 +124,7 @@ KERN_CORE_USES_PID=52, /* int: use core or core.%pid */ KERN_TAINTED=53, /* int: various kernel tainted flags */ KERN_CADPID=54, /* int: PID of the process to notify on CAD */ + KERN_SCHELPER=55, /* string: path to s_context reboot helper */ }; diff -ru kernel-source-2.4.19.orig/kernel/sys.c kernel-source-2.4.19/kernel/sys.c --- kernel-source-2.4.19.orig/kernel/sys.c Fri Nov 8 09:07:16 2002 +++ kernel-source-2.4.19/kernel/sys.c Fri Nov 8 09:08:19 2002 @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -259,6 +261,11 @@ return retval; } +/* + argv["/sbin/schelper", context, "sys_reboot", "restart|halt" ...] + schelper_path is set via /proc/sys/kernel/schelper +*/ +char schelper_path[256] = "/sbin/schelper"; /* * Reboot system call: for obvious reasons only root may call it, @@ -272,8 +279,22 @@ { char buffer[256]; + /* CAP_SYS_BOOT logic. + We have three code-paths, I think they should probably be: + (No, I can't believe I had to resort to a state table either! ;-) + + +--------------------------+----------------+----------------+ + | | CAP_SYS_BOOT | !CAP_SYS_BOOT | + +--------------------------+----------------+----------------+ + | ctx == 0 && uid == 0 | Real reboot | EPERM | + | ctx == 0 && uid >= 0 | Real reboot | EPERM | + | ctx >= 0 && uid >= 0 | Real reboot | EPERM | + | ctx >= 0 && uid == 0 | Real reboot | Fake reboot | + +--------------------------+----------------+----------------+ */ + /* We only trust the superuser with rebooting the system. */ - if (!capable(CAP_SYS_BOOT)) + /* For vservers, fail unless they're *real root*, or root in a vserver */ + if (!capable(CAP_SYS_BOOT) && !(current->s_context && !current->uid)) return -EPERM; /* For safety, we require "magic" arguments. */ @@ -282,6 +303,54 @@ magic2 != LINUX_REBOOT_MAGIC2B)) return -EINVAL; + /* If this is a virtual server then for the appropriate request + we execute a userspace tool to perform the "action" */ + if (!capable(CAP_SYS_BOOT) && (current->s_context && !current->uid)) { + char *argv[] = {schelper_path, buffer+0, "sys_reboot", 0,0,0,0,}; + char *envp[] = {"HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + buffer+64, buffer+96, buffer+128, 0,0,0,0 }; + + switch (cmd) { + case LINUX_REBOOT_CMD_RESTART: + case LINUX_REBOOT_CMD_RESTART2: + argv[3] = "restart"; + break; + + case LINUX_REBOOT_CMD_HALT: + case LINUX_REBOOT_CMD_POWER_OFF: + argv[3] = "halt"; + break; + + case LINUX_REBOOT_CMD_CAD_ON: + case LINUX_REBOOT_CMD_CAD_OFF: + return 0; + + default: + return -EINVAL; + } + /* argv[] */ + snprintf(buffer+0, 63, "%d", current->s_context); + + /* env[] */ + snprintf(buffer+64, 31, "S_INFO_UID=%d", current->uid); + snprintf(buffer+96, 31, "S_INFO_PID=%d", current->pid); + snprintf(buffer+128, 66, "S_INFO_NODENAME=%s", current->s_info->nodename); + + buffer[sizeof(buffer)-1] = '\0'; + + if (call_usermodehelper(*argv, argv, envp)) + printk(KERN_WARNING + "s_context: sys_reboot(): " + "failed to exec(%s %s %s %s), " + "ctx = %d (%s), " + "pid = %d\n", + schelper_path, argv[1], argv[2], argv[3], + current->s_context, current->s_info->nodename, + current->pid); + return 0; + } + + /* straight, normal reboot path */ lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: diff -ru kernel-source-2.4.19.orig/kernel/sysctl.c kernel-source-2.4.19/kernel/sysctl.c --- kernel-source-2.4.19.orig/kernel/sysctl.c Fri Nov 8 08:49:59 2002 +++ kernel-source-2.4.19/kernel/sysctl.c Fri Nov 8 09:11:51 2002 @@ -86,6 +86,9 @@ extern int sysctl_userprocess_debug; #endif +/* s_context reboot helper, see kernel/sys.c#sys_reboot() */ +extern char schelper_path[]; + #ifdef CONFIG_PPC32 extern unsigned long zero_paged_on, powersave_nap; int proc_dol2crvec(ctl_table *table, int write, struct file *filp, @@ -256,6 +259,8 @@ {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug", &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec}, #endif + {KERN_SCHELPER, "schelper", &schelper_path, 256, + 0644, NULL, &proc_dostring, &sysctl_string }, {0} };