diff options
-rw-r--r-- | fs/binfmt_elf.c | 78 | ||||
-rw-r--r-- | include/linux/sched.h | 3 |
2 files changed, 55 insertions, 26 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 66cd711a6b1a..4263326ede04 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1201,35 +1201,68 @@ static int dump_seek(struct file *file, loff_t off) | |||
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | /* | 1203 | /* |
1204 | * Decide whether a segment is worth dumping; default is yes to be | 1204 | * Decide what to dump of a segment, part, all or none. |
1205 | * sure (missing info is worse than too much; etc). | ||
1206 | * Personally I'd include everything, and use the coredump limit... | ||
1207 | * | ||
1208 | * I think we should skip something. But I am not sure how. H.J. | ||
1209 | */ | 1205 | */ |
1210 | static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) | 1206 | static unsigned long vma_dump_size(struct vm_area_struct *vma, |
1207 | unsigned long mm_flags) | ||
1211 | { | 1208 | { |
1212 | /* The vma can be set up to tell us the answer directly. */ | 1209 | /* The vma can be set up to tell us the answer directly. */ |
1213 | if (vma->vm_flags & VM_ALWAYSDUMP) | 1210 | if (vma->vm_flags & VM_ALWAYSDUMP) |
1214 | return 1; | 1211 | goto whole; |
1215 | 1212 | ||
1216 | /* Do not dump I/O mapped devices or special mappings */ | 1213 | /* Do not dump I/O mapped devices or special mappings */ |
1217 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) | 1214 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) |
1218 | return 0; | 1215 | return 0; |
1219 | 1216 | ||
1217 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) | ||
1218 | |||
1220 | /* By default, dump shared memory if mapped from an anonymous file. */ | 1219 | /* By default, dump shared memory if mapped from an anonymous file. */ |
1221 | if (vma->vm_flags & VM_SHARED) { | 1220 | if (vma->vm_flags & VM_SHARED) { |
1222 | if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) | 1221 | if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0 ? |
1223 | return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); | 1222 | FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED)) |
1224 | else | 1223 | goto whole; |
1225 | return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); | 1224 | return 0; |
1226 | } | 1225 | } |
1227 | 1226 | ||
1228 | /* By default, if it hasn't been written to, don't write it out. */ | 1227 | /* Dump segments that have been written to. */ |
1229 | if (!vma->anon_vma) | 1228 | if (vma->anon_vma && FILTER(ANON_PRIVATE)) |
1230 | return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); | 1229 | goto whole; |
1230 | if (vma->vm_file == NULL) | ||
1231 | return 0; | ||
1231 | 1232 | ||
1232 | return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); | 1233 | if (FILTER(MAPPED_PRIVATE)) |
1234 | goto whole; | ||
1235 | |||
1236 | /* | ||
1237 | * If this looks like the beginning of a DSO or executable mapping, | ||
1238 | * check for an ELF header. If we find one, dump the first page to | ||
1239 | * aid in determining what was mapped here. | ||
1240 | */ | ||
1241 | if (FILTER(ELF_HEADERS) && vma->vm_file != NULL && vma->vm_pgoff == 0) { | ||
1242 | u32 __user *header = (u32 __user *) vma->vm_start; | ||
1243 | u32 word; | ||
1244 | /* | ||
1245 | * Doing it this way gets the constant folded by GCC. | ||
1246 | */ | ||
1247 | union { | ||
1248 | u32 cmp; | ||
1249 | char elfmag[SELFMAG]; | ||
1250 | } magic; | ||
1251 | BUILD_BUG_ON(SELFMAG != sizeof word); | ||
1252 | magic.elfmag[EI_MAG0] = ELFMAG0; | ||
1253 | magic.elfmag[EI_MAG1] = ELFMAG1; | ||
1254 | magic.elfmag[EI_MAG2] = ELFMAG2; | ||
1255 | magic.elfmag[EI_MAG3] = ELFMAG3; | ||
1256 | if (get_user(word, header) == 0 && word == magic.cmp) | ||
1257 | return PAGE_SIZE; | ||
1258 | } | ||
1259 | |||
1260 | #undef FILTER | ||
1261 | |||
1262 | return 0; | ||
1263 | |||
1264 | whole: | ||
1265 | return vma->vm_end - vma->vm_start; | ||
1233 | } | 1266 | } |
1234 | 1267 | ||
1235 | /* An ELF note in memory */ | 1268 | /* An ELF note in memory */ |
@@ -1669,16 +1702,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1669 | for (vma = first_vma(current, gate_vma); vma != NULL; | 1702 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1670 | vma = next_vma(vma, gate_vma)) { | 1703 | vma = next_vma(vma, gate_vma)) { |
1671 | struct elf_phdr phdr; | 1704 | struct elf_phdr phdr; |
1672 | size_t sz; | ||
1673 | |||
1674 | sz = vma->vm_end - vma->vm_start; | ||
1675 | 1705 | ||
1676 | phdr.p_type = PT_LOAD; | 1706 | phdr.p_type = PT_LOAD; |
1677 | phdr.p_offset = offset; | 1707 | phdr.p_offset = offset; |
1678 | phdr.p_vaddr = vma->vm_start; | 1708 | phdr.p_vaddr = vma->vm_start; |
1679 | phdr.p_paddr = 0; | 1709 | phdr.p_paddr = 0; |
1680 | phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; | 1710 | phdr.p_filesz = vma_dump_size(vma, mm_flags); |
1681 | phdr.p_memsz = sz; | 1711 | phdr.p_memsz = vma->vm_end - vma->vm_start; |
1682 | offset += phdr.p_filesz; | 1712 | offset += phdr.p_filesz; |
1683 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1713 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
1684 | if (vma->vm_flags & VM_WRITE) | 1714 | if (vma->vm_flags & VM_WRITE) |
@@ -1718,13 +1748,11 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1718 | for (vma = first_vma(current, gate_vma); vma != NULL; | 1748 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1719 | vma = next_vma(vma, gate_vma)) { | 1749 | vma = next_vma(vma, gate_vma)) { |
1720 | unsigned long addr; | 1750 | unsigned long addr; |
1751 | unsigned long end; | ||
1721 | 1752 | ||
1722 | if (!maydump(vma, mm_flags)) | 1753 | end = vma->vm_start + vma_dump_size(vma, mm_flags); |
1723 | continue; | ||
1724 | 1754 | ||
1725 | for (addr = vma->vm_start; | 1755 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { |
1726 | addr < vma->vm_end; | ||
1727 | addr += PAGE_SIZE) { | ||
1728 | struct page *page; | 1756 | struct page *page; |
1729 | struct vm_area_struct *vma; | 1757 | struct vm_area_struct *vma; |
1730 | 1758 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index e643357eda05..cb952bc225e4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -359,8 +359,9 @@ extern int get_dumpable(struct mm_struct *mm); | |||
359 | #define MMF_DUMP_ANON_SHARED 3 | 359 | #define MMF_DUMP_ANON_SHARED 3 |
360 | #define MMF_DUMP_MAPPED_PRIVATE 4 | 360 | #define MMF_DUMP_MAPPED_PRIVATE 4 |
361 | #define MMF_DUMP_MAPPED_SHARED 5 | 361 | #define MMF_DUMP_MAPPED_SHARED 5 |
362 | #define MMF_DUMP_ELF_HEADERS 6 | ||
362 | #define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS | 363 | #define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS |
363 | #define MMF_DUMP_FILTER_BITS 4 | 364 | #define MMF_DUMP_FILTER_BITS 5 |
364 | #define MMF_DUMP_FILTER_MASK \ | 365 | #define MMF_DUMP_FILTER_MASK \ |
365 | (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) | 366 | (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) |
366 | #define MMF_DUMP_FILTER_DEFAULT \ | 367 | #define MMF_DUMP_FILTER_DEFAULT \ |