2009-12-24 09:05:50

by Hatayama, Daisuke

[permalink] [raw]
Subject: [PATCH v2, 4/5] elf coredump: make offset calculation process and writing process explicit

By the next patch, elf_core_dump() and elf_fdpic_core_dump() will
support extended numbering and so will possibly produce the corefiles
with section header table.

The problem is the process of writing a file header offset of the
section header table into e_shoff field of the ELF header. ELF header
is positioned at the beginning of the corefile, while section header
at the end. So, there are two ways to do this:

1. Seek backward to retry writing operation for ELF header
after writing process for a whole part

2. Make offset calculation process and writing process
totally sequential

The clause 1. is not always possible: one cannot assume that file
system supports seek function. Consider the no_llseek case.

Therefore, this patch adopts the clause 2.

Signed-off-by: Daisuke HATAYAMA <[email protected]>
---
fs/binfmt_elf.c | 27 ++++++++++++++++-----------
fs/binfmt_elf_fdpic.c | 29 ++++++++++++++++-------------
2 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 1b7e9de..b1ded32 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1879,6 +1879,7 @@ static int elf_core_dump(struct coredump_params *cprm)
loff_t offset = 0, dataoff, foffset;
unsigned long mm_flags;
struct elf_note_info info;
+ struct elf_phdr *phdr4note = NULL;

/*
* We no longer stop all VM operations.
@@ -1921,28 +1922,22 @@ static int elf_core_dump(struct coredump_params *cprm)
fs = get_fs();
set_fs(KERNEL_DS);

- size += sizeof(*elf);
- if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
- goto end_coredump;
-
offset += sizeof(*elf); /* Elf header */
offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */
foffset = offset;

/* Write notes phdr entry */
{
- struct elf_phdr phdr;
size_t sz = get_note_info_size(&info);

sz += elf_coredump_extra_notes_size();

- fill_elf_note_phdr(&phdr, sz, offset);
- offset += sz;
-
- size += sizeof(phdr);
- if (size > cprm->limit
- || !dump_write(cprm->file, &phdr, sizeof(phdr)))
+ phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
+ if (!phdr4note)
goto end_coredump;
+
+ fill_elf_note_phdr(phdr4note, sz, offset);
+ offset += sz;
}

dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
@@ -1954,6 +1949,15 @@ static int elf_core_dump(struct coredump_params *cprm)
*/
mm_flags = current->mm->flags;

+ size += sizeof(*elf);
+ if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
+ goto end_coredump;
+
+ size += sizeof(*phdr4note);
+ if (size > cprm->limit
+ || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
+ goto end_coredump;
+
/* Write program headers for segments dump */
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
@@ -2027,6 +2031,7 @@ end_coredump:

cleanup:
free_note_info(&info);
+ kfree(phdr4note);
kfree(elf);
out:
return has_dumped;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 4c16ff6..cbfa34e 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1588,6 +1588,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
int thread_status_size = 0;
elf_addr_t *auxv;
unsigned long mm_flags;
+ struct elf_phdr *phdr4note = NULL;

/*
* We no longer stop all VM operations.
@@ -1694,18 +1695,12 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
fs = get_fs();
set_fs(KERNEL_DS);

- size += sizeof(*elf);
- if (size > cprm->limit
- || !dump_write(cprm->file, elf, sizeof(*elf)))
- goto end_coredump;
-
offset += sizeof(*elf); /* Elf header */
offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
foffset = offset;

/* Write notes phdr entry */
{
- struct elf_phdr phdr;
int sz = 0;

for (i = 0; i < numnote; i++)
@@ -1713,13 +1708,12 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)

sz += thread_status_size;

- fill_elf_note_phdr(&phdr, sz, offset);
- offset += sz;
-
- size += sizeof(phdr);
- if (size > cprm->limit
- || !dump_write(cprm->file, &phdr, sizeof(phdr)))
+ phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
+ if (!phdr4note)
goto end_coredump;
+
+ fill_elf_note_phdr(phdr4note, sz, offset);
+ offset += sz;
}

/* Page-align dumped data */
@@ -1732,6 +1726,15 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
*/
mm_flags = current->mm->flags;

+ size += sizeof(*elf);
+ if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
+ goto end_coredump;
+
+ size += sizeof(*phdr4note);
+ if (size > cprm->limit
+ || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
+ goto end_coredump;
+
/* write program headers for segments dump */
for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
struct elf_phdr phdr;
@@ -1803,7 +1806,7 @@ cleanup:
list_del(tmp);
kfree(list_entry(tmp, struct elf_thread_status, list));
}
-
+ kfree(phdr4note);
kfree(elf);
kfree(prstatus);
kfree(psinfo);
--
1.6.5.1