summaryrefslogtreecommitdiff
path: root/net/core/net-sysfs.c
diff options
context:
space:
mode:
authorAntoine Tenart <atenart@kernel.org>2021-03-18 19:37:43 +0100
committerDavid S. Miller <davem@davemloft.net>2021-03-18 14:56:22 -0700
commit255c04a87f4381849fce9ed81e5efabf78a71a30 (patch)
tree702d869692566f7ba3bfde4907d51f0f78921e5e /net/core/net-sysfs.c
parent73f5e52b15e3aa4ef641264228cd9069b1948149 (diff)
net: embed num_tc in the xps maps
The xps cpus/rxqs map is accessed using dev->num_tc, which is used when allocating the map. But later updates of dev->num_tc can lead to having a mismatch between the maps and how they're accessed. In such cases the map values do not make any sense and out of bound accesses can occur (that can be easily seen using KASAN). This patch aims at fixing this by embedding num_tc into the maps, using the value at the time the map is created. This brings two improvements: - The maps can be accessed using the embedded num_tc, so we know for sure we won't have out of bound accesses. - Checks can be made before accessing the maps so we know the values retrieved will make sense. We also update __netif_set_xps_queue to conditionally copy old maps from dev_maps in the new one only if the number of traffic classes from both maps match. Signed-off-by: Antoine Tenart <atenart@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/net-sysfs.c')
-rw-r--r--net/core/net-sysfs.c45
1 files changed, 17 insertions, 28 deletions
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 5f76183ad5bc..1364d0f39cb0 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -1364,9 +1364,9 @@ static const struct attribute_group dql_group = {
static ssize_t xps_cpus_show(struct netdev_queue *queue,
char *buf)
{
- int j, len, ret, num_tc = 1, tc = 0;
struct net_device *dev = queue->dev;
struct xps_dev_maps *dev_maps;
+ int j, len, ret, tc = 0;
unsigned long *mask;
unsigned int index;
@@ -1378,22 +1378,13 @@ static ssize_t xps_cpus_show(struct netdev_queue *queue,
if (!rtnl_trylock())
return restart_syscall();
- if (dev->num_tc) {
- /* Do not allow XPS on subordinate device directly */
- num_tc = dev->num_tc;
- if (num_tc < 0) {
- ret = -EINVAL;
- goto err_rtnl_unlock;
- }
-
- /* If queue belongs to subordinate dev use its map */
- dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev;
+ /* If queue belongs to subordinate dev use its map */
+ dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev;
- tc = netdev_txq_to_tc(dev, index);
- if (tc < 0) {
- ret = -EINVAL;
- goto err_rtnl_unlock;
- }
+ tc = netdev_txq_to_tc(dev, index);
+ if (tc < 0) {
+ ret = -EINVAL;
+ goto err_rtnl_unlock;
}
mask = bitmap_zalloc(nr_cpu_ids, GFP_KERNEL);
@@ -1404,12 +1395,12 @@ static ssize_t xps_cpus_show(struct netdev_queue *queue,
rcu_read_lock();
dev_maps = rcu_dereference(dev->xps_cpus_map);
- if (!dev_maps)
+ if (!dev_maps || tc >= dev_maps->num_tc)
goto out_no_maps;
for (j = -1; j = netif_attrmask_next(j, NULL, nr_cpu_ids),
j < nr_cpu_ids;) {
- int i, tci = j * num_tc + tc;
+ int i, tci = j * dev_maps->num_tc + tc;
struct xps_map *map;
map = rcu_dereference(dev_maps->attr_map[tci]);
@@ -1480,9 +1471,9 @@ static struct netdev_queue_attribute xps_cpus_attribute __ro_after_init
static ssize_t xps_rxqs_show(struct netdev_queue *queue, char *buf)
{
- int j, len, ret, num_tc = 1, tc = 0;
struct net_device *dev = queue->dev;
struct xps_dev_maps *dev_maps;
+ int j, len, ret, tc = 0;
unsigned long *mask;
unsigned int index;
@@ -1491,14 +1482,12 @@ static ssize_t xps_rxqs_show(struct netdev_queue *queue, char *buf)
if (!rtnl_trylock())
return restart_syscall();
- if (dev->num_tc) {
- num_tc = dev->num_tc;
- tc = netdev_txq_to_tc(dev, index);
- if (tc < 0) {
- ret = -EINVAL;
- goto err_rtnl_unlock;
- }
+ tc = netdev_txq_to_tc(dev, index);
+ if (tc < 0) {
+ ret = -EINVAL;
+ goto err_rtnl_unlock;
}
+
mask = bitmap_zalloc(dev->num_rx_queues, GFP_KERNEL);
if (!mask) {
ret = -ENOMEM;
@@ -1507,12 +1496,12 @@ static ssize_t xps_rxqs_show(struct netdev_queue *queue, char *buf)
rcu_read_lock();
dev_maps = rcu_dereference(dev->xps_rxqs_map);
- if (!dev_maps)
+ if (!dev_maps || tc >= dev_maps->num_tc)
goto out_no_maps;
for (j = -1; j = netif_attrmask_next(j, NULL, dev->num_rx_queues),
j < dev->num_rx_queues;) {
- int i, tci = j * num_tc + tc;
+ int i, tci = j * dev_maps->num_tc + tc;
struct xps_map *map;
map = rcu_dereference(dev_maps->attr_map[tci]);