diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 85 |
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 | */ | ||
335 | int register_reboot_notifier(struct notifier_block *nb) | ||
336 | { | ||
337 | return blocking_notifier_chain_register(&reboot_notifier_list, nb); | ||
338 | } | ||
339 | EXPORT_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 | */ | ||
350 | int unregister_reboot_notifier(struct notifier_block *nb) | ||
351 | { | ||
352 | return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); | ||
353 | } | ||
354 | EXPORT_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 | */ | ||
1172 | static 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 | |||
1127 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | 1196 | SYSCALL_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 |