diff options
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r-- | net/core/ethtool.c | 41 |
1 files changed, 30 insertions, 11 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 072d1d3796cb..7a85367b3c2f 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -300,23 +300,33 @@ out: | |||
300 | } | 300 | } |
301 | 301 | ||
302 | static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, | 302 | static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, |
303 | void __user *useraddr) | 303 | u32 cmd, void __user *useraddr) |
304 | { | 304 | { |
305 | struct ethtool_rxnfc cmd; | 305 | struct ethtool_rxnfc info; |
306 | size_t info_size = sizeof(info); | ||
306 | 307 | ||
307 | if (!dev->ethtool_ops->set_rxnfc) | 308 | if (!dev->ethtool_ops->set_rxnfc) |
308 | return -EOPNOTSUPP; | 309 | return -EOPNOTSUPP; |
309 | 310 | ||
310 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) | 311 | /* struct ethtool_rxnfc was originally defined for |
312 | * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data | ||
313 | * members. User-space might still be using that | ||
314 | * definition. */ | ||
315 | if (cmd == ETHTOOL_SRXFH) | ||
316 | info_size = (offsetof(struct ethtool_rxnfc, data) + | ||
317 | sizeof(info.data)); | ||
318 | |||
319 | if (copy_from_user(&info, useraddr, info_size)) | ||
311 | return -EFAULT; | 320 | return -EFAULT; |
312 | 321 | ||
313 | return dev->ethtool_ops->set_rxnfc(dev, &cmd); | 322 | return dev->ethtool_ops->set_rxnfc(dev, &info); |
314 | } | 323 | } |
315 | 324 | ||
316 | static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, | 325 | static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, |
317 | void __user *useraddr) | 326 | u32 cmd, void __user *useraddr) |
318 | { | 327 | { |
319 | struct ethtool_rxnfc info; | 328 | struct ethtool_rxnfc info; |
329 | size_t info_size = sizeof(info); | ||
320 | const struct ethtool_ops *ops = dev->ethtool_ops; | 330 | const struct ethtool_ops *ops = dev->ethtool_ops; |
321 | int ret; | 331 | int ret; |
322 | void *rule_buf = NULL; | 332 | void *rule_buf = NULL; |
@@ -324,13 +334,22 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, | |||
324 | if (!ops->get_rxnfc) | 334 | if (!ops->get_rxnfc) |
325 | return -EOPNOTSUPP; | 335 | return -EOPNOTSUPP; |
326 | 336 | ||
327 | if (copy_from_user(&info, useraddr, sizeof(info))) | 337 | /* struct ethtool_rxnfc was originally defined for |
338 | * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data | ||
339 | * members. User-space might still be using that | ||
340 | * definition. */ | ||
341 | if (cmd == ETHTOOL_GRXFH) | ||
342 | info_size = (offsetof(struct ethtool_rxnfc, data) + | ||
343 | sizeof(info.data)); | ||
344 | |||
345 | if (copy_from_user(&info, useraddr, info_size)) | ||
328 | return -EFAULT; | 346 | return -EFAULT; |
329 | 347 | ||
330 | if (info.cmd == ETHTOOL_GRXCLSRLALL) { | 348 | if (info.cmd == ETHTOOL_GRXCLSRLALL) { |
331 | if (info.rule_cnt > 0) { | 349 | if (info.rule_cnt > 0) { |
332 | rule_buf = kmalloc(info.rule_cnt * sizeof(u32), | 350 | if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32)) |
333 | GFP_USER); | 351 | rule_buf = kmalloc(info.rule_cnt * sizeof(u32), |
352 | GFP_USER); | ||
334 | if (!rule_buf) | 353 | if (!rule_buf) |
335 | return -ENOMEM; | 354 | return -ENOMEM; |
336 | } | 355 | } |
@@ -341,7 +360,7 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, | |||
341 | goto err_out; | 360 | goto err_out; |
342 | 361 | ||
343 | ret = -EFAULT; | 362 | ret = -EFAULT; |
344 | if (copy_to_user(useraddr, &info, sizeof(info))) | 363 | if (copy_to_user(useraddr, &info, info_size)) |
345 | goto err_out; | 364 | goto err_out; |
346 | 365 | ||
347 | if (rule_buf) { | 366 | if (rule_buf) { |
@@ -1572,12 +1591,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1572 | case ETHTOOL_GRXCLSRLCNT: | 1591 | case ETHTOOL_GRXCLSRLCNT: |
1573 | case ETHTOOL_GRXCLSRULE: | 1592 | case ETHTOOL_GRXCLSRULE: |
1574 | case ETHTOOL_GRXCLSRLALL: | 1593 | case ETHTOOL_GRXCLSRLALL: |
1575 | rc = ethtool_get_rxnfc(dev, useraddr); | 1594 | rc = ethtool_get_rxnfc(dev, ethcmd, useraddr); |
1576 | break; | 1595 | break; |
1577 | case ETHTOOL_SRXFH: | 1596 | case ETHTOOL_SRXFH: |
1578 | case ETHTOOL_SRXCLSRLDEL: | 1597 | case ETHTOOL_SRXCLSRLDEL: |
1579 | case ETHTOOL_SRXCLSRLINS: | 1598 | case ETHTOOL_SRXCLSRLINS: |
1580 | rc = ethtool_set_rxnfc(dev, useraddr); | 1599 | rc = ethtool_set_rxnfc(dev, ethcmd, useraddr); |
1581 | break; | 1600 | break; |
1582 | case ETHTOOL_GGRO: | 1601 | case ETHTOOL_GGRO: |
1583 | rc = ethtool_get_gro(dev, useraddr); | 1602 | rc = ethtool_get_gro(dev, useraddr); |