lkml.org 
[lkml]   [2020]   [Jul]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.7 028/244] ethtool: fix genlmsg_put() failure handling in ethnl_default_dumpit()
    Date
    From: Michal Kubecek <mkubecek@suse.cz>

    [ Upstream commit 365f9ae4ee36037e2a9268fe7296065356840b4c ]

    If the genlmsg_put() call in ethnl_default_dumpit() fails, we bail out
    without checking if we already have some messages in current skb like we do
    with ethnl_default_dump_one() failure later. Therefore if existing messages
    almost fill up the buffer so that there is not enough space even for
    netlink and genetlink header, we lose all prepared messages and return and
    error.

    Rather than duplicating the skb->len check, move the genlmsg_put(),
    genlmsg_cancel() and genlmsg_end() calls into ethnl_default_dump_one().
    This is also more logical as all message composition will be in
    ethnl_default_dump_one() and only iteration logic will be left in
    ethnl_default_dumpit().

    Fixes: 728480f12442 ("ethtool: default handlers for GET requests")
    Reported-by: Jakub Kicinski <kuba@kernel.org>
    Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
    Reviewed-by: Jakub Kicinski <kuba@kernel.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    net/ethtool/netlink.c | 27 +++++++++++++--------------
    1 file changed, 13 insertions(+), 14 deletions(-)

    --- a/net/ethtool/netlink.c
    +++ b/net/ethtool/netlink.c
    @@ -376,10 +376,17 @@ err_dev:
    }

    static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
    - const struct ethnl_dump_ctx *ctx)
    + const struct ethnl_dump_ctx *ctx,
    + struct netlink_callback *cb)
    {
    + void *ehdr;
    int ret;

    + ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
    + &ethtool_genl_family, 0, ctx->ops->reply_cmd);
    + if (!ehdr)
    + return -EMSGSIZE;
    +
    ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
    rtnl_lock();
    ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, NULL);
    @@ -395,6 +402,10 @@ out:
    if (ctx->ops->cleanup_data)
    ctx->ops->cleanup_data(ctx->reply_data);
    ctx->reply_data->dev = NULL;
    + if (ret < 0)
    + genlmsg_cancel(skb, ehdr);
    + else
    + genlmsg_end(skb, ehdr);
    return ret;
    }

    @@ -411,7 +422,6 @@ static int ethnl_default_dumpit(struct s
    int s_idx = ctx->pos_idx;
    int h, idx = 0;
    int ret = 0;
    - void *ehdr;

    rtnl_lock();
    for (h = ctx->pos_hash; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
    @@ -431,26 +441,15 @@ restart_chain:
    dev_hold(dev);
    rtnl_unlock();

    - ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
    - cb->nlh->nlmsg_seq,
    - &ethtool_genl_family, 0,
    - ctx->ops->reply_cmd);
    - if (!ehdr) {
    - dev_put(dev);
    - ret = -EMSGSIZE;
    - goto out;
    - }
    - ret = ethnl_default_dump_one(skb, dev, ctx);
    + ret = ethnl_default_dump_one(skb, dev, ctx, cb);
    dev_put(dev);
    if (ret < 0) {
    - genlmsg_cancel(skb, ehdr);
    if (ret == -EOPNOTSUPP)
    goto lock_and_cont;
    if (likely(skb->len))
    ret = skb->len;
    goto out;
    }
    - genlmsg_end(skb, ehdr);
    lock_and_cont:
    rtnl_lock();
    if (net->dev_base_seq != seq) {

    \
     
     \ /
      Last update: 2020-07-20 18:07    [W:2.766 / U:0.952 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site