[makedumpfile PATCH RFC v0.1] Implemented the --fill-excluded-pages=<value> feature
Eric DeVolder
eric.devolder at oracle.com
Thu Jul 20 02:57:53 PDT 2017
I have fixed the problem with the patch below.
I will re-submit soon.
eric
On 07/18/2017 09:19 AM, Eric DeVolder wrote:
> When a page is excluded by any of the existing dump levels,
> that page may still be written to the ELF dump file, depending
> upon the PFN_EXCLUDED mechanism.
>
> The PFN_EXCLUDED mechanism looks for N consecutive "not
> dumpable" pages, and if found, the current ELF segment is
> closed out and a new ELF segment started, at the next dumpable
> page. Otherwise, if the PFN_EXCLUDED criteria is not meet (that
> is, there is a mix of dumpable and not dumpable pages, but not
> N consecutive not dumpable pages) all pages are written to the
> dump file.
>
> This patch implements a mechanism for those "not dumpable" pages
> that are written to the ELF dump file to fill those pages with
> constant data, rather than the original data. In other words,
> the dump file still contains the page, but its data is wiped.
>
> The motivation for doing this is to protect real user data from
> "leaking" through to a dump file when that data was asked to be
> omitted. This is especially important for effort I currently am
> working on to allow further refinement of what is allowed to be
> dumped, all in an effort to protect user (customer) data.
>
> The patch is simple enough, however, it causes problems with
> crash; crash is unable to load the resulting ELF dump file.
> For example, I do the following as a test scenario for this
> change:
>
> - Obtain a non-filtered dump file (eg. dump level 0, no -d option,
> or straight copy of /proc/vmcore)
> - Run vmcore through 'crash' to ensure loads ok, test with
> commands like: ps, files, etc.
> % crash vmlinux vmcore
> - Apply this patch and rebuild makedumpfile
> - Run vmcore through makedumpfile *without* --fill-excluded-pages
> and with filtering to ensure no uintended side effects of patch:
> % ./makedumpfile -E -d31 -x vmlinux vmcore newvmcore
> - Run new vmcore through crash to ensure still loads ok, test
> with commands like: ps, files, etc.
> % crash vmlinux newvmcore
> - Run vmcore through makedumpfile *with* --fill-excluded-pages
> and with filtering to check side effects of patch:
> % ./makedumpfile -E -d31 --fill-excluded-pages=0 -x vmlinux vmcore newvmcore2
> - Run new vmcore through crash to ensure still loads ok, test
> with commands like: ps, files, etc.
> % crash vmlinux newvmcore2
>
> But crash yields errors like:
> [...]
> This GDB was configured as "x86_64-unknown-linux-gnu"...
>
> crash: cannot determine thread return address
> please wait... (gathering kmem slab cache data)
> crash: invalid kernel virtual address: 1c type: "kmem_cache objsize/object_size"
>
> If the patch is correct/accurate, then that may mean that crash
> is using data which it should not be.
>
> The more likely scenario is that the patch is not correct/accurate,
> and I'm corrupting the dump file.
>
> Please provide feedback!!
> ---
> makedumpfile.c | 28 +++++++++++++++++++++-------
> makedumpfile.h | 3 +++
> 2 files changed, 24 insertions(+), 7 deletions(-)
>
> diff --git a/makedumpfile.c b/makedumpfile.c
> index e69b6df..3f9816a 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -7102,7 +7102,7 @@ out:
>
> int
> write_elf_load_segment(struct cache_data *cd_page, unsigned long long paddr,
> - off_t off_memory, long long size)
> + off_t off_memory, long long size, struct cycle *cycle)
> {
> long page_size = info->page_size;
> long long bufsz_write;
> @@ -7126,10 +7126,18 @@ write_elf_load_segment(struct cache_data *cd_page, unsigned long long paddr,
> else
> bufsz_write = size;
>
> - if (read(info->fd_memory, buf, bufsz_write) != bufsz_write) {
> - ERRMSG("Can't read the dump memory(%s). %s\n",
> - info->name_memory, strerror(errno));
> - return FALSE;
> + if (info->flag_fill_excluded_pages && !is_dumpable(info->bitmap2, paddr_to_pfn(paddr), cycle)) {
> + unsigned k;
> + unsigned long *p = (unsigned long *)buf;
> + for (k = 0; k < info->page_size; k += sizeof(unsigned long)) {
> + *p++ = info->fill_excluded_pages_value;
> + }
> + } else {
> + if (read(info->fd_memory, buf, bufsz_write) != bufsz_write) {
> + ERRMSG("Can't read the dump memory(%s). %s\n",
> + info->name_memory, strerror(errno));
> + return FALSE;
> + }
> }
> filter_data_buffer((unsigned char *)buf, paddr, bufsz_write);
> paddr += bufsz_write;
> @@ -7396,7 +7404,7 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
> */
> if (load.p_filesz)
> if (!write_elf_load_segment(cd_page, paddr,
> - off_memory, load.p_filesz))
> + off_memory, load.p_filesz, &cycle))
> return FALSE;
>
> load.p_paddr += load.p_memsz;
> @@ -7438,7 +7446,7 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
> */
> if (load.p_filesz)
> if (!write_elf_load_segment(cd_page, paddr,
> - off_memory, load.p_filesz))
> + off_memory, load.p_filesz, &cycle))
> return FALSE;
>
> off_seg_load += load.p_filesz;
> @@ -11007,6 +11015,7 @@ static struct option longopts[] = {
> {"splitblock-size", required_argument, NULL, OPT_SPLITBLOCK_SIZE},
> {"work-dir", required_argument, NULL, OPT_WORKING_DIR},
> {"num-threads", required_argument, NULL, OPT_NUM_THREADS},
> + {"fill-excluded-pages", optional_argument, NULL, OPT_FILL_EXCLUDED_PAGES},
> {0, 0, 0, 0}
> };
>
> @@ -11163,6 +11172,11 @@ main(int argc, char *argv[])
> case OPT_NUM_THREADS:
> info->num_threads = MAX(atoi(optarg), 0);
> break;
> + case OPT_FILL_EXCLUDED_PAGES:
> + info->flag_fill_excluded_pages = 1;
> + if (optarg)
> + info->fill_excluded_pages_value = strtoul(optarg, NULL, 0);
> + break;
> case '?':
> MSG("Commandline parameter is invalid.\n");
> MSG("Try `makedumpfile --help' for more information.\n");
> diff --git a/makedumpfile.h b/makedumpfile.h
> index e32e567..4069672 100644
> --- a/makedumpfile.h
> +++ b/makedumpfile.h
> @@ -1135,6 +1135,8 @@ struct DumpInfo {
> int flag_vmemmap; /* kernel supports vmemmap address space */
> int flag_excludevm; /* -e - excluding unused vmemmap pages */
> int flag_use_count; /* _refcount is named _count in struct page */
> + int flag_fill_excluded_pages; /* if pages are excluded but still dumped (see PFN_EXCLUDED operation), replace with page with fill */
> + unsigned long fill_excluded_pages_value; /* fill value for excluded pages */
> unsigned long vaddr_for_vtop; /* virtual address for debugging */
> long page_size; /* size of page */
> long page_shift;
> @@ -2143,6 +2145,7 @@ struct elf_prstatus {
> #define OPT_SPLITBLOCK_SIZE OPT_START+14
> #define OPT_WORKING_DIR OPT_START+15
> #define OPT_NUM_THREADS OPT_START+16
> +#define OPT_FILL_EXCLUDED_PAGES OPT_START+17
>
> /*
> * Function Prototype.
>
More information about the kexec
mailing list