From cffca6f9950f8b07c00e537aafd8105ee0c136c1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 17 Jul 2023 11:23:03 +0200 Subject: [PATCH 1/2] glib-aux: add NM_ASCII_SPACES_KERNEL helper --- src/libnm-core-impl/tests/test-general.c | 69 +++++++++++++++++++----- src/libnm-glib-aux/nm-macros-internal.h | 22 ++++++-- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index 4bbb3df451..30b1ca5da8 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -7,6 +7,7 @@ #include "libnm-core-impl/nm-default-libnm-core.h" +#include #include #include #include @@ -87,21 +88,65 @@ G_STATIC_ASSERT(NM_UTILS_HWADDR_LEN_MAX == _NM_UTILS_HWADDR_LEN_MAX); static void test_nm_ascii_spaces(void) { - int i; - const char *const S = NM_ASCII_SPACES; + int i; - for (i = 0; S[i]; i++) - g_assert(!strchr(&S[i + 1], S[i])); + { + const char *const S = NM_ASCII_SPACES; - for (i = 0; S[i] != '\0'; i++) - g_assert(g_ascii_isspace(S[i])); + for (i = 0; S[i]; i++) + g_assert(!strchr(&S[i + 1], S[i])); - g_assert(!g_ascii_isspace((char) 0)); - for (i = 1; i < 0x100; i++) { - if (g_ascii_isspace((char) i)) - g_assert(strchr(S, (char) i)); - else - g_assert(!strchr(S, (char) i)); + for (i = 0; S[i] != '\0'; i++) + g_assert(g_ascii_isspace(S[i])); + + g_assert(!g_ascii_isspace((char) 0)); + for (i = 1; i < 0x100; i++) { + g_assert((!!g_ascii_isspace((char) i)) == (!!strchr(S, (char) i))); + } + } + + { + const char *const S = NM_ASCII_WHITESPACES; + + for (i = 0; S[i]; i++) + g_assert(!strchr(&S[i + 1], S[i])); + + for (i = 0; S[i] != '\0'; i++) + g_assert(nm_ascii_is_whitespace(S[i])); + + g_assert(!nm_ascii_is_whitespace((char) 0)); + for (i = 1; i < 0x100; i++) { + g_assert(nm_ascii_is_whitespace((char) i) == (!!strchr(S, (char) i))); + } + } + + { + const char *const S = NM_ASCII_SPACES_CTYPE; + + for (i = 0; S[i]; i++) + g_assert(!strchr(&S[i + 1], S[i])); + + if (nm_streq0(g_getenv("LANG"), "C")) { + g_assert(!isspace((char) 0)); + for (i = 1; i < 0x100; i++) { + g_assert((!!isspace((char) i)) == (!!strchr(S, (char) i))); + } + } + } + + { + const char *const S = NM_ASCII_SPACES_KERNEL; + + for (i = 0; S[i]; i++) + g_assert(!strchr(&S[i + 1], S[i])); + + for (i = 0; S[i] != '\0'; i++) + g_assert(nm_ascii_is_space_kernel(S[i])); + + g_assert(!nm_ascii_is_space_kernel((char) 0)); + for (i = 1; i < 0x100; i++) { + g_assert(nm_ascii_is_space_kernel((char) i) == (!!strchr(S, (char) i))); + } } } diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h index b74d732407..9972dc4452 100644 --- a/src/libnm-glib-aux/nm-macros-internal.h +++ b/src/libnm-glib-aux/nm-macros-internal.h @@ -1086,11 +1086,20 @@ nm_g_variant_equal(GVariant *a, GVariant *b) /* mirrors g_ascii_isspace() and what we consider spaces in general. */ #define NM_ASCII_SPACES " \n\t\r\f" -/* Like NM_ASCII_SPACES, but without "\f" (0x0c, Formfeed Page Break). - * This is what for example systemd calls WHITESPACE and what it uses to tokenize - * the kernel command line. */ +/* Like NM_ASCII_SPACES, but without "\f" (0x0c, Formfeed Page Break). This is + * what for example systemd calls WHITESPACE and what it uses to tokenize the + * kernel command line. */ #define NM_ASCII_WHITESPACES " \n\t\r" +/* mirrors 's isspace() with C locale. It's like NM_ASCII_SPACES but + * additionally also considers '\v' (vertical tab). */ +#define NM_ASCII_SPACES_CTYPE NM_ASCII_SPACES "\v" + +/* mirrors kernel's isspace() from "include/linux/ctype.h", which treats as + * space the common ASCII spaces, including '\v' (vertical tab), but also + * '\240' (non-breaking space, NBSP in Latin-1). */ +#define NM_ASCII_SPACES_KERNEL NM_ASCII_SPACES_CTYPE "\240" + static inline gboolean nm_ascii_is_whitespace(char ch) { @@ -1100,6 +1109,13 @@ nm_ascii_is_whitespace(char ch) return NM_IN_SET(ch, ' ', '\n', '\t', '\r'); } +static inline gboolean +nm_ascii_is_space_kernel(char ch) +{ + /* Checks whether @ch is in NM_ASCII_SPACES_KERNEL. */ + return NM_IN_SET(ch, ' ', '\n', '\t', '\r', '\f', '\v', '\240'); +} + #define NM_ASCII_NEWLINE "\n\r" static inline gboolean From ab69d430a7fa5fe16c9b4c4d2b57b85df8c3011b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 17 Jul 2023 11:23:43 +0200 Subject: [PATCH 2/2] glib-aux: fix rejecting '\v' and NBSP in nm_utils_ifname_valid_kernel() Kernel's dev_valid_name() calls isspace(), which also rejects '\v' and '\240'. As this tightens the check, the change can break code that partly worked before. It surely didn't work to the point, where an interface with such name could be created in kernel. # ip link add name $'foo\240bar' type dummy RTNETLINK answers: Invalid argument --- src/libnm-glib-aux/nm-shared-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index a51ff765d7..34a3af2053 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -5352,7 +5352,7 @@ nm_utils_ifname_valid_kernel(const char *name, GError **error) if (ch == '\0') return TRUE; - if (NM_IN_SET(ch, '/', ':') || g_ascii_isspace(ch)) { + if (NM_IN_SET(ch, '/', ':') || nm_ascii_is_space_kernel(ch)) { g_set_error_literal(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,