import kexec-tools-2.0.20-69.el8

This commit is contained in:
CentOS Sources 2022-05-07 10:10:55 +00:00 committed by Stepan Oksanichenko
parent dd532a4e63
commit dbf4d4a69b
11 changed files with 1144 additions and 1 deletions

View File

@ -0,0 +1,191 @@
commit feae3d1754d2b0788ce1f18b0cd4b40098ff52ff
Author: Philipp Rudo <prudo@redhat.com>
Date: Mon Mar 14 17:04:29 2022 +0100
[PATCH v2 1/3] add generic cycle detection
In order to work makedumpfile needs to interpret data read from the
dump. This can cause problems as the data from the dump cannot be
trusted (otherwise the kernel wouldn't have panicked in the first
place). This also means that every loop which stop condition depend on
data read from the dump has a chance to loop forever. Thus add a generic
cycle detection mechanism that allows to detect and handle such
situations appropriately.
For cycle detection use Brent's algorithm [1] as it has constant memory
usage. With this it can also be used in the kdump kernel without the
danger that it runs oom when iterating large data structures.
Furthermore it only depends on some pointer arithmetic. Thus the
performance impact (as long as no cycle was detected) should be
comparatively small.
[1] https://en.wikipedia.org/wiki/Cycle_detection#Brent's_algorithm
Suggested-by: Dave Wysochanski <dwysocha@redhat.com>
Signed-off-by: Philipp Rudo <prudo@redhat.com>
Reviewed-and-tested-by: Dave Wysochanski <dwysocha@redhat.com>
diff --git a/makedumpfile-1.7.0/Makefile b/makedumpfile-1.7.0/Makefile
index f118b31e45989d9590ae075fb9b8ed2f27353a92..3441364cb6c7103a20072bd50ec58f1eed01ab69 100644
--- a/makedumpfile-1.7.0/Makefile
+++ b/makedumpfile-1.7.0/Makefile
@@ -45,7 +45,7 @@ CFLAGS_ARCH += -m32
endif
SRC_BASE = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info.h
-SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c
+SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c detect_cycle.c
OBJ_PART=$(patsubst %.c,%.o,$(SRC_PART))
SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c
OBJ_ARCH=$(patsubst %.c,%.o,$(SRC_ARCH))
diff --git a/makedumpfile-1.7.0/detect_cycle.c b/makedumpfile-1.7.0/detect_cycle.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b551a75d1c83d64fba2c078be8133efbc791fbe
--- /dev/null
+++ b/makedumpfile-1.7.0/detect_cycle.c
@@ -0,0 +1,99 @@
+/*
+ * detect_cycle.c -- Generic cycle detection using Brent's algorithm
+ *
+ * Created by: Philipp Rudo <prudo@redhat.com>
+ *
+ * Copyright (c) 2022 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdlib.h>
+
+#include "detect_cycle.h"
+
+struct detect_cycle {
+ /* First entry of the list */
+ void *head;
+
+ /* Variables required by Brent's algorithm */
+ void *fast_p;
+ void *slow_p;
+ unsigned long length;
+ unsigned long power;
+
+ /* Function to get the next entry in the list */
+ dc_next_t next;
+
+ /* Private data passed to next */
+ void *data;
+};
+
+struct detect_cycle *dc_init(void *head, void *data, dc_next_t next)
+{
+ struct detect_cycle *new;
+
+ new = malloc(sizeof(*new));
+ if (!new)
+ return NULL;
+
+ new->next = next;
+ new->data = data;
+
+ new->head = head;
+ new->slow_p = head;
+ new->fast_p = head;
+ new->length = 0;
+ new->power = 2;
+
+ return new;
+}
+
+int dc_next(struct detect_cycle *dc, void **next)
+{
+
+ if (dc->length == dc->power) {
+ dc->length = 0;
+ dc->power *= 2;
+ dc->slow_p = dc->fast_p;
+ }
+
+ dc->fast_p = dc->next(dc->fast_p, dc->data);
+ dc->length++;
+
+ if (dc->slow_p == dc->fast_p)
+ return 1;
+
+ *next = dc->fast_p;
+ return 0;
+}
+
+void dc_find_start(struct detect_cycle *dc, void **first, unsigned long *len)
+{
+ void *slow_p, *fast_p;
+ unsigned long tmp;
+
+ slow_p = fast_p = dc->head;
+ tmp = dc->length;
+
+ while (tmp) {
+ fast_p = dc->next(fast_p, dc->data);
+ tmp--;
+ }
+
+ while (slow_p != fast_p) {
+ slow_p = dc->next(slow_p, dc->data);
+ fast_p = dc->next(fast_p, dc->data);
+ }
+
+ *first = slow_p;
+ *len = dc->length;
+}
diff --git a/makedumpfile-1.7.0/detect_cycle.h b/makedumpfile-1.7.0/detect_cycle.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ca75c78b59a98274fc5a98666b1be74f7bbfc2c
--- /dev/null
+++ b/makedumpfile-1.7.0/detect_cycle.h
@@ -0,0 +1,40 @@
+/*
+ * detect_cycle.h -- Generic cycle detection using Brent's algorithm
+ *
+ * Created by: Philipp Rudo <prudo@redhat.com>
+ *
+ * Copyright (c) 2022 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+struct detect_cycle;
+
+typedef void *(*dc_next_t)(void *prev, void *data);
+
+/*
+ * Initialize cycle detection.
+ * Returns a pointer to allocated struct detect_cycle. The caller is
+ * responsible to free the memory after use.
+ */
+struct detect_cycle *dc_init(void *head, void *data, dc_next_t next);
+
+/*
+ * Get next entry in the list using dc->next.
+ * Returns 1 when cycle was detected, 0 otherwise.
+ */
+int dc_next(struct detect_cycle *dc, void **next);
+
+/*
+ * Get the start and length of the cycle. Must only be called after cycle was
+ * detected by dc_next.
+ */
+void dc_find_start(struct detect_cycle *dc, void **first, unsigned long *len);

