Commit e11eb32d authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Steffen Klassert

netlink/compat: Append NLMSG_DONE/extack to frag_list

Modules those use netlink may supply a 2nd skb, (via frag_list)
that contains an alternative data set meant for applications
using 32bit compatibility mode.

In such a case, netlink_recvmsg will use this 2nd skb instead of the
original one.

Without this patch, such compat applications will retrieve
all netlink dump data, but will then get an unexpected EOF.

Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarDmitry Safonov <dima@arista.com>
Reviewed-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 5f3eea6b
...@@ -2186,13 +2186,35 @@ EXPORT_SYMBOL(__nlmsg_put); ...@@ -2186,13 +2186,35 @@ EXPORT_SYMBOL(__nlmsg_put);
* It would be better to create kernel thread. * It would be better to create kernel thread.
*/ */
static int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb,
struct netlink_callback *cb,
struct netlink_ext_ack *extack)
{
struct nlmsghdr *nlh;
nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(nlk->dump_done_errno),
NLM_F_MULTI | cb->answer_flags);
if (WARN_ON(!nlh))
return -ENOBUFS;
nl_dump_check_consistent(cb, nlh);
memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno));
if (extack->_msg && nlk->flags & NETLINK_F_EXT_ACK) {
nlh->nlmsg_flags |= NLM_F_ACK_TLVS;
if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg))
nlmsg_end(skb, nlh);
}
return 0;
}
static int netlink_dump(struct sock *sk) static int netlink_dump(struct sock *sk)
{ {
struct netlink_sock *nlk = nlk_sk(sk); struct netlink_sock *nlk = nlk_sk(sk);
struct netlink_ext_ack extack = {}; struct netlink_ext_ack extack = {};
struct netlink_callback *cb; struct netlink_callback *cb;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
struct module *module; struct module *module;
int err = -ENOBUFS; int err = -ENOBUFS;
int alloc_min_size; int alloc_min_size;
...@@ -2258,22 +2280,19 @@ static int netlink_dump(struct sock *sk) ...@@ -2258,22 +2280,19 @@ static int netlink_dump(struct sock *sk)
return 0; return 0;
} }
nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, if (netlink_dump_done(nlk, skb, cb, &extack))
sizeof(nlk->dump_done_errno),
NLM_F_MULTI | cb->answer_flags);
if (WARN_ON(!nlh))
goto errout_skb; goto errout_skb;
nl_dump_check_consistent(cb, nlh); #ifdef CONFIG_COMPAT_NETLINK_MESSAGES
/* frag_list skb's data is used for compat tasks
memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, * and the regular skb's data for normal (non-compat) tasks.
sizeof(nlk->dump_done_errno)); * See netlink_recvmsg().
*/
if (extack._msg && nlk->flags & NETLINK_F_EXT_ACK) { if (unlikely(skb_shinfo(skb)->frag_list)) {
nlh->nlmsg_flags |= NLM_F_ACK_TLVS; if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack))
if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack._msg)) goto errout_skb;
nlmsg_end(skb, nlh);
} }
#endif
if (sk_filter(sk, skb)) if (sk_filter(sk, skb))
kfree_skb(skb); kfree_skb(skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment