From 7230df2ed5fba37a68f7ad8c4f7f59c7058b881e65ac5ab6ed3a432e4379ff64 Mon Sep 17 00:00:00 2001 From: Mark Post Date: Tue, 10 Mar 2020 19:03:33 +0000 Subject: [PATCH] Accepting request 783519 from home:markkp:branches:Base:System - Added the following patches for bsc#1165978. zpcictl --reset only issues a SCLP reset and leaves the PCI function in an error state. Initiate an OS level recovery by calling /sys/bus/devices//recover after the SCLP reset. * s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch * s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch * s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch - The zipl boot loader may crash during boot. The solution is to implement vsnprintf and make use of it. (bsc#1165317) * s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch * s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch * s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch * s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch OBS-URL: https://build.opensuse.org/request/show/783519 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=90 --- ...sp2-01-zipl-libc-Introduce-vsnprintf.patch | 319 ++++++++++++++++++ ...zpcictl-Initiate-recover-after-reset.patch | 70 ++++ ...-potential-buffer-overflow-in-printf.patch | 63 ++++ ...l-Rename-misleading-sysfs_write_data.patch | 51 +++ ...l-libc-Replace-sprintf-with-snprintf.patch | 236 +++++++++++++ ...-Exit-on-error-in-sysfs_report_error.patch | 119 +++++++ ...icate-truncated-lines-in-printf-with.patch | 82 +++++ s390-tools.changes | 22 ++ s390-tools.spec | 9 +- 9 files changed, 970 insertions(+), 1 deletion(-) create mode 100644 s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch create mode 100644 s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch create mode 100644 s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch create mode 100644 s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch create mode 100644 s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch create mode 100644 s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch create mode 100644 s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch diff --git a/s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch b/s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch new file mode 100644 index 0000000..8da7a48 --- /dev/null +++ b/s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch @@ -0,0 +1,319 @@ +Subject: [PATCH] [BZ 184060] zipl/libc: Introduce vsnprintf +From: Philipp Rudo + +Description: zipl/libc: Fix potential buffer overflow in printf +Symptom: Crash of the zipl boot loader during boot. +Problem: The zipl boot loaders have their own minimalistic libc + implementation. In it printf and sprintf use vsprintf for string + formatting. Per definition vsprintf assumes that the buffer it + writes to is large enough to contain the formatted string and + performs no size checks. This is problematic for the boot + loaders because the buffer they use are often allocated on the + stack. Thus even small changes to the string format can + potentially cause buffer overflows on the stack. +Solution: Implement vsnprintf and make use of it. +Reproduction: Use printf to print a string with >81 characters (exact number + depends on the stack layout/compiler used). +Upstream-ID: 6fe9e6c55c69c14971dca55551009f5060418aae +Problem-ID: 184060 + +Upstream-Description: + + zipl/libc: Introduce vsnprintf + + The zipl boot loaders have their own minimalistic libc implementation. + In it printf and sprintf use vsprintf for string formatting. Per + definition vsprintf assumes that the buffer it writes to is large enough + to contain the formatted string and performs no size checks. This is + problematic for the boot loaders because the buffer they use are often + allocated on the stack. Thus even small changes to the string format can + potentially cause buffer overflows on the stack with the well known + consequences. Protect against such errors by implementing vsnprintf. + Later patches will make use of it. + + This implementation of vsnprintf only supports a small subset of format + options defined in the C standard. In particular it allows the + specifiers: + * %s (strings) + * %o (unsigned int octal) + * %u (unsigned int decimal) + * %x (unsigned int hexadecimal) + + Integer specifiers (o, u, and x) always use the long form, i.e. assume the + argument to be of type 'unsigned long int'. The length modified 'l' can + be given but is ignored. + + Furthermore, it is possible to provide the optional field width (aligned + to the right only) and precision as decimal integer (i.e. not via '*') + as well as the flag for zero padding integers (i.e. '0'). + + The implementation was heavily inspired by the implementation in + lib/vsprintf.c from the Linux kernel tree. + + Signed-off-by: Philipp Rudo + Reviewed-by: Stefan Haberland + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Philipp Rudo +--- + zipl/boot/libc.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 248 insertions(+) + +--- a/zipl/boot/libc.c ++++ b/zipl/boot/libc.c +@@ -218,6 +218,254 @@ unsigned long ebcstrtoul(char *nptr, cha + return val; + } + ++static int skip_atoi(const char **c) ++{ ++ int i = 0; ++ ++ do { ++ i = i*10 + *((*c)++) - '0'; ++ } while (isdigit(**c)); ++ ++ return i; ++} ++ ++enum format_type { ++ FORMAT_TYPE_NONE, ++ FORMAT_TYPE_STR, ++ FORMAT_TYPE_ULONG, ++}; ++ ++struct printf_spec { ++ unsigned int type:8; /* format_type enum */ ++ signed int field_width:24; /* width of output field */ ++ unsigned int zeropad:1; /* pad numbers with zero */ ++ unsigned int base:8; /* number base, 8, 10 or 16 only */ ++ signed int precision:16; /* # of digits/chars */ ++}; ++ ++#define FIELD_WIDTH_MAX ((1 << 23) - 1) ++ ++static int format_decode(const char *fmt, struct printf_spec *spec) ++{ ++ const char *start = fmt; ++ ++ spec->type = FORMAT_TYPE_NONE; ++ while (*fmt) { ++ if (*fmt == '%') ++ break; ++ fmt++; ++ } ++ ++ /* return current non-format string */ ++ if (fmt != start || !*fmt) ++ return fmt - start; ++ ++ /* first char is '%', skip it */ ++ fmt++; ++ if (*fmt == '0') { ++ spec->zeropad = 1; ++ fmt++; ++ } ++ ++ spec->field_width = -1; ++ if (isdigit(*fmt)) ++ spec->field_width = skip_atoi(&fmt); ++ ++ spec->precision = -1; ++ if (*fmt == '.') { ++ fmt++; ++ if (isdigit(*fmt)) ++ spec->precision = skip_atoi(&fmt); ++ } ++ ++ /* always use long form, i.e. ignore long qualifier */ ++ if (*fmt == 'l') ++ fmt++; ++ ++ switch (*fmt) { ++ case 's': ++ spec->type = FORMAT_TYPE_STR; ++ break; ++ ++ case 'o': ++ spec->base = 8; ++ spec->type = FORMAT_TYPE_ULONG; ++ break; ++ ++ case 'u': ++ spec->base = 10; ++ spec->type = FORMAT_TYPE_ULONG; ++ break; ++ ++ case 'x': ++ spec->base = 16; ++ spec->type = FORMAT_TYPE_ULONG; ++ break; ++ ++ default: ++ libc_stop(EINTERNAL); ++ } ++ ++ return ++fmt - start; ++} ++ ++static char *string(char *buf, char *end, const char *s, ++ struct printf_spec *spec) ++{ ++ int limit = spec->precision; ++ int len = 0; ++ int spaces; ++ ++ /* Copy string to buffer */ ++ while (limit--) { ++ char c = *s++; ++ if (!c) ++ break; ++ if (buf < end) ++ *buf = c; ++ buf++; ++ len++; ++ } ++ ++ /* right align if necessary */ ++ if (len < spec->field_width && buf < end) { ++ spaces = spec->field_width - len; ++ if (spaces >= end - buf) ++ spaces = end - buf; ++ memmove(buf + spaces, buf, len); ++ memset(buf, ' ', spaces); ++ buf += spaces; ++ } ++ ++ return buf; ++} ++ ++static char *number(char *buf, char *end, unsigned long val, ++ struct printf_spec *spec) ++{ ++ /* temporary buffer to prepare the string. ++ * Worst case: base = 8 -> 3 bits per char -> 2.67 chars per byte */ ++ char tmp[3 * sizeof(val)]; ++ static const char vec[] = {'0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; ++ int field_width = spec->field_width; ++ int precision = spec->precision; ++ int len; ++ ++ /* prepare string in reverse order */ ++ len = 0; ++ while (val) { ++ tmp[len++] = vec[val % spec->base]; ++ val /= spec->base; ++ } ++ ++ if (len > precision) ++ precision = len; ++ ++ field_width -= precision; ++ while (field_width-- > 0) { ++ char c = spec->zeropad ? '0' : ' '; ++ if (buf < end) ++ *buf = c; ++ buf++; ++ } ++ ++ /* needed if no field width but a precision is given */ ++ while (len < precision--) { ++ if (buf < end) ++ *buf = '0'; ++ buf++; ++ } ++ ++ while (len-- > 0) { ++ if (buf < end) ++ *buf = tmp[len]; ++ buf++; ++ } ++ ++ return buf; ++} ++ ++/* ++ * vsnprintf - Format string and place in a buffer ++ * ++ * This funcion only supports a subset of format options defined in the ++ * C standard, i.e. ++ * specifiers: ++ * * %s (strings) ++ * * %o (unsigned int octal) ++ * * %u (unsigned int decimal) ++ * * %x (unsigned int hexadecimal) ++ * ++ * length modifier: ++ * * 'l' (ignored, see below) ++ * ++ * flag: ++ * * '0' (zero padding for integers) ++ * ++ * precision and field width as integers, i.e. _not_ by asterix '*'. ++ * ++ * The integer specifiers (o, u and, x) always use the long form, i.e. ++ * assume the argument to be of type 'unsigned long int'. ++ * ++ * Returns the number of characters the function would have generated for ++ * the given input (excluding the trailing '\0'. If the return value is ++ * greater than or equal @size the resulting string is trunctuated. ++ */ ++static int vsnprintf(char *buf, unsigned long size, const char *fmt, ++ va_list args) ++{ ++ struct printf_spec spec = {0}; ++ char *str, *end; ++ ++ str = buf; ++ end = buf + size; ++ ++ /* use negative (large positive) buffer sizes as indication for ++ * unknown/unlimited buffer sizes. */ ++ if (end < buf) { ++ end = ((void *)-1); ++ size = end - buf; ++ } ++ ++ while (*fmt) { ++ const char *old_fmt = fmt; ++ int read = format_decode(fmt, &spec); ++ int copy; ++ ++ fmt += read; ++ ++ switch (spec.type) { ++ case FORMAT_TYPE_NONE: ++ copy = read; ++ if (str < end) { ++ if (copy > end - str) ++ copy = end - str; ++ memcpy(str, old_fmt, copy); ++ } ++ str += read; ++ break; ++ ++ case FORMAT_TYPE_STR: ++ str = string(str, end, va_arg(args, char *), &spec); ++ break; ++ ++ case FORMAT_TYPE_ULONG: ++ str = number(str, end, va_arg(args, unsigned long), ++ &spec); ++ break; ++ } ++ } ++ ++ if (size) { ++ if (str < end) ++ *str = '\0'; ++ else ++ end[-1] = '\0'; ++ } ++ return str - buf; ++} ++ + /* + * Convert string to number with given base + */ diff --git a/s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch b/s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch new file mode 100644 index 0000000..91aa36c --- /dev/null +++ b/s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch @@ -0,0 +1,70 @@ +Subject: [PATCH] [BZ 184174] zpcictl: Initiate recover after reset +From: Jan Hoeppner + +Description: zpcictl: Initiate recover after reset +Symptom: If a PCI function is reset using zpcictl --reset, the function + is in an error state. +Problem: zpcictl --reset only issues a SCLP reset and leaves the PCI + function in an error state. +Solution: Initiate an OS level recovery by calling + /sys/bus/devices//recover after the SCLP reset. +Reproduction: Call zpcictl --reset + Under z/VM check the state of the function with 'vmcp q pcif' +Upstream-ID: bc0d40c5803d4c5426b17b6d59aa0f1e46a2aacc +Problem-ID: 184174 + +Upstream-Description: + + zpcictl: Initiate recover after reset + + After a zpcitctl --reset the PCI function is currently left in an error + state. This seems unexpected, so follow the SCLP reset with an OS level + recovery using /sys/bus/devices//recover. + + Signed-off-by: Niklas Schnelle + Reviewed-by: Jan Hoeppner + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Jan Hoeppner +--- + zpcictl/zpcictl.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/zpcictl/zpcictl.c ++++ b/zpcictl/zpcictl.c +@@ -163,6 +163,26 @@ static unsigned int sysfs_read_value(str + return val; + } + ++static void sysfs_write_value(struct zpci_device *pdev, const char *attr, ++ unsigned int val) ++{ ++ char *path; ++ FILE *fp; ++ ++ path = util_path_sysfs("bus/pci/devices/%s/%s", pdev->slot, attr); ++ fp = fopen(path, "w"); ++ if (!fp) ++ fopen_err(path); ++ if (fprintf(fp, "%x", val) < 0) { ++ fclose(fp); ++ warnx("Could not write to file %s: %s", path, strerror(errno)); ++ free(path); ++ exit(EXIT_FAILURE); ++ } ++ fclose(fp); ++ free(path); ++} ++ + static void sysfs_write_data(struct zpci_report_error *report, char *slot) + { + size_t r_size; +@@ -297,6 +317,7 @@ static void sclp_issue_action(struct zpc + static void sclp_reset_device(struct zpci_device *pdev) + { + sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET); ++ sysfs_write_value(pdev, "recover", 1); + } + + /* diff --git a/s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch b/s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch new file mode 100644 index 0000000..c322f35 --- /dev/null +++ b/s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch @@ -0,0 +1,63 @@ +Subject: [PATCH] [BZ 184060] zipl/libc: Fix potential buffer overflow in printf +From: Philipp Rudo + +Description: zipl/libc: Fix potential buffer overflow in printf +Symptom: Crash of the zipl boot loader during boot. +Problem: The zipl boot loaders have their own minimalistic libc + implementation. In it printf and sprintf use vsprintf for string + formatting. Per definition vsprintf assumes that the buffer it + writes to is large enough to contain the formatted string and + performs no size checks. This is problematic for the boot + loaders because the buffer they use are often allocated on the + stack. Thus even small changes to the string format can + potentially cause buffer overflows on the stack. +Solution: Implement vsnprintf and make use of it. +Reproduction: Use printf to print a string with >81 characters (exact number + depends on the stack layout/compiler used). +Upstream-ID: 8874b908254c47c8a6fd7a1aca2c7371c11035c4 +Problem-ID: 184060 + +Upstream-Description: + + zipl/libc: Fix potential buffer overflow in printf + + Per definition vsprint assumes that the provided buffer it writes to is + large enough to contain the formatted string. As printf uses a fixed + sized buffer (81 bytes) and has no size checks the use of vsprintf can + easily cause buffer overflows. Protect against these buffer overflows by + using vsnprintf instead. + + While at it fix a typo in the comment. + + Reported-by: Marc Hartmayer + Signed-off-by: Philipp Rudo + Reviewed-by: Marc Hartmayer + Reviewed-by: Stefan Haberland + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Philipp Rudo +--- + zipl/boot/libc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/zipl/boot/libc.c ++++ b/zipl/boot/libc.c +@@ -530,7 +530,7 @@ void sprintf(char *str, const char *fmt, + } + + /* +- * Print formated string ++ * Print formatted string to console + */ + void printf(const char *fmt, ...) + { +@@ -538,7 +538,7 @@ void printf(const char *fmt, ...) + va_list va; + + va_start(va, fmt); +- vsprintf(buf, fmt, va); ++ vsnprintf(buf, sizeof(buf), fmt, va); + sclp_print(buf); + va_end(va); + } diff --git a/s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch b/s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch new file mode 100644 index 0000000..29107f3 --- /dev/null +++ b/s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch @@ -0,0 +1,51 @@ +Subject: [PATCH] [BZ 184174] zpcictl: Rename misleading sysfs_write_data +From: Jan Hoeppner + +Description: zpcictl: Initiate recover after reset +Symptom: If a PCI function is reset using zpcictl --reset, the function + is in an error state. +Problem: zpcictl --reset only issues a SCLP reset and leaves the PCI + function in an error state. +Solution: Initiate an OS level recovery by calling + /sys/bus/devices//recover after the SCLP reset. +Reproduction: Call zpcictl --reset + Under z/VM check the state of the function with 'vmcp q pcif' +Upstream-ID: d77234ddb68719819c7e8380c71dbebc555539ab +Problem-ID: 184174 + +Upstream-Description: + + zpcictl: Rename misleading sysfs_write_data + + To sysfs_report_error as it only writes to the report_error attribute. + + Signed-off-by: Niklas Schnelle + Reviewed-by: Jan Hoeppner + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Jan Hoeppner +--- + zpcictl/zpcictl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/zpcictl/zpcictl.c ++++ b/zpcictl/zpcictl.c +@@ -183,7 +183,7 @@ static void sysfs_write_value(struct zpc + free(path); + } + +-static void sysfs_write_data(struct zpci_report_error *report, char *slot) ++static void sysfs_report_error(struct zpci_report_error *report, char *slot) + { + size_t r_size; + char *path; +@@ -308,7 +308,7 @@ static void sclp_issue_action(struct zpc + sizeof(report.data.log_data)); + free(sdata); + } +- sysfs_write_data(&report, pdev->slot); ++ sysfs_report_error(&report, pdev->slot); + } + + /* diff --git a/s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch b/s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch new file mode 100644 index 0000000..d6b9a30 --- /dev/null +++ b/s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch @@ -0,0 +1,236 @@ +Subject: [PATCH] [BZ 184060] zipl/libc: Replace sprintf with snprintf +From: Philipp Rudo + +Description: zipl/libc: Fix potential buffer overflow in printf +Symptom: Crash of the zipl boot loader during boot. +Problem: The zipl boot loaders have their own minimalistic libc + implementation. In it printf and sprintf use vsprintf for string + formatting. Per definition vsprintf assumes that the buffer it + writes to is large enough to contain the formatted string and + performs no size checks. This is problematic for the boot + loaders because the buffer they use are often allocated on the + stack. Thus even small changes to the string format can + potentially cause buffer overflows on the stack. +Solution: Implement vsnprintf and make use of it. +Reproduction: Use printf to print a string with >81 characters (exact number + depends on the stack layout/compiler used). +Upstream-ID: f7430027b41d5ad6220e962a179c2a5213330a44 +Problem-ID: 184060 + +Upstream-Description: + + zipl/libc: Replace sprintf with snprintf + + The use of sprintf can easily result in buffer overflows as it assumes + that the buffer it writes to is large enough to contain the formatted + string. Thus replace sprintf by snprintf and update its users. + + This removes the last user of vsprintf. Thus also remove vsprintf and + its dependencies. + + Signed-off-by: Philipp Rudo + Reviewed-by: Marc Hartmayer + Reviewed-by: Stefan Haberland + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Philipp Rudo +--- + zipl/boot/libc.c | 132 +------------------------------------------------- + zipl/boot/libc.h | 3 - + zipl/boot/menu.c | 2 + zipl/boot/tape2dump.c | 2 + 4 files changed, 6 insertions(+), 133 deletions(-) + +--- a/zipl/boot/libc.c ++++ b/zipl/boot/libc.c +@@ -126,81 +126,6 @@ int strncmp(const char *s1, const char * + } + + /* +- * Convert number to string +- * +- * Parameters: +- * +- * - buf: Output buffer +- * - base: Base used for formatting (e.g. 10 or 16) +- * - val: Number to format +- * - zero: If > 0, fill with leading zeros, otherwise use blanks +- * - count: Minimum number of characters used for output string +- */ +-static int num_to_str(char *buf, int base, unsigned long val, int zero, +- unsigned long count) +-{ +- static const char conv_vec[] = {'0', '1', '2', '3', '4', '5', '6', '7', +- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; +- unsigned long num = 0, val_work = val, in_number = 1; +- int i; +- +- /* Count number of characters needed for number */ +- do { +- num++; +- val_work /= base; +- } while (val_work); +- /* Real character number overwrites count */ +- if (count < num) +- count = num; +- /* Format number */ +- for (i = count - 1; i >= 0; i--) { +- if (in_number) { +- buf[i] = conv_vec[val % base]; +- val /= base; +- in_number = val ? 1 : 0; +- } else { +- buf[i] = zero ? '0' : ' '; +- } +- } +- buf[count] = 0; +- return count; +-} +- +-/* +- * Convert string to string with indentation +- */ +-static int str_to_str(char *buf, const char *str, unsigned long count) +-{ +- unsigned long size; +- +- size = strlen(str); +- if (count < size) +- count = size; +- else +- memset(buf, ' ', count - size); +- strcpy(buf + (count - size), str); +- return count; +-} +- +-/* +- * Convert string to number with given base +- */ +-unsigned long strtoul(const char *nptr, char **endptr, int base) +-{ +- unsigned long val = 0; +- +- while (isdigit(*nptr)) { +- if (val != 0) +- val *= base; +- val += *nptr - '0'; +- nptr++; +- } +- if (endptr) +- *endptr = (char *) nptr; +- return val; +-} +- +-/* + * Convert ebcdic string to number with given base + */ + unsigned long ebcstrtoul(char *nptr, char **endptr, int base) +@@ -467,65 +392,14 @@ static int vsnprintf(char *buf, unsigned + } + + /* +- * Convert string to number with given base +- */ +-static int sprintf_fmt(char type, char *buf, unsigned long val, int zero, +- int count) +-{ +- switch (type) { +- case 's': +- return str_to_str(buf, (const char *) val, count); +- case 'x': +- return num_to_str(buf, 16, val, zero, count); +- case 'u': +- return num_to_str(buf, 10, val, zero, count); +- default: +- libc_stop(EINTERNAL); +- } +- return 0; +-} +- +-/* +- * Print formated string (va version) +- */ +-static void vsprintf(char *str, const char *fmt, va_list va) +-{ +- unsigned long val, zero, count; +- char *fmt_next; +- +- do { +- if (*fmt == '%') { +- fmt++; +- if (*fmt == '0') { +- zero = 1; +- fmt++; +- } else { +- zero = 0; +- } +- /* No number found by strtoul: count=0 fmt_next=fmt */ +- count = strtoul(fmt, &fmt_next, 10); +- fmt = fmt_next; +- if (*fmt == 'l') +- fmt++; +- val = va_arg(va, unsigned long); +- str += sprintf_fmt(*fmt, str, val, zero, count); +- fmt++; +- } else { +- *str++ = *fmt++; +- } +- } while (*fmt); +- *str = 0; +-} +- +-/* +- * Write formated string to string ++ * Write formatted string to buffer + */ +-void sprintf(char *str, const char *fmt, ...) ++void snprintf(char *buf, unsigned long size, const char *fmt, ...) + { + va_list va; + + va_start(va, fmt); +- vsprintf(str, fmt, va); ++ vsnprintf(buf, size, fmt, va); + va_end(va); + } + +--- a/zipl/boot/libc.h ++++ b/zipl/boot/libc.h +@@ -47,13 +47,12 @@ typedef unsigned short uint16_t; + typedef unsigned char uint8_t; + + void printf(const char *, ...); +-void sprintf(char *, const char *, ...); ++void snprintf(char *buf, unsigned long size, const char *fmt, ...); + void *memcpy(void *, const void *, unsigned long); + void *memmove(void *, const void *, unsigned long); + void *memset(void *, int c, unsigned long); + char *strcat(char *, const char *); + int strncmp(const char *, const char *, unsigned long); +-unsigned long strtoul(const char *, char **, int); + unsigned long ebcstrtoul(char *, char **, int); + int strlen(const char *); + char *strcpy(char *, const char *); +--- a/zipl/boot/menu.c ++++ b/zipl/boot/menu.c +@@ -189,7 +189,7 @@ boot: + (void *)&__stage2_params + TEXT_OFFSET)); + + /* append 'BOOT_IMAGE=' to parmline */ +- sprintf(endstring, " BOOT_IMAGE=%u", value); ++ snprintf(endstring, sizeof(endstring), " BOOT_IMAGE=%u", value); + if ((strlen(cmd_line_extra) + strlen(endstring)) < COMMAND_LINE_SIZE) + strcat(cmd_line_extra, endstring); + +--- a/zipl/boot/tape2dump.c ++++ b/zipl/boot/tape2dump.c +@@ -186,7 +186,7 @@ static void progress_print_disp(unsigned + + if (addr % (1024 * 1024 * 16) != 0) + return; +- sprintf(msg, "%08u", addr >> 20); ++ snprintf(msg, sizeof(msg), "%08u", addr >> 20); + ccw_load_display(msg); + } + diff --git a/s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch b/s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch new file mode 100644 index 0000000..6580a79 --- /dev/null +++ b/s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch @@ -0,0 +1,119 @@ +Subject: [PATCH] [BZ 184174] zpcitctl: Exit on error in sysfs_report_error +From: Jan Hoeppner + +Description: zpcictl: Initiate recover after reset +Symptom: If a PCI function is reset using zpcictl --reset, the function + is in an error state. +Problem: zpcictl --reset only issues a SCLP reset and leaves the PCI + function in an error state. +Solution: Initiate an OS level recovery by calling + /sys/bus/devices//recover after the SCLP reset. +Reproduction: Call zpcictl --reset + Under z/VM check the state of the function with 'vmcp q pcif' +Upstream-ID: 304c3d8086bc2a9230c5404f9c9fec72de08d229 +Problem-ID: 184174 + +Upstream-Description: + + zpcitctl: Exit on error in sysfs_report_error + + This also makes sure that we don't try to write to the + /sys/bus/pci/device//recover attribute if reset failed. + + Signed-off-by: Niklas Schnelle + Reviewed-by: Jan Hoeppner + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Jan Hoeppner +--- + zpcictl/zpcictl.c | 55 +++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 38 insertions(+), 17 deletions(-) + +--- a/zpcictl/zpcictl.c ++++ b/zpcictl/zpcictl.c +@@ -97,6 +97,35 @@ static void fopen_err(char *path) + exit(EXIT_FAILURE); + } + ++static void fclose_err(char *path) ++{ ++ if (errno == EIO || errno == EOPNOTSUPP) ++ warnx("Unsupported operation: %s: %s", path, strerror(errno)); ++ else ++ warnx("Could not close file: %s: %s", path, strerror(errno)); ++ free(path); ++ exit(EXIT_FAILURE); ++ ++} ++ ++static void fread_err(FILE *fp, char *path) ++{ ++ warnx("Could not read file: %s: %s", path, strerror(errno)); ++ if (fclose(fp)) ++ fclose_err(path); ++ free(path); ++ exit(EXIT_FAILURE); ++} ++ ++static void fwrite_err(FILE *fp, char *path) ++{ ++ warnx("Could not write to file: %s: %s", path, strerror(errno)); ++ if (fclose(fp)) ++ fclose_err(path); ++ free(path); ++ exit(EXIT_FAILURE); ++} ++ + #define READ_CHUNK_SIZE 512 + + static char *collect_smart_data(struct zpci_device *pdev) +@@ -152,12 +181,10 @@ static unsigned int sysfs_read_value(str + if (!fp) + fopen_err(path); + if (fscanf(fp, "%x", &val) != 1) { +- fclose(fp); +- warnx("Could not read file %s: %s", path, strerror(errno)); +- free(path); +- exit(EXIT_FAILURE); ++ fread_err(fp, path); + } +- fclose(fp); ++ if (fclose(fp)) ++ fclose_err(path); + free(path); + + return val; +@@ -174,12 +201,10 @@ static void sysfs_write_value(struct zpc + if (!fp) + fopen_err(path); + if (fprintf(fp, "%x", val) < 0) { +- fclose(fp); +- warnx("Could not write to file %s: %s", path, strerror(errno)); +- free(path); +- exit(EXIT_FAILURE); ++ fwrite_err(fp, path); + } +- fclose(fp); ++ if (fclose(fp)) ++ fclose_err(path); + free(path); + } + +@@ -196,13 +221,9 @@ static void sysfs_report_error(struct zp + if (!fp) + fopen_err(path); + if (fwrite(report, 1, r_size, fp) != r_size) +- warnx("Could not write to file: %s: %s", path, strerror(errno)); +- if (fclose(fp)) { +- if (errno == EIO || errno == EOPNOTSUPP) +- warnx("Unsupported operation: %s: %s", path, strerror(errno)); +- else +- warnx("Could not close file: %s: %s", path, strerror(errno)); +- } ++ fwrite_err(fp, path); ++ if (fclose(fp)) ++ fclose_err(path); + free(path); + } + diff --git a/s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch b/s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch new file mode 100644 index 0000000..608931a --- /dev/null +++ b/s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch @@ -0,0 +1,82 @@ +Subject: [PATCH] [BZ 184060] zipl/libc: Indicate truncated lines in printf with '...' +From: Philipp Rudo + +Description: zipl/libc: Fix potential buffer overflow in printf +Symptom: Crash of the zipl boot loader during boot. +Problem: The zipl boot loaders have their own minimalistic libc + implementation. In it printf and sprintf use vsprintf for string + formatting. Per definition vsprintf assumes that the buffer it + writes to is large enough to contain the formatted string and + performs no size checks. This is problematic for the boot + loaders because the buffer they use are often allocated on the + stack. Thus even small changes to the string format can + potentially cause buffer overflows on the stack. +Solution: Implement vsnprintf and make use of it. +Reproduction: Use printf to print a string with >81 characters (exact number + depends on the stack layout/compiler used). +Upstream-ID: 36fed0e6c6590631c4ce1707c8fe3c3397bcce4d +Problem-ID: 184060 + +Upstream-Description: + + zipl/libc: Indicate truncated lines in printf with '...' + + Append '...' to lines exceeding the maximum line length instead of + silently truncating them. + + Suggested-by: Marc Hartmayer + Signed-off-by: Philipp Rudo + Reviewed-by: Marc Hartmayer + Reviewed-by: Stefan Haberland + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Philipp Rudo +--- + zipl/boot/libc.c | 10 ++++++++-- + zipl/boot/libc.h | 1 + + zipl/boot/menu.h | 1 - + 3 files changed, 9 insertions(+), 3 deletions(-) + +--- a/zipl/boot/libc.c ++++ b/zipl/boot/libc.c +@@ -408,11 +408,17 @@ void snprintf(char *buf, unsigned long s + */ + void printf(const char *fmt, ...) + { +- char buf[81]; ++ char buf[LINE_LENGTH + 1]; ++ int len; + va_list va; + + va_start(va, fmt); +- vsnprintf(buf, sizeof(buf), fmt, va); ++ len = vsnprintf(buf, sizeof(buf), fmt, va); ++ if (len > LINE_LENGTH) { ++ buf[LINE_LENGTH - 1] = '.'; ++ buf[LINE_LENGTH - 2] = '.'; ++ buf[LINE_LENGTH - 3] = '.'; ++ } + sclp_print(buf); + va_end(va); + } +--- a/zipl/boot/libc.h ++++ b/zipl/boot/libc.h +@@ -40,6 +40,7 @@ + #define ENOTTY 25 /* Not a typewriter */ + + #define MIB (1024ULL * 1024) ++#define LINE_LENGTH 80 /* max line length printed by printf */ + + typedef unsigned long long uint64_t; + typedef unsigned int uint32_t; +--- a/zipl/boot/menu.h ++++ b/zipl/boot/menu.h +@@ -20,7 +20,6 @@ + /* max command line length */ + #define COMMAND_LINE_SIZE 896 + #define BOOT_MENU_ENTRIES 63 +-#define LINE_LENGTH 80 + #define PARAM_SIZE 8 + #define TEXT_OFFSET 4 + diff --git a/s390-tools.changes b/s390-tools.changes index 9b010a3..6c7672b 100644 --- a/s390-tools.changes +++ b/s390-tools.changes @@ -1,3 +1,25 @@ +------------------------------------------------------------------- +Tue Mar 10 18:25:51 UTC 2020 - Mark Post + +- Added the following patches for bsc#1165978. + zpcictl --reset only issues a SCLP reset and leaves the PCI function + in an error state. + Initiate an OS level recovery by calling /sys/bus/devices//recover + after the SCLP reset. + * s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch + * s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch + * s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch + +------------------------------------------------------------------- +Tue Mar 3 22:11:44 UTC 2020 - Mark Post + +- The zipl boot loader may crash during boot. The solution is to + implement vsnprintf and make use of it. (bsc#1165317) + * s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch + * s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch + * s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch + * s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch + ------------------------------------------------------------------- Tue Feb 18 20:10:50 UTC 2020 - Mark Post diff --git a/s390-tools.spec b/s390-tools.spec index 74546bb..56d2910 100644 --- a/s390-tools.spec +++ b/s390-tools.spec @@ -1,7 +1,7 @@ # # spec file for package s390-tools # -# Copyright (c) 2009-2020 SUSE LLC, Nuernberg, Germany. +# Copyright (c) 2001-2020 SUSE LLC, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -128,6 +128,13 @@ Patch38: s390-tools-sles15sp2-zkey-Fix-listing-of-keys-on-file-systems-re Patch39: s390-tools-sles15sp2-zkey-Fix-display-of-clear-key-size-for-XTS-keys.patch Patch40: s390-tools-sles15sp2-zkey-Fix-display-of-XTS-attribute-for-validate-comma.patch Patch41: s390-tools-sles15sp2-zkey-Fix-display-of-clear-key-size-for-CCA-AESCIPHER.patch +Patch42: s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch +Patch43: s390-tools-sles15sp2-02-zipl-libc-Fix-potential-buffer-overflow-in-printf.patch +Patch44: s390-tools-sles15sp2-03-zipl-libc-Replace-sprintf-with-snprintf.patch +Patch45: s390-tools-sles15sp2-04-zipl-libc-Indicate-truncated-lines-in-printf-with.patch +Patch46: s390-tools-sles15sp2-01-zpcictl-Initiate-recover-after-reset.patch +Patch47: s390-tools-sles15sp2-02-zpcictl-Rename-misleading-sysfs_write_data.patch +Patch48: s390-tools-sles15sp2-03-zpcitctl-Exit-on-error-in-sysfs_report_error.patch # SUSE patches Patch900: s390-tools-sles12-zipl_boot_msg.patch