diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 81878b7..b585ba1 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1358,6 +1358,73 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); } +#define MAX_FILE_NOTE_SIZE (4*1024*1024) + +static void fill_files_note(struct memelfnote *note) +{ + struct vm_area_struct *vma; + struct file *file; + unsigned count, word_count, size, remaining; + long *data; + long *start_end_ofs; + char *name; + + count = 0; + for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + file = vma->vm_file; + if (!file) + continue; + count++; + if (count >= MAX_FILE_NOTE_SIZE / 64) /* paranoia check */ + goto err; + } + + size = count * 64; + word_count = 2 + 3 * count; + alloc: + if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ + goto err; + size = (size + PAGE_SIZE - 1) & (-PAGE_SIZE); + data = vmalloc(size); + if (!data) + goto err; + start_end_ofs = data; + name = (void*)&start_end_ofs[word_count]; + remaining = size - word_count * sizeof(long); + + *start_end_ofs++ = count; + *start_end_ofs++ = PAGE_SIZE; + for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + const char *filename; + + file = vma->vm_file; + if (!file) + continue; + if (remaining == 0) { + try_new_size: + vfree(data); + size = size * 5 / 4; + goto alloc; + } + filename = d_path(&file->f_path, name, remaining); + if (IS_ERR(filename)) { + if (PTR_ERR(filename) == -ENAMETOOLONG) + goto try_new_size; + /* continue; -- WRONG, we must have COUNT elements */ + filename = ""; + } + while ((remaining--, *name++ = *filename++) != '\0') + continue; + *start_end_ofs++ = vma->vm_start; + *start_end_ofs++ = vma->vm_end; + *start_end_ofs++ = vma->vm_pgoff; + } + + size = name - (char*)data; + fill_note(note, "CORE", NT_FILE, size, data); + err: ; +} + #ifdef CORE_DUMP_USE_REGSET #include @@ -1372,6 +1439,7 @@ struct elf_note_info { struct elf_thread_core_info *thread; struct memelfnote psinfo; struct memelfnote auxv; + struct memelfnote files; size_t size; int thread_notes; }; @@ -1532,6 +1600,9 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_auxv_note(&info->auxv, current->mm); info->size += notesize(&info->auxv); + fill_files_note(&info->files); + info->size += notesize(&info->files); + return 1; } @@ -1560,6 +1631,8 @@ static int write_note_info(struct elf_note_info *info, return 0; if (first && !writenote(&info->auxv, file, foffset)) return 0; + if (first && !writenote(&info->files, file, foffset)) + return 0; for (i = 1; i < info->thread_notes; ++i) if (t->notes[i].data && @@ -1586,6 +1659,7 @@ static void free_note_info(struct elf_note_info *info) kfree(t); } kfree(info->psinfo.data); + vfree(info->files.data); } #else diff --git a/include/linux/elf.h b/include/linux/elf.h index 999b4f5..5e6c08f 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -372,6 +372,7 @@ typedef struct elf64_shdr { #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 #define NT_AUXV 6 +#define NT_FILE 0x46494c45 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */