diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-11-24 20:14:51 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:30:30 -0500 |
commit | 4a89c2562cb81c24c515b9de041aced4d21cb6d1 (patch) | |
tree | 9c4610a00e49f2318601122a4634a8ee78764a75 /net/decnet/dn_dev.c | |
parent | b020b942cdc238e9761cb38598eda6691c366d68 (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/dn_dev.c')
-rw-r--r-- | net/decnet/dn_dev.c | 142 |
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 | ||
648 | static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 648 | static 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 | |||
655 | static 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; | 683 | errout: |
684 | return err; | ||
669 | } | 685 | } |
670 | 686 | ||
671 | static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 687 | static 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 | ||
714 | static inline size_t dn_ifaddr_nlmsg_size(void) | 738 | static 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 | ||
722 | static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | 746 | static 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 | ||
746 | nlmsg_failure: | 770 | return nlmsg_end(skb, nlh); |
747 | rtattr_failure: | 771 | |
748 | skb_trim(skb, b - skb->data); | 772 | nla_put_failure: |
749 | return -1; | 773 | return nlmsg_cancel(skb, nlh); |
750 | } | 774 | } |
751 | 775 | ||
752 | static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa) | 776 | static 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 | ||
771 | static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 795 | static 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 | } |
802 | done: | 829 | done: |
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 | ||
1418 | static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] = | 1446 | static 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, }, |