Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760378Ab0G3TBo (ORCPT ); Fri, 30 Jul 2010 15:01:44 -0400 Received: from kroah.org ([198.145.64.141]:51732 "EHLO coco.kroah.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758203Ab0G3RTB (ORCPT ); Fri, 30 Jul 2010 13:19:01 -0400 X-Mailbox-Line: From gregkh@clark.site Fri Jul 30 10:15:06 2010 Message-Id: <20100730171506.902841631@clark.site> User-Agent: quilt/0.48-11.2 Date: Fri, 30 Jul 2010 10:15:08 -0700 From: Greg KH To: linux-kernel@vger.kernel.org, stable@kernel.org Cc: stable-review@kernel.org, torvalds@linux-foundation.org, akpm@linux-foundation.org, alan@lxorguk.ukuu.org.uk, Ben Hutchings , "David S. Miller" Subject: [080/165] ethtool: Fix potential user buffer overflow for ETHTOOL_{G, S}RXFH In-Reply-To: <20100730171550.GA1299@kroah.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4245 Lines: 126 2.6.32-stable review patch. If anyone has any objections, please let us know. ------------------ commit bf988435bd5b53529f4408a8efb1f433f6ddfda9 upstream. struct ethtool_rxnfc was originally defined in 2.6.27 for the ETHTOOL_{G,S}RXFH command with only the cmd, flow_type and data fields. It was then extended in 2.6.30 to support various additional commands. These commands should have been defined to use a new structure, but it is too late to change that now. Since user-space may still be using the old structure definition for the ETHTOOL_{G,S}RXFH commands, and since they do not need the additional fields, only copy the originally defined fields to and from user-space. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/ethtool.h | 2 ++ net/core/ethtool.c | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -357,6 +357,8 @@ struct ethtool_rxnfc { __u32 flow_type; /* The rx flow hash value or the rule DB size */ __u64 data; + /* The following fields are not valid and must not be used for + * the ETHTOOL_{G,X}RXFH commands. */ struct ethtool_rx_flow_spec fs; __u32 rule_cnt; __u32 rule_locs[0]; --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -216,22 +216,34 @@ static int ethtool_get_drvinfo(struct ne return 0; } -static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) +static int ethtool_set_rxnfc(struct net_device *dev, + u32 cmd, void __user *useraddr) { - struct ethtool_rxnfc cmd; + struct ethtool_rxnfc info; + size_t info_size = sizeof(info); if (!dev->ethtool_ops->set_rxnfc) return -EOPNOTSUPP; - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + /* struct ethtool_rxnfc was originally defined for + * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data + * members. User-space might still be using that + * definition. */ + if (cmd == ETHTOOL_SRXFH) + info_size = (offsetof(struct ethtool_rxnfc, data) + + sizeof(info.data)); + + if (copy_from_user(&info, useraddr, info_size)) return -EFAULT; - return dev->ethtool_ops->set_rxnfc(dev, &cmd); + return dev->ethtool_ops->set_rxnfc(dev, &info); } -static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr) +static int ethtool_get_rxnfc(struct net_device *dev, + u32 cmd, void __user *useraddr) { struct ethtool_rxnfc info; + size_t info_size = sizeof(info); const struct ethtool_ops *ops = dev->ethtool_ops; int ret; void *rule_buf = NULL; @@ -239,7 +251,15 @@ static int ethtool_get_rxnfc(struct net_ if (!ops->get_rxnfc) return -EOPNOTSUPP; - if (copy_from_user(&info, useraddr, sizeof(info))) + /* struct ethtool_rxnfc was originally defined for + * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data + * members. User-space might still be using that + * definition. */ + if (cmd == ETHTOOL_GRXFH) + info_size = (offsetof(struct ethtool_rxnfc, data) + + sizeof(info.data)); + + if (copy_from_user(&info, useraddr, info_size)) return -EFAULT; if (info.cmd == ETHTOOL_GRXCLSRLALL) { @@ -257,7 +277,7 @@ static int ethtool_get_rxnfc(struct net_ goto err_out; ret = -EFAULT; - if (copy_to_user(useraddr, &info, sizeof(info))) + if (copy_to_user(useraddr, &info, info_size)) goto err_out; if (rule_buf) { @@ -1112,12 +1132,12 @@ int dev_ethtool(struct net *net, struct case ETHTOOL_GRXCLSRLCNT: case ETHTOOL_GRXCLSRULE: case ETHTOOL_GRXCLSRLALL: - rc = ethtool_get_rxnfc(dev, useraddr); + rc = ethtool_get_rxnfc(dev, ethcmd, useraddr); break; case ETHTOOL_SRXFH: case ETHTOOL_SRXCLSRLDEL: case ETHTOOL_SRXCLSRLINS: - rc = ethtool_set_rxnfc(dev, useraddr); + rc = ethtool_set_rxnfc(dev, ethcmd, useraddr); break; case ETHTOOL_GGRO: rc = ethtool_get_gro(dev, useraddr); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/