diff options
Diffstat (limited to 'net/ipv6/ip6_flowlabel.c')
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 80 |
1 files changed, 22 insertions, 58 deletions
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 29124b7a04c..54303945019 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -21,8 +21,6 @@ | |||
21 | #include <linux/proc_fs.h> | 21 | #include <linux/proc_fs.h> |
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/export.h> | ||
25 | #include <linux/pid_namespace.h> | ||
26 | 24 | ||
27 | #include <net/net_namespace.h> | 25 | #include <net/net_namespace.h> |
28 | #include <net/sock.h> | 26 | #include <net/sock.h> |
@@ -92,8 +90,6 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) | |||
92 | static void fl_free(struct ip6_flowlabel *fl) | 90 | static void fl_free(struct ip6_flowlabel *fl) |
93 | { | 91 | { |
94 | if (fl) { | 92 | if (fl) { |
95 | if (fl->share == IPV6_FL_S_PROCESS) | ||
96 | put_pid(fl->owner.pid); | ||
97 | release_net(fl->fl_net); | 93 | release_net(fl->fl_net); |
98 | kfree(fl->opt); | 94 | kfree(fl->opt); |
99 | } | 95 | } |
@@ -297,7 +293,6 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, | |||
297 | opt_space->opt_flen = fopt->opt_flen; | 293 | opt_space->opt_flen = fopt->opt_flen; |
298 | return opt_space; | 294 | return opt_space; |
299 | } | 295 | } |
300 | EXPORT_SYMBOL_GPL(fl6_merge_options); | ||
301 | 296 | ||
302 | static unsigned long check_linger(unsigned long ttl) | 297 | static unsigned long check_linger(unsigned long ttl) |
303 | { | 298 | { |
@@ -390,17 +385,17 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq, | |||
390 | err = -EINVAL; | 385 | err = -EINVAL; |
391 | goto done; | 386 | goto done; |
392 | } | 387 | } |
393 | fl->dst = freq->flr_dst; | 388 | ipv6_addr_copy(&fl->dst, &freq->flr_dst); |
394 | atomic_set(&fl->users, 1); | 389 | atomic_set(&fl->users, 1); |
395 | switch (fl->share) { | 390 | switch (fl->share) { |
396 | case IPV6_FL_S_EXCL: | 391 | case IPV6_FL_S_EXCL: |
397 | case IPV6_FL_S_ANY: | 392 | case IPV6_FL_S_ANY: |
398 | break; | 393 | break; |
399 | case IPV6_FL_S_PROCESS: | 394 | case IPV6_FL_S_PROCESS: |
400 | fl->owner.pid = get_task_pid(current, PIDTYPE_PID); | 395 | fl->owner = current->pid; |
401 | break; | 396 | break; |
402 | case IPV6_FL_S_USER: | 397 | case IPV6_FL_S_USER: |
403 | fl->owner.uid = current_euid(); | 398 | fl->owner = current_euid(); |
404 | break; | 399 | break; |
405 | default: | 400 | default: |
406 | err = -EINVAL; | 401 | err = -EINVAL; |
@@ -436,32 +431,32 @@ static int mem_check(struct sock *sk) | |||
436 | return 0; | 431 | return 0; |
437 | } | 432 | } |
438 | 433 | ||
439 | static bool ipv6_hdr_cmp(struct ipv6_opt_hdr *h1, struct ipv6_opt_hdr *h2) | 434 | static int ipv6_hdr_cmp(struct ipv6_opt_hdr *h1, struct ipv6_opt_hdr *h2) |
440 | { | 435 | { |
441 | if (h1 == h2) | 436 | if (h1 == h2) |
442 | return false; | 437 | return 0; |
443 | if (h1 == NULL || h2 == NULL) | 438 | if (h1 == NULL || h2 == NULL) |
444 | return true; | 439 | return 1; |
445 | if (h1->hdrlen != h2->hdrlen) | 440 | if (h1->hdrlen != h2->hdrlen) |
446 | return true; | 441 | return 1; |
447 | return memcmp(h1+1, h2+1, ((h1->hdrlen+1)<<3) - sizeof(*h1)); | 442 | return memcmp(h1+1, h2+1, ((h1->hdrlen+1)<<3) - sizeof(*h1)); |
448 | } | 443 | } |
449 | 444 | ||
450 | static bool ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2) | 445 | static int ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2) |
451 | { | 446 | { |
452 | if (o1 == o2) | 447 | if (o1 == o2) |
453 | return false; | 448 | return 0; |
454 | if (o1 == NULL || o2 == NULL) | 449 | if (o1 == NULL || o2 == NULL) |
455 | return true; | 450 | return 1; |
456 | if (o1->opt_nflen != o2->opt_nflen) | 451 | if (o1->opt_nflen != o2->opt_nflen) |
457 | return true; | 452 | return 1; |
458 | if (ipv6_hdr_cmp(o1->hopopt, o2->hopopt)) | 453 | if (ipv6_hdr_cmp(o1->hopopt, o2->hopopt)) |
459 | return true; | 454 | return 1; |
460 | if (ipv6_hdr_cmp(o1->dst0opt, o2->dst0opt)) | 455 | if (ipv6_hdr_cmp(o1->dst0opt, o2->dst0opt)) |
461 | return true; | 456 | return 1; |
462 | if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt)) | 457 | if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt)) |
463 | return true; | 458 | return 1; |
464 | return false; | 459 | return 0; |
465 | } | 460 | } |
466 | 461 | ||
467 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | 462 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, |
@@ -519,8 +514,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
519 | } | 514 | } |
520 | read_unlock_bh(&ip6_sk_fl_lock); | 515 | read_unlock_bh(&ip6_sk_fl_lock); |
521 | 516 | ||
522 | if (freq.flr_share == IPV6_FL_S_NONE && | 517 | if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) { |
523 | ns_capable(net->user_ns, CAP_NET_ADMIN)) { | ||
524 | fl = fl_lookup(net, freq.flr_label); | 518 | fl = fl_lookup(net, freq.flr_label); |
525 | if (fl) { | 519 | if (fl) { |
526 | err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); | 520 | err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); |
@@ -565,10 +559,7 @@ recheck: | |||
565 | err = -EPERM; | 559 | err = -EPERM; |
566 | if (fl1->share == IPV6_FL_S_EXCL || | 560 | if (fl1->share == IPV6_FL_S_EXCL || |
567 | fl1->share != fl->share || | 561 | fl1->share != fl->share || |
568 | ((fl1->share == IPV6_FL_S_PROCESS) && | 562 | fl1->owner != fl->owner) |
569 | (fl1->owner.pid == fl->owner.pid)) || | ||
570 | ((fl1->share == IPV6_FL_S_USER) && | ||
571 | uid_eq(fl1->owner.uid, fl->owner.uid))) | ||
572 | goto release; | 563 | goto release; |
573 | 564 | ||
574 | err = -EINVAL; | 565 | err = -EINVAL; |
@@ -628,7 +619,6 @@ done: | |||
628 | 619 | ||
629 | struct ip6fl_iter_state { | 620 | struct ip6fl_iter_state { |
630 | struct seq_net_private p; | 621 | struct seq_net_private p; |
631 | struct pid_namespace *pid_ns; | ||
632 | int bucket; | 622 | int bucket; |
633 | }; | 623 | }; |
634 | 624 | ||
@@ -707,7 +697,6 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v) | |||
707 | 697 | ||
708 | static int ip6fl_seq_show(struct seq_file *seq, void *v) | 698 | static int ip6fl_seq_show(struct seq_file *seq, void *v) |
709 | { | 699 | { |
710 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); | ||
711 | if (v == SEQ_START_TOKEN) | 700 | if (v == SEQ_START_TOKEN) |
712 | seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", | 701 | seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", |
713 | "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); | 702 | "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); |
@@ -715,13 +704,9 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v) | |||
715 | struct ip6_flowlabel *fl = v; | 704 | struct ip6_flowlabel *fl = v; |
716 | seq_printf(seq, | 705 | seq_printf(seq, |
717 | "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", | 706 | "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", |
718 | (unsigned int)ntohl(fl->label), | 707 | (unsigned)ntohl(fl->label), |
719 | fl->share, | 708 | fl->share, |
720 | ((fl->share == IPV6_FL_S_PROCESS) ? | 709 | (unsigned)fl->owner, |
721 | pid_nr_ns(fl->owner.pid, state->pid_ns) : | ||
722 | ((fl->share == IPV6_FL_S_USER) ? | ||
723 | from_kuid_munged(seq_user_ns(seq), fl->owner.uid) : | ||
724 | 0)), | ||
725 | atomic_read(&fl->users), | 710 | atomic_read(&fl->users), |
726 | fl->linger/HZ, | 711 | fl->linger/HZ, |
727 | (long)(fl->expires - jiffies)/HZ, | 712 | (long)(fl->expires - jiffies)/HZ, |
@@ -740,29 +725,8 @@ static const struct seq_operations ip6fl_seq_ops = { | |||
740 | 725 | ||
741 | static int ip6fl_seq_open(struct inode *inode, struct file *file) | 726 | static int ip6fl_seq_open(struct inode *inode, struct file *file) |
742 | { | 727 | { |
743 | struct seq_file *seq; | 728 | return seq_open_net(inode, file, &ip6fl_seq_ops, |
744 | struct ip6fl_iter_state *state; | 729 | sizeof(struct ip6fl_iter_state)); |
745 | int err; | ||
746 | |||
747 | err = seq_open_net(inode, file, &ip6fl_seq_ops, | ||
748 | sizeof(struct ip6fl_iter_state)); | ||
749 | |||
750 | if (!err) { | ||
751 | seq = file->private_data; | ||
752 | state = ip6fl_seq_private(seq); | ||
753 | rcu_read_lock(); | ||
754 | state->pid_ns = get_pid_ns(task_active_pid_ns(current)); | ||
755 | rcu_read_unlock(); | ||
756 | } | ||
757 | return err; | ||
758 | } | ||
759 | |||
760 | static int ip6fl_seq_release(struct inode *inode, struct file *file) | ||
761 | { | ||
762 | struct seq_file *seq = file->private_data; | ||
763 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); | ||
764 | put_pid_ns(state->pid_ns); | ||
765 | return seq_release_net(inode, file); | ||
766 | } | 730 | } |
767 | 731 | ||
768 | static const struct file_operations ip6fl_seq_fops = { | 732 | static const struct file_operations ip6fl_seq_fops = { |
@@ -770,7 +734,7 @@ static const struct file_operations ip6fl_seq_fops = { | |||
770 | .open = ip6fl_seq_open, | 734 | .open = ip6fl_seq_open, |
771 | .read = seq_read, | 735 | .read = seq_read, |
772 | .llseek = seq_lseek, | 736 | .llseek = seq_lseek, |
773 | .release = ip6fl_seq_release, | 737 | .release = seq_release_net, |
774 | }; | 738 | }; |
775 | 739 | ||
776 | static int __net_init ip6_flowlabel_proc_init(struct net *net) | 740 | static int __net_init ip6_flowlabel_proc_init(struct net *net) |