aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-09-07 00:35:19 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-08 17:01:52 -0400
commitee9c5cfad29c8a13199962614b9b16f1c4137ac9 (patch)
tree12c53593c04b2c443029fe1a4b64393b3e6e92b9
parent6523ce1525e88c598c75a1a6b8c4edddfa9defe8 (diff)
niu: Fix kernel buffer overflow for ETHTOOL_GRXCLSRLALL
niu_get_ethtool_tcam_all() assumes that its output buffer is the right size, and warns before returning if it is not. However, the output buffer size is under user control and ETHTOOL_GRXCLSRLALL is an unprivileged ethtool command. Therefore this is at least a local denial-of-service vulnerability. Change it to check before writing each entry and to return an error if the buffer is already full. Compile-tested only. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/niu.c16
1 files changed, 6 insertions, 10 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index b9b950845b0..340cbec4894 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -7272,32 +7272,28 @@ static int niu_get_ethtool_tcam_all(struct niu *np,
7272 struct niu_parent *parent = np->parent; 7272 struct niu_parent *parent = np->parent;
7273 struct niu_tcam_entry *tp; 7273 struct niu_tcam_entry *tp;
7274 int i, idx, cnt; 7274 int i, idx, cnt;
7275 u16 n_entries;
7276 unsigned long flags; 7275 unsigned long flags;
7277 7276 int ret = 0;
7278 7277
7279 /* put the tcam size here */ 7278 /* put the tcam size here */
7280 nfc->data = tcam_get_size(np); 7279 nfc->data = tcam_get_size(np);
7281 7280
7282 niu_lock_parent(np, flags); 7281 niu_lock_parent(np, flags);
7283 n_entries = nfc->rule_cnt;
7284 for (cnt = 0, i = 0; i < nfc->data; i++) { 7282 for (cnt = 0, i = 0; i < nfc->data; i++) {
7285 idx = tcam_get_index(np, i); 7283 idx = tcam_get_index(np, i);
7286 tp = &parent->tcam[idx]; 7284 tp = &parent->tcam[idx];
7287 if (!tp->valid) 7285 if (!tp->valid)
7288 continue; 7286 continue;
7287 if (cnt == nfc->rule_cnt) {
7288 ret = -EMSGSIZE;
7289 break;
7290 }
7289 rule_locs[cnt] = i; 7291 rule_locs[cnt] = i;
7290 cnt++; 7292 cnt++;
7291 } 7293 }
7292 niu_unlock_parent(np, flags); 7294 niu_unlock_parent(np, flags);
7293 7295
7294 if (n_entries != cnt) { 7296 return ret;
7295 /* print warning, this should not happen */
7296 netdev_info(np->dev, "niu%d: In %s(): n_entries[%d] != cnt[%d]!!!\n",
7297 np->parent->index, __func__, n_entries, cnt);
7298 }
7299
7300 return 0;
7301} 7297}
7302 7298
7303static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 7299static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,