View File

@ -0,0 +1,216 @@
commit defb80a20bf1e4d778596ce2447e19d44f31ae5a
Author: Sven Schnelle <svens@linux.ibm.com>
Date: Thu Dec 16 12:43:52 2021 +0100
s390: add variable command line size
Newer s390 kernels support a command line size longer than 896
bytes. Such kernels contain a new member in the parameter area,
which might be utilized by tools like kexec. Older kernels have
the location initialized to zero, so we check whether there's a
non-zero number present and use that. If there isn't, we fallback
to the legacy command line size of 896 bytes.
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/kexec/arch/s390/crashdump-s390.c b/kexec/arch/s390/crashdump-s390.c
index 10f4d607bbcc1aea362de3de687b0e7b2401d879..3bd9efe6dafebab2f364c656ae703c71c4494c35 100644
--- a/kexec/arch/s390/crashdump-s390.c
+++ b/kexec/arch/s390/crashdump-s390.c
@@ -52,7 +52,8 @@ static int create_elf_header(struct kexec_info *info, unsigned long crash_base,
elfcorehdr_size = bufsz;
snprintf(str, sizeof(str), " elfcorehdr=%ld@%ldK\n",
elfcorehdr_size, elfcorehdr / 1024);
- command_line_add(str);
+ if (command_line_add(info, str))
+ return -1;
#endif
return 0;
}
diff --git a/kexec/arch/s390/kexec-image.c b/kexec/arch/s390/kexec-image.c
index 3c24fdfe3c7ccafddee9fb4a68c0d8874cf6a61e..a52399eafd2abd4a24142f0512251598ea812ca5 100644
--- a/kexec/arch/s390/kexec-image.c
+++ b/kexec/arch/s390/kexec-image.c
@@ -25,7 +25,6 @@
#include <fcntl.h>
static uint64_t crash_base, crash_end;
-static char command_line[COMMAND_LINESIZE];
static void add_segment_check(struct kexec_info *info, const void *buf,
size_t bufsz, unsigned long base, size_t memsz)
@@ -36,13 +35,18 @@ static void add_segment_check(struct kexec_info *info, const void *buf,
add_segment(info, buf, bufsz, crash_base + base, memsz);
}
-int command_line_add(const char *str)
+int command_line_add(struct kexec_info *info, const char *str)
{
- if (strlen(command_line) + strlen(str) + 1 > COMMAND_LINESIZE) {
- fprintf(stderr, "Command line too long.\n");
+ char *tmp = NULL;
+
+ tmp = concat_cmdline(info->command_line, str);
+ if (!tmp) {
+ fprintf(stderr, "out of memory\n");
return -1;
}
- strcat(command_line, str);
+
+ free(info->command_line);
+ info->command_line = tmp;
return 0;
}
@@ -64,7 +68,7 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch(opt) {
case OPT_APPEND:
- if (command_line_add(optarg))
+ if (command_line_add(info, optarg))
return -1;
break;
case OPT_RAMDISK:
@@ -78,13 +82,16 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
if (info->initrd_fd == -1) {
fprintf(stderr, "Could not open initrd file %s:%s\n",
ramdisk, strerror(errno));
+ free(info->command_line);
+ info->command_line = NULL;
return -1;
}
}
- info->command_line = command_line;
- info->command_line_len = strlen (command_line) + 1;
-
+ if (info->command_line)
+ info->command_line_len = strlen(info->command_line) + 1;
+ else
+ info->command_line_len = 0;
return 0;
}
@@ -97,7 +104,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
const char *ramdisk;
off_t ramdisk_len;
unsigned int ramdisk_origin;
- int opt;
+ int opt, ret = -1;
if (info->file_mode)
return image_s390_load_file(argc, argv, info);
@@ -120,7 +126,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
while ((opt = getopt_long(argc,argv,short_options,options,0)) != -1) {
switch(opt) {
case OPT_APPEND:
- if (command_line_add(optarg))
+ if (command_line_add(info, optarg))
return -1;
break;
case OPT_RAMDISK:
@@ -132,7 +138,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
if (info->kexec_flags & KEXEC_ON_CRASH) {
if (parse_iomem_single("Crash kernel\n", &crash_base,
&crash_end))
- return -1;
+ goto out;
}
/* Add kernel segment */
@@ -151,7 +157,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
rd_buffer = slurp_file_mmap(ramdisk, &ramdisk_len);
if (rd_buffer == NULL) {
fprintf(stderr, "Could not read ramdisk.\n");
- return -1;
+ goto out;
}
ramdisk_origin = MAX(RAMDISK_ORIGIN_ADDR, kernel_size);
ramdisk_origin = _ALIGN_UP(ramdisk_origin, 0x100000);
@@ -160,7 +166,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
}
if (info->kexec_flags & KEXEC_ON_CRASH) {
if (load_crashdump_segments(info, crash_base, crash_end))
- return -1;
+ goto out;
} else {
info->entry = (void *) IMAGE_READ_OFFSET;
}
@@ -183,15 +189,28 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
*tmp = crash_end - crash_base + 1;
}
}
- /*
- * We will write a probably given command line.
- * First, erase the old area, then setup the new parameters:
- */
- if (strlen(command_line) != 0) {
- memset(krnl_buffer + COMMAND_LINE_OFFS, 0, COMMAND_LINESIZE);
- memcpy(krnl_buffer + COMMAND_LINE_OFFS, command_line, strlen(command_line));
+
+ if (info->command_line) {
+ unsigned long maxsize;
+ char *dest = krnl_buffer + COMMAND_LINE_OFFS;
+
+ maxsize = *(unsigned long *)(krnl_buffer + MAX_COMMAND_LINESIZE_OFFS);
+ if (!maxsize)
+ maxsize = LEGACY_COMMAND_LINESIZE;
+
+ if (strlen(info->command_line) > maxsize-1) {
+ fprintf(stderr, "command line too long, maximum allowed size %ld\n",
+ maxsize-1);
+ goto out;
+ }
+ strncpy(dest, info->command_line, maxsize-1);
+ dest[maxsize-1] = '\0';
}
- return 0;
+ ret = 0;
+out:
+ free(info->command_line);
+ info->command_line = NULL;
+ return ret;
}
int
diff --git a/kexec/arch/s390/kexec-s390.h b/kexec/arch/s390/kexec-s390.h
index ef53b111e16719d15e5364c18435e272f98b9086..6a99518c1c9e411ed853489daf0de6463972ab6f 100644
--- a/kexec/arch/s390/kexec-s390.h
+++ b/kexec/arch/s390/kexec-s390.h
@@ -10,16 +10,17 @@
#ifndef KEXEC_S390_H
#define KEXEC_S390_H
-#define IMAGE_READ_OFFSET 0x10000
+#define IMAGE_READ_OFFSET 0x10000
-#define RAMDISK_ORIGIN_ADDR 0x800000
-#define INITRD_START_OFFS 0x408
-#define INITRD_SIZE_OFFS 0x410
-#define OLDMEM_BASE_OFFS 0x418
-#define OLDMEM_SIZE_OFFS 0x420
-#define COMMAND_LINE_OFFS 0x480
-#define COMMAND_LINESIZE 896
-#define MAX_MEMORY_RANGES 1024
+#define RAMDISK_ORIGIN_ADDR 0x800000
+#define INITRD_START_OFFS 0x408
+#define INITRD_SIZE_OFFS 0x410
+#define OLDMEM_BASE_OFFS 0x418
+#define OLDMEM_SIZE_OFFS 0x420
+#define MAX_COMMAND_LINESIZE_OFFS 0x430
+#define COMMAND_LINE_OFFS 0x480
+#define LEGACY_COMMAND_LINESIZE 896
+#define MAX_MEMORY_RANGES 1024
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -32,6 +33,6 @@ extern int load_crashdump_segments(struct kexec_info *info,
unsigned long crash_end);
extern int get_memory_ranges_s390(struct memory_range range[], int *ranges,
int with_crashk);
-extern int command_line_add(const char *str);
+extern int command_line_add(struct kexec_info *info, const char *str);
#endif /* KEXEC_S390_H */

