Blob Blame History Raw
From 31e882a46229c74649216ddc80fdb2ecbf75ab9e Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Tue, 16 Mar 2021 10:00:44 +0100
Subject: [PATCH 1/1] initrd: fix crash parsing empty rd.znet argument

Ignore a rd.znet argument without subchannels. When using net.ifnames
(the default), subchannels are used to build the interface name, which
is required to match the right connection.

With net.ifnames=0 the interface name is build using a prefix and a
global counter and therefore in theory it is possible to omit
subchannels. However, without subchannels there won't be a udev rule
that renames the interface and so it can't work.

https://bugzilla.redhat.com/show_bug.cgi?id=1931284
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/783
(cherry picked from commit 0f8fe3c76b9ecdf52c1690295f7dcc7b7ade16b6)
(cherry picked from commit d0d2d97ca51444bc7013943748ede334cc79a33f)
---
 src/core/initrd/nmi-cmdline-reader.c        |  5 +++++
 src/core/initrd/tests/test-cmdline-reader.c | 19 +++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/src/core/initrd/nmi-cmdline-reader.c b/src/core/initrd/nmi-cmdline-reader.c
index 5f40f63ef269..e3ecc7d969bb 100644
--- a/src/core/initrd/nmi-cmdline-reader.c
+++ b/src/core/initrd/nmi-cmdline-reader.c
@@ -917,6 +917,11 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
     subchannels[0] = get_word(&argument, ',');
     subchannels[1] = get_word(&argument, ',');
 
+    /* Without subchannels we can't univocally match
+     * a device. */
+    if (!subchannels[0] || !subchannels[1])
+        return;
+
     if (nm_streq0(nettype, "ctc")) {
         if (net_ifnames == TRUE) {
             prefix = "sl";
diff --git a/src/core/initrd/tests/test-cmdline-reader.c b/src/core/initrd/tests/test-cmdline-reader.c
index 4b450aae0fa4..ba072e7933dc 100644
--- a/src/core/initrd/tests/test-cmdline-reader.c
+++ b/src/core/initrd/tests/test-cmdline-reader.c
@@ -1815,6 +1815,24 @@ test_rd_znet_no_ip(void)
     g_assert_cmpint(g_hash_table_size(connections), ==, 0);
 }
 
+static void
+test_rd_znet_malformed(void)
+{
+    const char *const *const ARGV0  = NM_MAKE_STRV("rd.znet=");
+    const char *const *const ARGV1  = NM_MAKE_STRV("rd.znet=,");
+    const char *const *const ARGV2  = NM_MAKE_STRV("rd.znet=foobar");
+    const char *const *const ARGV3  = NM_MAKE_STRV("rd.znet=qeth,0.0.0800,,,layer2=0,portno=1");
+    const char *const *const ARGV[] = {ARGV0, ARGV1, ARGV2, ARGV3};
+    guint                    i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_hashtable GHashTable *connections = NULL;
+
+        connections = _parse_cons(ARGV[i]);
+        g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    }
+}
+
 static void
 test_bootif_ip(void)
 {
@@ -2173,6 +2191,7 @@ main(int argc, char **argv)
     g_test_add_func("/initrd/cmdline/rd_znet", test_rd_znet);
     g_test_add_func("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy);
     g_test_add_func("/initrd/cmdline/rd_znet/no_ip", test_rd_znet_no_ip);
+    g_test_add_func("/initrd/cmdline/rd_znet/empty", test_rd_znet_malformed);
     g_test_add_func("/initrd/cmdline/bootif/ip", test_bootif_ip);
     g_test_add_func("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip);
     g_test_add_func("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype);
-- 
2.30.2