Blame SOURCES/kexec-tools-2.0.20-03-_PATCH_v2_3_3_use_cycle_detection_when_parsing_the_prink_log_buf.patch

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