| From 02b3cbc135549e2ad979efa8e30bd457afd82c5f Mon Sep 17 00:00:00 2001 |
| From: Li RongQing <lirongqing@baidu.com> |
| Date: Fri, 29 Mar 2019 09:18:02 +0800 |
| Subject: net: ethtool: not call vzalloc for zero sized memory request |
| |
| [ Upstream commit 3d8830266ffc28c16032b859e38a0252e014b631 ] |
| |
| NULL or ZERO_SIZE_PTR will be returned for zero sized memory |
| request, and derefencing them will lead to a segfault |
| |
| so it is unnecessory to call vzalloc for zero sized memory |
| request and not call functions which maybe derefence the |
| NULL allocated memory |
| |
| this also fixes a possible memory leak if phy_ethtool_get_stats |
| returns error, memory should be freed before exit |
| |
| Signed-off-by: Li RongQing <lirongqing@baidu.com> |
| Reviewed-by: Wang Li <wangli39@baidu.com> |
| Reviewed-by: Michal Kubecek <mkubecek@suse.cz> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/core/ethtool.c | 46 ++++++++++++++++++++++++++++++---------------- |
| 1 file changed, 30 insertions(+), 16 deletions(-) |
| |
| diff --git a/net/core/ethtool.c b/net/core/ethtool.c |
| index 158264f7cfaf..3a7f19a61768 100644 |
| --- a/net/core/ethtool.c |
| +++ b/net/core/ethtool.c |
| @@ -1794,11 +1794,16 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) |
| WARN_ON_ONCE(!ret); |
| |
| gstrings.len = ret; |
| - data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN)); |
| - if (gstrings.len && !data) |
| - return -ENOMEM; |
| |
| - __ethtool_get_strings(dev, gstrings.string_set, data); |
| + if (gstrings.len) { |
| + data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN)); |
| + if (!data) |
| + return -ENOMEM; |
| + |
| + __ethtool_get_strings(dev, gstrings.string_set, data); |
| + } else { |
| + data = NULL; |
| + } |
| |
| ret = -EFAULT; |
| if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) |
| @@ -1894,11 +1899,15 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) |
| return -EFAULT; |
| |
| stats.n_stats = n_stats; |
| - data = vzalloc(array_size(n_stats, sizeof(u64))); |
| - if (n_stats && !data) |
| - return -ENOMEM; |
| |
| - ops->get_ethtool_stats(dev, &stats, data); |
| + if (n_stats) { |
| + data = vzalloc(array_size(n_stats, sizeof(u64))); |
| + if (!data) |
| + return -ENOMEM; |
| + ops->get_ethtool_stats(dev, &stats, data); |
| + } else { |
| + data = NULL; |
| + } |
| |
| ret = -EFAULT; |
| if (copy_to_user(useraddr, &stats, sizeof(stats))) |
| @@ -1938,16 +1947,21 @@ static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr) |
| return -EFAULT; |
| |
| stats.n_stats = n_stats; |
| - data = vzalloc(array_size(n_stats, sizeof(u64))); |
| - if (n_stats && !data) |
| - return -ENOMEM; |
| |
| - if (dev->phydev && !ops->get_ethtool_phy_stats) { |
| - ret = phy_ethtool_get_stats(dev->phydev, &stats, data); |
| - if (ret < 0) |
| - return ret; |
| + if (n_stats) { |
| + data = vzalloc(array_size(n_stats, sizeof(u64))); |
| + if (!data) |
| + return -ENOMEM; |
| + |
| + if (dev->phydev && !ops->get_ethtool_phy_stats) { |
| + ret = phy_ethtool_get_stats(dev->phydev, &stats, data); |
| + if (ret < 0) |
| + goto out; |
| + } else { |
| + ops->get_ethtool_phy_stats(dev, &stats, data); |
| + } |
| } else { |
| - ops->get_ethtool_phy_stats(dev, &stats, data); |
| + data = NULL; |
| } |
| |
| ret = -EFAULT; |
| -- |
| 2.19.1 |
| |