diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-09-02 11:04:51 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-09-02 14:25:46 +0200 |
commit | bb9133bb467f49bdfc236b19a51558634681d2c4 (patch) | |
tree | e5f4530c8b08198e69dfde6a6b6fd7a54eade6d4 /src/shared/bootspec.c | |
parent | 81e327c42c26b0a716fc75718e8d5fce8f6893e2 (diff) | |
download | systemd-bb9133bb467f49bdfc236b19a51558634681d2c4.tar.gz |
bootspec: simplify paths + insist they are normalized
Inspired by #23913, let's complain if people use paths with ".."
in Type #1 bootspec entries.
Let's prefix all paths with "/" if it is missing.
Let's simplify all paths.
let's refuse paths/warn with "..".
Fixes: #23913
Diffstat (limited to 'src/shared/bootspec.c')
-rw-r--r-- | src/shared/bootspec.c | 112 |
1 files changed, 99 insertions, 13 deletions
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 1a47fff167..90ae7887bf 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -53,6 +53,98 @@ static void boot_entry_free(BootEntry *entry) { strv_free(entry->device_tree_overlay); } +static int mangle_path(const char *field, const char *p, char **ret) { + _cleanup_free_ char *c = NULL; + + assert(field); + assert(p); + assert(ret); + + /* Spec leaves open if prefixed with "/" or not, let's normalize that */ + if (path_is_absolute(p)) + c = strdup(p); + else + c = strjoin("/", p); + if (!c) + return -ENOMEM; + + /* We only reference files, never directories */ + if (endswith(c, "/")) { + log_warning("Path in field '%s' has trailing slash, ignoring: %s", field, c); + *ret = NULL; + return 0; + } + + /* Remove duplicate "/" */ + path_simplify(c); + + /* No ".." or "." or so */ + if (!path_is_normalized(c)) { + log_warning("Path in field '%s' is not normalized, ignoring: %s", field, c); + *ret = NULL; + return 0; + } + + *ret = TAKE_PTR(c); + return 1; +} + +static int parse_path_one(const char *field, char **s, const char *p) { + _cleanup_free_ char *c = NULL; + int r; + + assert(field); + assert(s); + assert(p); + + r = mangle_path(field, p, &c); + if (r <= 0) + return r; + + free_and_replace(*s, c); + return 0; +} + +static int parse_path_strv(const char *field, char ***s, const char *p) { + char *c; + int r; + + assert(field); + assert(s); + assert(p); + + r = mangle_path(field, p, &c); + if (r <= 0) + return r; + + return strv_consume(s, c); +} + +static int parse_path_many(const char *field, char ***s, const char *p) { + _cleanup_strv_free_ char **l = NULL, **f = NULL; + int r; + + l = strv_split(p, NULL); + if (!l) + return -ENOMEM; + + STRV_FOREACH(i, l) { + char *c; + + r = mangle_path(field, *i, &c); + if (r < 0) + return r; + if (r == 0) + continue; + + r = strv_consume(&f, c); + if (r < 0) + return r; + } + + return strv_extend_strv(s, f, /* filter_duplicates= */ false); +} + static int boot_entry_load_type1( FILE *f, const char *root, @@ -147,22 +239,16 @@ static int boot_entry_load_type1( else if (streq(field, "options")) r = strv_extend(&tmp.options, p); else if (streq(field, "linux")) - r = free_and_strdup(&tmp.kernel, p); + r = parse_path_one(field, &tmp.kernel, p); else if (streq(field, "efi")) - r = free_and_strdup(&tmp.efi, p); + r = parse_path_one(field, &tmp.efi, p); else if (streq(field, "initrd")) - r = strv_extend(&tmp.initrd, p); + r = parse_path_strv(field, &tmp.initrd, p); else if (streq(field, "devicetree")) - r = free_and_strdup(&tmp.device_tree, p); - else if (streq(field, "devicetree-overlay")) { - _cleanup_strv_free_ char **l = NULL; - - l = strv_split(p, NULL); - if (!l) - return log_oom(); - - r = strv_extend_strv(&tmp.device_tree_overlay, l, false); - } else { + r = parse_path_one(field, &tmp.device_tree, p); + else if (streq(field, "devicetree-overlay")) + r = parse_path_many(field, &tmp.device_tree_overlay, p); + else { log_notice("%s:%u: Unknown line \"%s\", ignoring.", tmp.path, line, field); continue; } |