View File

@ -0,0 +1,102 @@
commit e1d2e5302b016c6f7942f46ffa27aa31326686c5
Author: Philipp Rudo <prudo@redhat.com>
Date: Mon Mar 14 17:04:30 2022 +0100
[PATCH v2 2/3] use pointer arithmetics for dump_dmesg
When parsing the printk buffer for the old printk mechanism (> v3.5.0+ and
< 5.10.0) a log entry is currently specified by the offset into the
buffer where the entry starts. Change this to use a pointers instead.
This is done in preparation for using the new cycle detection mechanism.
Signed-off-by: Philipp Rudo <prudo@redhat.com>
Reviewed-and-tested-by: Dave Wysochanski <dwysocha@redhat.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
diff --git a/makedumpfile-1.7.0/makedumpfile.c b/makedumpfile-1.7.0/makedumpfile.c
index 7ed9756a8c43ae4a2b6770e86dc81763796c2187..e72dba219eec198ec865045562f39a14b5a092eb 100644
--- a/makedumpfile-1.7.0/makedumpfile.c
+++ b/makedumpfile-1.7.0/makedumpfile.c
@@ -5482,13 +5482,10 @@ dump_log_entry(char *logptr, int fp, const char *file_name)
* get log record by index; idx must point to valid message.
*/
static char *
-log_from_idx(unsigned int idx, char *logbuf)
+log_from_ptr(char *logptr, char *logbuf)
{
- char *logptr;
unsigned int msglen;
- logptr = logbuf + idx;
-
/*
* A length == 0 record is the end of buffer marker.
* Wrap around and return the message at the start of
@@ -5497,19 +5494,16 @@ log_from_idx(unsigned int idx, char *logbuf)
msglen = USHORT(logptr + OFFSET(printk_log.len));
if (!msglen)
- logptr = logbuf;
+ return logbuf;
return logptr;
}
-static long
-log_next(unsigned int idx, char *logbuf)
+static void *
+log_next(void *logptr, void *logbuf)
{
- char *logptr;
unsigned int msglen;
- logptr = logbuf + idx;
-
/*
* A length == 0 record is the end of buffer marker. Wrap around and
* read the message at the start of the buffer as *this* one, and
@@ -5519,10 +5513,10 @@ log_next(unsigned int idx, char *logbuf)
msglen = USHORT(logptr + OFFSET(printk_log.len));
if (!msglen) {
msglen = USHORT(logbuf + OFFSET(printk_log.len));
- return msglen;
+ return logbuf + msglen;
}
- return idx + msglen;
+ return logptr + msglen;
}
int
@@ -5530,11 +5524,12 @@ dump_dmesg()
{
int log_buf_len, length_log, length_oldlog, ret = FALSE;
unsigned long index, log_buf, log_end;
- unsigned int idx, log_first_idx, log_next_idx;
+ unsigned int log_first_idx, log_next_idx;
unsigned long long first_idx_sym;
unsigned long log_end_2_6_24;
unsigned log_end_2_6_25;
char *log_buffer = NULL, *log_ptr = NULL;
+ char *ptr;
/*
* log_end has been changed to "unsigned" since linux-2.6.25.
@@ -5681,13 +5676,13 @@ dump_dmesg()
ERRMSG("Can't open output file.\n");
goto out;
}
- idx = log_first_idx;
- while (idx != log_next_idx) {
- log_ptr = log_from_idx(idx, log_buffer);
+ ptr = log_buffer + log_first_idx;
+ while (ptr != log_buffer + log_next_idx) {
+ log_ptr = log_from_ptr(ptr, log_buffer);
if (!dump_log_entry(log_ptr, info->fd_dumpfile,
info->name_dumpfile))
goto out;
- idx = log_next(idx, log_buffer);
+ ptr = log_next(ptr, log_buffer);
}
if (!close_files_for_creating_dumpfile())
goto out;

View File

@ -0,0 +1,43 @@
commit 91a3d0e00a5c18ee9bdd2c6c03ac64a6471e2559
Author: Sven Schnelle <svens@linux.ibm.com>
Date: Thu Dec 16 12:43:53 2021 +0100
s390: use KEXEC_ALL_OPTIONS
KEXEC_ALL_OPTIONS could be used instead defining the same
array several times. This makes code easier to maintain when
new options are added.
Suggested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/kexec/arch/s390/kexec-image.c b/kexec/arch/s390/kexec-image.c
index a52399eafd2abd4a24142f0512251598ea812ca5..209ab77ddccbd60f10989e2d9fc273324aefa76d 100644
--- a/kexec/arch/s390/kexec-image.c
+++ b/kexec/arch/s390/kexec-image.c
@@ -57,10 +57,7 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
static const struct option options[] =
{
- KEXEC_OPTIONS
- {"command-line", 1, 0, OPT_APPEND},
- {"append", 1, 0, OPT_APPEND},
- {"initrd", 1, 0, OPT_RAMDISK},
+ KEXEC_ALL_OPTIONS
{0, 0, 0, 0},
};
static const char short_options[] = KEXEC_OPT_STR "";
@@ -111,10 +108,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
static const struct option options[] =
{
- KEXEC_OPTIONS
- {"command-line", 1, 0, OPT_APPEND},
- {"append", 1, 0, OPT_APPEND},
- {"initrd", 1, 0, OPT_RAMDISK},
+ KEXEC_ALL_OPTIONS
{0, 0, 0, 0},
};
static const char short_options[] = KEXEC_OPT_STR "";

View File

@ -0,0 +1,118 @@
commit 68d120b30af5e930afafed81e79712af3c1a278c
Author: Philipp Rudo <prudo@redhat.com>
Date: Mon Mar 14 17:04:31 2022 +0100
[PATCH v2 3/3] use cycle detection when parsing the prink log_buf
The old printk mechanism (> v3.5.0 and < v5.10.0) had a fixed size
buffer (log_buf) that contains all messages. The location for the next
message is stored in log_next_idx. In case the log_buf runs full
log_next_idx wraps around and starts overwriting old messages at the
beginning of the buffer. The wraparound is denoted by a message with
msg->len == 0.
Following the behavior described above blindly in makedumpfile is
dangerous as e.g. a memory corruption could overwrite (parts of) the
log_buf. If the corruption adds a message with msg->len == 0 this leads
to an endless loop when dumping the dmesg with makedumpfile appending
the messages up to the corruption over and over again to the output file
until file system is full. Fix this by using cycle detection and aboard
once one is detected.
While at it also verify that the index is within the log_buf and thus
guard against corruptions with msg->len != 0.
Reported-by: Audra Mitchell <aubaker@redhat.com>
Suggested-by: Dave Wysochanski <dwysocha@redhat.com>
Signed-off-by: Philipp Rudo <prudo@redhat.com>
Reviewed-and-tested-by: Dave Wysochanski <dwysocha@redhat.com>
diff --git a/makedumpfile-1.7.0/makedumpfile.c b/makedumpfile-1.7.0/makedumpfile.c
index e72dba219eec198ec865045562f39a14b5a092eb..2b94446b8f2ad513da060e15821544ae32e1a2c6 100644
--- a/makedumpfile-1.7.0/makedumpfile.c
+++ b/makedumpfile-1.7.0/makedumpfile.c
@@ -15,6 +15,7 @@
*/
#include "makedumpfile.h"
#include "print_info.h"
+#include "detect_cycle.h"
#include "dwarf_info.h"
#include "elf_info.h"
#include "erase_info.h"
@@ -5526,10 +5527,11 @@ dump_dmesg()
unsigned long index, log_buf, log_end;
unsigned int log_first_idx, log_next_idx;
unsigned long long first_idx_sym;
+ struct detect_cycle *dc = NULL;
unsigned long log_end_2_6_24;
unsigned log_end_2_6_25;
char *log_buffer = NULL, *log_ptr = NULL;
- char *ptr;
+ char *ptr, *next_ptr;
/*
* log_end has been changed to "unsigned" since linux-2.6.25.
@@ -5677,12 +5679,55 @@ dump_dmesg()
goto out;
}
ptr = log_buffer + log_first_idx;
+ dc = dc_init(ptr, log_buffer, log_next);
while (ptr != log_buffer + log_next_idx) {
log_ptr = log_from_ptr(ptr, log_buffer);
if (!dump_log_entry(log_ptr, info->fd_dumpfile,
info->name_dumpfile))
goto out;
ptr = log_next(ptr, log_buffer);
+ if (dc_next(dc, (void **) &next_ptr)) {
+ unsigned long len;
+ int in_cycle;
+ char *first;
+
+ /* Clear everything we have already written... */
+ ftruncate(info->fd_dumpfile, 0);
+ lseek(info->fd_dumpfile, 0, SEEK_SET);
+
+ /* ...and only write up to the corruption. */
+ dc_find_start(dc, (void **) &first, &len);
+ ptr = log_buffer + log_first_idx;
+ in_cycle = FALSE;
+ while (len) {
+ log_ptr = log_from_ptr(ptr, log_buffer);
+ if (!dump_log_entry(log_ptr,
+ info->fd_dumpfile,
+ info->name_dumpfile))
+ goto out;
+ ptr = log_next(ptr, log_buffer);
+
+ if (log_ptr == first)
+ in_cycle = TRUE;
+
+ if (in_cycle)
+ len--;
+ }
+ ERRMSG("Cycle when parsing dmesg detected.\n");
+ ERRMSG("The printk log_buf is most likely corrupted.\n");
+ ERRMSG("log_buf = 0x%lx, idx = 0x%lx\n", log_buf, ptr - log_buffer);
+ close_files_for_creating_dumpfile();
+ goto out;
+ }
+ if (next_ptr < log_buffer ||
+ next_ptr > log_buffer + log_buf_len - SIZE(printk_log)) {
+ ERRMSG("Index outside log_buf detected.\n");
+ ERRMSG("The printk log_buf is most likely corrupted.\n");
+ ERRMSG("log_buf = 0x%lx, idx = 0x%lx\n", log_buf, ptr - log_buffer);
+ close_files_for_creating_dumpfile();
+ goto out;
+ }
+ ptr = next_ptr;
}
if (!close_files_for_creating_dumpfile())
goto out;
@@ -5692,6 +5737,7 @@ dump_dmesg()
out:
if (log_buffer)
free(log_buffer);
+ free(dc);
return ret;
}

