diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 11 | ||||
| -rw-r--r-- | kernel/module.c | 26 | ||||
| -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/signal.c | 8 | ||||
| -rw-r--r-- | kernel/softirq.c | 1 | ||||
| -rw-r--r-- | kernel/sys.c | 31 | ||||
| -rw-r--r-- | kernel/tsacct.c | 6 | ||||
| -rw-r--r-- | kernel/user.c | 34 | ||||
| -rw-r--r-- | kernel/user_namespace.c | 21 |
14 files changed, 131 insertions, 52 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index a66fbde20715..4854c2c4a82e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1179,10 +1179,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1179 | #endif | 1179 | #endif |
| 1180 | clear_all_latency_tracing(p); | 1180 | clear_all_latency_tracing(p); |
| 1181 | 1181 | ||
| 1182 | /* Our parent execution domain becomes current domain | ||
| 1183 | These must match for thread signalling to apply */ | ||
| 1184 | p->parent_exec_id = p->self_exec_id; | ||
| 1185 | |||
| 1186 | /* ok, now we should be set up.. */ | 1182 | /* ok, now we should be set up.. */ |
| 1187 | p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); | 1183 | p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); |
| 1188 | p->pdeath_signal = 0; | 1184 | p->pdeath_signal = 0; |
| @@ -1220,10 +1216,13 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1220 | set_task_cpu(p, smp_processor_id()); | 1216 | set_task_cpu(p, smp_processor_id()); |
| 1221 | 1217 | ||
| 1222 | /* CLONE_PARENT re-uses the old parent */ | 1218 | /* CLONE_PARENT re-uses the old parent */ |
| 1223 | if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) | 1219 | if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) { |
| 1224 | p->real_parent = current->real_parent; | 1220 | p->real_parent = current->real_parent; |
| 1225 | else | 1221 | p->parent_exec_id = current->parent_exec_id; |
| 1222 | } else { | ||
| 1226 | p->real_parent = current; | 1223 | p->real_parent = current; |
| 1224 | p->parent_exec_id = current->self_exec_id; | ||
| 1225 | } | ||
| 1227 | 1226 | ||
| 1228 | spin_lock(¤t->sighand->siglock); | 1227 | spin_lock(¤t->sighand->siglock); |
| 1229 | 1228 | ||
diff --git a/kernel/module.c b/kernel/module.c index ba22484a987e..1196f5d11700 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -2015,14 +2015,6 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2015 | if (err < 0) | 2015 | if (err < 0) |
| 2016 | goto free_mod; | 2016 | goto free_mod; |
| 2017 | 2017 | ||
| 2018 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | ||
| 2019 | mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t), | ||
| 2020 | mod->name); | ||
| 2021 | if (!mod->refptr) { | ||
| 2022 | err = -ENOMEM; | ||
| 2023 | goto free_mod; | ||
| 2024 | } | ||
| 2025 | #endif | ||
| 2026 | if (pcpuindex) { | 2018 | if (pcpuindex) { |
| 2027 | /* We have a special allocation for this section. */ | 2019 | /* We have a special allocation for this section. */ |
| 2028 | percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, | 2020 | percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, |
| @@ -2030,7 +2022,7 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2030 | mod->name); | 2022 | mod->name); |
| 2031 | if (!percpu) { | 2023 | if (!percpu) { |
| 2032 | err = -ENOMEM; | 2024 | err = -ENOMEM; |
| 2033 | goto free_percpu; | 2025 | goto free_mod; |
| 2034 | } | 2026 | } |
| 2035 | sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | 2027 | sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC; |
| 2036 | mod->percpu = percpu; | 2028 | mod->percpu = percpu; |
| @@ -2082,6 +2074,14 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2082 | /* Module has been moved. */ | 2074 | /* Module has been moved. */ |
| 2083 | mod = (void *)sechdrs[modindex].sh_addr; | 2075 | mod = (void *)sechdrs[modindex].sh_addr; |
| 2084 | 2076 | ||
| 2077 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | ||
| 2078 | mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t), | ||
| 2079 | mod->name); | ||
| 2080 | if (!mod->refptr) { | ||
| 2081 | err = -ENOMEM; | ||
| 2082 | goto free_init; | ||
| 2083 | } | ||
| 2084 | #endif | ||
| 2085 | /* Now we've moved module, initialize linked lists, etc. */ | 2085 | /* Now we've moved module, initialize linked lists, etc. */ |
| 2086 | module_unload_init(mod); | 2086 | module_unload_init(mod); |
| 2087 | 2087 | ||
| @@ -2288,15 +2288,17 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2288 | ftrace_release(mod->module_core, mod->core_size); | 2288 | ftrace_release(mod->module_core, mod->core_size); |
| 2289 | free_unload: | 2289 | free_unload: |
| 2290 | module_unload_free(mod); | 2290 | module_unload_free(mod); |
| 2291 | free_init: | ||
| 2292 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | ||
| 2293 | percpu_modfree(mod->refptr); | ||
| 2294 | #endif | ||
| 2291 | module_free(mod, mod->module_init); | 2295 | module_free(mod, mod->module_init); |
| 2292 | free_core: | 2296 | free_core: |
| 2293 | module_free(mod, mod->module_core); | 2297 | module_free(mod, mod->module_core); |
| 2298 | /* mod will be freed with core. Don't access it beyond this line! */ | ||
| 2294 | free_percpu: | 2299 | free_percpu: |
| 2295 | if (percpu) | 2300 | if (percpu) |
| 2296 | percpu_modfree(percpu); | 2301 | percpu_modfree(percpu); |
| 2297 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | ||
| 2298 | percpu_modfree(mod->refptr); | ||
| 2299 | #endif | ||
| 2300 | free_mod: | 2302 | free_mod: |
| 2301 | kfree(args); | 2303 | kfree(args); |
| 2302 | free_hdr: | 2304 | free_hdr: |
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/signal.c b/kernel/signal.c index 2a74fe87c0dd..1c8814481a11 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -1575,7 +1575,15 @@ static void ptrace_stop(int exit_code, int clear_code, siginfo_t *info) | |||
| 1575 | read_lock(&tasklist_lock); | 1575 | read_lock(&tasklist_lock); |
| 1576 | if (may_ptrace_stop()) { | 1576 | if (may_ptrace_stop()) { |
| 1577 | do_notify_parent_cldstop(current, CLD_TRAPPED); | 1577 | do_notify_parent_cldstop(current, CLD_TRAPPED); |
| 1578 | /* | ||
| 1579 | * Don't want to allow preemption here, because | ||
| 1580 | * sys_ptrace() needs this task to be inactive. | ||
| 1581 | * | ||
| 1582 | * XXX: implement read_unlock_no_resched(). | ||
| 1583 | */ | ||
| 1584 | preempt_disable(); | ||
| 1578 | read_unlock(&tasklist_lock); | 1585 | read_unlock(&tasklist_lock); |
| 1586 | preempt_enable_no_resched(); | ||
| 1579 | schedule(); | 1587 | schedule(); |
| 1580 | } else { | 1588 | } else { |
| 1581 | /* | 1589 | /* |
diff --git a/kernel/softirq.c b/kernel/softirq.c index bdbe9de9cd8d..9041ea7948fe 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -626,6 +626,7 @@ static int ksoftirqd(void * __bind_cpu) | |||
| 626 | preempt_enable_no_resched(); | 626 | preempt_enable_no_resched(); |
| 627 | cond_resched(); | 627 | cond_resched(); |
| 628 | preempt_disable(); | 628 | preempt_disable(); |
| 629 | rcu_qsctr_inc((long)__bind_cpu); | ||
| 629 | } | 630 | } |
| 630 | preempt_enable(); | 631 | preempt_enable(); |
| 631 | set_current_state(TASK_INTERRUPTIBLE); | 632 | set_current_state(TASK_INTERRUPTIBLE); |
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/tsacct.c b/kernel/tsacct.c index 43f891b05a4b..00d59d048edf 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c | |||
| @@ -122,8 +122,10 @@ void acct_update_integrals(struct task_struct *tsk) | |||
| 122 | if (likely(tsk->mm)) { | 122 | if (likely(tsk->mm)) { |
| 123 | cputime_t time, dtime; | 123 | cputime_t time, dtime; |
| 124 | struct timeval value; | 124 | struct timeval value; |
| 125 | unsigned long flags; | ||
| 125 | u64 delta; | 126 | u64 delta; |
| 126 | 127 | ||
| 128 | local_irq_save(flags); | ||
| 127 | time = tsk->stime + tsk->utime; | 129 | time = tsk->stime + tsk->utime; |
| 128 | dtime = cputime_sub(time, tsk->acct_timexpd); | 130 | dtime = cputime_sub(time, tsk->acct_timexpd); |
| 129 | jiffies_to_timeval(cputime_to_jiffies(dtime), &value); | 131 | jiffies_to_timeval(cputime_to_jiffies(dtime), &value); |
| @@ -131,10 +133,12 @@ void acct_update_integrals(struct task_struct *tsk) | |||
| 131 | delta = delta * USEC_PER_SEC + value.tv_usec; | 133 | delta = delta * USEC_PER_SEC + value.tv_usec; |
| 132 | 134 | ||
| 133 | if (delta == 0) | 135 | if (delta == 0) |
| 134 | return; | 136 | goto out; |
| 135 | tsk->acct_timexpd = time; | 137 | tsk->acct_timexpd = time; |
| 136 | tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm); | 138 | tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm); |
| 137 | tsk->acct_vm_mem1 += delta * tsk->mm->total_vm; | 139 | tsk->acct_vm_mem1 += delta * tsk->mm->total_vm; |
| 140 | out: | ||
| 141 | local_irq_restore(flags); | ||
| 138 | } | 142 | } |
| 139 | } | 143 | } |
| 140 | 144 | ||
diff --git a/kernel/user.c b/kernel/user.c index 3551ac742395..850e0ba41c1e 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | struct user_namespace init_user_ns = { | 21 | struct user_namespace init_user_ns = { |
| 22 | .kref = { | 22 | .kref = { |
| 23 | .refcount = ATOMIC_INIT(1), | 23 | .refcount = ATOMIC_INIT(2), |
| 24 | }, | 24 | }, |
| 25 | .creator = &root_user, | 25 | .creator = &root_user, |
| 26 | }; | 26 | }; |
| @@ -286,14 +286,12 @@ int __init uids_sysfs_init(void) | |||
| 286 | /* work function to remove sysfs directory for a user and free up | 286 | /* work function to remove sysfs directory for a user and free up |
| 287 | * corresponding structures. | 287 | * corresponding structures. |
| 288 | */ | 288 | */ |
| 289 | static void remove_user_sysfs_dir(struct work_struct *w) | 289 | static void cleanup_user_struct(struct work_struct *w) |
| 290 | { | 290 | { |
| 291 | struct user_struct *up = container_of(w, struct user_struct, work); | 291 | struct user_struct *up = container_of(w, struct user_struct, work); |
| 292 | unsigned long flags; | 292 | unsigned long flags; |
| 293 | int remove_user = 0; | 293 | int remove_user = 0; |
| 294 | 294 | ||
| 295 | if (up->user_ns != &init_user_ns) | ||
| 296 | return; | ||
| 297 | /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del() | 295 | /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del() |
| 298 | * atomic. | 296 | * atomic. |
| 299 | */ | 297 | */ |
| @@ -312,9 +310,11 @@ static void remove_user_sysfs_dir(struct work_struct *w) | |||
| 312 | if (!remove_user) | 310 | if (!remove_user) |
| 313 | goto done; | 311 | goto done; |
| 314 | 312 | ||
| 315 | kobject_uevent(&up->kobj, KOBJ_REMOVE); | 313 | if (up->user_ns == &init_user_ns) { |
| 316 | kobject_del(&up->kobj); | 314 | kobject_uevent(&up->kobj, KOBJ_REMOVE); |
| 317 | kobject_put(&up->kobj); | 315 | kobject_del(&up->kobj); |
| 316 | kobject_put(&up->kobj); | ||
| 317 | } | ||
| 318 | 318 | ||
| 319 | sched_destroy_user(up); | 319 | sched_destroy_user(up); |
| 320 | key_put(up->uid_keyring); | 320 | key_put(up->uid_keyring); |
| @@ -335,7 +335,7 @@ static void free_user(struct user_struct *up, unsigned long flags) | |||
| 335 | atomic_inc(&up->__count); | 335 | atomic_inc(&up->__count); |
| 336 | spin_unlock_irqrestore(&uidhash_lock, flags); | 336 | spin_unlock_irqrestore(&uidhash_lock, flags); |
| 337 | 337 | ||
| 338 | INIT_WORK(&up->work, remove_user_sysfs_dir); | 338 | INIT_WORK(&up->work, cleanup_user_struct); |
| 339 | schedule_work(&up->work); | 339 | schedule_work(&up->work); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| @@ -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); |
