diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d4ff41739b0f..9837bebf93ce 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -774,7 +774,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, | |||
774 | return 0; | 774 | return 0; |
775 | } | 775 | } |
776 | 776 | ||
777 | static size_t rtnl_port_size(const struct net_device *dev) | 777 | static size_t rtnl_port_size(const struct net_device *dev, |
778 | u32 ext_filter_mask) | ||
778 | { | 779 | { |
779 | size_t port_size = nla_total_size(4) /* PORT_VF */ | 780 | size_t port_size = nla_total_size(4) /* PORT_VF */ |
780 | + nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */ | 781 | + nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */ |
@@ -790,7 +791,8 @@ static size_t rtnl_port_size(const struct net_device *dev) | |||
790 | size_t port_self_size = nla_total_size(sizeof(struct nlattr)) | 791 | size_t port_self_size = nla_total_size(sizeof(struct nlattr)) |
791 | + port_size; | 792 | + port_size; |
792 | 793 | ||
793 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent) | 794 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent || |
795 | !(ext_filter_mask & RTEXT_FILTER_VF)) | ||
794 | return 0; | 796 | return 0; |
795 | if (dev_num_vf(dev->dev.parent)) | 797 | if (dev_num_vf(dev->dev.parent)) |
796 | return port_self_size + vf_ports_size + | 798 | return port_self_size + vf_ports_size + |
@@ -826,7 +828,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, | |||
826 | + nla_total_size(ext_filter_mask | 828 | + nla_total_size(ext_filter_mask |
827 | & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */ | 829 | & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */ |
828 | + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */ | 830 | + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */ |
829 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ | 831 | + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ |
830 | + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ | 832 | + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ |
831 | + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */ | 833 | + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */ |
832 | + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */ | 834 | + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */ |
@@ -888,11 +890,13 @@ static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev) | |||
888 | return 0; | 890 | return 0; |
889 | } | 891 | } |
890 | 892 | ||
891 | static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev) | 893 | static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev, |
894 | u32 ext_filter_mask) | ||
892 | { | 895 | { |
893 | int err; | 896 | int err; |
894 | 897 | ||
895 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent) | 898 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent || |
899 | !(ext_filter_mask & RTEXT_FILTER_VF)) | ||
896 | return 0; | 900 | return 0; |
897 | 901 | ||
898 | err = rtnl_port_self_fill(skb, dev); | 902 | err = rtnl_port_self_fill(skb, dev); |
@@ -1079,7 +1083,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
1079 | nla_nest_end(skb, vfinfo); | 1083 | nla_nest_end(skb, vfinfo); |
1080 | } | 1084 | } |
1081 | 1085 | ||
1082 | if (rtnl_port_fill(skb, dev)) | 1086 | if (rtnl_port_fill(skb, dev, ext_filter_mask)) |
1083 | goto nla_put_failure; | 1087 | goto nla_put_failure; |
1084 | 1088 | ||
1085 | if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) { | 1089 | if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) { |
@@ -1198,6 +1202,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1198 | struct hlist_head *head; | 1202 | struct hlist_head *head; |
1199 | struct nlattr *tb[IFLA_MAX+1]; | 1203 | struct nlattr *tb[IFLA_MAX+1]; |
1200 | u32 ext_filter_mask = 0; | 1204 | u32 ext_filter_mask = 0; |
1205 | int err; | ||
1201 | 1206 | ||
1202 | s_h = cb->args[0]; | 1207 | s_h = cb->args[0]; |
1203 | s_idx = cb->args[1]; | 1208 | s_idx = cb->args[1]; |
@@ -1218,11 +1223,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1218 | hlist_for_each_entry_rcu(dev, head, index_hlist) { | 1223 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
1219 | if (idx < s_idx) | 1224 | if (idx < s_idx) |
1220 | goto cont; | 1225 | goto cont; |
1221 | if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, | 1226 | err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, |
1222 | NETLINK_CB(cb->skb).portid, | 1227 | NETLINK_CB(cb->skb).portid, |
1223 | cb->nlh->nlmsg_seq, 0, | 1228 | cb->nlh->nlmsg_seq, 0, |
1224 | NLM_F_MULTI, | 1229 | NLM_F_MULTI, |
1225 | ext_filter_mask) <= 0) | 1230 | ext_filter_mask); |
1231 | /* If we ran out of room on the first message, | ||
1232 | * we're in trouble | ||
1233 | */ | ||
1234 | WARN_ON((err == -EMSGSIZE) && (skb->len == 0)); | ||
1235 | |||
1236 | if (err <= 0) | ||
1226 | goto out; | 1237 | goto out; |
1227 | 1238 | ||
1228 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | 1239 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
@@ -1395,7 +1406,8 @@ static int do_set_master(struct net_device *dev, int ifindex) | |||
1395 | return 0; | 1406 | return 0; |
1396 | } | 1407 | } |
1397 | 1408 | ||
1398 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | 1409 | static int do_setlink(const struct sk_buff *skb, |
1410 | struct net_device *dev, struct ifinfomsg *ifm, | ||
1399 | struct nlattr **tb, char *ifname, int modified) | 1411 | struct nlattr **tb, char *ifname, int modified) |
1400 | { | 1412 | { |
1401 | const struct net_device_ops *ops = dev->netdev_ops; | 1413 | const struct net_device_ops *ops = dev->netdev_ops; |
@@ -1407,7 +1419,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1407 | err = PTR_ERR(net); | 1419 | err = PTR_ERR(net); |
1408 | goto errout; | 1420 | goto errout; |
1409 | } | 1421 | } |
1410 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) { | 1422 | if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { |
1411 | err = -EPERM; | 1423 | err = -EPERM; |
1412 | goto errout; | 1424 | goto errout; |
1413 | } | 1425 | } |
@@ -1661,7 +1673,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1661 | if (err < 0) | 1673 | if (err < 0) |
1662 | goto errout; | 1674 | goto errout; |
1663 | 1675 | ||
1664 | err = do_setlink(dev, ifm, tb, ifname, 0); | 1676 | err = do_setlink(skb, dev, ifm, tb, ifname, 0); |
1665 | errout: | 1677 | errout: |
1666 | return err; | 1678 | return err; |
1667 | } | 1679 | } |
@@ -1778,7 +1790,8 @@ err: | |||
1778 | } | 1790 | } |
1779 | EXPORT_SYMBOL(rtnl_create_link); | 1791 | EXPORT_SYMBOL(rtnl_create_link); |
1780 | 1792 | ||
1781 | static int rtnl_group_changelink(struct net *net, int group, | 1793 | static int rtnl_group_changelink(const struct sk_buff *skb, |
1794 | struct net *net, int group, | ||
1782 | struct ifinfomsg *ifm, | 1795 | struct ifinfomsg *ifm, |
1783 | struct nlattr **tb) | 1796 | struct nlattr **tb) |
1784 | { | 1797 | { |
@@ -1787,7 +1800,7 @@ static int rtnl_group_changelink(struct net *net, int group, | |||
1787 | 1800 | ||
1788 | for_each_netdev(net, dev) { | 1801 | for_each_netdev(net, dev) { |
1789 | if (dev->group == group) { | 1802 | if (dev->group == group) { |
1790 | err = do_setlink(dev, ifm, tb, NULL, 0); | 1803 | err = do_setlink(skb, dev, ifm, tb, NULL, 0); |
1791 | if (err < 0) | 1804 | if (err < 0) |
1792 | return err; | 1805 | return err; |
1793 | } | 1806 | } |
@@ -1929,12 +1942,12 @@ replay: | |||
1929 | modified = 1; | 1942 | modified = 1; |
1930 | } | 1943 | } |
1931 | 1944 | ||
1932 | return do_setlink(dev, ifm, tb, ifname, modified); | 1945 | return do_setlink(skb, dev, ifm, tb, ifname, modified); |
1933 | } | 1946 | } |
1934 | 1947 | ||
1935 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { | 1948 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
1936 | if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) | 1949 | if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) |
1937 | return rtnl_group_changelink(net, | 1950 | return rtnl_group_changelink(skb, net, |
1938 | nla_get_u32(tb[IFLA_GROUP]), | 1951 | nla_get_u32(tb[IFLA_GROUP]), |
1939 | ifm, tb); | 1952 | ifm, tb); |
1940 | return -ENODEV; | 1953 | return -ENODEV; |
@@ -2321,7 +2334,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2321 | int err = -EINVAL; | 2334 | int err = -EINVAL; |
2322 | __u8 *addr; | 2335 | __u8 *addr; |
2323 | 2336 | ||
2324 | if (!capable(CAP_NET_ADMIN)) | 2337 | if (!netlink_capable(skb, CAP_NET_ADMIN)) |
2325 | return -EPERM; | 2338 | return -EPERM; |
2326 | 2339 | ||
2327 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); | 2340 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); |
@@ -2773,7 +2786,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2773 | sz_idx = type>>2; | 2786 | sz_idx = type>>2; |
2774 | kind = type&3; | 2787 | kind = type&3; |
2775 | 2788 | ||
2776 | if (kind != 2 && !ns_capable(net->user_ns, CAP_NET_ADMIN)) | 2789 | if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN)) |
2777 | return -EPERM; | 2790 | return -EPERM; |
2778 | 2791 | ||
2779 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 2792 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |