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:
parent
9d48c28fee
commit
7230df2ed5
319
s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch
Normal file
319
s390-tools-sles15sp2-01-zipl-libc-Introduce-vsnprintf.patch
Normal 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
|
||||
*/
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user