From: Alexander H Duyck <alexander.duyck@gmail.com>
To: Ding Hui <dinghui@sangfor.com.cn>,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
pengdonglin@sangfor.com.cn, huangcun@sangfor.com.cn
Subject: Re: [PATCH net-next] net: ethtool: Fix out-of-bounds copy to user
Date: Thu, 01 Jun 2023 08:04:01 -0700 [thread overview]
Message-ID: <135a45b2c388fbaf9db4620cb01b95230709b9ac.camel@gmail.com> (raw)
In-Reply-To: <20230601112839.13799-1-dinghui@sangfor.com.cn>
On Thu, 2023-06-01 at 19:28 +0800, Ding Hui wrote:
> When we get statistics by ethtool during changing the number of NIC
> channels greater, the utility may crash due to memory corruption.
>
> The NIC drivers callback get_sset_count() could return a calculated
> length depends on current number of channels (e.g. i40e, igb).
>
The drivers shouldn't be changing that value. If the drivers are doing
this they should be fixed to provide a fixed length in terms of their
strings.
> The ethtool allocates a user buffer with the first ioctl returned
> length and invokes the second ioctl to get data. The kernel copies
> data to the user buffer but without checking its length. If the length
> returned by the second get_sset_count() is greater than the length
> allocated by the user, it will lead to an out-of-bounds copy.
>
> Fix it by restricting the copy length not exceed the buffer length
> specified by userspace.
>
> Signed-off-by: Ding Hui <dinghui@sangfor.com.cn>
Changing the copy size would not fix this. The problem is the driver
will be overwriting with the size that it thinks it should be using.
Reducing the value that is provided for the memory allocations will
cause the driver to corrupt memory.
> ---
> net/ethtool/ioctl.c | 16 +++++++++-------
> 1 file changed, 9 insertions(+), 7 deletions(-)
>
> diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
> index 6bb778e10461..82a975a9c895 100644
> --- a/net/ethtool/ioctl.c
> +++ b/net/ethtool/ioctl.c
> @@ -1902,7 +1902,7 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
> if (copy_from_user(&test, useraddr, sizeof(test)))
> return -EFAULT;
>
> - test.len = test_len;
> + test.len = min_t(u32, test.len, test_len);
> data = kcalloc(test_len, sizeof(u64), GFP_USER);
> if (!data)
> return -ENOMEM;
This is the wrong spot to be doing this. You need to use test_len for
your allocation as that is what the driver will be writing to. You
should look at adjusting after the allocation call and before you do
the copy
> @@ -1915,7 +1915,8 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
> if (copy_to_user(useraddr, &test, sizeof(test)))
> goto out;
> useraddr += sizeof(test);
> - if (copy_to_user(useraddr, data, array_size(test.len, sizeof(u64))))
> + if (test.len &&
> + copy_to_user(useraddr, data, array_size(test.len, sizeof(u64))))
> goto out;
> ret = 0;
>
I don't believe this is adding any value. I wouldn't bother with
checking for lengths of 0.
> @@ -1940,10 +1941,10 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
> return -ENOMEM;
> WARN_ON_ONCE(!ret);
>
> - gstrings.len = ret;
> + gstrings.len = min_t(u32, gstrings.len, ret);
>
> if (gstrings.len) {
> - data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN));
> + data = vzalloc(array_size(ret, ETH_GSTRING_LEN));
> if (!data)
> return -ENOMEM;
>
Same here. We should be using the returned value for the allocations
and tests, and then doing the min adjustment after the allocationis
completed.
> @@ -2055,9 +2056,9 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
> if (copy_from_user(&stats, useraddr, sizeof(stats)))
> return -EFAULT;
>
> - stats.n_stats = n_stats;
> + stats.n_stats = min_t(u32, stats.n_stats, n_stats);
>
> - if (n_stats) {
> + if (stats.n_stats) {
> data = vzalloc(array_size(n_stats, sizeof(u64)));
> if (!data)
> return -ENOMEM;
Same here. We should be using n_stats, not stats.n_stats and adjust
before you do the final copy.
> @@ -2070,7 +2071,8 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
> if (copy_to_user(useraddr, &stats, sizeof(stats)))
> goto out;
> useraddr += sizeof(stats);
> - if (n_stats && copy_to_user(useraddr, data, array_size(n_stats, sizeof(u64))))
> + if (stats.n_stats &&
> + copy_to_user(useraddr, data, array_size(stats.n_stats, sizeof(u64))))
> goto out;
> ret = 0;
>
Again. I am not sure what value is being added. If n_stats is 0 then I
am pretty sure this will do nothing anyway.
next prev parent reply other threads:[~2023-06-01 15:04 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-01 11:28 [PATCH net-next] net: ethtool: Fix out-of-bounds copy to user Ding Hui
2023-06-01 15:04 ` Alexander H Duyck [this message]
2023-06-02 1:46 ` Ding Hui
2023-06-02 12:26 ` Andrew Lunn
2023-06-02 15:01 ` Ding Hui
2023-06-02 15:37 ` Andrew Lunn
2023-06-02 16:01 ` Alexander Duyck
2023-06-02 16:37 ` Andrew Lunn
2023-06-02 18:02 ` Alexander Duyck
2023-06-03 1:51 ` Ding Hui
2023-06-03 5:55 ` Jakub Kicinski
2023-06-03 7:11 ` Ding Hui
2023-06-04 17:47 ` Jakub Kicinski
2023-06-05 3:39 ` Ding Hui
2023-06-05 18:39 ` Jakub Kicinski
2023-06-08 9:06 ` Ding Hui
2023-06-08 14:17 ` Alexander Duyck
2023-06-09 15:25 ` Ding Hui
2023-06-09 17:13 ` Jakub Kicinski
2023-06-09 17:59 ` Alexander Duyck
2023-06-10 3:47 ` Ding Hui
2023-06-10 4:01 ` Ding Hui
2023-06-02 15:30 ` Alexander Duyck
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=135a45b2c388fbaf9db4620cb01b95230709b9ac.camel@gmail.com \
--to=alexander.duyck@gmail.com \
--cc=davem@davemloft.net \
--cc=dinghui@sangfor.com.cn \
--cc=edumazet@google.com \
--cc=huangcun@sangfor.com.cn \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pengdonglin@sangfor.com.cn \
/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).