aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c85
1 files changed, 80 insertions, 5 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index e4128b278f2..1dbbe695a5e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -8,7 +8,6 @@
8#include <linux/mm.h> 8#include <linux/mm.h>
9#include <linux/utsname.h> 9#include <linux/utsname.h>
10#include <linux/mman.h> 10#include <linux/mman.h>
11#include <linux/notifier.h>
12#include <linux/reboot.h> 11#include <linux/reboot.h>
13#include <linux/prctl.h> 12#include <linux/prctl.h>
14#include <linux/highuid.h> 13#include <linux/highuid.h>
@@ -38,6 +37,8 @@
38#include <linux/fs_struct.h> 37#include <linux/fs_struct.h>
39#include <linux/gfp.h> 38#include <linux/gfp.h>
40#include <linux/syscore_ops.h> 39#include <linux/syscore_ops.h>
40#include <linux/version.h>
41#include <linux/ctype.h>
41 42
42#include <linux/compat.h> 43#include <linux/compat.h>
43#include <linux/syscalls.h> 44#include <linux/syscalls.h>
@@ -45,6 +46,8 @@
45#include <linux/user_namespace.h> 46#include <linux/user_namespace.h>
46 47
47#include <linux/kmsg_dump.h> 48#include <linux/kmsg_dump.h>
49/* Move somewhere else to avoid recompiling? */
50#include <generated/utsrelease.h>
48 51
49#include <asm/uaccess.h> 52#include <asm/uaccess.h>
50#include <asm/io.h> 53#include <asm/io.h>
@@ -320,6 +323,37 @@ void kernel_restart_prepare(char *cmd)
320} 323}
321 324
322/** 325/**
326 * register_reboot_notifier - Register function to be called at reboot time
327 * @nb: Info about notifier function to be called
328 *
329 * Registers a function with the list of functions
330 * to be called at reboot time.
331 *
332 * Currently always returns zero, as blocking_notifier_chain_register()
333 * always returns zero.
334 */
335int register_reboot_notifier(struct notifier_block *nb)
336{
337 return blocking_notifier_chain_register(&reboot_notifier_list, nb);
338}
339EXPORT_SYMBOL(register_reboot_notifier);
340
341/**
342 * unregister_reboot_notifier - Unregister previously registered reboot notifier
343 * @nb: Hook to be unregistered
344 *
345 * Unregisters a previously registered reboot
346 * notifier function.
347 *
348 * Returns zero on success, or %-ENOENT on failure.
349 */
350int unregister_reboot_notifier(struct notifier_block *nb)
351{
352 return blocking_notifier_chain_unregister(&reboot_notifier_list, nb);
353}
354EXPORT_SYMBOL(unregister_reboot_notifier);
355
356/**
323 * kernel_restart - reboot the system 357 * kernel_restart - reboot the system
324 * @cmd: pointer to buffer containing command to execute for restart 358 * @cmd: pointer to buffer containing command to execute for restart
325 * or %NULL 359 * or %NULL
@@ -591,11 +625,18 @@ static int set_user(struct cred *new)
591 if (!new_user) 625 if (!new_user)
592 return -EAGAIN; 626 return -EAGAIN;
593 627
628 /*
629 * We don't fail in case of NPROC limit excess here because too many
630 * poorly written programs don't check set*uid() return code, assuming
631 * it never fails if called by root. We may still enforce NPROC limit
632 * for programs doing set*uid()+execve() by harmlessly deferring the
633 * failure to the execve() stage.
634 */
594 if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && 635 if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
595 new_user != INIT_USER) { 636 new_user != INIT_USER)
596 free_uid(new_user); 637 current->flags |= PF_NPROC_EXCEEDED;
597 return -EAGAIN; 638 else
598 } 639 current->flags &= ~PF_NPROC_EXCEEDED;
599 640
600 free_uid(new->user); 641 free_uid(new->user);
601 new->user = new_user; 642 new->user = new_user;
@@ -1124,6 +1165,34 @@ DECLARE_RWSEM(uts_sem);
1124#define override_architecture(name) 0 1165#define override_architecture(name) 0
1125#endif 1166#endif
1126 1167
1168/*
1169 * Work around broken programs that cannot handle "Linux 3.0".
1170 * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
1171 */
1172static int override_release(char __user *release, int len)
1173{
1174 int ret = 0;
1175 char buf[65];
1176
1177 if (current->personality & UNAME26) {
1178 char *rest = UTS_RELEASE;
1179 int ndots = 0;
1180 unsigned v;
1181
1182 while (*rest) {
1183 if (*rest == '.' && ++ndots >= 3)
1184 break;
1185 if (!isdigit(*rest) && *rest != '.')
1186 break;
1187 rest++;
1188 }
1189 v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
1190 snprintf(buf, len, "2.6.%u%s", v, rest);
1191 ret = copy_to_user(release, buf, len);
1192 }
1193 return ret;
1194}
1195
1127SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) 1196SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
1128{ 1197{
1129 int errno = 0; 1198 int errno = 0;
@@ -1133,6 +1202,8 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
1133 errno = -EFAULT; 1202 errno = -EFAULT;
1134 up_read(&uts_sem); 1203 up_read(&uts_sem);
1135 1204
1205 if (!errno && override_release(name->release, sizeof(name->release)))
1206 errno = -EFAULT;
1136 if (!errno && override_architecture(name)) 1207 if (!errno && override_architecture(name))
1137 errno = -EFAULT; 1208 errno = -EFAULT;
1138 return errno; 1209 return errno;
@@ -1154,6 +1225,8 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
1154 error = -EFAULT; 1225 error = -EFAULT;
1155 up_read(&uts_sem); 1226 up_read(&uts_sem);
1156 1227
1228 if (!error && override_release(name->release, sizeof(name->release)))
1229 error = -EFAULT;
1157 if (!error && override_architecture(name)) 1230 if (!error && override_architecture(name))
1158 error = -EFAULT; 1231 error = -EFAULT;
1159 return error; 1232 return error;
@@ -1188,6 +1261,8 @@ SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
1188 1261
1189 if (!error && override_architecture(name)) 1262 if (!error && override_architecture(name))
1190 error = -EFAULT; 1263 error = -EFAULT;
1264 if (!error && override_release(name->release, sizeof(name->release)))
1265 error = -EFAULT;
1191 return error ? -EFAULT : 0; 1266 return error ? -EFAULT : 0;
1192} 1267}
1193#endif 1268#endif