aboutsummaryrefslogtreecommitdiff
path: root/fs/binfmt_elf_fdpic.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
-rw-r--r--fs/binfmt_elf_fdpic.c59
1 files changed, 38 insertions, 21 deletions
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 18d77297ccc..32d9b44c3cb 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1226,11 +1226,22 @@ static int dump_write(struct file *file, const void *addr, int nr)
static int dump_seek(struct file *file, loff_t off)
{
- if (file->f_op->llseek) {
- if (file->f_op->llseek(file, off, SEEK_SET) != off)
+ if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+ if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
return 0;
} else {
- file->f_pos = off;
+ char *buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf)
+ return 0;
+ while (off > 0) {
+ unsigned long n = off;
+ if (n > PAGE_SIZE)
+ n = PAGE_SIZE;
+ if (!dump_write(file, buf, n))
+ return 0;
+ off -= n;
+ }
+ free_page((unsigned long)buf);
}
return 1;
}
@@ -1313,30 +1324,35 @@ static int notesize(struct memelfnote *en)
/* #define DEBUG */
-#define DUMP_WRITE(addr, nr) \
- do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
-#define DUMP_SEEK(off) \
- do { if (!dump_seek(file, (off))) return 0; } while(0)
+#define DUMP_WRITE(addr, nr, foffset) \
+ do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)
-static int writenote(struct memelfnote *men, struct file *file)
+static int alignfile(struct file *file, loff_t *foffset)
{
- struct elf_note en;
+ static const char buf[4] = { 0, };
+ DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
+ return 1;
+}
+static int writenote(struct memelfnote *men, struct file *file,
+ loff_t *foffset)
+{
+ struct elf_note en;
en.n_namesz = strlen(men->name) + 1;
en.n_descsz = men->datasz;
en.n_type = men->type;
- DUMP_WRITE(&en, sizeof(en));
- DUMP_WRITE(men->name, en.n_namesz);
- /* XXX - cast from long long to long to avoid need for libgcc.a */
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
- DUMP_WRITE(men->data, men->datasz);
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+ DUMP_WRITE(&en, sizeof(en), foffset);
+ DUMP_WRITE(men->name, en.n_namesz, foffset);
+ if (!alignfile(file, foffset))
+ return 0;
+ DUMP_WRITE(men->data, men->datasz, foffset);
+ if (!alignfile(file, foffset))
+ return 0;
return 1;
}
#undef DUMP_WRITE
-#undef DUMP_SEEK
#define DUMP_WRITE(addr, nr) \
if ((size += (nr)) > cprm->limit || \
@@ -1552,7 +1568,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
err = -EIO;
kunmap(page);
page_cache_release(page);
- } else if (!dump_seek(file, file->f_pos + PAGE_SIZE))
+ } else if (!dump_seek(file, PAGE_SIZE))
err = -EFBIG;
if (err)
goto out;
@@ -1605,7 +1621,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
int i;
struct vm_area_struct *vma;
struct elfhdr *elf = NULL;
- loff_t offset = 0, dataoff;
+ loff_t offset = 0, dataoff, foffset;
int numnote;
struct memelfnote *notes = NULL;
struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
@@ -1730,6 +1746,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
DUMP_WRITE(elf, sizeof(*elf));
offset += sizeof(*elf); /* Elf header */
offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
+ foffset = offset;
/* Write notes phdr entry */
{
@@ -1786,7 +1803,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
/* write out the notes section */
for (i = 0; i < numnote; i++)
- if (!writenote(notes + i, cprm->file))
+ if (!writenote(notes + i, cprm->file, &foffset))
goto end_coredump;
/* write out the thread status notes section */
@@ -1795,11 +1812,11 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
list_entry(t, struct elf_thread_status, list);
for (i = 0; i < tmp->num_notes; i++)
- if (!writenote(&tmp->notes[i], cprm->file))
+ if (!writenote(&tmp->notes[i], cprm->file, &foffset))
goto end_coredump;
}
- if (!dump_seek(cprm->file, dataoff))
+ if (!dump_seek(cprm->file, dataoff - foffset))
goto end_coredump;
if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit,