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).

In hex32_arg(), num_arg(), strn_len() error out in case no characters are
available (maxlen = 0), in num_arg() additional error out in case no valid
character is parsed.

In get_labels() additional enable parsing labels up to MAX_IMIX_ENTRIES
instead of (MAX_IMIX_ENTRIES - 1).

Additional remove some superfluous variable initializing and align some
variable declarations to the most common pattern.

Signed-off-by: Peter Seiderer <ps.rep...@gmx.net>
---
Changes v1 -> v2:
  - additional fix get_imix_entries() and get_labels()
---
 net/core/pktgen.c | 213 ++++++++++++++++++++++++++++++----------------
 1 file changed, 140 insertions(+), 73 deletions(-)

diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 9fe2a2db0d34..1fc037641610 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -750,6 +750,9 @@ static int hex32_arg(const char __user *user_buffer, 
unsigned long maxlen,
        int i = 0;
        *num = 0;
 
+       if (!maxlen)
+               return -EINVAL;
+
        for (; i < maxlen; i++) {
                int value;
                char c;
@@ -797,6 +800,9 @@ static long num_arg(const char __user *user_buffer, 
unsigned long maxlen,
        int i;
        *num = 0;
 
+       if (!maxlen)
+               return -EINVAL;
+
        for (i = 0; i < maxlen; i++) {
                char c;
                if (get_user(c, &user_buffer[i]))
@@ -804,6 +810,9 @@ static long num_arg(const char __user *user_buffer, 
unsigned long maxlen,
                if ((c >= '0') && (c <= '9')) {
                        *num *= 10;
                        *num += c - '0';
+               } else if (i == 0) {
+                       // no valid character parsed, error out
+                       return -EINVAL;
                } else
                        break;
        }
@@ -814,6 +823,9 @@ static int strn_len(const char __user * user_buffer, 
unsigned int maxlen)
 {
        int i;
 
+       if (!maxlen)
+               return -EINVAL;
+
        for (i = 0; i < maxlen; i++) {
                char c;
                if (get_user(c, &user_buffer[i]))
@@ -840,11 +852,10 @@ static int strn_len(const char __user * user_buffer, 
unsigned int maxlen)
  * "size1,weight_1 size2,weight_2 ... size_n,weight_n" for example.
  */
 static ssize_t get_imix_entries(const char __user *buffer,
+                               unsigned int maxlen,
                                struct pktgen_dev *pkt_dev)
 {
-       const int max_digits = 10;
-       int i = 0;
-       long len;
+       int i = 0, max, len;
        char c;
 
        pkt_dev->n_imix_entries = 0;
@@ -856,10 +867,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], max_digits, &size);
+               max = min(10, 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 */
@@ -870,7 +884,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], max_digits, &weight);
+               max = min(10, maxlen - i);
+               len = num_arg(&buffer[i], max, &weight);
                if (len < 0)
                        return len;
                if (weight <= 0)
@@ -880,39 +895,45 @@ 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, int maxlen, struct 
pktgen_dev *pkt_dev)
 {
        unsigned int n = 0;
        char c;
-       ssize_t i = 0;
-       int len;
+       int i = 0, max, len;
 
        pkt_dev->nr_labels = 0;
        do {
                __u32 tmp;
-               len = hex32_arg(&buffer[i], 8, &tmp);
-               if (len <= 0)
+
+               if (n >= MAX_MPLS_LABELS)
+                       return -E2BIG;
+
+               max = min(8, 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++;
-               if (n >= MAX_MPLS_LABELS)
-                       return -E2BIG;
        } while (c == ',');
 
        pkt_dev->nr_labels = n;
@@ -958,7 +979,6 @@ static ssize_t pktgen_if_write(struct file *file,
        char name[16], valstr[32];
        unsigned long value = 0;
        char *pg_result = NULL;
-       int tmp = 0;
        char buf[128];
 
        pg_result = &(pkt_dev->result[0]);
@@ -968,17 +988,16 @@ static ssize_t pktgen_if_write(struct file *file,
                return -EINVAL;
        }
 
-       max = count;
-       tmp = count_trail_chars(user_buffer, max);
-       if (tmp < 0) {
+       len = count_trail_chars(user_buffer, count);
+       if (len < 0) {
                pr_warn("illegal format\n");
-               return tmp;
+               return len;
        }
-       i = tmp;
+       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;
 
@@ -1006,7 +1025,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "min_pkt_size")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1023,7 +1043,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "max_pkt_size")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1042,7 +1063,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], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1062,7 +1084,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;
 
@@ -1073,7 +1096,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "debug")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1084,7 +1108,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "frags")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1094,7 +1119,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "delay")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1109,7 +1135,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "rate")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1124,7 +1151,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "ratep")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1139,7 +1167,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_src_min")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1152,7 +1181,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_dst_min")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1165,7 +1195,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_src_max")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1178,7 +1209,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "udp_dst_max")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1191,7 +1223,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "clone_skb")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, 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
@@ -1212,7 +1245,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "count")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1223,7 +1257,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "src_mac_count")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1237,7 +1272,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "dst_mac_count")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1251,7 +1287,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "burst")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1270,7 +1307,8 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
        if (!strcmp(name, "node")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1291,11 +1329,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;
@@ -1331,11 +1370,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;
@@ -1380,7 +1420,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;
 
@@ -1400,7 +1441,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;
 
@@ -1420,7 +1462,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;
 
@@ -1443,7 +1486,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;
 
@@ -1465,7 +1509,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;
 
@@ -1486,7 +1531,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;
 
@@ -1509,7 +1555,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;
 
@@ -1529,7 +1576,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;
 
@@ -1549,7 +1597,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;
 
@@ -1566,7 +1615,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;
 
@@ -1590,7 +1640,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "flows")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1604,7 +1655,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 #ifdef CONFIG_XFRM
        if (!strcmp(name, "spi")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1615,7 +1667,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 #endif
        if (!strcmp(name, "flowlen")) {
-               len = num_arg(&user_buffer[i], 10, &value);
+               max = min(10, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1626,7 +1679,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "queue_map_min")) {
-               len = num_arg(&user_buffer[i], 5, &value);
+               max = min(5, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1637,7 +1691,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "queue_map_max")) {
-               len = num_arg(&user_buffer[i], 5, &value);
+               max = min(5, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1650,7 +1705,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;
@@ -1671,7 +1727,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "vlan_id")) {
-               len = num_arg(&user_buffer[i], 4, &value);
+               max = min(4, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1698,7 +1755,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "vlan_p")) {
-               len = num_arg(&user_buffer[i], 1, &value);
+               max = min(1, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1713,7 +1771,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "vlan_cfi")) {
-               len = num_arg(&user_buffer[i], 1, &value);
+               max = min(1, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1728,7 +1787,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "svlan_id")) {
-               len = num_arg(&user_buffer[i], 4, &value);
+               max = min(4, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1755,7 +1815,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "svlan_p")) {
-               len = num_arg(&user_buffer[i], 1, &value);
+               max = min(1, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1770,7 +1831,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "svlan_cfi")) {
-               len = num_arg(&user_buffer[i], 1, &value);
+               max = min(1, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
@@ -1785,8 +1847,10 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "tos")) {
-               __u32 tmp_value = 0;
-               len = hex32_arg(&user_buffer[i], 2, &tmp_value);
+               __u32 tmp_value;
+
+               max = min(2, count - i);
+               len = hex32_arg(&user_buffer[i], max, &tmp_value);
                if (len < 0)
                        return len;
 
@@ -1801,8 +1865,10 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "traffic_class")) {
-               __u32 tmp_value = 0;
-               len = hex32_arg(&user_buffer[i], 2, &tmp_value);
+               __u32 tmp_value;
+
+               max = min(2, count - i);
+               len = hex32_arg(&user_buffer[i], max, &tmp_value);
                if (len < 0)
                        return len;
 
@@ -1817,7 +1883,8 @@ static ssize_t pktgen_if_write(struct file *file,
        }
 
        if (!strcmp(name, "skb_priority")) {
-               len = num_arg(&user_buffer[i], 9, &value);
+               max = min(9, count - i);
+               len = num_arg(&user_buffer[i], max, &value);
                if (len < 0)
                        return len;
 
-- 
2.48.1

Reply via email to