Re: [PATCH v4] af_netlink: ensure that NLMSG_DONE never fails in dumps

From: Johannes Berg
Date: Sat Nov 11 2017 - 09:15:35 EST


On Sat, 2017-11-11 at 23:09 +0900, David Miller wrote:
> From: "Jason A. Donenfeld" <Jason@xxxxxxxxx>
> Date: Thu, 9 Nov 2017 13:04:44 +0900
>
> > @@ -2195,13 +2197,15 @@ static int netlink_dump(struct sock *sk)
> > return 0;
> > }
> >
> > - nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI);
> > - if (!nlh)
> > + nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE,
> > + sizeof(nlk->dump_done_errno), NLM_F_MULTI);
> > + if (WARN_ON(!nlh))
> > goto errout_skb;
>
> If you're handling this by forcing another read() to procude the
> NLMSG_DONE, then you have no reason to WARN_ON() here.
>
> In fact you are adding a WARN_ON() which is trivially triggerable by
> any user.

I added this in my suggestion for how this could work, but I don't
think you're right, since we previously check if there's enough space.
The patch is missing the full context, but this is:


+ if (nlk->dump_done_errno > 0 ||
+ skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) {
mutex_unlock(nlk->cb_mutex);

if (sk_filter(sk, skb))
kfree_skb(skb);
else
__netlink_sendskb(sk, skb);
return 0;
}

- nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI);
- if (!nlh)
+ nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE,
+ sizeof(nlk->dump_done_errno), NLM_F_MULTI);
+ if (WARN_ON(!nlh))


So unless the nlmsg_total_size() vs. nlmsg_put_answer() suddenly gets a
different idea of how much space is needed, nlh shouldn't ever be NULL
once we get here.

johannes