[RFC makedumpfile: add userinfo elf section 4/4] elf: add ability to read the userinfo data from note segment
Ivan Khoronzhuk
ivan.khoronzhuk at gmail.com
Wed Dec 1 05:47:30 PST 2021
Previously were added the ability to save userinfo data to separate
ELF note subsection. This patch adds read mechanism.
The command to retrieve user specific information:
makedumpfile -U userinfofile dumpfile.
Signed-off-by: Ivan Khoronzhuk <ikhoronz at cisco.com>
---
makedumpfile.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++
makedumpfile.h | 2 +
2 files changed, 226 insertions(+)
diff --git a/makedumpfile.c b/makedumpfile.c
index 6b6b4d2..0d29b87 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -1519,6 +1519,60 @@ open_files_for_generating_vmcoreinfo(void)
return TRUE;
}
+int
+open_files_for_generating_userinfo(void)
+{
+ FILE *file_userinfo;
+ int fd;
+
+ if ((file_userinfo = fopen(info->name_userinfo, "w+")) < 0) {
+ ERRMSG("Can't open the userinfo file(%s). %s\n",
+ info->name_userinfo, strerror(errno));
+ return FALSE;
+ }
+
+ info->file_userinfo = file_userinfo;
+
+ if ((fd = open(info->name_dumpfile, O_RDONLY)) < 0) {
+ ERRMSG("Can't open the dump file(%s). %s\n",
+ info->name_dumpfile, strerror(errno));
+ return FALSE;
+ }
+ info->fd_dumpfile = fd;
+
+ return TRUE;
+}
+
+int
+get_phdr_dumpfile(int index, Elf64_Phdr *phdr)
+{
+ Elf32_Phdr phdr32;
+
+ if (is_elf64_memory()) { /* ELF64 */
+ if (!get_elf64_phdr(info->fd_dumpfile, info->name_dumpfile,
+ index, phdr)) {
+ ERRMSG("Can't find Phdr %d.\n", index);
+ return FALSE;
+ }
+ } else {
+ if (!get_elf32_phdr(info->fd_dumpfile, info->name_dumpfile,
+ index, &phdr32)) {
+ ERRMSG("Can't find Phdr %d.\n", index);
+ return FALSE;
+ }
+ memset(phdr, 0, sizeof(Elf64_Phdr));
+ phdr->p_type = phdr32.p_type;
+ phdr->p_flags = phdr32.p_flags;
+ phdr->p_offset = phdr32.p_offset;
+ phdr->p_vaddr = phdr32.p_vaddr;
+ phdr->p_paddr = phdr32.p_paddr;
+ phdr->p_filesz = phdr32.p_filesz;
+ phdr->p_memsz = phdr32.p_memsz;
+ phdr->p_align = phdr32.p_align;
+ }
+ return TRUE;
+}
+
/*
* Open the following file when it rearranges the dump data.
* - dump file
@@ -4758,6 +4812,122 @@ read_cache(struct cache_data *cd)
return TRUE;
}
+int
+copy_userinfo(struct cache_data *cd)
+{
+ size_t buf_size, size;
+ char buf[BUFSIZE_FGETS];
+
+ cd->buf = buf;
+ buf_size = info->size_elf_userinfo;
+
+ while (buf_size > 0) {
+ size = buf_size >= BUFSIZE_FGETS ? BUFSIZE_FGETS : buf_size;
+
+ cd->cache_size = size;
+ if (!read_cache(cd))
+ return FALSE;
+
+ if (fwrite(cd->buf, size, 1, info->file_userinfo) != size)
+ return FALSE;
+
+ buf_size -= BUFSIZE_FGETS;
+ }
+
+ return TRUE;
+}
+
+int
+generate_userinfo(void)
+{
+ char buf[USERINFO_NOTE_NAME_BYTES];
+ size_t nhdr_size, size_note;
+ off_t userinfo_offset = 0;
+ Elf64_Phdr note_phdr;
+ struct cache_data ui;
+ Elf64_Ehdr ehdr64;
+ Elf32_Ehdr ehdr32;
+ int i, phnum;
+ off_t offset;
+ void *note;
+
+ if (!info->flag_elf_dumpfile)
+ return FALSE;
+
+ if (is_elf64_memory()) { /* ELF64 */
+ if (!get_elf64_ehdr(info->fd_dumpfile, info->name_dumpfile,
+ &ehdr64)) {
+ ERRMSG("Can't get ehdr64.\n");
+ return FALSE;
+ }
+ phnum = ehdr64.e_phnum;
+
+ } else { /* ELF32 */
+ if (!get_elf32_ehdr(info->fd_dumpfile, info->name_dumpfile,
+ &ehdr32)) {
+ ERRMSG("Can't get ehdr32.\n");
+ return FALSE;
+ }
+ phnum = ehdr32.e_phnum;
+ }
+
+ for (i = 0; i < phnum; i++) {
+ if (!get_phdr_dumpfile(i, ¬e_phdr))
+ return FALSE;
+
+ if (note_phdr.p_type == PT_NOTE)
+ break;
+ }
+
+ if (note_phdr.p_type != PT_NOTE) {
+ ERRMSG("Can't get a PT_NOTE header.\n");
+ return FALSE;
+ }
+
+ size_note = note_phdr.p_filesz;
+ ui.offset = note_phdr.p_offset;
+ ui.fd = info->fd_dumpfile;
+ ui.file_name = info->name_dumpfile;
+ ui.buf = buf;
+
+ nhdr_size = is_elf64_memory() ? sizeof(Elf64_Nhdr) :
+ sizeof(Elf32_Nhdr);
+
+ ui.cache_size = nhdr_size + USERINFO_NOTE_NAME_BYTES;
+
+ /* find userinfo section */
+ while (size_note > 0) {
+ if (!read_cache(&ui))
+ return FALSE;
+
+ note = ui.buf;
+ if (strcmp(note + nhdr_size, USERINFO_NOTE_NAME) == 0) {
+ userinfo_offset = ui.offset;
+ info->size_elf_userinfo = note_descsz(note);
+ break;
+ }
+
+ offset = offset_next_note(note);
+ size_note -= offset;
+
+ /* set next pnhdr */
+ ui.offset += note_descsz(note);
+ }
+
+ if (!userinfo_offset) {
+ ERRMSG("Can't get a USERINFO header.\n");
+ return FALSE;
+ }
+
+ ui.offset = userinfo_offset;
+
+ if (!copy_userinfo(&ui))
+ return FALSE;
+
+ return TRUE;
+}
+
+
int
is_bigendian(void)
{
@@ -9450,6 +9620,15 @@ close_files_for_generating_vmcoreinfo(void)
return TRUE;
}
+int
+close_files_for_generating_userinfo(void)
+{
+ close_dump_file();
+ close_userinfo_file();
+
+ return TRUE;
+}
+
/*
* Close the following file when it rearranges the dump data.
* - dump file
@@ -9458,6 +9637,7 @@ int
close_files_for_rearranging_dumpdata(void)
{
close_dump_file();
+ close_userinfo_file();
return TRUE;
}
@@ -11302,6 +11482,23 @@ check_param_for_rearranging_dumpdata(int argc, char *argv[])
return TRUE;
}
+int
+check_param_for_creating_userinfo_file(int argc, char *argv[])
+{
+ if (argc != optind + 1)
+ return FALSE;
+
+ if (info->flag_compress || info->dump_level
+ || info->flag_elf_dumpfile || info->flag_read_vmcoreinfo
+ || info->name_vmlinux || info->name_xen_syms
+ || info->flag_flatten || info->flag_generate_vmcoreinfo
+ || info->flag_exclude_xen_dom || info->flag_rearrange)
+ return FALSE;
+
+ info->name_dumpfile = argv[optind];
+ return TRUE;
+}
+
/*
* Parameters for reassembling multiple dumpfiles into one dumpfile.
*/
@@ -11974,6 +12171,10 @@ main(int argc, char *argv[])
info->flag_insert_userinfo = 1;
info->name_userinfo = optarg;
break;
+ case OPT_GENERATE_USERINFO:
+ info->flag_generate_userinfo = 1;
+ info->name_userinfo = optarg;
+ break;
case OPT_XEN_PHYS_START:
info->xen_phys_start = strtoul(optarg, NULL, 0);
break;
@@ -12097,6 +12298,29 @@ main(int argc, char *argv[])
MSG("\n");
MSG("The vmcoreinfo is saved to %s.\n", info->name_vmcoreinfo);
+ } else if (info->flag_generate_userinfo) {
+ if (!check_param_for_creating_userinfo_file(argc, argv)) {
+ MSG("Commandline parameter is invalid.\n");
+ MSG("Try `makedumpfile --help' for more information.\n");
+ goto out;
+ }
+ if (info->flag_check_params)
+ goto check_ok;
+
+ if (!check_file_is_writable(info->name_userinfo))
+ goto out;
+
+ if (!open_files_for_generating_userinfo())
+ goto out;
+
+ if (!generate_userinfo())
+ goto out;
+
+ if (!close_files_for_generating_userinfo())
+ goto out;
+
+ MSG("\n");
+ MSG("The userinfo file is saved to %s.\n", info->name_userinfo);
} else if (info->flag_rearrange) {
if (!check_param_for_rearranging_dumpdata(argc, argv)) {
diff --git a/makedumpfile.h b/makedumpfile.h
index b28b0a5..26f44c9 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1360,6 +1360,7 @@ struct DumpInfo {
int flag_generate_vmcoreinfo;/* flag of generating vmcoreinfo file */
int flag_read_vmcoreinfo; /* flag of reading vmcoreinfo file */
int flag_insert_userinfo; /* flag of inserting userinfo file into ELF note section */
+ int flag_generate_userinfo; /* flag of inserting userinfo file into ELF note section */
int flag_show_usage; /* flag of showing usage */
int flag_show_version; /* flag of showing version */
int flag_check_params; /* only check parameters */
@@ -2491,6 +2492,7 @@ struct elf_prstatus {
#define OPT_VMLINUX 'x'
#define OPT_COMPRESS_ZSTD 'z'
#define OPT_USERINFO 'u'
+#define OPT_GENERATE_USERINFO 'U'
#define OPT_START 256
#define OPT_SPLIT OPT_START+0
#define OPT_REASSEMBLE OPT_START+1
--
2.20.1
More information about the kexec
mailing list