Honour the user given buffer size for the hex32_arg(), num_arg(),
strn_len(), get_imix_entries() and get_labels() calls (otherwise they will
access memory outside of the user given buffer).

Signed-off-by: Peter Seiderer <ps.rep...@gmx.net>
Reviewed-by: Simon Horman <ho...@kernel.org>
---
Changes v4 -> v5
  - split up patchset into part i/ii (suggested by Simon Horman)
  - add rev-by Simon Horman

Changes v3 -> v4:
  - replace C99 comment (suggested by Paolo Abeni)
  - drop available characters check in strn_len() (suggested by Paolo Abeni)
  - factored out patch 'net: pktgen: align some variable declarations to the
    most common pattern' (suggested by Paolo Abeni)
  - factored out patch 'net: pktgen: remove extra tmp variable (re-use len
    instead)' (suggested by Paolo Abeni)
  - factored out patch 'net: pktgen: remove some superfluous variable
    initializing' (suggested by Paolo Abeni)
  - factored out patch 'net: pktgen: fix mpls maximum labels list parsing'
    (suggested by Paolo Abeni)
  - factored out 'net: pktgen: hex32_arg/num_arg error out in case no
    characters are available' (suggested by Paolo Abeni)
  - factored out 'net: pktgen: num_arg error out in case no valid character
    is parsed' (suggested by Paolo Abeni)

Changes v2 -> v3:
  - no changes

Changes v1 -> v2:
  - additional fix get_imix_entries() and get_labels()
---
 net/core/pktgen.c | 177 ++++++++++++++++++++++++++++++----------------
 1 file changed, 118 insertions(+), 59 deletions(-)

diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 9b63feb8a33e..780435a8e605 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -852,9 +852,10 @@ static ssize_t strn_len(const char __user *user_buffer, 
size_t maxlen)
  * "size1,weight_1 size2,weight_2 ... size_n,weight_n" for example.
  */
 static ssize_t get_imix_entries(const char __user *buffer,
+                               size_t maxlen,
                                struct pktgen_dev *pkt_dev)
 {
-       size_t i = 0;
+       size_t i = 0, max;
        ssize_t len;
        char c;
 
@@ -867,10 +868,13 @@ static ssize_t get_imix_entries(const char __user *buffer,
                if (pkt_dev->n_imix_entries >= MAX_IMIX_ENTRIES)
                        return -E2BIG;
 
-               len = num_arg(&buffer[i], DEC_10_DIGITS, &size);
+               max = min(DEC_10_DIGITS, maxlen - i);
+               len = num_arg(&buffer[i], max, &size);
                if (len < 0)
                        return len;
                i += len;
+               if (i >= maxlen)
+                       return -EINVAL;
                if (get_user(c, &buffer[i]))
                        return -EFAULT;
                /* Check for comma between size_i and weight_i */
@@ -881,7 +885,8 @@ static ssize_t get_imix_entries(const char __user *buffer,
                if (size < 14 + 20 + 8)
                        size = 14 + 20 + 8;
 
-               len = num_arg(&buffer[i], DEC_10_DIGITS, &weight);
+               max = min(DEC_10_DIGITS, maxlen - i);
+               len = num_arg(&buffer[i], max, &weight);
                if (len < 0)
                        return len;
                if (weight <= 0)
@@ -891,20 +896,23 @@ static ssize_t get_imix_entries(const char __user *buffer,
                pkt_dev->imix_entries[pkt_dev->n_imix_entries].weight = weight;
 
                i += len;
+               pkt_dev->n_imix_entries++;
+
+               if (i >= maxlen)
+                       break;
                if (get_user(c, &buffer[i]))
                        return -EFAULT;
-
                i++;
-               pkt_dev->n_imix_entries++;
        } while (c == ' ');
 
        return i;
 }
 
-static ssize_t get_labels(const char __user *buffer, struct pktgen_dev 
*pkt_dev)
+static ssize_t get_labels(const char __user *buffer,
+                         size_t maxlen, struct pktgen_dev *pkt_dev)
 {
        unsigned int n = 0;
-       size_t i = 0;
+       size_t i = 0, max;
        ssize_t len;
        char c;
 
@@ -915,17 +923,20 @@ static ssize_t get_labels(const char __user *buffer, 
struct pktgen_dev *pkt_dev)
                if (n >= MAX_MPLS_LABELS)
                        return -E2BIG;
 
-               len = hex32_arg(&buffer[i], HEX_8_DIGITS, &tmp);
+               max = min(HEX_8_DIGITS, maxlen - i);
+               len = hex32_arg(&buffer[i], max, &tmp);
                if (len <= 0)
                        return len;
                pkt_dev->labels[n] = htonl(tmp);
                if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
                        pkt_dev->flags |= F_MPLS_RND;
                i += len;
+               n++;
+               if (i >= maxlen)
+                       break;
                if (get_user(c, &buffer[i]))
                        return -EFAULT;
                i++;
-               n++;
        } while (c == ',');
 
        pkt_dev->nr_labels = n;
@@ -990,8 +1001,8 @@ static ssize_t pktgen_if_write(struct file *file,
        i = len;
 
        /* Read variable name */
-
-       len = strn_len(&user_buffer[i], sizeof(name) - 1);
+       max = min(sizeof(name) - 1, count - i);
+       len = strn_len(&user_buffer[i], max);
        if (len < 0)
                return len;
 
@@ -1019,7 +1030,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "min_pkt_size")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1036,7 +1048,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "max_pkt_size")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1055,7 +1068,8 @@ static ssize_t pktgen_if_write(struct file *file,
        /* Shortcut for min = max */
 
        if (!strcmp(name, "pkt_size")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1075,7 +1089,8 @@ static ssize_t pktgen_if_write(struct file *file,
                if (pkt_dev->clone_skb > 0)
                        return -EINVAL;
 
-               len = get_imix_entries(&user_buffer[i], pkt_dev);
+               max = count - i;
+               len = get_imix_entries(&user_buffer[i], max, pkt_dev);
                if (len < 0)
                        return len;
 
@@ -1086,7 +1101,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "debug")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1097,7 +1113,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "frags")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1107,7 +1124,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "delay")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1122,7 +1140,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "rate")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1137,7 +1156,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "ratep")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1152,7 +1172,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_src_min")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1165,7 +1186,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_dst_min")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1178,7 +1200,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_src_max")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1191,7 +1214,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_dst_max")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1204,7 +1228,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "clone_skb")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
                /* clone_skb is not supported for netif_receive xmit_mode and
@@ -1225,7 +1250,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "count")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1236,7 +1262,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "src_mac_count")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1250,7 +1277,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst_mac_count")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1264,7 +1292,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "burst")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1283,7 +1312,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "node")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1304,11 +1334,12 @@ static ssize_t pktgen_if_write(struct file *file,
        if (!strcmp(name, "xmit_mode")) {
                char f[32];
 
-               memset(f, 0, 32);
-               len = strn_len(&user_buffer[i], sizeof(f) - 1);
+               max = min(sizeof(f) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
+               memset(f, 0, sizeof(f));
                if (copy_from_user(f, &user_buffer[i], len))
                        return -EFAULT;
                i += len;
@@ -1344,11 +1375,12 @@ static ssize_t pktgen_if_write(struct file *file,
                char f[32];
                char *end;
 
-               memset(f, 0, 32);
-               len = strn_len(&user_buffer[i], sizeof(f) - 1);
+               max = min(sizeof(f) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
+               memset(f, 0, 32);
                if (copy_from_user(f, &user_buffer[i], len))
                        return -EFAULT;
                i += len;
@@ -1393,7 +1425,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
-               len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
+               max = min(sizeof(pkt_dev->dst_min) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1413,7 +1446,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst_max")) {
-               len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
+               max = min(sizeof(pkt_dev->dst_max) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1433,7 +1467,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst6")) {
-               len = strn_len(&user_buffer[i], sizeof(buf) - 1);
+               max = min(sizeof(buf) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1456,7 +1491,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst6_min")) {
-               len = strn_len(&user_buffer[i], sizeof(buf) - 1);
+               max = min(sizeof(buf) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1478,7 +1514,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst6_max")) {
-               len = strn_len(&user_buffer[i], sizeof(buf) - 1);
+               max = min(sizeof(buf) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1499,7 +1536,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "src6")) {
-               len = strn_len(&user_buffer[i], sizeof(buf) - 1);
+               max = min(sizeof(buf) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1522,7 +1560,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "src_min")) {
-               len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
+               max = min(sizeof(pkt_dev->src_min) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1542,7 +1581,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "src_max")) {
-               len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
+               max = min(sizeof(pkt_dev->src_max) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1562,7 +1602,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst_mac")) {
-               len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+               max = min(sizeof(valstr) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1579,7 +1620,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "src_mac")) {
-               len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+               max = min(sizeof(valstr) - 1, count - i);
+               len = strn_len(&user_buffer[i], max);
                if (len < 0)
                        return len;
 
@@ -1603,7 +1645,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "flows")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1617,7 +1660,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 #ifdef CONFIG_XFRM
        if (!strcmp(name, "spi")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1628,7 +1672,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 #endif
        if (!strcmp(name, "flowlen")) {
-               len = num_arg(&user_buffer[i], DEC_10_DIGITS, &value);
+               max = min(DEC_10_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1639,7 +1684,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "queue_map_min")) {
-               len = num_arg(&user_buffer[i], DEC_5_DIGITS, &value);
+               max = min(DEC_5_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1650,7 +1696,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "queue_map_max")) {
-               len = num_arg(&user_buffer[i], DEC_5_DIGITS, &value);
+               max = min(DEC_5_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1663,7 +1710,8 @@ static ssize_t pktgen_if_write(struct file *file,
        if (!strcmp(name, "mpls")) {
                unsigned int n, cnt;
 
-               len = get_labels(&user_buffer[i], pkt_dev);
+               max = count - i;
+               len = get_labels(&user_buffer[i], max, pkt_dev);
                if (len < 0)
                        return len;
                i += len;
@@ -1684,7 +1732,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "vlan_id")) {
-               len = num_arg(&user_buffer[i], DEC_4_DIGITS, &value);
+               max = min(DEC_4_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1711,7 +1760,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "vlan_p")) {
-               len = num_arg(&user_buffer[i], DEC_1_DIGITS, &value);
+               max = min(DEC_1_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1726,7 +1776,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "vlan_cfi")) {
-               len = num_arg(&user_buffer[i], DEC_1_DIGITS, &value);
+               max = min(DEC_1_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1741,7 +1792,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "svlan_id")) {
-               len = num_arg(&user_buffer[i], DEC_4_DIGITS, &value);
+               max = min(DEC_4_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1768,7 +1820,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "svlan_p")) {
-               len = num_arg(&user_buffer[i], DEC_1_DIGITS, &value);
+               max = min(DEC_1_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1783,7 +1836,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "svlan_cfi")) {
-               len = num_arg(&user_buffer[i], DEC_1_DIGITS, &value);
+               max = min(DEC_1_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1799,7 +1853,9 @@ static ssize_t pktgen_if_write(struct file *file,
 
        if (!strcmp(name, "tos")) {
                __u32 tmp_value;
-               len = hex32_arg(&user_buffer[i], HEX_2_DIGITS, &tmp_value);
+
+               max = min(HEX_2_DIGITS, count - i);
+               len = hex32_arg(&user_buffer[i], max, &tmp_value);
                if (len < 0)
                        return len;
 
@@ -1815,7 +1871,9 @@ static ssize_t pktgen_if_write(struct file *file,
 
        if (!strcmp(name, "traffic_class")) {
                __u32 tmp_value;
-               len = hex32_arg(&user_buffer[i], HEX_2_DIGITS, &tmp_value);
+
+               max = min(HEX_2_DIGITS, count - i);
+               len = hex32_arg(&user_buffer[i], max, &tmp_value);
                if (len < 0)
                        return len;
 
@@ -1830,7 +1888,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "skb_priority")) {
-               len = num_arg(&user_buffer[i], DEC_9_DIGITS, &value);
+               max = min(DEC_9_DIGITS, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
-- 
2.48.1

Reply via email to