lkml.org 
[lkml]   [2016]   [Mar]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.4 018/107] rtnetlink: verify IFLA_VF_INFO attributes before passing them to driver
    Date
    From: Daniel Borkmann <daniel@iogearbox.net>

    3.4.111-rc1 review patch. If anyone has any objections, please let me know.

    ------------------


    commit 4f7d2cdfdde71ffe962399b7020c674050329423 upstream.

    Jason Gunthorpe reported that since commit c02db8c6290b ("rtnetlink: make
    SR-IOV VF interface symmetric"), we don't verify IFLA_VF_INFO attributes
    anymore with respect to their policy, that is, ifla_vfinfo_policy[].

    Before, they were part of ifla_policy[], but they have been nested since
    placed under IFLA_VFINFO_LIST, that contains the attribute IFLA_VF_INFO,
    which is another nested attribute for the actual VF attributes such as
    IFLA_VF_MAC, IFLA_VF_VLAN, etc.

    Despite the policy being split out from ifla_policy[] in this commit,
    it's never applied anywhere. nla_for_each_nested() only does basic nla_ok()
    testing for struct nlattr, but it doesn't know about the data context and
    their requirements.

    Fix, on top of Jason's initial work, does 1) parsing of the attributes
    with the right policy, and 2) using the resulting parsed attribute table
    from 1) instead of the nla_for_each_nested() loop (just like we used to
    do when still part of ifla_policy[]).

    Reference: http://thread.gmane.org/gmane.linux.network/368913
    Fixes: c02db8c6290b ("rtnetlink: make SR-IOV VF interface symmetric")
    Reported-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
    Cc: Greg Rose <gregory.v.rose@intel.com>
    Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
    Cc: Rony Efraim <ronye@mellanox.com>
    Cc: Vlad Zolotarov <vladz@cloudius-systems.com>
    Cc: Nicolas Dichtel <nicolas.dichtel@6wind.com>
    Cc: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
    Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
    Acked-by: Vlad Zolotarov <vladz@cloudius-systems.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    [bwh: Backported to 3.2:
    - Drop unsupported attributes
    - Use ndo_set_vf_tx_rate operation, not ndo_set_vf_rate]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    Signed-off-by: Zefan Li <lizefan@huawei.com>
    ---
    net/core/rtnetlink.c | 106 +++++++++++++++++++++++++--------------------------
    1 file changed, 52 insertions(+), 54 deletions(-)

    diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
    index 43c6dd8..8941e962 100644
    --- a/net/core/rtnetlink.c
    +++ b/net/core/rtnetlink.c
    @@ -1139,10 +1139,6 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
    [IFLA_INFO_DATA] = { .type = NLA_NESTED },
    };

    -static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = {
    - [IFLA_VF_INFO] = { .type = NLA_NESTED },
    -};
    -
    static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
    [IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) },
    [IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) },
    @@ -1216,58 +1212,53 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
    return 0;
    }

    -static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
    +static int do_setvfinfo(struct net_device *dev, struct nlattr **tb)
    {
    - int rem, err = -EINVAL;
    - struct nlattr *vf;
    const struct net_device_ops *ops = dev->netdev_ops;
    + int err = -EINVAL;

    - nla_for_each_nested(vf, attr, rem) {
    - switch (nla_type(vf)) {
    - case IFLA_VF_MAC: {
    - struct ifla_vf_mac *ivm;
    - ivm = nla_data(vf);
    - err = -EOPNOTSUPP;
    - if (ops->ndo_set_vf_mac)
    - err = ops->ndo_set_vf_mac(dev, ivm->vf,
    - ivm->mac);
    - break;
    - }
    - case IFLA_VF_VLAN: {
    - struct ifla_vf_vlan *ivv;
    - ivv = nla_data(vf);
    - err = -EOPNOTSUPP;
    - if (ops->ndo_set_vf_vlan)
    - err = ops->ndo_set_vf_vlan(dev, ivv->vf,
    - ivv->vlan,
    - ivv->qos);
    - break;
    - }
    - case IFLA_VF_TX_RATE: {
    - struct ifla_vf_tx_rate *ivt;
    - ivt = nla_data(vf);
    - err = -EOPNOTSUPP;
    - if (ops->ndo_set_vf_tx_rate)
    - err = ops->ndo_set_vf_tx_rate(dev, ivt->vf,
    - ivt->rate);
    - break;
    - }
    - case IFLA_VF_SPOOFCHK: {
    - struct ifla_vf_spoofchk *ivs;
    - ivs = nla_data(vf);
    - err = -EOPNOTSUPP;
    - if (ops->ndo_set_vf_spoofchk)
    - err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
    - ivs->setting);
    - break;
    - }
    - default:
    - err = -EINVAL;
    - break;
    - }
    - if (err)
    - break;
    + if (tb[IFLA_VF_MAC]) {
    + struct ifla_vf_mac *ivm = nla_data(tb[IFLA_VF_MAC]);
    + err = -EOPNOTSUPP;
    + if (ops->ndo_set_vf_mac)
    + err = ops->ndo_set_vf_mac(dev, ivm->vf,
    + ivm->mac);
    + if (err < 0)
    + return err;
    }
    +
    + if (tb[IFLA_VF_VLAN]) {
    + struct ifla_vf_vlan *ivv = nla_data(tb[IFLA_VF_VLAN]);
    +
    + err = -EOPNOTSUPP;
    + if (ops->ndo_set_vf_vlan)
    + err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan,
    + ivv->qos);
    + if (err < 0)
    + return err;
    + }
    +
    + if (tb[IFLA_VF_TX_RATE]) {
    + struct ifla_vf_tx_rate *ivt = nla_data(tb[IFLA_VF_TX_RATE]);
    +
    + if (ops->ndo_set_vf_tx_rate)
    + err = ops->ndo_set_vf_tx_rate(dev, ivt->vf,
    + ivt->rate);
    + if (err < 0)
    + return err;
    + }
    +
    + if (tb[IFLA_VF_SPOOFCHK]) {
    + struct ifla_vf_spoofchk *ivs = nla_data(tb[IFLA_VF_SPOOFCHK]);
    +
    + err = -EOPNOTSUPP;
    + if (ops->ndo_set_vf_spoofchk)
    + err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
    + ivs->setting);
    + if (err < 0)
    + return err;
    + }
    +
    return err;
    }

    @@ -1450,14 +1441,21 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
    }

    if (tb[IFLA_VFINFO_LIST]) {
    + struct nlattr *vfinfo[IFLA_VF_MAX + 1];
    struct nlattr *attr;
    int rem;
    +
    nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) {
    - if (nla_type(attr) != IFLA_VF_INFO) {
    + if (nla_type(attr) != IFLA_VF_INFO ||
    + nla_len(attr) < NLA_HDRLEN) {
    err = -EINVAL;
    goto errout;
    }
    - err = do_setvfinfo(dev, attr);
    + err = nla_parse_nested(vfinfo, IFLA_VF_MAX, attr,
    + ifla_vf_policy);
    + if (err < 0)
    + goto errout;
    + err = do_setvfinfo(dev, vfinfo);
    if (err < 0)
    goto errout;
    modified = 1;
    --
    1.9.1
    \
     
     \ /
      Last update: 2016-03-16 10:21    [W:4.116 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site