From: Lennart Poettering Date: Fri, 2 Sep 2022 09:04:51 +0000 (+0200) Subject: bootspec: simplify paths + insist they are normalized X-Git-Tag: v252-rc1~268^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bb9133bb467f49bdfc236b19a51558634681d2c4;p=thirdparty%2Fsystemd.git 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 --- diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 1a47fff167c..90ae7887bf1 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; }