net: cxgb3_main: fix a missing-check bug
In cxgb_extension_ioctl(), the command of the ioctl is firstly copied from the user-space buffer 'useraddr' to 'cmd' and checked through the switch statement. If the command is not as expected, an error code EOPNOTSUPP is returned. In the following execution, i.e., the cases of the switch statement, the whole buffer of 'useraddr' is copied again to a specific data structure, according to what kind of command is requested. However, after the second copy, there is no re-check on the newly-copied command. Given that the buffer 'useraddr' is in the user space, a malicious user can race to change the command between the two copies. By doing so, the attacker can supply malicious data to the kernel and cause undefined behavior. This patch adds a re-check in each case of the switch statement if there is a second copy in that case, to re-check whether the command obtained in the second copy is the same as the one in the first copy. If not, an error code EINVAL is returned. Signed-off-by: Wenwen Wang <wang6495@umn.edu> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b8d5b7cec4
commit
2c05d88818
@ -2159,6 +2159,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EPERM;
|
||||
if (copy_from_user(&t, useraddr, sizeof(t)))
|
||||
return -EFAULT;
|
||||
if (t.cmd != CHELSIO_SET_QSET_PARAMS)
|
||||
return -EINVAL;
|
||||
if (t.qset_idx >= SGE_QSETS)
|
||||
return -EINVAL;
|
||||
if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
|
||||
@ -2258,6 +2260,9 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
if (copy_from_user(&t, useraddr, sizeof(t)))
|
||||
return -EFAULT;
|
||||
|
||||
if (t.cmd != CHELSIO_GET_QSET_PARAMS)
|
||||
return -EINVAL;
|
||||
|
||||
/* Display qsets for all ports when offload enabled */
|
||||
if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
|
||||
q1 = 0;
|
||||
@ -2303,6 +2308,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&edata, useraddr, sizeof(edata)))
|
||||
return -EFAULT;
|
||||
if (edata.cmd != CHELSIO_SET_QSET_NUM)
|
||||
return -EINVAL;
|
||||
if (edata.val < 1 ||
|
||||
(edata.val > 1 && !(adapter->flags & USING_MSIX)))
|
||||
return -EINVAL;
|
||||
@ -2343,6 +2350,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EPERM;
|
||||
if (copy_from_user(&t, useraddr, sizeof(t)))
|
||||
return -EFAULT;
|
||||
if (t.cmd != CHELSIO_LOAD_FW)
|
||||
return -EINVAL;
|
||||
/* Check t.len sanity ? */
|
||||
fw_data = memdup_user(useraddr + sizeof(t), t.len);
|
||||
if (IS_ERR(fw_data))
|
||||
@ -2366,6 +2375,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&m, useraddr, sizeof(m)))
|
||||
return -EFAULT;
|
||||
if (m.cmd != CHELSIO_SETMTUTAB)
|
||||
return -EINVAL;
|
||||
if (m.nmtus != NMTUS)
|
||||
return -EINVAL;
|
||||
if (m.mtus[0] < 81) /* accommodate SACK */
|
||||
@ -2407,6 +2418,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&m, useraddr, sizeof(m)))
|
||||
return -EFAULT;
|
||||
if (m.cmd != CHELSIO_SET_PM)
|
||||
return -EINVAL;
|
||||
if (!is_power_of_2(m.rx_pg_sz) ||
|
||||
!is_power_of_2(m.tx_pg_sz))
|
||||
return -EINVAL; /* not power of 2 */
|
||||
@ -2440,6 +2453,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EIO; /* need the memory controllers */
|
||||
if (copy_from_user(&t, useraddr, sizeof(t)))
|
||||
return -EFAULT;
|
||||
if (t.cmd != CHELSIO_GET_MEM)
|
||||
return -EINVAL;
|
||||
if ((t.addr & 7) || (t.len & 7))
|
||||
return -EINVAL;
|
||||
if (t.mem_id == MEM_CM)
|
||||
@ -2492,6 +2507,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
||||
return -EAGAIN;
|
||||
if (copy_from_user(&t, useraddr, sizeof(t)))
|
||||
return -EFAULT;
|
||||
if (t.cmd != CHELSIO_SET_TRACE_FILTER)
|
||||
return -EINVAL;
|
||||
|
||||
tp = (const struct trace_params *)&t.sip;
|
||||
if (t.config_tx)
|
||||
|
Loading…
Reference in New Issue
Block a user