| From adb99f7e0d4ff306713c969a8c6d062a9680b2ce Mon Sep 17 00:00:00 2001 |
| From: Wenwen Wang <wang6495@umn.edu> |
| Date: Fri, 5 Oct 2018 08:48:27 -0500 |
| Subject: net: cxgb3_main: fix a missing-check bug |
| |
| [ Upstream commit 2c05d88818ab6571816b93edce4d53703870d7ae ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 17 +++++++++++++++++ |
| 1 file changed, 17 insertions(+) |
| |
| diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c |
| index dc0efbd91c32..ddd1ec8f7bd0 100644 |
| --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c |
| +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c |
| @@ -2150,6 +2150,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) || |
| @@ -2249,6 +2251,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; |
| @@ -2294,6 +2299,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; |
| @@ -2334,6 +2341,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)) |
| @@ -2357,6 +2366,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 */ |
| @@ -2398,6 +2409,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 */ |
| @@ -2431,6 +2444,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) |
| @@ -2483,6 +2498,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) |
| -- |
| 2.17.1 |
| |