summaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorDmitry Safonov <dima@arista.com>2020-09-21 15:36:54 +0100
committerSteffen Klassert <steffen.klassert@secunet.com>2020-09-24 08:53:03 +0200
commite11eb32de3a7854d6b366dee17dd36c9ab0c39de (patch)
treeaa53029820cde8be17b80907d88432acdd19f438 /net/netlink
parent5f3eea6b7e8f58cf5c8a9d4b9679dc19e9e67ba3 (diff)
downloadlinux-e11eb32de3a7854d6b366dee17dd36c9ab0c39de.tar.gz
linux-e11eb32de3a7854d6b366dee17dd36c9ab0c39de.tar.bz2
linux-e11eb32de3a7854d6b366dee17dd36c9ab0c39de.zip
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: Florian Westphal <fw@strlen.de> Signed-off-by: Dmitry Safonov <dima@arista.com> Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c47
1 files changed, 33 insertions, 14 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index f9efd2c1cb50..56ade862662e 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2186,13 +2186,35 @@ EXPORT_SYMBOL(__nlmsg_put);
* 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)
{
struct netlink_sock *nlk = nlk_sk(sk);
struct netlink_ext_ack extack = {};
struct netlink_callback *cb;
struct sk_buff *skb = NULL;
- struct nlmsghdr *nlh;
struct module *module;
int err = -ENOBUFS;
int alloc_min_size;
@@ -2258,22 +2280,19 @@ static int netlink_dump(struct sock *sk)
return 0;
}
- nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE,
- sizeof(nlk->dump_done_errno),
- NLM_F_MULTI | cb->answer_flags);
- if (WARN_ON(!nlh))
+ if (netlink_dump_done(nlk, skb, cb, &extack))
goto errout_skb;
- 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);
+#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
+ /* frag_list skb's data is used for compat tasks
+ * and the regular skb's data for normal (non-compat) tasks.
+ * See netlink_recvmsg().
+ */
+ if (unlikely(skb_shinfo(skb)->frag_list)) {
+ if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack))
+ goto errout_skb;
}
+#endif
if (sk_filter(sk, skb))
kfree_skb(skb);