Skip to content

Commit 95c3376

Browse files
Wenwen Wanggregkh
authored andcommitted
ethtool: fix a privilege escalation bug
[ Upstream commit 58f5bbe ] In dev_ethtool(), the eth command 'ethcmd' is firstly copied from the use-space buffer 'useraddr' and checked to see whether it is ETHTOOL_PERQUEUE. If yes, the sub-command 'sub_cmd' is further copied from the user space. Otherwise, 'sub_cmd' is the same as 'ethcmd'. Next, according to 'sub_cmd', a permission check is enforced through the function ns_capable(). For example, the permission check is required if 'sub_cmd' is ETHTOOL_SCOALESCE, but it is not necessary if 'sub_cmd' is ETHTOOL_GCOALESCE, as suggested in the comment "Allow some commands to be done by anyone". The following execution invokes different handlers according to 'ethcmd'. Specifically, if 'ethcmd' is ETHTOOL_PERQUEUE, ethtool_set_per_queue() is called. In ethtool_set_per_queue(), the kernel object 'per_queue_opt' is copied again from the user-space buffer 'useraddr' and 'per_queue_opt.sub_command' is used to determine which operation should be performed. Given that the buffer 'useraddr' is in the user space, a malicious user can race to change the sub-command between the two copies. In particular, the attacker can supply ETHTOOL_PERQUEUE and ETHTOOL_GCOALESCE to bypass the permission check in dev_ethtool(). Then before ethtool_set_per_queue() is called, the attacker changes ETHTOOL_GCOALESCE to ETHTOOL_SCOALESCE. In this way, the attacker can bypass the permission check and execute ETHTOOL_SCOALESCE. This patch enforces a check in ethtool_set_per_queue() after the second copy from 'useraddr'. If the sub-command is different from the one obtained in the first copy in dev_ethtool(), an error code EINVAL will be returned. Fixes: f38d138 ("net/ethtool: support set coalesce per queue") Signed-off-by: Wenwen Wang <wang6495@umn.edu> Reviewed-by: Michal Kubecek <mkubecek@suse.cz> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 574af67 commit 95c3376

1 file changed

Lines changed: 6 additions & 2 deletions

File tree

net/core/ethtool.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,13 +2410,17 @@ static int ethtool_set_per_queue_coalesce(struct net_device *dev,
24102410
return ret;
24112411
}
24122412

2413-
static int ethtool_set_per_queue(struct net_device *dev, void __user *useraddr)
2413+
static int ethtool_set_per_queue(struct net_device *dev,
2414+
void __user *useraddr, u32 sub_cmd)
24142415
{
24152416
struct ethtool_per_queue_op per_queue_opt;
24162417

24172418
if (copy_from_user(&per_queue_opt, useraddr, sizeof(per_queue_opt)))
24182419
return -EFAULT;
24192420

2421+
if (per_queue_opt.sub_command != sub_cmd)
2422+
return -EINVAL;
2423+
24202424
switch (per_queue_opt.sub_command) {
24212425
case ETHTOOL_GCOALESCE:
24222426
return ethtool_get_per_queue_coalesce(dev, useraddr, &per_queue_opt);
@@ -2787,7 +2791,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
27872791
rc = ethtool_get_phy_stats(dev, useraddr);
27882792
break;
27892793
case ETHTOOL_PERQUEUE:
2790-
rc = ethtool_set_per_queue(dev, useraddr);
2794+
rc = ethtool_set_per_queue(dev, useraddr, sub_cmd);
27912795
break;
27922796
case ETHTOOL_GLINKSETTINGS:
27932797
rc = ethtool_get_link_ksettings(dev, useraddr);

0 commit comments

Comments
 (0)