]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util-lib: add new ifname_valid() call that validates interface names
authorLennart Poettering <lennart@poettering.net>
Fri, 6 May 2016 18:58:32 +0000 (20:58 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 9 May 2016 13:45:31 +0000 (15:45 +0200)
Make use of this in nspawn at a couple of places. A later commit should port
more code over to this, including networkd.

src/basic/socket-util.c
src/basic/socket-util.h
src/nspawn/nspawn-network.c
src/nspawn/nspawn.c
src/test/test-socket-util.c

index c634f1d5649d71ef7c362bdc9870a5f9fde8bab3..c8769a54f4e089bd25f7c3dcc591d820d1e89d4c 100644 (file)
@@ -43,7 +43,9 @@
 #include "socket-util.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "strv.h"
 #include "user-util.h"
+#include "utf8.h"
 #include "util.h"
 
 int socket_address_parse(SocketAddress *a, const char *s) {
@@ -795,6 +797,42 @@ static const char* const ip_tos_table[] = {
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
 
+bool ifname_valid(const char *p) {
+        bool numeric = true;
+
+        /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
+         * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
+         * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
+
+        if (isempty(p))
+                return false;
+
+        if (strlen(p) >= IFNAMSIZ)
+                return false;
+
+        if (STR_IN_SET(p, ".", ".."))
+                return false;
+
+        while (*p) {
+                if ((unsigned char) *p >= 127U)
+                        return false;
+
+                if ((unsigned char) *p <= 32U)
+                        return false;
+
+                if (*p == ':' || *p == '/')
+                        return false;
+
+                numeric = numeric && (*p >= '0' && *p <= '9');
+                p++;
+        }
+
+        if (numeric)
+                return false;
+
+        return true;
+}
+
 int getpeercred(int fd, struct ucred *ucred) {
         socklen_t n = sizeof(struct ucred);
         struct ucred u;
index 160f7c484baa315daa9636b1b10117a44eea04a3..e9230e4a9f621aad904642d49dbbe2a11332f89f 100644 (file)
@@ -123,6 +123,8 @@ int fd_inc_rcvbuf(int fd, size_t n);
 int ip_tos_to_string_alloc(int i, char **s);
 int ip_tos_from_string(const char *s);
 
+bool ifname_valid(const char *p);
+
 int getpeercred(int fd, struct ucred *ucred);
 int getpeersec(int fd, char **ret);
 
index f2b7e4dd797ccfb1ec638a27bb3b15d5fb65c781..9938fce503bbddd1f0ac76358e6b74467504e8b1 100644 (file)
@@ -29,6 +29,8 @@
 #include "netlink-util.h"
 #include "nspawn-network.h"
 #include "siphash24.h"
+#include "socket-util.h"
+#include "stat-util.h"
 #include "string-util.h"
 #include "udev-util.h"
 #include "util.h"
@@ -515,13 +517,13 @@ int veth_extra_parse(char ***l, const char *p) {
         r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
         if (r < 0)
                 return r;
-        if (r == 0 || isempty(a))
+        if (r == 0 || !ifname_valid(a))
                 return -EINVAL;
 
         r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
         if (r < 0)
                 return r;
-        if (r == 0 || isempty(b)) {
+        if (r == 0 || !ifname_valid(b)) {
                 free(b);
                 b = strdup(a);
                 if (!b)
index 3fc6cc955cf8277abb2f79d51e34146fc986fab9..643f459851eca71655e460e2af9cb736d712836f 100644 (file)
@@ -467,6 +467,12 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_NETWORK_BRIDGE:
+
+                        if (!ifname_valid(optarg)) {
+                                log_error("Bridge interface name not valid: %s", optarg);
+                                return -EINVAL;
+                        }
+
                         r = free_and_strdup(&arg_network_bridge, optarg);
                         if (r < 0)
                                 return log_oom();
@@ -489,6 +495,12 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_NETWORK_INTERFACE:
+
+                        if (!ifname_valid(optarg)) {
+                                log_error("Network interface name not valid: %s", optarg);
+                                return -EINVAL;
+                        }
+
                         if (strv_extend(&arg_network_interfaces, optarg) < 0)
                                 return log_oom();
 
@@ -497,6 +509,12 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_NETWORK_MACVLAN:
+
+                        if (!ifname_valid(optarg)) {
+                                log_error("MACVLAN network interface name not valid: %s", optarg);
+                                return -EINVAL;
+                        }
+
                         if (strv_extend(&arg_network_macvlan, optarg) < 0)
                                 return log_oom();
 
@@ -505,6 +523,12 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_NETWORK_IPVLAN:
+
+                        if (!ifname_valid(optarg)) {
+                                log_error("IPVLAN network interface name not valid: %s", optarg);
+                                return -EINVAL;
+                        }
+
                         if (strv_extend(&arg_network_ipvlan, optarg) < 0)
                                 return log_oom();
 
index 9e01f3afd45de6d5aba2e550060cd41ee41557a7..b480fdaa9cceb4b38bbb7fc18b6687fab1440a79 100644 (file)
 #include "string-util.h"
 #include "util.h"
 
+static void test_ifname_valid(void) {
+        assert(ifname_valid("foo"));
+        assert(ifname_valid("eth0"));
+
+        assert(!ifname_valid("0"));
+        assert(!ifname_valid("99"));
+        assert(ifname_valid("a99"));
+        assert(ifname_valid("99a"));
+
+        assert(!ifname_valid(NULL));
+        assert(!ifname_valid(""));
+        assert(!ifname_valid(" "));
+        assert(!ifname_valid(" foo"));
+        assert(!ifname_valid("bar\n"));
+        assert(!ifname_valid("."));
+        assert(!ifname_valid(".."));
+        assert(ifname_valid("foo.bar"));
+        assert(!ifname_valid("x:y"));
+
+        assert(ifname_valid("xxxxxxxxxxxxxxx"));
+        assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
+}
+
 static void test_socket_address_parse(void) {
         SocketAddress a;
 
@@ -362,6 +385,8 @@ int main(int argc, char *argv[]) {
 
         log_set_max_level(LOG_DEBUG);
 
+        test_ifname_valid();
+
         test_socket_address_parse();
         test_socket_address_parse_netlink();
         test_socket_address_equal();