diff options
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
| -rw-r--r-- | fs/binfmt_elf_fdpic.c | 59 | 
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,  |