diff options
Diffstat (limited to 'kernel/taskstats.c')
-rw-r--r-- | kernel/taskstats.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index d0a32796550f..145bb4d3bd4d 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/cgroup.h> | 27 | #include <linux/cgroup.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/file.h> | 29 | #include <linux/file.h> |
30 | #include <linux/pid_namespace.h> | ||
30 | #include <net/genetlink.h> | 31 | #include <net/genetlink.h> |
31 | #include <linux/atomic.h> | 32 | #include <linux/atomic.h> |
32 | 33 | ||
@@ -174,7 +175,9 @@ static void send_cpu_listeners(struct sk_buff *skb, | |||
174 | up_write(&listeners->sem); | 175 | up_write(&listeners->sem); |
175 | } | 176 | } |
176 | 177 | ||
177 | static void fill_stats(struct task_struct *tsk, struct taskstats *stats) | 178 | static void fill_stats(struct user_namespace *user_ns, |
179 | struct pid_namespace *pid_ns, | ||
180 | struct task_struct *tsk, struct taskstats *stats) | ||
178 | { | 181 | { |
179 | memset(stats, 0, sizeof(*stats)); | 182 | memset(stats, 0, sizeof(*stats)); |
180 | /* | 183 | /* |
@@ -190,7 +193,7 @@ static void fill_stats(struct task_struct *tsk, struct taskstats *stats) | |||
190 | stats->version = TASKSTATS_VERSION; | 193 | stats->version = TASKSTATS_VERSION; |
191 | stats->nvcsw = tsk->nvcsw; | 194 | stats->nvcsw = tsk->nvcsw; |
192 | stats->nivcsw = tsk->nivcsw; | 195 | stats->nivcsw = tsk->nivcsw; |
193 | bacct_add_tsk(stats, tsk); | 196 | bacct_add_tsk(user_ns, pid_ns, stats, tsk); |
194 | 197 | ||
195 | /* fill in extended acct fields */ | 198 | /* fill in extended acct fields */ |
196 | xacct_add_tsk(stats, tsk); | 199 | xacct_add_tsk(stats, tsk); |
@@ -207,7 +210,7 @@ static int fill_stats_for_pid(pid_t pid, struct taskstats *stats) | |||
207 | rcu_read_unlock(); | 210 | rcu_read_unlock(); |
208 | if (!tsk) | 211 | if (!tsk) |
209 | return -ESRCH; | 212 | return -ESRCH; |
210 | fill_stats(tsk, stats); | 213 | fill_stats(current_user_ns(), task_active_pid_ns(current), tsk, stats); |
211 | put_task_struct(tsk); | 214 | put_task_struct(tsk); |
212 | return 0; | 215 | return 0; |
213 | } | 216 | } |
@@ -291,6 +294,12 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd) | |||
291 | if (!cpumask_subset(mask, cpu_possible_mask)) | 294 | if (!cpumask_subset(mask, cpu_possible_mask)) |
292 | return -EINVAL; | 295 | return -EINVAL; |
293 | 296 | ||
297 | if (current_user_ns() != &init_user_ns) | ||
298 | return -EINVAL; | ||
299 | |||
300 | if (task_active_pid_ns(current) != &init_pid_ns) | ||
301 | return -EINVAL; | ||
302 | |||
294 | if (isadd == REGISTER) { | 303 | if (isadd == REGISTER) { |
295 | for_each_cpu(cpu, mask) { | 304 | for_each_cpu(cpu, mask) { |
296 | s = kmalloc_node(sizeof(struct listener), | 305 | s = kmalloc_node(sizeof(struct listener), |
@@ -415,16 +424,15 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
415 | struct nlattr *na; | 424 | struct nlattr *na; |
416 | size_t size; | 425 | size_t size; |
417 | u32 fd; | 426 | u32 fd; |
418 | struct file *file; | 427 | struct fd f; |
419 | int fput_needed; | ||
420 | 428 | ||
421 | na = info->attrs[CGROUPSTATS_CMD_ATTR_FD]; | 429 | na = info->attrs[CGROUPSTATS_CMD_ATTR_FD]; |
422 | if (!na) | 430 | if (!na) |
423 | return -EINVAL; | 431 | return -EINVAL; |
424 | 432 | ||
425 | fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]); | 433 | fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]); |
426 | file = fget_light(fd, &fput_needed); | 434 | f = fdget(fd); |
427 | if (!file) | 435 | if (!f.file) |
428 | return 0; | 436 | return 0; |
429 | 437 | ||
430 | size = nla_total_size(sizeof(struct cgroupstats)); | 438 | size = nla_total_size(sizeof(struct cgroupstats)); |
@@ -437,6 +445,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
437 | na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS, | 445 | na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS, |
438 | sizeof(struct cgroupstats)); | 446 | sizeof(struct cgroupstats)); |
439 | if (na == NULL) { | 447 | if (na == NULL) { |
448 | nlmsg_free(rep_skb); | ||
440 | rc = -EMSGSIZE; | 449 | rc = -EMSGSIZE; |
441 | goto err; | 450 | goto err; |
442 | } | 451 | } |
@@ -444,7 +453,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
444 | stats = nla_data(na); | 453 | stats = nla_data(na); |
445 | memset(stats, 0, sizeof(*stats)); | 454 | memset(stats, 0, sizeof(*stats)); |
446 | 455 | ||
447 | rc = cgroupstats_build(stats, file->f_dentry); | 456 | rc = cgroupstats_build(stats, f.file->f_dentry); |
448 | if (rc < 0) { | 457 | if (rc < 0) { |
449 | nlmsg_free(rep_skb); | 458 | nlmsg_free(rep_skb); |
450 | goto err; | 459 | goto err; |
@@ -453,7 +462,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
453 | rc = send_reply(rep_skb, info); | 462 | rc = send_reply(rep_skb, info); |
454 | 463 | ||
455 | err: | 464 | err: |
456 | fput_light(file, fput_needed); | 465 | fdput(f); |
457 | return rc; | 466 | return rc; |
458 | } | 467 | } |
459 | 468 | ||
@@ -467,7 +476,7 @@ static int cmd_attr_register_cpumask(struct genl_info *info) | |||
467 | rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask); | 476 | rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask); |
468 | if (rc < 0) | 477 | if (rc < 0) |
469 | goto out; | 478 | goto out; |
470 | rc = add_del_listener(info->snd_pid, mask, REGISTER); | 479 | rc = add_del_listener(info->snd_portid, mask, REGISTER); |
471 | out: | 480 | out: |
472 | free_cpumask_var(mask); | 481 | free_cpumask_var(mask); |
473 | return rc; | 482 | return rc; |
@@ -483,7 +492,7 @@ static int cmd_attr_deregister_cpumask(struct genl_info *info) | |||
483 | rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask); | 492 | rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask); |
484 | if (rc < 0) | 493 | if (rc < 0) |
485 | goto out; | 494 | goto out; |
486 | rc = add_del_listener(info->snd_pid, mask, DEREGISTER); | 495 | rc = add_del_listener(info->snd_portid, mask, DEREGISTER); |
487 | out: | 496 | out: |
488 | free_cpumask_var(mask); | 497 | free_cpumask_var(mask); |
489 | return rc; | 498 | return rc; |
@@ -631,11 +640,12 @@ void taskstats_exit(struct task_struct *tsk, int group_dead) | |||
631 | if (rc < 0) | 640 | if (rc < 0) |
632 | return; | 641 | return; |
633 | 642 | ||
634 | stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, tsk->pid); | 643 | stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, |
644 | task_pid_nr_ns(tsk, &init_pid_ns)); | ||
635 | if (!stats) | 645 | if (!stats) |
636 | goto err; | 646 | goto err; |
637 | 647 | ||
638 | fill_stats(tsk, stats); | 648 | fill_stats(&init_user_ns, &init_pid_ns, tsk, stats); |
639 | 649 | ||
640 | /* | 650 | /* |
641 | * Doesn't matter if tsk is the leader or the last group member leaving | 651 | * Doesn't matter if tsk is the leader or the last group member leaving |
@@ -643,7 +653,8 @@ void taskstats_exit(struct task_struct *tsk, int group_dead) | |||
643 | if (!is_thread_group || !group_dead) | 653 | if (!is_thread_group || !group_dead) |
644 | goto send; | 654 | goto send; |
645 | 655 | ||
646 | stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tsk->tgid); | 656 | stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, |
657 | task_tgid_nr_ns(tsk, &init_pid_ns)); | ||
647 | if (!stats) | 658 | if (!stats) |
648 | goto err; | 659 | goto err; |
649 | 660 | ||