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 | ||
