You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
12 KiB
276 lines
12 KiB
From f62231a54abff6566415ea82aa8773e61f5688d6 Mon Sep 17 00:00:00 2001
|
|
From: Michal Sekletar <msekleta@redhat.com>
|
|
Date: Tue, 15 Mar 2022 19:02:05 +0100
|
|
Subject: [PATCH] core: shorten long unit names that are based on paths and
|
|
append path hash at the end
|
|
|
|
Fixes #18077
|
|
|
|
(cherry picked from commit 1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7)
|
|
|
|
Resolves: #1940973
|
|
---
|
|
src/basic/string-util.h | 23 +++++-----
|
|
src/basic/unit-name.c | 88 ++++++++++++++++++++++++++++++++++++++-
|
|
src/basic/unit-name.h | 3 ++
|
|
src/core/mount.c | 3 ++
|
|
src/test/test-unit-name.c | 25 ++++++++++-
|
|
5 files changed, 129 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
|
|
index 742b566932..0d406ff64a 100644
|
|
--- a/src/basic/string-util.h
|
|
+++ b/src/basic/string-util.h
|
|
@@ -9,17 +9,18 @@
|
|
#include "macro.h"
|
|
|
|
/* What is interpreted as whitespace? */
|
|
-#define WHITESPACE " \t\n\r"
|
|
-#define NEWLINE "\n\r"
|
|
-#define QUOTES "\"\'"
|
|
-#define COMMENTS "#;"
|
|
-#define GLOB_CHARS "*?["
|
|
-#define DIGITS "0123456789"
|
|
-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
|
|
-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
-#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
|
-#define ALPHANUMERICAL LETTERS DIGITS
|
|
-#define HEXDIGITS DIGITS "abcdefABCDEF"
|
|
+#define WHITESPACE " \t\n\r"
|
|
+#define NEWLINE "\n\r"
|
|
+#define QUOTES "\"\'"
|
|
+#define COMMENTS "#;"
|
|
+#define GLOB_CHARS "*?["
|
|
+#define DIGITS "0123456789"
|
|
+#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
|
|
+#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
+#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
|
+#define ALPHANUMERICAL LETTERS DIGITS
|
|
+#define HEXDIGITS DIGITS "abcdefABCDEF"
|
|
+#define LOWERCASE_HEXDIGITS DIGITS "abcdef"
|
|
|
|
#define streq(a,b) (strcmp((a),(b)) == 0)
|
|
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
|
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
|
|
index f9b3fafd4d..65ed979e39 100644
|
|
--- a/src/basic/unit-name.c
|
|
+++ b/src/basic/unit-name.c
|
|
@@ -6,11 +6,17 @@
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
+#include "sd-id128.h"
|
|
+
|
|
#include "alloc-util.h"
|
|
#include "glob-util.h"
|
|
#include "hexdecoct.h"
|
|
#include "path-util.h"
|
|
+#include "random-util.h"
|
|
+#include "siphash24.h"
|
|
+#include "sparse-endian.h"
|
|
#include "special.h"
|
|
+#include "stdio-util.h"
|
|
#include "string-util.h"
|
|
#include "strv.h"
|
|
#include "unit-name.h"
|
|
@@ -31,6 +37,9 @@
|
|
VALID_CHARS_WITH_AT \
|
|
"[]!-*?"
|
|
|
|
+#define LONG_UNIT_NAME_HASH_KEY SD_ID128_MAKE(ec,f2,37,fb,58,32,4a,32,84,9f,06,9b,0d,21,eb,9a)
|
|
+#define UNIT_NAME_HASH_LENGTH_CHARS 16
|
|
+
|
|
bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
|
|
const char *e, *i, *at;
|
|
|
|
@@ -513,6 +522,68 @@ int unit_name_template(const char *f, char **ret) {
|
|
return 0;
|
|
}
|
|
|
|
+bool unit_name_is_hashed(const char *name) {
|
|
+ char *s;
|
|
+
|
|
+ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
|
|
+ return false;
|
|
+
|
|
+ assert_se(s = strrchr(name, '.'));
|
|
+
|
|
+ if (s - name < UNIT_NAME_HASH_LENGTH_CHARS + 1)
|
|
+ return false;
|
|
+
|
|
+ s -= UNIT_NAME_HASH_LENGTH_CHARS;
|
|
+ if (s[-1] != '_')
|
|
+ return false;
|
|
+
|
|
+ for (size_t i = 0; i < UNIT_NAME_HASH_LENGTH_CHARS; i++)
|
|
+ if (!strchr(LOWERCASE_HEXDIGITS, s[i]))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+int unit_name_hash_long(const char *name, char **ret) {
|
|
+ _cleanup_free_ char *n = NULL, *hash = NULL;
|
|
+ char *suffix;
|
|
+ le64_t h;
|
|
+ size_t len;
|
|
+
|
|
+ if (strlen(name) < UNIT_NAME_MAX)
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ suffix = strrchr(name, '.');
|
|
+ if (!suffix)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (unit_type_from_string(suffix+1) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ h = htole64(siphash24(name, strlen(name) + 1, LONG_UNIT_NAME_HASH_KEY.bytes));
|
|
+
|
|
+ hash = hexmem(&h, sizeof(h));
|
|
+ if (!hash)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ assert_se(strlen(hash) == UNIT_NAME_HASH_LENGTH_CHARS);
|
|
+
|
|
+ len = UNIT_NAME_MAX - 1 - strlen(suffix+1) - UNIT_NAME_HASH_LENGTH_CHARS - 2;
|
|
+ assert(len > 0 && len < UNIT_NAME_MAX);
|
|
+
|
|
+ n = strndup(name, len);
|
|
+ if (!n)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (!strextend(&n, "_", hash, suffix, NULL))
|
|
+ return -ENOMEM;
|
|
+ assert_se(unit_name_is_valid(n, UNIT_NAME_PLAIN));
|
|
+
|
|
+ *ret = TAKE_PTR(n);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int unit_name_from_path(const char *path, const char *suffix, char **ret) {
|
|
_cleanup_free_ char *p = NULL, *s = NULL;
|
|
int r;
|
|
@@ -532,7 +603,19 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret) {
|
|
if (!s)
|
|
return -ENOMEM;
|
|
|
|
- /* Refuse this if this got too long or for some other reason didn't result in a valid name */
|
|
+ if (strlen(s) >= UNIT_NAME_MAX) {
|
|
+ _cleanup_free_ char *n = NULL;
|
|
+
|
|
+ log_debug("Unit name \"%s\" too long, falling back to hashed unit name.", s);
|
|
+
|
|
+ r = unit_name_hash_long(s, &n);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ free_and_replace(s, n);
|
|
+ }
|
|
+
|
|
+ /* Refuse if this for some other reason didn't result in a valid name */
|
|
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
|
|
return -EINVAL;
|
|
|
|
@@ -582,6 +665,9 @@ int unit_name_to_path(const char *name, char **ret) {
|
|
if (r < 0)
|
|
return r;
|
|
|
|
+ if (unit_name_is_hashed(name))
|
|
+ return -ENAMETOOLONG;
|
|
+
|
|
return unit_name_path_unescape(prefix, ret);
|
|
}
|
|
|
|
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
|
|
index 61abcd585b..602295af8f 100644
|
|
--- a/src/basic/unit-name.h
|
|
+++ b/src/basic/unit-name.h
|
|
@@ -45,6 +45,9 @@ int unit_name_replace_instance(const char *f, const char *i, char **ret);
|
|
|
|
int unit_name_template(const char *f, char **ret);
|
|
|
|
+int unit_name_hash_long(const char *name, char **ret);
|
|
+bool unit_name_is_hashed(const char *name);
|
|
+
|
|
int unit_name_from_path(const char *path, const char *suffix, char **ret);
|
|
int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret);
|
|
int unit_name_to_path(const char *name, char **ret);
|
|
diff --git a/src/core/mount.c b/src/core/mount.c
|
|
index d37b5731f8..e69ecb7ce3 100644
|
|
--- a/src/core/mount.c
|
|
+++ b/src/core/mount.c
|
|
@@ -572,6 +572,9 @@ static int mount_add_extras(Mount *m) {
|
|
|
|
if (!m->where) {
|
|
r = unit_name_to_path(u->id, &m->where);
|
|
+ if (r == -ENAMETOOLONG)
|
|
+ log_unit_error_errno(u, r, "Failed to derive mount point path from unit name, because unit name is hashed. "
|
|
+ "Set \"Where=\" in the unit file explicitly.");
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
|
|
index 2b00ef8cb7..35cfaafd30 100644
|
|
--- a/src/test/test-unit-name.c
|
|
+++ b/src/test/test-unit-name.c
|
|
@@ -82,6 +82,7 @@ static void test_unit_name_replace_instance(void) {
|
|
|
|
static void test_unit_name_from_path_one(const char *path, const char *suffix, const char *expected, int ret) {
|
|
_cleanup_free_ char *t = NULL;
|
|
+ int r;
|
|
|
|
assert_se(unit_name_from_path(path, suffix, &t) == ret);
|
|
puts(strna(t));
|
|
@@ -89,12 +90,31 @@ static void test_unit_name_from_path_one(const char *path, const char *suffix, c
|
|
|
|
if (t) {
|
|
_cleanup_free_ char *k = NULL;
|
|
- assert_se(unit_name_to_path(t, &k) == 0);
|
|
+
|
|
+ /* We don't support converting hashed unit names back to paths */
|
|
+ r = unit_name_to_path(t, &k);
|
|
+ if (r == -ENAMETOOLONG)
|
|
+ return;
|
|
+ assert(r == 0);
|
|
+
|
|
puts(strna(k));
|
|
assert_se(path_equal(k, empty_to_root(path)));
|
|
}
|
|
}
|
|
|
|
+static void test_unit_name_is_hashed(void) {
|
|
+ assert_se(!unit_name_is_hashed(""));
|
|
+ assert_se(!unit_name_is_hashed("foo@bar.service"));
|
|
+ assert_se(!unit_name_is_hashed("foo@.service"));
|
|
+ assert_se(unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9ed33c2ec55.mount"));
|
|
+ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736D9ED33C2EC55.mount"));
|
|
+ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!7736d9ed33c2ec55.mount"));
|
|
+ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9gd33c2ec55.mount"));
|
|
+ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_.mount"));
|
|
+ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_2103e1466b87f7f7@waldo.mount"));
|
|
+ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_2103e1466b87f7f7@.mount"));
|
|
+}
|
|
+
|
|
static void test_unit_name_from_path(void) {
|
|
puts("-------------------------------------------------");
|
|
test_unit_name_from_path_one("/waldo", ".mount", "waldo.mount", 0);
|
|
@@ -105,6 +125,8 @@ static void test_unit_name_from_path(void) {
|
|
test_unit_name_from_path_one("///", ".mount", "-.mount", 0);
|
|
test_unit_name_from_path_one("/foo/../bar", ".mount", NULL, -EINVAL);
|
|
test_unit_name_from_path_one("/foo/./bar", ".mount", NULL, -EINVAL);
|
|
+ test_unit_name_from_path_one("/waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ".mount",
|
|
+ "waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9ed33c2ec55.mount", 0);
|
|
}
|
|
|
|
static void test_unit_name_from_path_instance_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) {
|
|
@@ -824,6 +846,7 @@ int main(int argc, char* argv[]) {
|
|
|
|
test_unit_name_is_valid();
|
|
test_unit_name_replace_instance();
|
|
+ test_unit_name_is_hashed();
|
|
test_unit_name_from_path();
|
|
test_unit_name_from_path_instance();
|
|
test_unit_name_mangle();
|