diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kexec.c | 7 | ||||
-rw-r--r-- | kernel/power/console.c | 6 | ||||
-rw-r--r-- | kernel/power/disk.c | 22 | ||||
-rw-r--r-- | kernel/power/main.c | 8 | ||||
-rw-r--r-- | kernel/power/user.c | 8 | ||||
-rw-r--r-- | kernel/printk.c | 15 | ||||
-rw-r--r-- | kernel/rcuclassic.c | 4 | ||||
-rw-r--r-- | kernel/rcupdate.c | 12 | ||||
-rw-r--r-- | kernel/rcupreempt.c | 3 | ||||
-rw-r--r-- | kernel/rcutree.c | 4 | ||||
-rw-r--r-- | kernel/sched.c | 15 | ||||
-rw-r--r-- | kernel/seccomp.c | 7 | ||||
-rw-r--r-- | kernel/sys.c | 31 | ||||
-rw-r--r-- | kernel/user.c | 18 | ||||
-rw-r--r-- | kernel/user_namespace.c | 21 |
15 files changed, 144 insertions, 37 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index 8a6d7b08864e..483899578259 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -1465,6 +1465,11 @@ int kernel_kexec(void) | |||
1465 | error = device_power_down(PMSG_FREEZE); | 1465 | error = device_power_down(PMSG_FREEZE); |
1466 | if (error) | 1466 | if (error) |
1467 | goto Enable_irqs; | 1467 | goto Enable_irqs; |
1468 | |||
1469 | /* Suspend system devices */ | ||
1470 | error = sysdev_suspend(PMSG_FREEZE); | ||
1471 | if (error) | ||
1472 | goto Power_up_devices; | ||
1468 | } else | 1473 | } else |
1469 | #endif | 1474 | #endif |
1470 | { | 1475 | { |
@@ -1477,6 +1482,8 @@ int kernel_kexec(void) | |||
1477 | 1482 | ||
1478 | #ifdef CONFIG_KEXEC_JUMP | 1483 | #ifdef CONFIG_KEXEC_JUMP |
1479 | if (kexec_image->preserve_context) { | 1484 | if (kexec_image->preserve_context) { |
1485 | sysdev_resume(); | ||
1486 | Power_up_devices: | ||
1480 | device_power_up(PMSG_RESTORE); | 1487 | device_power_up(PMSG_RESTORE); |
1481 | Enable_irqs: | 1488 | Enable_irqs: |
1482 | local_irq_enable(); | 1489 | local_irq_enable(); |
diff --git a/kernel/power/console.c b/kernel/power/console.c index b8628be2a465..a3961b205de7 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c | |||
@@ -78,6 +78,12 @@ void pm_restore_console(void) | |||
78 | } | 78 | } |
79 | set_console(orig_fgconsole); | 79 | set_console(orig_fgconsole); |
80 | release_console_sem(); | 80 | release_console_sem(); |
81 | |||
82 | if (vt_waitactive(orig_fgconsole)) { | ||
83 | pr_debug("Resume: Can't switch VCs."); | ||
84 | return; | ||
85 | } | ||
86 | |||
81 | kmsg_redirect = orig_kmsg; | 87 | kmsg_redirect = orig_kmsg; |
82 | } | 88 | } |
83 | #endif | 89 | #endif |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 432ee575c9ee..4a4a206b1979 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -227,6 +227,12 @@ static int create_image(int platform_mode) | |||
227 | "aborting hibernation\n"); | 227 | "aborting hibernation\n"); |
228 | goto Enable_irqs; | 228 | goto Enable_irqs; |
229 | } | 229 | } |
230 | sysdev_suspend(PMSG_FREEZE); | ||
231 | if (error) { | ||
232 | printk(KERN_ERR "PM: Some devices failed to power down, " | ||
233 | "aborting hibernation\n"); | ||
234 | goto Power_up_devices; | ||
235 | } | ||
230 | 236 | ||
231 | if (hibernation_test(TEST_CORE)) | 237 | if (hibernation_test(TEST_CORE)) |
232 | goto Power_up; | 238 | goto Power_up; |
@@ -242,9 +248,11 @@ static int create_image(int platform_mode) | |||
242 | if (!in_suspend) | 248 | if (!in_suspend) |
243 | platform_leave(platform_mode); | 249 | platform_leave(platform_mode); |
244 | Power_up: | 250 | Power_up: |
251 | sysdev_resume(); | ||
245 | /* NOTE: device_power_up() is just a resume() for devices | 252 | /* NOTE: device_power_up() is just a resume() for devices |
246 | * that suspended with irqs off ... no overall powerup. | 253 | * that suspended with irqs off ... no overall powerup. |
247 | */ | 254 | */ |
255 | Power_up_devices: | ||
248 | device_power_up(in_suspend ? | 256 | device_power_up(in_suspend ? |
249 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
250 | Enable_irqs: | 258 | Enable_irqs: |
@@ -335,6 +343,7 @@ static int resume_target_kernel(void) | |||
335 | "aborting resume\n"); | 343 | "aborting resume\n"); |
336 | goto Enable_irqs; | 344 | goto Enable_irqs; |
337 | } | 345 | } |
346 | sysdev_suspend(PMSG_QUIESCE); | ||
338 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 347 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
339 | save_processor_state(); | 348 | save_processor_state(); |
340 | error = restore_highmem(); | 349 | error = restore_highmem(); |
@@ -357,6 +366,7 @@ static int resume_target_kernel(void) | |||
357 | swsusp_free(); | 366 | swsusp_free(); |
358 | restore_processor_state(); | 367 | restore_processor_state(); |
359 | touch_softlockup_watchdog(); | 368 | touch_softlockup_watchdog(); |
369 | sysdev_resume(); | ||
360 | device_power_up(PMSG_RECOVER); | 370 | device_power_up(PMSG_RECOVER); |
361 | Enable_irqs: | 371 | Enable_irqs: |
362 | local_irq_enable(); | 372 | local_irq_enable(); |
@@ -440,6 +450,7 @@ int hibernation_platform_enter(void) | |||
440 | local_irq_disable(); | 450 | local_irq_disable(); |
441 | error = device_power_down(PMSG_HIBERNATE); | 451 | error = device_power_down(PMSG_HIBERNATE); |
442 | if (!error) { | 452 | if (!error) { |
453 | sysdev_suspend(PMSG_HIBERNATE); | ||
443 | hibernation_ops->enter(); | 454 | hibernation_ops->enter(); |
444 | /* We should never get here */ | 455 | /* We should never get here */ |
445 | while (1); | 456 | while (1); |
@@ -595,6 +606,12 @@ static int software_resume(void) | |||
595 | unsigned int flags; | 606 | unsigned int flags; |
596 | 607 | ||
597 | /* | 608 | /* |
609 | * If the user said "noresume".. bail out early. | ||
610 | */ | ||
611 | if (noresume) | ||
612 | return 0; | ||
613 | |||
614 | /* | ||
598 | * name_to_dev_t() below takes a sysfs buffer mutex when sysfs | 615 | * name_to_dev_t() below takes a sysfs buffer mutex when sysfs |
599 | * is configured into the kernel. Since the regular hibernate | 616 | * is configured into the kernel. Since the regular hibernate |
600 | * trigger path is via sysfs which takes a buffer mutex before | 617 | * trigger path is via sysfs which takes a buffer mutex before |
@@ -610,6 +627,11 @@ static int software_resume(void) | |||
610 | mutex_unlock(&pm_mutex); | 627 | mutex_unlock(&pm_mutex); |
611 | return -ENOENT; | 628 | return -ENOENT; |
612 | } | 629 | } |
630 | /* | ||
631 | * Some device discovery might still be in progress; we need | ||
632 | * to wait for this to finish. | ||
633 | */ | ||
634 | wait_for_device_probe(); | ||
613 | swsusp_resume_device = name_to_dev_t(resume_file); | 635 | swsusp_resume_device = name_to_dev_t(resume_file); |
614 | pr_debug("PM: Resume from partition %s\n", resume_file); | 636 | pr_debug("PM: Resume from partition %s\n", resume_file); |
615 | } else { | 637 | } else { |
diff --git a/kernel/power/main.c b/kernel/power/main.c index b4d219016b6c..c9632f841f64 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -298,8 +298,12 @@ static int suspend_enter(suspend_state_t state) | |||
298 | goto Done; | 298 | goto Done; |
299 | } | 299 | } |
300 | 300 | ||
301 | if (!suspend_test(TEST_CORE)) | 301 | error = sysdev_suspend(PMSG_SUSPEND); |
302 | error = suspend_ops->enter(state); | 302 | if (!error) { |
303 | if (!suspend_test(TEST_CORE)) | ||
304 | error = suspend_ops->enter(state); | ||
305 | sysdev_resume(); | ||
306 | } | ||
303 | 307 | ||
304 | device_power_up(PMSG_RESUME); | 308 | device_power_up(PMSG_RESUME); |
305 | Done: | 309 | Done: |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 005b93d839ba..6c85359364f2 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -95,15 +95,15 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
95 | data->swap = swsusp_resume_device ? | 95 | data->swap = swsusp_resume_device ? |
96 | swap_type_of(swsusp_resume_device, 0, NULL) : -1; | 96 | swap_type_of(swsusp_resume_device, 0, NULL) : -1; |
97 | data->mode = O_RDONLY; | 97 | data->mode = O_RDONLY; |
98 | error = pm_notifier_call_chain(PM_RESTORE_PREPARE); | 98 | error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); |
99 | if (error) | 99 | if (error) |
100 | pm_notifier_call_chain(PM_POST_RESTORE); | 100 | pm_notifier_call_chain(PM_POST_HIBERNATION); |
101 | } else { | 101 | } else { |
102 | data->swap = -1; | 102 | data->swap = -1; |
103 | data->mode = O_WRONLY; | 103 | data->mode = O_WRONLY; |
104 | error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); | 104 | error = pm_notifier_call_chain(PM_RESTORE_PREPARE); |
105 | if (error) | 105 | if (error) |
106 | pm_notifier_call_chain(PM_POST_HIBERNATION); | 106 | pm_notifier_call_chain(PM_POST_RESTORE); |
107 | } | 107 | } |
108 | if (error) | 108 | if (error) |
109 | atomic_inc(&snapshot_device_available); | 109 | atomic_inc(&snapshot_device_available); |
diff --git a/kernel/printk.c b/kernel/printk.c index 69188f226a93..e3602d0755b0 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress); | |||
73 | * driver system. | 73 | * driver system. |
74 | */ | 74 | */ |
75 | static DECLARE_MUTEX(console_sem); | 75 | static DECLARE_MUTEX(console_sem); |
76 | static DECLARE_MUTEX(secondary_console_sem); | ||
77 | struct console *console_drivers; | 76 | struct console *console_drivers; |
78 | EXPORT_SYMBOL_GPL(console_drivers); | 77 | EXPORT_SYMBOL_GPL(console_drivers); |
79 | 78 | ||
@@ -891,12 +890,14 @@ void suspend_console(void) | |||
891 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); | 890 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); |
892 | acquire_console_sem(); | 891 | acquire_console_sem(); |
893 | console_suspended = 1; | 892 | console_suspended = 1; |
893 | up(&console_sem); | ||
894 | } | 894 | } |
895 | 895 | ||
896 | void resume_console(void) | 896 | void resume_console(void) |
897 | { | 897 | { |
898 | if (!console_suspend_enabled) | 898 | if (!console_suspend_enabled) |
899 | return; | 899 | return; |
900 | down(&console_sem); | ||
900 | console_suspended = 0; | 901 | console_suspended = 0; |
901 | release_console_sem(); | 902 | release_console_sem(); |
902 | } | 903 | } |
@@ -912,11 +913,9 @@ void resume_console(void) | |||
912 | void acquire_console_sem(void) | 913 | void acquire_console_sem(void) |
913 | { | 914 | { |
914 | BUG_ON(in_interrupt()); | 915 | BUG_ON(in_interrupt()); |
915 | if (console_suspended) { | ||
916 | down(&secondary_console_sem); | ||
917 | return; | ||
918 | } | ||
919 | down(&console_sem); | 916 | down(&console_sem); |
917 | if (console_suspended) | ||
918 | return; | ||
920 | console_locked = 1; | 919 | console_locked = 1; |
921 | console_may_schedule = 1; | 920 | console_may_schedule = 1; |
922 | } | 921 | } |
@@ -926,6 +925,10 @@ int try_acquire_console_sem(void) | |||
926 | { | 925 | { |
927 | if (down_trylock(&console_sem)) | 926 | if (down_trylock(&console_sem)) |
928 | return -1; | 927 | return -1; |
928 | if (console_suspended) { | ||
929 | up(&console_sem); | ||
930 | return -1; | ||
931 | } | ||
929 | console_locked = 1; | 932 | console_locked = 1; |
930 | console_may_schedule = 0; | 933 | console_may_schedule = 0; |
931 | return 0; | 934 | return 0; |
@@ -979,7 +982,7 @@ void release_console_sem(void) | |||
979 | unsigned wake_klogd = 0; | 982 | unsigned wake_klogd = 0; |
980 | 983 | ||
981 | if (console_suspended) { | 984 | if (console_suspended) { |
982 | up(&secondary_console_sem); | 985 | up(&console_sem); |
983 | return; | 986 | return; |
984 | } | 987 | } |
985 | 988 | ||
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c index bd5a9003497c..654c640a6b9c 100644 --- a/kernel/rcuclassic.c +++ b/kernel/rcuclassic.c | |||
@@ -679,8 +679,8 @@ int rcu_needs_cpu(int cpu) | |||
679 | void rcu_check_callbacks(int cpu, int user) | 679 | void rcu_check_callbacks(int cpu, int user) |
680 | { | 680 | { |
681 | if (user || | 681 | if (user || |
682 | (idle_cpu(cpu) && !in_softirq() && | 682 | (idle_cpu(cpu) && rcu_scheduler_active && |
683 | hardirq_count() <= (1 << HARDIRQ_SHIFT))) { | 683 | !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) { |
684 | 684 | ||
685 | /* | 685 | /* |
686 | * Get here if this CPU took its interrupt from user | 686 | * Get here if this CPU took its interrupt from user |
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index d92a76a881aa..cae8a059cf47 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/cpu.h> | 44 | #include <linux/cpu.h> |
45 | #include <linux/mutex.h> | 45 | #include <linux/mutex.h> |
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
47 | #include <linux/kernel_stat.h> | ||
47 | 48 | ||
48 | enum rcu_barrier { | 49 | enum rcu_barrier { |
49 | RCU_BARRIER_STD, | 50 | RCU_BARRIER_STD, |
@@ -55,6 +56,7 @@ static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; | |||
55 | static atomic_t rcu_barrier_cpu_count; | 56 | static atomic_t rcu_barrier_cpu_count; |
56 | static DEFINE_MUTEX(rcu_barrier_mutex); | 57 | static DEFINE_MUTEX(rcu_barrier_mutex); |
57 | static struct completion rcu_barrier_completion; | 58 | static struct completion rcu_barrier_completion; |
59 | int rcu_scheduler_active __read_mostly; | ||
58 | 60 | ||
59 | /* | 61 | /* |
60 | * Awaken the corresponding synchronize_rcu() instance now that a | 62 | * Awaken the corresponding synchronize_rcu() instance now that a |
@@ -80,6 +82,10 @@ void wakeme_after_rcu(struct rcu_head *head) | |||
80 | void synchronize_rcu(void) | 82 | void synchronize_rcu(void) |
81 | { | 83 | { |
82 | struct rcu_synchronize rcu; | 84 | struct rcu_synchronize rcu; |
85 | |||
86 | if (rcu_blocking_is_gp()) | ||
87 | return; | ||
88 | |||
83 | init_completion(&rcu.completion); | 89 | init_completion(&rcu.completion); |
84 | /* Will wake me after RCU finished. */ | 90 | /* Will wake me after RCU finished. */ |
85 | call_rcu(&rcu.head, wakeme_after_rcu); | 91 | call_rcu(&rcu.head, wakeme_after_rcu); |
@@ -175,3 +181,9 @@ void __init rcu_init(void) | |||
175 | __rcu_init(); | 181 | __rcu_init(); |
176 | } | 182 | } |
177 | 183 | ||
184 | void rcu_scheduler_starting(void) | ||
185 | { | ||
186 | WARN_ON(num_online_cpus() != 1); | ||
187 | WARN_ON(nr_context_switches() > 0); | ||
188 | rcu_scheduler_active = 1; | ||
189 | } | ||
diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index 33cfc50781f9..5d59e850fb71 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c | |||
@@ -1181,6 +1181,9 @@ void __synchronize_sched(void) | |||
1181 | { | 1181 | { |
1182 | struct rcu_synchronize rcu; | 1182 | struct rcu_synchronize rcu; |
1183 | 1183 | ||
1184 | if (num_online_cpus() == 1) | ||
1185 | return; /* blocking is gp if only one CPU! */ | ||
1186 | |||
1184 | init_completion(&rcu.completion); | 1187 | init_completion(&rcu.completion); |
1185 | /* Will wake me after RCU finished. */ | 1188 | /* Will wake me after RCU finished. */ |
1186 | call_rcu_sched(&rcu.head, wakeme_after_rcu); | 1189 | call_rcu_sched(&rcu.head, wakeme_after_rcu); |
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index b2fd602a6f6f..97ce31579ec0 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -948,8 +948,8 @@ static void rcu_do_batch(struct rcu_data *rdp) | |||
948 | void rcu_check_callbacks(int cpu, int user) | 948 | void rcu_check_callbacks(int cpu, int user) |
949 | { | 949 | { |
950 | if (user || | 950 | if (user || |
951 | (idle_cpu(cpu) && !in_softirq() && | 951 | (idle_cpu(cpu) && rcu_scheduler_active && |
952 | hardirq_count() <= (1 << HARDIRQ_SHIFT))) { | 952 | !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) { |
953 | 953 | ||
954 | /* | 954 | /* |
955 | * Get here if this CPU took its interrupt from user | 955 | * Get here if this CPU took its interrupt from user |
diff --git a/kernel/sched.c b/kernel/sched.c index 410eec404133..8e2558c2ba67 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -223,7 +223,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b) | |||
223 | { | 223 | { |
224 | ktime_t now; | 224 | ktime_t now; |
225 | 225 | ||
226 | if (rt_bandwidth_enabled() && rt_b->rt_runtime == RUNTIME_INF) | 226 | if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF) |
227 | return; | 227 | return; |
228 | 228 | ||
229 | if (hrtimer_active(&rt_b->rt_period_timer)) | 229 | if (hrtimer_active(&rt_b->rt_period_timer)) |
@@ -9224,6 +9224,16 @@ static int sched_rt_global_constraints(void) | |||
9224 | 9224 | ||
9225 | return ret; | 9225 | return ret; |
9226 | } | 9226 | } |
9227 | |||
9228 | int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk) | ||
9229 | { | ||
9230 | /* Don't accept realtime tasks when there is no way for them to run */ | ||
9231 | if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0) | ||
9232 | return 0; | ||
9233 | |||
9234 | return 1; | ||
9235 | } | ||
9236 | |||
9227 | #else /* !CONFIG_RT_GROUP_SCHED */ | 9237 | #else /* !CONFIG_RT_GROUP_SCHED */ |
9228 | static int sched_rt_global_constraints(void) | 9238 | static int sched_rt_global_constraints(void) |
9229 | { | 9239 | { |
@@ -9317,8 +9327,7 @@ cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, | |||
9317 | struct task_struct *tsk) | 9327 | struct task_struct *tsk) |
9318 | { | 9328 | { |
9319 | #ifdef CONFIG_RT_GROUP_SCHED | 9329 | #ifdef CONFIG_RT_GROUP_SCHED |
9320 | /* Don't accept realtime tasks when there is no way for them to run */ | 9330 | if (!sched_rt_can_attach(cgroup_tg(cgrp), tsk)) |
9321 | if (rt_task(tsk) && cgroup_tg(cgrp)->rt_bandwidth.rt_runtime == 0) | ||
9322 | return -EINVAL; | 9331 | return -EINVAL; |
9323 | #else | 9332 | #else |
9324 | /* We don't support RT-tasks being in separate groups */ | 9333 | /* We don't support RT-tasks being in separate groups */ |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index ad64fcb731f2..57d4b13b631d 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/seccomp.h> | 9 | #include <linux/seccomp.h> |
10 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
11 | #include <linux/compat.h> | ||
11 | 12 | ||
12 | /* #define SECCOMP_DEBUG 1 */ | 13 | /* #define SECCOMP_DEBUG 1 */ |
13 | #define NR_SECCOMP_MODES 1 | 14 | #define NR_SECCOMP_MODES 1 |
@@ -22,7 +23,7 @@ static int mode1_syscalls[] = { | |||
22 | 0, /* null terminated */ | 23 | 0, /* null terminated */ |
23 | }; | 24 | }; |
24 | 25 | ||
25 | #ifdef TIF_32BIT | 26 | #ifdef CONFIG_COMPAT |
26 | static int mode1_syscalls_32[] = { | 27 | static int mode1_syscalls_32[] = { |
27 | __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, | 28 | __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, |
28 | 0, /* null terminated */ | 29 | 0, /* null terminated */ |
@@ -37,8 +38,8 @@ void __secure_computing(int this_syscall) | |||
37 | switch (mode) { | 38 | switch (mode) { |
38 | case 1: | 39 | case 1: |
39 | syscall = mode1_syscalls; | 40 | syscall = mode1_syscalls; |
40 | #ifdef TIF_32BIT | 41 | #ifdef CONFIG_COMPAT |
41 | if (test_thread_flag(TIF_32BIT)) | 42 | if (is_compat_task()) |
42 | syscall = mode1_syscalls_32; | 43 | syscall = mode1_syscalls_32; |
43 | #endif | 44 | #endif |
44 | do { | 45 | do { |
diff --git a/kernel/sys.c b/kernel/sys.c index f145c415bc16..37f458e6882a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -559,7 +559,7 @@ error: | |||
559 | abort_creds(new); | 559 | abort_creds(new); |
560 | return retval; | 560 | return retval; |
561 | } | 561 | } |
562 | 562 | ||
563 | /* | 563 | /* |
564 | * change the user struct in a credentials set to match the new UID | 564 | * change the user struct in a credentials set to match the new UID |
565 | */ | 565 | */ |
@@ -571,6 +571,11 @@ static int set_user(struct cred *new) | |||
571 | if (!new_user) | 571 | if (!new_user) |
572 | return -EAGAIN; | 572 | return -EAGAIN; |
573 | 573 | ||
574 | if (!task_can_switch_user(new_user, current)) { | ||
575 | free_uid(new_user); | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
574 | if (atomic_read(&new_user->processes) >= | 579 | if (atomic_read(&new_user->processes) >= |
575 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && | 580 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && |
576 | new_user != INIT_USER) { | 581 | new_user != INIT_USER) { |
@@ -631,10 +636,11 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
631 | goto error; | 636 | goto error; |
632 | } | 637 | } |
633 | 638 | ||
634 | retval = -EAGAIN; | 639 | if (new->uid != old->uid) { |
635 | if (new->uid != old->uid && set_user(new) < 0) | 640 | retval = set_user(new); |
636 | goto error; | 641 | if (retval < 0) |
637 | 642 | goto error; | |
643 | } | ||
638 | if (ruid != (uid_t) -1 || | 644 | if (ruid != (uid_t) -1 || |
639 | (euid != (uid_t) -1 && euid != old->uid)) | 645 | (euid != (uid_t) -1 && euid != old->uid)) |
640 | new->suid = new->euid; | 646 | new->suid = new->euid; |
@@ -680,9 +686,10 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
680 | retval = -EPERM; | 686 | retval = -EPERM; |
681 | if (capable(CAP_SETUID)) { | 687 | if (capable(CAP_SETUID)) { |
682 | new->suid = new->uid = uid; | 688 | new->suid = new->uid = uid; |
683 | if (uid != old->uid && set_user(new) < 0) { | 689 | if (uid != old->uid) { |
684 | retval = -EAGAIN; | 690 | retval = set_user(new); |
685 | goto error; | 691 | if (retval < 0) |
692 | goto error; | ||
686 | } | 693 | } |
687 | } else if (uid != old->uid && uid != new->suid) { | 694 | } else if (uid != old->uid && uid != new->suid) { |
688 | goto error; | 695 | goto error; |
@@ -734,11 +741,13 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
734 | goto error; | 741 | goto error; |
735 | } | 742 | } |
736 | 743 | ||
737 | retval = -EAGAIN; | ||
738 | if (ruid != (uid_t) -1) { | 744 | if (ruid != (uid_t) -1) { |
739 | new->uid = ruid; | 745 | new->uid = ruid; |
740 | if (ruid != old->uid && set_user(new) < 0) | 746 | if (ruid != old->uid) { |
741 | goto error; | 747 | retval = set_user(new); |
748 | if (retval < 0) | ||
749 | goto error; | ||
750 | } | ||
742 | } | 751 | } |
743 | if (euid != (uid_t) -1) | 752 | if (euid != (uid_t) -1) |
744 | new->euid = euid; | 753 | new->euid = euid; |
diff --git a/kernel/user.c b/kernel/user.c index 3551ac742395..6a9b696128c8 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -362,6 +362,24 @@ static void free_user(struct user_struct *up, unsigned long flags) | |||
362 | 362 | ||
363 | #endif | 363 | #endif |
364 | 364 | ||
365 | #if defined(CONFIG_RT_GROUP_SCHED) && defined(CONFIG_USER_SCHED) | ||
366 | /* | ||
367 | * We need to check if a setuid can take place. This function should be called | ||
368 | * before successfully completing the setuid. | ||
369 | */ | ||
370 | int task_can_switch_user(struct user_struct *up, struct task_struct *tsk) | ||
371 | { | ||
372 | |||
373 | return sched_rt_can_attach(up->tg, tsk); | ||
374 | |||
375 | } | ||
376 | #else | ||
377 | int task_can_switch_user(struct user_struct *up, struct task_struct *tsk) | ||
378 | { | ||
379 | return 1; | ||
380 | } | ||
381 | #endif | ||
382 | |||
365 | /* | 383 | /* |
366 | * Locate the user_struct for the passed UID. If found, take a ref on it. The | 384 | * Locate the user_struct for the passed UID. If found, take a ref on it. The |
367 | * caller must undo that ref with free_uid(). | 385 | * caller must undo that ref with free_uid(). |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 79084311ee57..076c7c8215b0 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -60,12 +60,25 @@ int create_user_ns(struct cred *new) | |||
60 | return 0; | 60 | return 0; |
61 | } | 61 | } |
62 | 62 | ||
63 | void free_user_ns(struct kref *kref) | 63 | /* |
64 | * Deferred destructor for a user namespace. This is required because | ||
65 | * free_user_ns() may be called with uidhash_lock held, but we need to call | ||
66 | * back to free_uid() which will want to take the lock again. | ||
67 | */ | ||
68 | static void free_user_ns_work(struct work_struct *work) | ||
64 | { | 69 | { |
65 | struct user_namespace *ns; | 70 | struct user_namespace *ns = |
66 | 71 | container_of(work, struct user_namespace, destroyer); | |
67 | ns = container_of(kref, struct user_namespace, kref); | ||
68 | free_uid(ns->creator); | 72 | free_uid(ns->creator); |
69 | kfree(ns); | 73 | kfree(ns); |
70 | } | 74 | } |
75 | |||
76 | void free_user_ns(struct kref *kref) | ||
77 | { | ||
78 | struct user_namespace *ns = | ||
79 | container_of(kref, struct user_namespace, kref); | ||
80 | |||
81 | INIT_WORK(&ns->destroyer, free_user_ns_work); | ||
82 | schedule_work(&ns->destroyer); | ||
83 | } | ||
71 | EXPORT_SYMBOL(free_user_ns); | 84 | EXPORT_SYMBOL(free_user_ns); |