]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
datatype: validate port number in inet_service_type_parse
authorPhil Oester <kernel@linuxace.com>
Thu, 15 Aug 2013 17:19:11 +0000 (10:19 -0700)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 17 Aug 2013 09:47:56 +0000 (11:47 +0200)
At present, nft accepts out of range port values such as in this example:

    nft add rule ip filter input tcp dport 123456 accept

Attached patch adds checks for both integer overflow and 16 bit overflow,
and avoids getaddrinfo call in the (common) case of digit input. Example
above now produces this output:

    <cmdline>:1:36-41: Error: Service out of range
    add rule ip filter input tcp dport 123456 accept
                                       ^^^^^^
Signed-off-by: Phil Oester <kernel@linuxace.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/datatype.c

index 55368eed418e6e3ef17521d508aa61372326306f..be328518f24f74fd0fc18045db72ba99f8ca31d9 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <inttypes.h>
+#include <errno.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <linux/types.h>
@@ -500,18 +501,30 @@ static struct error_record *inet_service_type_parse(const struct expr *sym,
 {
        struct addrinfo *ai;
        uint16_t port;
+       uintmax_t i;
        int err;
+       char *end;
+
+       errno = 0;
+       i = strtoumax(sym->identifier, &end, 0);
+       if (sym->identifier != end && *end == '\0') {
+               if (errno == ERANGE || i > UINT16_MAX)
+                       return error(&sym->location, "Service out of range");
+
+               port = i;
+       } else {
+               err = getaddrinfo(NULL, sym->identifier, NULL, &ai);
+               if (err != 0)
+                       return error(&sym->location, "Could not resolve service: %s",
+                                    gai_strerror(err));
+
+               port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+               freeaddrinfo(ai);
+       }
 
-       err = getaddrinfo(NULL, sym->identifier, NULL, &ai);
-       if (err != 0)
-               return error(&sym->location, "Could not resolve service: %s",
-                            gai_strerror(err));
-
-       port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
        *res = constant_expr_alloc(&sym->location, &inet_service_type,
                                   BYTEORDER_BIG_ENDIAN,
                                   sizeof(port) * BITS_PER_BYTE, &port);
-       freeaddrinfo(ai);
        return NULL;
 }