aboutsummaryrefslogtreecommitdiffstats
path: root/net/decnet
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-11-24 20:14:51 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:30:30 -0500
commit4a89c2562cb81c24c515b9de041aced4d21cb6d1 (patch)
tree9c4610a00e49f2318601122a4634a8ee78764a75 /net/decnet
parentb020b942cdc238e9761cb38598eda6691c366d68 (diff)
[DECNET] address: Convert to new netlink interface
Extends the netlink interface to support the __le16 type and converts address addition, deletion and, dumping to use the new netlink interface. Fixes multiple occasions of possible illegal memory references due to not validated netlink attributes. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/decnet')
-rw-r--r--net/decnet/dn_dev.c142
1 files changed, 85 insertions, 57 deletions
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 309b2c7a4c6c..0b9d4c955154 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -645,41 +645,62 @@ static struct dn_dev *dn_dev_by_index(int ifindex)
645 return dn_dev; 645 return dn_dev;
646} 646}
647 647
648static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 648static struct nla_policy dn_ifa_policy[IFA_MAX+1] __read_mostly = {
649 [IFA_ADDRESS] = { .type = NLA_U16 },
650 [IFA_LOCAL] = { .type = NLA_U16 },
651 [IFA_LABEL] = { .type = NLA_STRING,
652 .len = IFNAMSIZ - 1 },
653};
654
655static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
649{ 656{
650 struct rtattr **rta = arg; 657 struct nlattr *tb[IFA_MAX+1];
651 struct dn_dev *dn_db; 658 struct dn_dev *dn_db;
652 struct ifaddrmsg *ifm = NLMSG_DATA(nlh); 659 struct ifaddrmsg *ifm;
653 struct dn_ifaddr *ifa, **ifap; 660 struct dn_ifaddr *ifa, **ifap;
661 int err = -EADDRNOTAVAIL;
662
663 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);
664 if (err < 0)
665 goto errout;
654 666
667 ifm = nlmsg_data(nlh);
655 if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL) 668 if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)
656 return -EADDRNOTAVAIL; 669 goto errout;
670
671 for (ifap = &dn_db->ifa_list; (ifa = *ifap); ifap = &ifa->ifa_next) {
672 if (tb[IFA_LOCAL] &&
673 nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))
674 continue;
657 675
658 for(ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) { 676 if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
659 void *tmp = rta[IFA_LOCAL-1];
660 if ((tmp && memcmp(RTA_DATA(tmp), &ifa->ifa_local, 2)) ||
661 (rta[IFA_LABEL-1] && rtattr_strcmp(rta[IFA_LABEL-1], ifa->ifa_label)))
662 continue; 677 continue;
663 678
664 dn_dev_del_ifa(dn_db, ifap, 1); 679 dn_dev_del_ifa(dn_db, ifap, 1);
665 return 0; 680 return 0;
666 } 681 }
667 682
668 return -EADDRNOTAVAIL; 683errout:
684 return err;
669} 685}
670 686
671static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 687static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
672{ 688{
673 struct rtattr **rta = arg; 689 struct nlattr *tb[IFA_MAX+1];
674 struct net_device *dev; 690 struct net_device *dev;
675 struct dn_dev *dn_db; 691 struct dn_dev *dn_db;
676 struct ifaddrmsg *ifm = NLMSG_DATA(nlh); 692 struct ifaddrmsg *ifm;
677 struct dn_ifaddr *ifa; 693 struct dn_ifaddr *ifa;
678 int rv; 694 int err;
695
696 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);
697 if (err < 0)
698 return err;
679 699
680 if (rta[IFA_LOCAL-1] == NULL) 700 if (tb[IFA_LOCAL] == NULL)
681 return -EINVAL; 701 return -EINVAL;
682 702
703 ifm = nlmsg_data(nlh);
683 if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) 704 if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
684 return -ENODEV; 705 return -ENODEV;
685 706
@@ -693,22 +714,25 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
693 if ((ifa = dn_dev_alloc_ifa()) == NULL) 714 if ((ifa = dn_dev_alloc_ifa()) == NULL)
694 return -ENOBUFS; 715 return -ENOBUFS;
695 716
696 if (!rta[IFA_ADDRESS - 1]) 717 if (tb[IFA_ADDRESS] == NULL)
697 rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1]; 718 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
698 memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2); 719
699 memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 2); 720 ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]);
721 ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]);
700 ifa->ifa_flags = ifm->ifa_flags; 722 ifa->ifa_flags = ifm->ifa_flags;
701 ifa->ifa_scope = ifm->ifa_scope; 723 ifa->ifa_scope = ifm->ifa_scope;
702 ifa->ifa_dev = dn_db; 724 ifa->ifa_dev = dn_db;
703 if (rta[IFA_LABEL-1]) 725
704 rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL-1], IFNAMSIZ); 726 if (tb[IFA_LABEL])
727 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
705 else 728 else
706 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 729 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
707 730
708 rv = dn_dev_insert_ifa(dn_db, ifa); 731 err = dn_dev_insert_ifa(dn_db, ifa);
709 if (rv) 732 if (err)
710 dn_dev_free_ifa(ifa); 733 dn_dev_free_ifa(ifa);
711 return rv; 734
735 return err;
712} 736}
713 737
714static inline size_t dn_ifaddr_nlmsg_size(void) 738static inline size_t dn_ifaddr_nlmsg_size(void)
@@ -719,34 +743,34 @@ static inline size_t dn_ifaddr_nlmsg_size(void)
719 + nla_total_size(2); /* IFA_LOCAL */ 743 + nla_total_size(2); /* IFA_LOCAL */
720} 744}
721 745
722static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, 746static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
723 u32 pid, u32 seq, int event, unsigned int flags) 747 u32 pid, u32 seq, int event, unsigned int flags)
724{ 748{
725 struct ifaddrmsg *ifm; 749 struct ifaddrmsg *ifm;
726 struct nlmsghdr *nlh; 750 struct nlmsghdr *nlh;
727 unsigned char *b = skb->tail;
728 751
729 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); 752 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
730 ifm = NLMSG_DATA(nlh); 753 if (nlh == NULL)
754 return -ENOBUFS;
731 755
756 ifm = nlmsg_data(nlh);
732 ifm->ifa_family = AF_DECnet; 757 ifm->ifa_family = AF_DECnet;
733 ifm->ifa_prefixlen = 16; 758 ifm->ifa_prefixlen = 16;
734 ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; 759 ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
735 ifm->ifa_scope = ifa->ifa_scope; 760 ifm->ifa_scope = ifa->ifa_scope;
736 ifm->ifa_index = ifa->ifa_dev->dev->ifindex; 761 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
762
737 if (ifa->ifa_address) 763 if (ifa->ifa_address)
738 RTA_PUT(skb, IFA_ADDRESS, 2, &ifa->ifa_address); 764 NLA_PUT_LE16(skb, IFA_ADDRESS, ifa->ifa_address);
739 if (ifa->ifa_local) 765 if (ifa->ifa_local)
740 RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local); 766 NLA_PUT_LE16(skb, IFA_LOCAL, ifa->ifa_local);
741 if (ifa->ifa_label[0]) 767 if (ifa->ifa_label[0])
742 RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label); 768 NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
743 nlh->nlmsg_len = skb->tail - b;
744 return skb->len;
745 769
746nlmsg_failure: 770 return nlmsg_end(skb, nlh);
747rtattr_failure: 771
748 skb_trim(skb, b - skb->data); 772nla_put_failure:
749 return -1; 773 return nlmsg_cancel(skb, nlh);
750} 774}
751 775
752static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa) 776static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
@@ -758,7 +782,7 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
758 if (skb == NULL) 782 if (skb == NULL)
759 goto errout; 783 goto errout;
760 784
761 err = dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0); 785 err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
762 /* failure implies BUG in dn_ifaddr_nlmsg_size() */ 786 /* failure implies BUG in dn_ifaddr_nlmsg_size() */
763 BUG_ON(err < 0); 787 BUG_ON(err < 0);
764 788
@@ -768,39 +792,43 @@ errout:
768 rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err); 792 rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err);
769} 793}
770 794
771static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) 795static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
772{ 796{
773 int idx, dn_idx; 797 int idx, dn_idx = 0, skip_ndevs, skip_naddr;
774 int s_idx, s_dn_idx;
775 struct net_device *dev; 798 struct net_device *dev;
776 struct dn_dev *dn_db; 799 struct dn_dev *dn_db;
777 struct dn_ifaddr *ifa; 800 struct dn_ifaddr *ifa;
778 801
779 s_idx = cb->args[0]; 802 skip_ndevs = cb->args[0];
780 s_dn_idx = dn_idx = cb->args[1]; 803 skip_naddr = cb->args[1];
804
781 read_lock(&dev_base_lock); 805 read_lock(&dev_base_lock);
782 for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { 806 for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
783 if (idx < s_idx) 807 if (idx < skip_ndevs)
784 continue; 808 continue;
785 if (idx > s_idx) 809 else if (idx > skip_ndevs) {
786 s_dn_idx = 0; 810 /* Only skip over addresses for first dev dumped
811 * in this iteration (idx == skip_ndevs) */
812 skip_naddr = 0;
813 }
814
787 if ((dn_db = dev->dn_ptr) == NULL) 815 if ((dn_db = dev->dn_ptr) == NULL)
788 continue; 816 continue;
789 817
790 for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) { 818 for (ifa = dn_db->ifa_list, dn_idx = 0; ifa;
791 if (dn_idx < s_dn_idx) 819 ifa = ifa->ifa_next, dn_idx++) {
820 if (dn_idx < skip_naddr)
792 continue; 821 continue;
793 822
794 if (dn_dev_fill_ifaddr(skb, ifa, 823 if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
795 NETLINK_CB(cb->skb).pid, 824 cb->nlh->nlmsg_seq, RTM_NEWADDR,
796 cb->nlh->nlmsg_seq, 825 NLM_F_MULTI) < 0)
797 RTM_NEWADDR,
798 NLM_F_MULTI) <= 0)
799 goto done; 826 goto done;
800 } 827 }
801 } 828 }
802done: 829done:
803 read_unlock(&dev_base_lock); 830 read_unlock(&dev_base_lock);
831
804 cb->args[0] = idx; 832 cb->args[0] = idx;
805 cb->args[1] = dn_idx; 833 cb->args[1] = dn_idx;
806 834
@@ -1417,9 +1445,9 @@ static struct file_operations dn_dev_seq_fops = {
1417 1445
1418static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] = 1446static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] =
1419{ 1447{
1420 [RTM_NEWADDR - RTM_BASE] = { .doit = dn_dev_rtm_newaddr, }, 1448 [RTM_NEWADDR - RTM_BASE] = { .doit = dn_nl_newaddr, },
1421 [RTM_DELADDR - RTM_BASE] = { .doit = dn_dev_rtm_deladdr, }, 1449 [RTM_DELADDR - RTM_BASE] = { .doit = dn_nl_deladdr, },
1422 [RTM_GETADDR - RTM_BASE] = { .dumpit = dn_dev_dump_ifaddr, }, 1450 [RTM_GETADDR - RTM_BASE] = { .dumpit = dn_nl_dump_ifaddr, },
1423#ifdef CONFIG_DECNET_ROUTER 1451#ifdef CONFIG_DECNET_ROUTER
1424 [RTM_NEWROUTE - RTM_BASE] = { .doit = dn_fib_rtm_newroute, }, 1452 [RTM_NEWROUTE - RTM_BASE] = { .doit = dn_fib_rtm_newroute, },
1425 [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, }, 1453 [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, },