|
@@ -1817,11 +1817,13 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
|
|
|
ret = __ethtool_get_sset_count(dev, gstrings.string_set);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
+ if (ret > S32_MAX / ETH_GSTRING_LEN)
|
|
|
+ return -ENOMEM;
|
|
|
+ WARN_ON_ONCE(!ret);
|
|
|
|
|
|
gstrings.len = ret;
|
|
|
-
|
|
|
- data = kcalloc(gstrings.len, ETH_GSTRING_LEN, GFP_USER);
|
|
|
- if (!data)
|
|
|
+ data = vzalloc(gstrings.len * ETH_GSTRING_LEN);
|
|
|
+ if (gstrings.len && !data)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
__ethtool_get_strings(dev, gstrings.string_set, data);
|
|
@@ -1830,12 +1832,13 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
|
|
|
if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
|
|
|
goto out;
|
|
|
useraddr += sizeof(gstrings);
|
|
|
- if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
|
|
|
+ if (gstrings.len &&
|
|
|
+ copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
|
|
|
goto out;
|
|
|
ret = 0;
|
|
|
|
|
|
out:
|
|
|
- kfree(data);
|
|
|
+ vfree(data);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1912,14 +1915,15 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
|
|
|
n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
|
|
|
if (n_stats < 0)
|
|
|
return n_stats;
|
|
|
- WARN_ON(n_stats == 0);
|
|
|
-
|
|
|
+ if (n_stats > S32_MAX / sizeof(u64))
|
|
|
+ return -ENOMEM;
|
|
|
+ WARN_ON_ONCE(!n_stats);
|
|
|
if (copy_from_user(&stats, useraddr, sizeof(stats)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
stats.n_stats = n_stats;
|
|
|
- data = kmalloc(n_stats * sizeof(u64), GFP_USER);
|
|
|
- if (!data)
|
|
|
+ data = vzalloc(n_stats * sizeof(u64));
|
|
|
+ if (n_stats && !data)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
ops->get_ethtool_stats(dev, &stats, data);
|
|
@@ -1928,12 +1932,12 @@ 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 (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
|
|
|
+ if (n_stats && copy_to_user(useraddr, data, n_stats * sizeof(u64)))
|
|
|
goto out;
|
|
|
ret = 0;
|
|
|
|
|
|
out:
|
|
|
- kfree(data);
|
|
|
+ vfree(data);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1948,17 +1952,18 @@ static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
n_stats = phy_get_sset_count(phydev);
|
|
|
-
|
|
|
if (n_stats < 0)
|
|
|
return n_stats;
|
|
|
- WARN_ON(n_stats == 0);
|
|
|
+ if (n_stats > S32_MAX / sizeof(u64))
|
|
|
+ return -ENOMEM;
|
|
|
+ WARN_ON_ONCE(!n_stats);
|
|
|
|
|
|
if (copy_from_user(&stats, useraddr, sizeof(stats)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
stats.n_stats = n_stats;
|
|
|
- data = kmalloc_array(n_stats, sizeof(u64), GFP_USER);
|
|
|
- if (!data)
|
|
|
+ data = vzalloc(n_stats * sizeof(u64));
|
|
|
+ if (n_stats && !data)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
mutex_lock(&phydev->lock);
|
|
@@ -1969,12 +1974,12 @@ static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr)
|
|
|
if (copy_to_user(useraddr, &stats, sizeof(stats)))
|
|
|
goto out;
|
|
|
useraddr += sizeof(stats);
|
|
|
- if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
|
|
|
+ if (n_stats && copy_to_user(useraddr, data, n_stats * sizeof(u64)))
|
|
|
goto out;
|
|
|
ret = 0;
|
|
|
|
|
|
out:
|
|
|
- kfree(data);
|
|
|
+ vfree(data);
|
|
|
return ret;
|
|
|
}
|
|
|
|