aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-10-03 17:34:00 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-10-04 03:30:59 -0400
commit132a55f3c5c0b1a364d32f65595ad8838c30a60e (patch)
tree587a0dc800b4f40fc74d3541615d2498cc44c6b8 /net
parent81771b3b20fb4e98c6f2b2aac2bc10ed41a8f006 (diff)
[UDP6]: Fix flowi clobbering
The udp6_sendmsg function uses a shared buffer to store the flow without taking any locks. This leads to races with SMP. This patch moves the flowi object onto the stack. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/udp.c62
1 files changed, 31 insertions, 31 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 9662561701d1..552ec0f449af 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -546,7 +546,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
546 struct in6_addr *daddr, *final_p = NULL, final; 546 struct in6_addr *daddr, *final_p = NULL, final;
547 struct ipv6_txoptions *opt = NULL; 547 struct ipv6_txoptions *opt = NULL;
548 struct ip6_flowlabel *flowlabel = NULL; 548 struct ip6_flowlabel *flowlabel = NULL;
549 struct flowi *fl = &inet->cork.fl; 549 struct flowi fl;
550 struct dst_entry *dst; 550 struct dst_entry *dst;
551 int addr_len = msg->msg_namelen; 551 int addr_len = msg->msg_namelen;
552 int ulen = len; 552 int ulen = len;
@@ -626,19 +626,19 @@ do_udp_sendmsg:
626 } 626 }
627 ulen += sizeof(struct udphdr); 627 ulen += sizeof(struct udphdr);
628 628
629 memset(fl, 0, sizeof(*fl)); 629 memset(&fl, 0, sizeof(fl));
630 630
631 if (sin6) { 631 if (sin6) {
632 if (sin6->sin6_port == 0) 632 if (sin6->sin6_port == 0)
633 return -EINVAL; 633 return -EINVAL;
634 634
635 fl->fl_ip_dport = sin6->sin6_port; 635 fl.fl_ip_dport = sin6->sin6_port;
636 daddr = &sin6->sin6_addr; 636 daddr = &sin6->sin6_addr;
637 637
638 if (np->sndflow) { 638 if (np->sndflow) {
639 fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; 639 fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
640 if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) { 640 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
641 flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); 641 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
642 if (flowlabel == NULL) 642 if (flowlabel == NULL)
643 return -EINVAL; 643 return -EINVAL;
644 daddr = &flowlabel->dst; 644 daddr = &flowlabel->dst;
@@ -656,32 +656,32 @@ do_udp_sendmsg:
656 if (addr_len >= sizeof(struct sockaddr_in6) && 656 if (addr_len >= sizeof(struct sockaddr_in6) &&
657 sin6->sin6_scope_id && 657 sin6->sin6_scope_id &&
658 ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) 658 ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
659 fl->oif = sin6->sin6_scope_id; 659 fl.oif = sin6->sin6_scope_id;
660 } else { 660 } else {
661 if (sk->sk_state != TCP_ESTABLISHED) 661 if (sk->sk_state != TCP_ESTABLISHED)
662 return -EDESTADDRREQ; 662 return -EDESTADDRREQ;
663 663
664 fl->fl_ip_dport = inet->dport; 664 fl.fl_ip_dport = inet->dport;
665 daddr = &np->daddr; 665 daddr = &np->daddr;
666 fl->fl6_flowlabel = np->flow_label; 666 fl.fl6_flowlabel = np->flow_label;
667 connected = 1; 667 connected = 1;
668 } 668 }
669 669
670 if (!fl->oif) 670 if (!fl.oif)
671 fl->oif = sk->sk_bound_dev_if; 671 fl.oif = sk->sk_bound_dev_if;
672 672
673 if (msg->msg_controllen) { 673 if (msg->msg_controllen) {
674 opt = &opt_space; 674 opt = &opt_space;
675 memset(opt, 0, sizeof(struct ipv6_txoptions)); 675 memset(opt, 0, sizeof(struct ipv6_txoptions));
676 opt->tot_len = sizeof(*opt); 676 opt->tot_len = sizeof(*opt);
677 677
678 err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass); 678 err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
679 if (err < 0) { 679 if (err < 0) {
680 fl6_sock_release(flowlabel); 680 fl6_sock_release(flowlabel);
681 return err; 681 return err;
682 } 682 }
683 if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { 683 if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
684 flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); 684 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
685 if (flowlabel == NULL) 685 if (flowlabel == NULL)
686 return -EINVAL; 686 return -EINVAL;
687 } 687 }
@@ -695,39 +695,39 @@ do_udp_sendmsg:
695 opt = fl6_merge_options(&opt_space, flowlabel, opt); 695 opt = fl6_merge_options(&opt_space, flowlabel, opt);
696 opt = ipv6_fixup_options(&opt_space, opt); 696 opt = ipv6_fixup_options(&opt_space, opt);
697 697
698 fl->proto = IPPROTO_UDP; 698 fl.proto = IPPROTO_UDP;
699 ipv6_addr_copy(&fl->fl6_dst, daddr); 699 ipv6_addr_copy(&fl.fl6_dst, daddr);
700 if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr)) 700 if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
701 ipv6_addr_copy(&fl->fl6_src, &np->saddr); 701 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
702 fl->fl_ip_sport = inet->sport; 702 fl.fl_ip_sport = inet->sport;
703 703
704 /* merge ip6_build_xmit from ip6_output */ 704 /* merge ip6_build_xmit from ip6_output */
705 if (opt && opt->srcrt) { 705 if (opt && opt->srcrt) {
706 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; 706 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
707 ipv6_addr_copy(&final, &fl->fl6_dst); 707 ipv6_addr_copy(&final, &fl.fl6_dst);
708 ipv6_addr_copy(&fl->fl6_dst, rt0->addr); 708 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
709 final_p = &final; 709 final_p = &final;
710 connected = 0; 710 connected = 0;
711 } 711 }
712 712
713 if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) { 713 if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
714 fl->oif = np->mcast_oif; 714 fl.oif = np->mcast_oif;
715 connected = 0; 715 connected = 0;
716 } 716 }
717 717
718 security_sk_classify_flow(sk, fl); 718 security_sk_classify_flow(sk, &fl);
719 719
720 err = ip6_sk_dst_lookup(sk, &dst, fl); 720 err = ip6_sk_dst_lookup(sk, &dst, &fl);
721 if (err) 721 if (err)
722 goto out; 722 goto out;
723 if (final_p) 723 if (final_p)
724 ipv6_addr_copy(&fl->fl6_dst, final_p); 724 ipv6_addr_copy(&fl.fl6_dst, final_p);
725 725
726 if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) 726 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
727 goto out; 727 goto out;
728 728
729 if (hlimit < 0) { 729 if (hlimit < 0) {
730 if (ipv6_addr_is_multicast(&fl->fl6_dst)) 730 if (ipv6_addr_is_multicast(&fl.fl6_dst))
731 hlimit = np->mcast_hops; 731 hlimit = np->mcast_hops;
732 else 732 else
733 hlimit = np->hop_limit; 733 hlimit = np->hop_limit;
@@ -763,7 +763,7 @@ back_from_confirm:
763do_append_data: 763do_append_data:
764 up->len += ulen; 764 up->len += ulen;
765 err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, 765 err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
766 sizeof(struct udphdr), hlimit, tclass, opt, fl, 766 sizeof(struct udphdr), hlimit, tclass, opt, &fl,
767 (struct rt6_info*)dst, 767 (struct rt6_info*)dst,
768 corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); 768 corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
769 if (err) 769 if (err)
@@ -774,10 +774,10 @@ do_append_data:
774 if (dst) { 774 if (dst) {
775 if (connected) { 775 if (connected) {
776 ip6_dst_store(sk, dst, 776 ip6_dst_store(sk, dst,
777 ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? 777 ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
778 &np->daddr : NULL, 778 &np->daddr : NULL,
779#ifdef CONFIG_IPV6_SUBTREES 779#ifdef CONFIG_IPV6_SUBTREES
780 ipv6_addr_equal(&fl->fl6_src, &np->saddr) ? 780 ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
781 &np->saddr : 781 &np->saddr :
782#endif 782#endif
783 NULL); 783 NULL);