View File

@ -0,0 +1,76 @@
commit 193e51deccc62544f6423eb5e5eefc8a23aad679
Author: Sven Schnelle <svens@linux.ibm.com>
Date: Thu Dec 16 12:43:54 2021 +0100
add slurp_proc_file()
slurp_file() cannot be used to read proc files, as they are returning
a size of zero in stat(). Add a function slurp_proc_file() which is
similar to slurp_file(), but doesn't require the size of the file to
be known.
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/kexec/kexec.c b/kexec/kexec.c
index f63b36b771eb95a93f07a7c286c4974a558aec8d..f3adac517161d448552a16fd79488c1df100d356 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -1106,6 +1106,57 @@ static void remove_parameter(char *line, const char *param_name)
}
}
+static ssize_t _read(int fd, void *buf, size_t count)
+{
+ ssize_t ret, offset = 0;
+
+ do {
+ ret = read(fd, buf + offset, count - offset);
+ if (ret < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ return ret;
+ }
+ offset += ret;
+ } while (ret && offset < count);
+
+ return offset;
+}
+
+static char *slurp_proc_file(const char *filename, size_t *len)
+{
+ ssize_t ret, startpos = 0;
+ unsigned int size = 64;
+ char *buf = NULL, *tmp;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+
+ do {
+ size *= 2;
+ tmp = realloc(buf, size);
+ if (!tmp) {
+ free(buf);
+ return NULL;
+ }
+ buf = tmp;
+
+ ret = _read(fd, buf + startpos, size - startpos);
+ if (ret < 0) {
+ free(buf);
+ return NULL;
+ }
+
+ startpos += ret;
+
+ } while(ret);
+
+ *len = startpos;
+ return buf;
+}
+
/*
* Returns the contents of the current command line to be used with
* --reuse-cmdline option. The function gets called from architecture specific

View File

@ -0,0 +1,150 @@
commit 5035c0821f07da3badda645cd0064d4b80e1667d
Author: Philipp Rudo <prudo@redhat.com>
Date: Mon Mar 14 17:04:32 2022 +0100
[PATCH] print error when reading with unsupported compression
Currently makedumpfile only checks if the required compression algorithm
was enabled during build when compressing a dump but not when reading
from one. This can lead to situations where, one version of makedumpfile
creates the dump using a compression algorithm an other version of
makedumpfile doesn't support. When the second version now tries to, e.g.
extract the dmesg from the dump it will fail with an error similar to
# makedumpfile --dump-dmesg vmcore dmesg.txt
__vtop4_x86_64: Can't get a valid pgd.
readmem: Can't convert a virtual address(ffffffff92e18284) to physical address.
readmem: type_addr: 0, addr:ffffffff92e18284, size:390
check_release: Can't get the address of system_utsname.
makedumpfile Failed.
That's because readpage_kdump_compressed{_parallel} does not return
with an error if the page it is trying to read is compressed with an
unsupported compression algorithm. Thus readmem copies random data from
the (uninitialized) cachebuf to its caller and thus causing the error
above.
Fix this by checking if the required compression algorithm is supported
in readpage_kdump_compressed{_parallel} and print a proper error message
if it isn't.
Reported-by: Dave Wysochanski <dwysocha@redhat.com>
Signed-off-by: Philipp Rudo <prudo@redhat.com>
Reviewed-and-tested-by: Dave Wysochanski <dwysocha@redhat.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
diff --git a/makedumpfile-1.7.0/makedumpfile.c b/makedumpfile-1.7.0/makedumpfile.c
index 2b94446b8f2ad513da060e15821544ae32e1a2c6..14556db15627617cb394bba85bb7ebec6b35fb34 100644
--- a/makedumpfile-1.7.0/makedumpfile.c
+++ b/makedumpfile-1.7.0/makedumpfile.c
@@ -865,9 +865,13 @@ readpage_kdump_compressed(unsigned long long paddr, void *bufptr)
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+ } else if ((pd.flags & DUMP_DH_COMPRESSED_LZO)) {
#ifdef USELZO
- } else if (info->flag_lzo_support
- && (pd.flags & DUMP_DH_COMPRESSED_LZO)) {
+ if (!info->flag_lzo_support) {
+ ERRMSG("lzo compression unsupported\n");
+ return FALSE;
+ }
+
retlen = info->page_size;
ret = lzo1x_decompress_safe((unsigned char *)buf, pd.size,
(unsigned char *)bufptr, &retlen,
@@ -876,9 +880,13 @@ readpage_kdump_compressed(unsigned long long paddr, void *bufptr)
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+#else
+ ERRMSG("lzo compression unsupported\n");
+ ERRMSG("Try `make USELZO=on` when building.\n");
+ return FALSE;
#endif
-#ifdef USESNAPPY
} else if ((pd.flags & DUMP_DH_COMPRESSED_SNAPPY)) {
+#ifdef USESNAPPY
ret = snappy_uncompressed_length(buf, pd.size, (size_t *)&retlen);
if (ret != SNAPPY_OK) {
@@ -891,14 +899,22 @@ readpage_kdump_compressed(unsigned long long paddr, void *bufptr)
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+#else
+ ERRMSG("snappy compression unsupported\n");
+ ERRMSG("Try `make USESNAPPY=on` when building.\n");
+ return FALSE;
#endif
-#ifdef USEZSTD
} else if ((pd.flags & DUMP_DH_COMPRESSED_ZSTD)) {
+#ifdef USEZSTD
ret = ZSTD_decompress(bufptr, info->page_size, buf, pd.size);
if (ZSTD_isError(ret) || (ret != info->page_size)) {
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+#else
+ ERRMSG("zstd compression unsupported\n");
+ ERRMSG("Try `make USEZSTD=on` when building.\n");
+ return FALSE;
#endif
}
@@ -964,9 +980,13 @@ readpage_kdump_compressed_parallel(int fd_memory, unsigned long long paddr,
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+ } else if ((pd.flags & DUMP_DH_COMPRESSED_LZO)) {
#ifdef USELZO
- } else if (info->flag_lzo_support
- && (pd.flags & DUMP_DH_COMPRESSED_LZO)) {
+ if (!info->flag_lzo_support) {
+ ERRMSG("lzo compression unsupported\n");
+ return FALSE;
+ }
+
retlen = info->page_size;
ret = lzo1x_decompress_safe((unsigned char *)buf, pd.size,
(unsigned char *)bufptr, &retlen,
@@ -975,9 +995,13 @@ readpage_kdump_compressed_parallel(int fd_memory, unsigned long long paddr,
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+#else
+ ERRMSG("lzo compression unsupported\n");
+ ERRMSG("Try `make USELZO=on` when building.\n");
+ return FALSE;
#endif
-#ifdef USESNAPPY
} else if ((pd.flags & DUMP_DH_COMPRESSED_SNAPPY)) {
+#ifdef USESNAPPY
ret = snappy_uncompressed_length(buf, pd.size, (size_t *)&retlen);
if (ret != SNAPPY_OK) {
@@ -990,14 +1014,22 @@ readpage_kdump_compressed_parallel(int fd_memory, unsigned long long paddr,
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+#else
+ ERRMSG("snappy compression unsupported\n");
+ ERRMSG("Try `make USESNAPPY=on` when building.\n");
+ return FALSE;
#endif
-#ifdef USEZSTD
} else if ((pd.flags & DUMP_DH_COMPRESSED_ZSTD)) {
+#ifdef USEZSTD
ret = ZSTD_decompress(bufptr, info->page_size, buf, pd.size);
if (ZSTD_isError(ret) || (ret != info->page_size)) {
ERRMSG("Uncompress failed: %d\n", ret);
return FALSE;
}
+#else
+ ERRMSG("zstd compression unsupported\n");
+ ERRMSG("Try `make USEZSTD=on` when building.\n");
+ return FALSE;
#endif
}

View File

@ -0,0 +1,52 @@
commit d6516ba4c88f217fe14455db92c60cd0e9af18f8
Author: Sven Schnelle <svens@linux.ibm.com>
Date: Thu Dec 16 12:43:55 2021 +0100
use slurp_proc_file() in get_command_line()
This way the size of the command line that get_command_line() can handle
is no longer fixed.
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/kexec/kexec.c b/kexec/kexec.c
index f3adac517161d448552a16fd79488c1df100d356..7e4787bc821107b7af66ebdbcfc31f4e7e1d48cd 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -1172,25 +1172,19 @@ static char *slurp_proc_file(const char *filename, size_t *len)
*/
char *get_command_line(void)
{
- FILE *fp;
- char *line;
- const int sizeof_line = 2048;
-
- line = malloc(sizeof_line);
- if (line == NULL)
- die("Could not allocate memory to read /proc/cmdline.");
-
- fp = fopen("/proc/cmdline", "r");
- if (!fp)
- die("Could not open /proc/cmdline.");
-
- if (fgets(line, sizeof_line, fp) == NULL)
- die("Can't read /proc/cmdline.");
+ char *p, *line;
+ size_t size;
- fclose(fp);
+ line = slurp_proc_file("/proc/cmdline", &size);
+ if (!line || !size)
+ die("Failed to read /proc/cmdline\n");
/* strip newline */
- line[strlen(line) - 1] = '\0';
+ line[size-1] = '\0';
+
+ p = strpbrk(line, "\r\n");
+ if (p)
+ *p = '\0';
remove_parameter(line, "BOOT_IMAGE");
if (kexec_flags & KEXEC_ON_CRASH)

View File

@ -0,0 +1,75 @@
commit 2e1ec106dc5aac951ba884ebe4cca036e9a2d45f
Author: Sven Schnelle <svens@linux.ibm.com>
Date: Thu Dec 16 12:43:56 2021 +0100
s390: add support for --reuse-cmdline
--reuse-cmdline reads the command line of the currently
running kernel from /proc/cmdline and uses that for the
kernel that should be kexec'd.
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/kexec/arch/s390/include/arch/options.h b/kexec/arch/s390/include/arch/options.h
index 76044a301ceb3cca013f70dff330a8ad343d808a..c150244996c79165cf1e83e331f728432b752652 100644
--- a/kexec/arch/s390/include/arch/options.h
+++ b/kexec/arch/s390/include/arch/options.h
@@ -1,9 +1,10 @@
#ifndef KEXEC_ARCH_S390_OPTIONS_H
#define KEXEC_ARCH_S390_OPTIONS_H
-#define OPT_ARCH_MAX (OPT_MAX+0)
-#define OPT_APPEND OPT_MAX+0
-#define OPT_RAMDISK OPT_MAX+1
+#define OPT_ARCH_MAX (OPT_MAX+0)
+#define OPT_APPEND (OPT_MAX+0)
+#define OPT_RAMDISK (OPT_MAX+1)
+#define OPT_REUSE_CMDLINE (OPT_MAX+2)
/* Options relevant to the architecture (excluding loader-specific ones),
* in this case none:
@@ -31,7 +32,8 @@
KEXEC_ARCH_OPTIONS \
{"command-line", 1, 0, OPT_APPEND}, \
{"append", 1, 0, OPT_APPEND}, \
- {"initrd", 1, 0, OPT_RAMDISK},
+ {"initrd", 1, 0, OPT_RAMDISK}, \
+ {"reuse-cmdline", 0, 0, OPT_REUSE_CMDLINE },
#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR
diff --git a/kexec/arch/s390/kexec-image.c b/kexec/arch/s390/kexec-image.c
index 209ab77ddccbd60f10989e2d9fc273324aefa76d..69aaf96812f741110bf323b4bb8d5dda155f293a 100644
--- a/kexec/arch/s390/kexec-image.c
+++ b/kexec/arch/s390/kexec-image.c
@@ -71,6 +71,10 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
case OPT_RAMDISK:
ramdisk = optarg;
break;
+ case OPT_REUSE_CMDLINE:
+ free(info->command_line);
+ info->command_line = get_command_line();
+ break;
}
}
@@ -123,6 +127,10 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
if (command_line_add(info, optarg))
return -1;
break;
+ case OPT_REUSE_CMDLINE:
+ free(info->command_line);
+ info->command_line = get_command_line();
+ break;
case OPT_RAMDISK:
ramdisk = optarg;
break;
@@ -223,5 +231,6 @@ image_s390_usage(void)
printf("--command-line=STRING Set the kernel command line to STRING.\n"
"--append=STRING Set the kernel command line to STRING.\n"
"--initrd=FILENAME Use the file FILENAME as a ramdisk.\n"
+ "--reuse-cmdline Use kernel command line from running system.\n"
);
}

View File

@ -0,0 +1,86 @@
commit f4c59879b830c7d574a953e6ce970ddaf20910d7
Author: Philipp Rudo <prudo@redhat.com>
Date: Wed Mar 23 16:35:36 2022 +0100
util_lib/elf_info: harden parsing of printk buffer
The old printk mechanism (> v3.5.0 and < v5.10.0) had a fixed size
buffer (log_buf) that contains all messages. The location for the next
message is stored in log_next_idx. In case the log_buf runs full
log_next_idx wraps around and starts overwriting old messages at the
beginning of the buffer. The wraparound is denoted by a message with
msg->len == 0.
Following the behavior described above blindly is dangerous as e.g. a
memory corruption could overwrite (parts of) the log_buf. If the
corruption adds a message with msg->len == 0 this leads to an endless
loop when dumping the dmesg. Fix this by verifying that not wrapped
around before when it encounters a message with msg->len == 0.
While at it also verify that the index is within the log_buf and thus
guard against corruptions with msg->len != 0.
The same bug has been reported and fixed in makedumpfile [1].
[1] http://lists.infradead.org/pipermail/kexec/2022-March/024272.html
Signed-off-by: Philipp Rudo <prudo@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/util_lib/elf_info.c b/util_lib/elf_info.c
index d252eff5bd582837595a22aa387f53675c402121..ce71c6055c3a6ce8698d35960a8448be1dc8adc1 100644
--- a/util_lib/elf_info.c
+++ b/util_lib/elf_info.c
@@ -763,8 +763,9 @@ static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
{
#define OUT_BUF_SIZE 4096
uint64_t log_buf, log_buf_offset, ts_nsec;
- uint32_t log_first_idx, log_next_idx, current_idx, len = 0, i;
+ uint32_t log_buf_len, log_first_idx, log_next_idx, current_idx, len = 0, i;
char *buf, out_buf[OUT_BUF_SIZE];
+ bool has_wrapped_around = false;
ssize_t ret;
char *msg;
uint16_t text_len;
@@ -811,6 +812,7 @@ static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
}
log_buf = read_file_pointer(fd, vaddr_to_offset(log_buf_vaddr));
+ log_buf_len = read_file_s32(fd, vaddr_to_offset(log_buf_len_vaddr));
log_first_idx = read_file_u32(fd, vaddr_to_offset(log_first_idx_vaddr));
log_next_idx = read_file_u32(fd, vaddr_to_offset(log_next_idx_vaddr));
@@ -882,11 +884,31 @@ static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
* and read the message at the start of the buffer.
*/
loglen = struct_val_u16(buf, log_offset_len);
- if (!loglen)
+ if (!loglen) {
+ if (has_wrapped_around) {
+ if (len && handler)
+ handler(out_buf, len);
+ fprintf(stderr, "Cycle when parsing dmesg detected.\n");
+ fprintf(stderr, "The prink log_buf is most likely corrupted.\n");
+ fprintf(stderr, "log_buf = 0x%lx, idx = 0x%x\n",
+ log_buf, current_idx);
+ exit(68);
+ }
current_idx = 0;
- else
+ has_wrapped_around = true;
+ } else {
/* Move to next record */
current_idx += loglen;
+ if(current_idx > log_buf_len - log_sz) {
+ if (len && handler)
+ handler(out_buf, len);
+ fprintf(stderr, "Index outside log_buf detected.\n");
+ fprintf(stderr, "The prink log_buf is most likely corrupted.\n");
+ fprintf(stderr, "log_buf = 0x%lx, idx = 0x%x\n",
+ log_buf, current_idx);
+ exit(69);
+ }
+ }
}
free(buf);
if (len && handler)

