From 46dc83440fc60cc4044c7b2e2c9004921a6b08f8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 27 Jan 2020 17:38:41 +0900 Subject: [PATCH 1/4] escape: make cunescape() and cunescape_length() inline --- src/basic/escape.c | 8 -------- src/basic/escape.h | 8 ++++++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/basic/escape.c b/src/basic/escape.c index 33a6f204f55..a0b0a771090 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -360,14 +360,6 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return t - r; } -int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { - return cunescape_length_with_prefix(s, length, NULL, flags, ret); -} - -int cunescape(const char *s, UnescapeFlags flags, char **ret) { - return cunescape_length(s, strlen(s), flags, ret); -} - char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) { char *ans, *t, *prev, *prev2; const char *f; diff --git a/src/basic/escape.h b/src/basic/escape.h index b26054c5df8..dfd10f93154 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -41,9 +41,13 @@ char *cescape(const char *s); char *cescape_length(const char *s, size_t n); int cescape_char(char c, char *buf); -int cunescape(const char *s, UnescapeFlags flags, char **ret); -int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); +static inline int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { + return cunescape_length_with_prefix(s, length, NULL, flags, ret); +} +static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) { + return cunescape_length(s, strlen(s), flags, ret); +} int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit); char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits); From 0e72e469f88ce866668a0ca1965f51feb52d5e98 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 27 Jan 2020 17:46:22 +0900 Subject: [PATCH 2/4] escape: introduce UNESCAPE_ACCEPT_NUL flag --- src/basic/escape.c | 12 ++++++------ src/basic/escape.h | 7 ++++--- src/basic/extract-word.c | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/basic/escape.c b/src/basic/escape.c index a0b0a771090..c5c44d2e7d8 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -102,7 +102,7 @@ char *cescape(const char *s) { return cescape_length(s, strlen(s)); } -int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) { +int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul) { int r = 1; assert(p); @@ -171,7 +171,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) return -EINVAL; /* Don't allow NUL bytes */ - if (a == 0 && b == 0) + if (a == 0 && b == 0 && !accept_nul) return -EINVAL; *ret = (a << 4U) | b; @@ -199,7 +199,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; /* Don't allow 0 chars */ - if (c == 0) + if (c == 0 && !accept_nul) return -EINVAL; *ret = c; @@ -227,7 +227,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; /* Don't allow 0 chars */ - if (c == 0) + if (c == 0 && !accept_nul) return -EINVAL; /* Don't allow invalid code points */ @@ -267,7 +267,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) return -EINVAL; /* don't allow NUL bytes */ - if (a == 0 && b == 0 && c == 0) + if (a == 0 && b == 0 && c == 0 && !accept_nul) return -EINVAL; /* Don't allow bytes above 255 */ @@ -333,7 +333,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return -EINVAL; } - k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit); + k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit, flags & UNESCAPE_ACCEPT_NUL); if (k < 0) { if (flags & UNESCAPE_RELAX) { /* Invalid escape code, let's take it literal then */ diff --git a/src/basic/escape.h b/src/basic/escape.h index dfd10f93154..b8eb137c3d3 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -29,12 +29,13 @@ #define SHELL_NEED_ESCAPE_POSIX "\\\'" typedef enum UnescapeFlags { - UNESCAPE_RELAX = 1, + UNESCAPE_RELAX = 1 << 0, + UNESCAPE_ACCEPT_NUL = 1 << 1, } UnescapeFlags; typedef enum EscapeStyle { ESCAPE_BACKSLASH = 1, - ESCAPE_POSIX = 2, + ESCAPE_POSIX = 2, } EscapeStyle; char *cescape(const char *s); @@ -48,7 +49,7 @@ static inline int cunescape_length(const char *s, size_t length, UnescapeFlags f static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) { return cunescape_length(s, strlen(s), flags, ret); } -int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit); +int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul); char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits); static inline char *xescape(const char *s, const char *bad) { diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index d7c215cb48e..ac9bf6099d8 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -90,7 +90,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra bool eight_bit = false; char32_t u; - r = cunescape_one(*p, (size_t) -1, &u, &eight_bit); + r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false); if (r < 0) { if (flags & EXTRACT_CUNESCAPE_RELAX) { s[sz++] = '\\'; From a6a36dea2d40553fcb6dbbde510c10ac97cb8062 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 27 Jan 2020 18:09:25 +0900 Subject: [PATCH 3/4] test: add tests for UNESCAPE_ACCEPT_NUL --- src/test/test-escape.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/test-escape.c b/src/test/test-escape.c index add17f9547d..f6aae1eb182 100644 --- a/src/test/test-escape.c +++ b/src/test/test-escape.c @@ -96,6 +96,22 @@ static void test_cunescape(void) { assert_se(cunescape("A=A\\\\x0aB", UNESCAPE_RELAX, &unescaped) >= 0); assert_se(streq_ptr(unescaped, "A=A\\x0aB")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\x00\\x00\\x00", UNESCAPE_ACCEPT_NUL, &unescaped) == 3); + assert_se(memcmp(unescaped, "\0\0\0", 3) == 0); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\u0000\\u0000\\u0000", UNESCAPE_ACCEPT_NUL, &unescaped) == 3); + assert_se(memcmp(unescaped, "\0\0\0", 3) == 0); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\U00000000\\U00000000\\U00000000", UNESCAPE_ACCEPT_NUL, &unescaped) == 3); + assert_se(memcmp(unescaped, "\0\0\0", 3) == 0); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\000\\000\\000", UNESCAPE_ACCEPT_NUL, &unescaped) == 3); + assert_se(memcmp(unescaped, "\0\0\0", 3) == 0); } static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { From 732e3a61043b970d1d55be0e3593313e412093e9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 27 Jan 2020 18:11:08 +0900 Subject: [PATCH 4/4] network: accept NUL character in SendOption= Closes #14609. --- src/network/networkd-dhcp-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 6465a8cfe9c..8664d8cdc0d 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -390,7 +390,7 @@ int config_parse_dhcp_send_option( break; } case DHCP_OPTION_DATA_STRING: - sz = cunescape(p, 0, &q); + sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q); if (sz < 0) { log_syntax(unit, LOG_ERR, filename, line, sz, "Failed to decode DHCPv4 option data, ignoring assignment: %s", p);