From 301eece09b7ea7243dfb9b207e4906f4f01e23f5 Mon Sep 17 00:00:00 2001 From: Eduard Shishkin Date: Mon, 24 Aug 2020 11:36:21 +0200 Subject: [PATCH] zipl: fix Error when title is not the first field in BLS file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: zipl implementation (specifically the scan code) implicitly assumes that title field is always on the top of BLS file, and this assumption doesn't comply the bootloader standards: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ Solution: Before parsing in-memory BLS entry, rearrange its lines as following: search for a line with keyword "title" and move it to the top. The scan code is invariant against such transform Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/64 Signed-off-by: Stefan Haberland Signed-off-by: Eduard Shishkin Signed-off-by: Jan Höppner --- zipl/src/scan.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/zipl/src/scan.c b/zipl/src/scan.c index 064709f4..48260f98 100644 --- a/zipl/src/scan.c +++ b/zipl/src/scan.c @@ -21,6 +21,7 @@ #define _GNU_SOURCE #endif +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include @@ -730,6 +732,67 @@ scan_bls_field(struct misc_file_buffer *file, struct scan_token* scan, return 0; } +/** + * find a line with keyword "title" and move it to the top + */ +static int sort_bls_fields(struct misc_file_buffer *file, char *filename) +{ + bool is_title = false; + size_t title_len = 0; + int nr_titles = 0; + size_t title_off; + char *title; + int current; + size_t len; + + while (file->length - file->pos > 4 /* for "title" */) { + if (strncmp("title", &file->buffer[file->pos], 5) == 0) { + is_title = true; + nr_titles++; + title_off = file->pos; + } + for (len = 0;; file->pos++, len++) { + current = misc_get_char(file, 0); + if (current == '\n' || current == EOF) + break; + } + if (is_title == true) + title_len = len; + if (current == EOF) + break; + file->pos++; + } + file->pos = 0; + + if (nr_titles == 0) { + error_reason("no title in %s", filename); + return -1; + } + if (nr_titles > 1) { + error_reason("more than one title in %s", filename); + return -1; + } + if (title_off == 0) + return 0; + + title = misc_malloc(title_len); + if (!title) + return -1; + /* + * copy the title field w/o trailing '\n' to the temporary buffer + */ + memcpy(title, &file->buffer[title_off], title_len); + /* + * shift preceded memory region w/o trailing '\n' to the right + */ + assert(file->buffer[title_off - 1] == '\n'); + memmove(&file->buffer[title_len + 1], &file->buffer[0], title_off - 1); + file->buffer[title_len] = '\n'; + memcpy(&file->buffer[0], title, title_len); + + free(title); + return 0; +} int scan_bls(const char* blsdir, struct scan_token** token, int scan_size) @@ -780,6 +843,10 @@ scan_bls(const char* blsdir, struct scan_token** token, int scan_size) if (rc) goto err; + rc = sort_bls_fields(&file, filename); + if (rc) + goto err; + while ((size_t)file.pos < file.length) { current = misc_get_char(&file, 0); switch (current) {