From: Ido Schimmel <idosch@idosch.org>
To: Cong Wang <xiyou.wangcong@gmail.com>
Cc: netdev@vger.kernel.org,
syzbot+21f04f481f449c8db840@syzkaller.appspotmail.com,
"Jason A. Donenfeld" <Jason@zx2c4.com>,
Florian Westphal <fw@strlen.de>,
Pablo Neira Ayuso <pablo@netfilter.org>,
Jiri Pirko <jiri@mellanox.com>,
YueHaibing <yuehaibing@huawei.com>,
Shaochun Chen <cscnull@gmail.com>
Subject: Re: [Patch net v2] genetlink: fix memory leaks in genl_family_rcv_msg_dumpit()
Date: Wed, 10 Jun 2020 17:27:00 +0300 [thread overview]
Message-ID: <20200610142700.GA2174714@splinter> (raw)
In-Reply-To: <20200603044910.27259-1-xiyou.wangcong@gmail.com>
On Tue, Jun 02, 2020 at 09:49:10PM -0700, Cong Wang wrote:
> diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
> index 9f357aa22b94..bcbba0bef1c2 100644
> --- a/net/netlink/genetlink.c
> +++ b/net/netlink/genetlink.c
> @@ -513,15 +513,58 @@ static void genl_family_rcv_msg_attrs_free(const struct genl_family *family,
> kfree(attrbuf);
> }
>
> -static int genl_lock_start(struct netlink_callback *cb)
> +struct genl_start_context {
> + const struct genl_family *family;
> + struct nlmsghdr *nlh;
> + struct netlink_ext_ack *extack;
> + const struct genl_ops *ops;
> + int hdrlen;
> +};
> +
> +static int genl_start(struct netlink_callback *cb)
> {
> - const struct genl_ops *ops = genl_dumpit_info(cb)->ops;
> + struct genl_start_context *ctx = cb->data;
> + const struct genl_ops *ops = ctx->ops;
> + struct genl_dumpit_info *info;
> + struct nlattr **attrs = NULL;
> int rc = 0;
>
> + if (ops->validate & GENL_DONT_VALIDATE_DUMP)
> + goto no_attrs;
> +
> + if (ctx->nlh->nlmsg_len < nlmsg_msg_size(ctx->hdrlen))
> + return -EINVAL;
> +
> + attrs = genl_family_rcv_msg_attrs_parse(ctx->family, ctx->nlh, ctx->extack,
> + ops, ctx->hdrlen,
> + GENL_DONT_VALIDATE_DUMP_STRICT,
> + true);
> + if (IS_ERR(attrs))
> + return PTR_ERR(attrs);
> +
> +no_attrs:
> + info = genl_dumpit_info_alloc();
> + if (!info) {
> + kfree(attrs);
> + return -ENOMEM;
> + }
> + info->family = ctx->family;
> + info->ops = ops;
> + info->attrs = attrs;
> +
> + cb->data = info;
> if (ops->start) {
> - genl_lock();
> + if (!ctx->family->parallel_ops)
> + genl_lock();
> rc = ops->start(cb);
> - genl_unlock();
> + if (!ctx->family->parallel_ops)
> + genl_unlock();
> + }
> +
> + if (rc) {
> + kfree(attrs);
> + genl_dumpit_info_free(info);
> + cb->data = NULL;
> }
> return rc;
> }
> @@ -548,7 +591,7 @@ static int genl_lock_done(struct netlink_callback *cb)
> rc = ops->done(cb);
> genl_unlock();
> }
> - genl_family_rcv_msg_attrs_free(info->family, info->attrs, true);
> + genl_family_rcv_msg_attrs_free(info->family, info->attrs, false);
Cong,
This seems to result in a memory leak because 'info->attrs' is never
freed in the non-parallel case.
Both the parallel and non-parallel code paths call genl_start() which
allocates the array, but the latter calls genl_lock_done() as its done()
callback which never frees it.
Can be reproduced as follows:
echo "10 1" > /sys/bus/netdevsim/new_device
devlink trap &> /dev/null
echo scan > /sys/kernel/debug/kmemleak
cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff88810f1ed000 (size 2048):
comm "devlink", pid 201, jiffies 4295606431 (age 35.858s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<00000000a7cb7530>] __kmalloc+0x1d6/0x3d0
[<000000001cb013e1>] genl_family_rcv_msg_attrs_parse+0x1f3/0x320
[<00000000b201bc93>] genl_start+0x1ab/0x5e0
[<00000000786e531e>] __netlink_dump_start+0x5b5/0x940
[<00000000a2332fcb>] genl_family_rcv_msg_dumpit+0x32e/0x3a0
[<00000000112052dd>] genl_rcv_msg+0x6d7/0xb40
[<000000005826e358>] netlink_rcv_skb+0x175/0x490
[<000000002c5f41ae>] genl_rcv+0x2d/0x40
[<00000000f0301e6d>] netlink_unicast+0x5d0/0x7f0
[<00000000a76a3934>] netlink_sendmsg+0x981/0xe90
[<000000001c478a6f>] __sys_sendto+0x2cd/0x450
[<0000000079d420b0>] __x64_sys_sendto+0xe6/0x1a0
[<000000004e535e4b>] do_syscall_64+0xc1/0x600
[<000000006e5dd3c4>] entry_SYSCALL_64_after_hwframe+0x49/0xb3
> genl_dumpit_info_free(info);
> return rc;
> }
> @@ -573,43 +616,23 @@ static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
> const struct genl_ops *ops,
> int hdrlen, struct net *net)
> {
> - struct genl_dumpit_info *info;
> - struct nlattr **attrs = NULL;
> + struct genl_start_context ctx;
> int err;
>
> if (!ops->dumpit)
> return -EOPNOTSUPP;
>
> - if (ops->validate & GENL_DONT_VALIDATE_DUMP)
> - goto no_attrs;
> -
> - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
> - return -EINVAL;
> -
> - attrs = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
> - ops, hdrlen,
> - GENL_DONT_VALIDATE_DUMP_STRICT,
> - true);
> - if (IS_ERR(attrs))
> - return PTR_ERR(attrs);
> -
> -no_attrs:
> - /* Allocate dumpit info. It is going to be freed by done() callback. */
> - info = genl_dumpit_info_alloc();
> - if (!info) {
> - genl_family_rcv_msg_attrs_free(family, attrs, true);
> - return -ENOMEM;
> - }
> -
> - info->family = family;
> - info->ops = ops;
> - info->attrs = attrs;
> + ctx.family = family;
> + ctx.nlh = nlh;
> + ctx.extack = extack;
> + ctx.ops = ops;
> + ctx.hdrlen = hdrlen;
>
> if (!family->parallel_ops) {
> struct netlink_dump_control c = {
> .module = family->module,
> - .data = info,
> - .start = genl_lock_start,
> + .data = &ctx,
> + .start = genl_start,
> .dump = genl_lock_dumpit,
> .done = genl_lock_done,
> };
> @@ -617,12 +640,11 @@ static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
> genl_unlock();
> err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
> genl_lock();
> -
> } else {
> struct netlink_dump_control c = {
> .module = family->module,
> - .data = info,
> - .start = ops->start,
> + .data = &ctx,
> + .start = genl_start,
> .dump = ops->dumpit,
> .done = genl_parallel_done,
> };
> --
> 2.26.2
>
next prev parent reply other threads:[~2020-06-10 14:27 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-03 4:49 [Patch net v2] genetlink: fix memory leaks in genl_family_rcv_msg_dumpit() Cong Wang
2020-06-04 22:36 ` David Miller
2020-06-10 14:27 ` Ido Schimmel [this message]
2020-06-11 4:14 ` Cong Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200610142700.GA2174714@splinter \
--to=idosch@idosch.org \
--cc=Jason@zx2c4.com \
--cc=cscnull@gmail.com \
--cc=fw@strlen.de \
--cc=jiri@mellanox.com \
--cc=netdev@vger.kernel.org \
--cc=pablo@netfilter.org \
--cc=syzbot+21f04f481f449c8db840@syzkaller.appspotmail.com \
--cc=xiyou.wangcong@gmail.com \
--cc=yuehaibing@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).