From 574a202f622b9db5fd3eb266f0be9fdf42cbfcb4 Mon Sep 17 00:00:00 2001 From: Philipp Rudo Date: Mar 28 2022 17:20:45 +0000 Subject: util_lib/elf_info: harden parsing of printk buffer Resolves: bz2069200 Upstream: git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git Conflicts: None commit f4c59879b830c7d574a953e6ce970ddaf20910d7 Author: Philipp Rudo 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 Signed-off-by: Simon Horman Signed-off-by: Philipp Rudo --- diff --git a/kexec-tools-2.0.23-05-util_lib_elf_info_harden_parsing_of_printk_buffer.patch b/kexec-tools-2.0.23-05-util_lib_elf_info_harden_parsing_of_printk_buffer.patch new file mode 100644 index 0000000..519eaef --- /dev/null +++ b/kexec-tools-2.0.23-05-util_lib_elf_info_harden_parsing_of_printk_buffer.patch @@ -0,0 +1,86 @@ + commit f4c59879b830c7d574a953e6ce970ddaf20910d7 + Author: Philipp Rudo + 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 + Signed-off-by: Simon Horman + + 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) diff --git a/kexec-tools.spec b/kexec-tools.spec index bdb908e..a762a10 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -117,6 +117,7 @@ Patch603: ./kexec-tools-2.0.23-01-_PATCH_v2_1_3_add_generic_cycle_detection.patc Patch604: ./kexec-tools-2.0.23-02-_PATCH_v2_2_3_use_pointer_arithmetics_for_dump_dmesg.patch Patch605: ./kexec-tools-2.0.23-03-_PATCH_v2_3_3_use_cycle_detection_when_parsing_the_prink_log_buf.patch Patch606: ./kexec-tools-2.0.23-04-_PATCH_print_error_when_reading_with_unsupported_compression.patch +Patch607: ./kexec-tools-2.0.23-05-util_lib_elf_info_harden_parsing_of_printk_buffer.patch %description kexec-tools provides /sbin/kexec binary that facilitates a new @@ -138,6 +139,7 @@ tar -z -x -v -f %{SOURCE19} %patch604 -p1 %patch605 -p1 %patch606 -p1 +%patch607 -p1 %ifarch ppc %define archdef ARCH=ppc