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/<dev>/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
This commit is contained in:
Mark Post 2020-03-10 19:03:33 +00:00 committed by Git OBS Bridge
parent 9d48c28fee
commit 7230df2ed5
9 changed files with 970 additions and 1 deletions

View File

@ -0,0 +1,319 @@
Subject: [PATCH] [BZ 184060] zipl/libc: Introduce vsnprintf
From: Philipp Rudo <prudo@linux.ibm.com>
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 <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
---
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
*/

View File

@ -0,0 +1,70 @@
Subject: [PATCH] [BZ 184174] zpcictl: Initiate recover after reset
From: Jan Hoeppner <hoeppner@linux.ibm.com>
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/<dev>/recover after the SCLP reset.
Reproduction: Call zpcictl --reset <dev>
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/<dev>/recover.
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
---
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);
}
/*

View File

@ -0,0 +1,63 @@
Subject: [PATCH] [BZ 184060] zipl/libc: Fix potential buffer overflow in printf
From: Philipp Rudo <prudo@linux.ibm.com>
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 <mhartmay@linux.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
---
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);
}

View File

@ -0,0 +1,51 @@
Subject: [PATCH] [BZ 184174] zpcictl: Rename misleading sysfs_write_data
From: Jan Hoeppner <hoeppner@linux.ibm.com>
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/<dev>/recover after the SCLP reset.
Reproduction: Call zpcictl --reset <dev>
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 <schnelle@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
---
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);
}
/*

View File

@ -0,0 +1,236 @@
Subject: [PATCH] [BZ 184060] zipl/libc: Replace sprintf with snprintf
From: Philipp Rudo <prudo@linux.ibm.com>
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 <prudo@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
---
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=<num>' 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);
}

View File

@ -0,0 +1,119 @@
Subject: [PATCH] [BZ 184174] zpcitctl: Exit on error in sysfs_report_error
From: Jan Hoeppner <hoeppner@linux.ibm.com>
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/<dev>/recover after the SCLP reset.
Reproduction: Call zpcictl --reset <dev>
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/<dev>/recover attribute if reset failed.
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
---
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);
}

View File

@ -0,0 +1,82 @@
Subject: [PATCH] [BZ 184060] zipl/libc: Indicate truncated lines in printf with '...'
From: Philipp Rudo <prudo@linux.ibm.com>
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 <mhartmay@linux.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
---
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

View File

@ -1,3 +1,25 @@
-------------------------------------------------------------------
Tue Mar 10 18:25:51 UTC 2020 - Mark Post <mpost@suse.com>
- 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/<dev>/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 <mpost@suse.com>
- 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 <mpost@suse.com>

View File

@ -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