diff options
Diffstat (limited to 'kernel/taskstats.c')
| -rw-r--r-- | kernel/taskstats.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index d0a32796550f..5eab1f3edfa5 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), |
| @@ -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 | ||