View File

@ -1,6 +1,6 @@
Name: kexec-tools
Version: 2.0.20
Release: 68%{?dist}
Release: 69%{?dist}
License: GPLv2
Group: Applications/System
Summary: The kexec/kdump userspace component
@ -98,6 +98,12 @@ ExcludeArch: i686
#
# Patches 401 through 500 are meant for s390 kexec-tools enablement
#
Patch401: ./kexec-tools-2.0.20-01-s390_add_variable_command_line_size.patch
Patch402: ./kexec-tools-2.0.20-02-s390_use_KEXEC_ALL_OPTIONS.patch
Patch403: ./kexec-tools-2.0.20-03-add_slurp_proc_file_.patch
Patch404: ./kexec-tools-2.0.20-04-use_slurp_proc_file_in_get_command_line_.patch
Patch405: ./kexec-tools-2.0.20-05-s390_add_support_for_reuse_cmdline.patch
#
# Patches 501 through 600 are meant for ARM kexec-tools enablement
#
@ -121,10 +127,15 @@ Patch613: kexec-tools-2.0.20-eppic-Remove-duplicated-variable-declaration.patch
Patch614: kexec-tools-2.0.20-1-printk-add-support-for-lockless-ringbuffer.patch
Patch615: kexec-tools-2.0.20-2-printk-Use-ULL-suffix-for-64-bit-constants.patch
Patch616: kexec-tools-2.0.20-3-printk-Use-zu-to-format-size_t.patch
Patch617: kexec-tools-2.0.20-05-util_lib_elf_info_harden_parsing_of_printk_buffer.patch
# Patches 701 onward for makedumpfile
Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch
Patch702: kexec-tools-2.0.20-01-_PATCH_v2_1_3_add_generic_cycle_detection.patch
Patch703: kexec-tools-2.0.20-02-_PATCH_v2_2_3_use_pointer_arithmetics_for_dump_dmesg.patch
Patch704: kexec-tools-2.0.20-03-_PATCH_v2_3_3_use_cycle_detection_when_parsing_the_prink_log_buf.patch
Patch705: kexec-tools-2.0.20-04-_PATCH_print_error_when_reading_with_unsupported_compression.patch
%description
kexec-tools provides /usr/sbin/kexec binary that facilitates a new
@ -140,6 +151,11 @@ mkdir -p -m755 kcp
tar -z -x -v -f %{SOURCE9}
tar -z -x -v -f %{SOURCE19}
%patch401 -p1
%patch402 -p1
%patch403 -p1
%patch404 -p1
%patch405 -p1
%patch601 -p1
%patch602 -p1
#%patch603 -p1
@ -156,7 +172,13 @@ tar -z -x -v -f %{SOURCE19}
%patch614 -p1
%patch615 -p1
%patch616 -p1
%patch617 -p1
%patch701 -p1
%patch702 -p1
%patch703 -p1
%patch704 -p1
%patch705 -p1
%ifarch ppc
%define archdef ARCH=ppc
@ -418,6 +440,18 @@ done
%endif
%changelog
* Fri Apr 15 2022 Pingfan Liu <piliu@redhat.com> - 2.0.20-69
- s390: add support for --reuse-cmdline
- use slurp_proc_file() in get_command_line()
- add slurp_proc_file()
- s390: use KEXEC_ALL_OPTIONS
- s390: add variable command line size
- util_lib/elf_info: harden parsing of printk buffer
- print error when reading with unsupported compression
- use cycle detection when parsing the prink log_buf
- use pointer arithmetics for dump_dmesg
- add generic cycle detection
* Thu Jan 27 2022 Pingfan Liu <piliu@redhat.com> - 2.0.20-68
- Revert "Remove trace_buf_size and trace_event from the kernel bootparameters of the kdump kernel"