Blame view

fs/binfmt_elf.c 60.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * linux/fs/binfmt_elf.c
   *
   * These are the functions used to load ELF format executables as used
   * on SVr4 machines.  Information on the format may be found in the book
   * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
   * Tools".
   *
   * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
   */
  
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/mm.h>
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/binfmts.h>
  #include <linux/string.h>
  #include <linux/file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
  #include <linux/personality.h>
  #include <linux/elfcore.h>
  #include <linux/init.h>
  #include <linux/highuid.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include <linux/compiler.h>
  #include <linux/highmem.h>
  #include <linux/pagemap.h>
2aa362c49   Denys Vlasenko   coredump: extend ...
30
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include <linux/random.h>
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
33
  #include <linux/elf.h>
d1fd836dc   Kees Cook   mm: split ET_DYN ...
34
  #include <linux/elf-randomize.h>
7e80d0d0b   Alexey Dobriyan   i386: sched.h inc...
35
  #include <linux/utsname.h>
088e7af73   Daisuke HATAYAMA   coredump: move du...
36
  #include <linux/coredump.h>
6fac4829c   Frederic Weisbecker   cputime: Use acce...
37
  #include <linux/sched.h>
5037835c1   Ross Zwisler   coredump: add DAX...
38
  #include <linux/dax.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <asm/uaccess.h>
  #include <asm/param.h>
  #include <asm/page.h>
2aa362c49   Denys Vlasenko   coredump: extend ...
42
43
44
  #ifndef user_long_t
  #define user_long_t long
  #endif
49ae4d4b1   Denys Vlasenko   coredump: add a n...
45
46
47
  #ifndef user_siginfo_t
  #define user_siginfo_t siginfo_t
  #endif
71613c3b8   Al Viro   get rid of pt_reg...
48
  static int load_elf_binary(struct linux_binprm *bprm);
bb1ad8205   Andrew Morton   x86: PIE executab...
49
50
  static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *,
  				int, int, unsigned long);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

69369a700   Josh Triplett   fs, kernel: permi...
52
53
54
55
56
  #ifdef CONFIG_USELIB
  static int load_elf_library(struct file *);
  #else
  #define load_elf_library NULL
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
  /*
   * If we don't support core dumping, then supply a NULL so we
   * don't even try.
   */
698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
61
  #ifdef CONFIG_ELF_CORE
f6151dfea   Masami Hiramatsu   mm: introduce cor...
62
  static int elf_core_dump(struct coredump_params *cprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
  #else
  #define elf_core_dump	NULL
  #endif
  
  #if ELF_EXEC_PAGESIZE > PAGE_SIZE
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
68
  #define ELF_MIN_ALIGN	ELF_EXEC_PAGESIZE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  #else
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
70
  #define ELF_MIN_ALIGN	PAGE_SIZE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
81
  #endif
  
  #ifndef ELF_CORE_EFLAGS
  #define ELF_CORE_EFLAGS	0
  #endif
  
  #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1))
  #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1))
  #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))
  
  static struct linux_binfmt elf_format = {
f670d0ecd   Mikael Pettersson   binfmt_elf: cleanups
82
83
84
85
86
  	.module		= THIS_MODULE,
  	.load_binary	= load_elf_binary,
  	.load_shlib	= load_elf_library,
  	.core_dump	= elf_core_dump,
  	.min_coredump	= ELF_EXEC_PAGESIZE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  };
d4e3cc387   Andrew Morton   revert "PIE rando...
88
  #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
  
  static int set_brk(unsigned long start, unsigned long end)
  {
  	start = ELF_PAGEALIGN(start);
  	end = ELF_PAGEALIGN(end);
  	if (end > start) {
5d22fc25d   Linus Torvalds   mm: remove more I...
95
96
97
  		int error = vm_brk(start, end - start);
  		if (error)
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
  	}
  	current->mm->start_brk = current->mm->brk = end;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
  /* We need to explicitly zero any fractional pages
     after the data section (i.e. bss).  This would
     contain the junk from the file that should not
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
105
106
     be in memory
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
113
114
115
116
117
118
  static int padzero(unsigned long elf_bss)
  {
  	unsigned long nbyte;
  
  	nbyte = ELF_PAGEOFFSET(elf_bss);
  	if (nbyte) {
  		nbyte = ELF_MIN_ALIGN - nbyte;
  		if (clear_user((void __user *) elf_bss, nbyte))
  			return -EFAULT;
  	}
  	return 0;
  }
09c6dd3c9   Ohad Ben-Cohen   fs/binfmt_elf.c: ...
119
  /* Let's use some macros to make this stack manipulation a little clearer */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
  #ifdef CONFIG_STACK_GROWSUP
  #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))
  #define STACK_ROUND(sp, items) \
  	((15 + (unsigned long) ((sp) + (items))) &~ 15UL)
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
124
125
126
  #define STACK_ALLOC(sp, len) ({ \
  	elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \
  	old_sp; })
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
  #else
  #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items))
  #define STACK_ROUND(sp, items) \
  	(((unsigned long) (sp - items)) &~ 15UL)
  #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; })
  #endif
483fad1c3   Nathan Lynch   ELF loader suppor...
133
134
135
136
137
138
139
140
  #ifndef ELF_BASE_PLATFORM
  /*
   * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture.
   * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value
   * will be copied to the user stack in the same manner as AT_PLATFORM.
   */
  #define ELF_BASE_PLATFORM NULL
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  static int
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
142
  create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
d20894a23   Andi Kleen   Remove a.out inte...
143
  		unsigned long load_addr, unsigned long interp_load_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
  {
  	unsigned long p = bprm->p;
  	int argc = bprm->argc;
  	int envc = bprm->envc;
  	elf_addr_t __user *argv;
  	elf_addr_t __user *envp;
  	elf_addr_t __user *sp;
  	elf_addr_t __user *u_platform;
483fad1c3   Nathan Lynch   ELF loader suppor...
152
  	elf_addr_t __user *u_base_platform;
f06295b44   Kees Cook   ELF: implement AT...
153
  	elf_addr_t __user *u_rand_bytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	const char *k_platform = ELF_PLATFORM;
483fad1c3   Nathan Lynch   ELF loader suppor...
155
  	const char *k_base_platform = ELF_BASE_PLATFORM;
f06295b44   Kees Cook   ELF: implement AT...
156
  	unsigned char k_rand_bytes[16];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
  	int items;
  	elf_addr_t *elf_info;
  	int ei_index = 0;
86a264abe   David Howells   CRED: Wrap curren...
160
  	const struct cred *cred = current_cred();
b6a2fea39   Ollie Wild   mm: variable leng...
161
  	struct vm_area_struct *vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  
  	/*
d68c9d6ae   Franck Bui-Huu   Break ELF_PLATFOR...
164
165
166
167
168
169
170
171
  	 * In some cases (e.g. Hyper-Threading), we want to avoid L1
  	 * evictions by the processes running on the same package. One
  	 * thing we can do is to shuffle the initial stack for them.
  	 */
  
  	p = arch_align_stack(p);
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
  	 * If this architecture has a platform capability string, copy it
  	 * to userspace.  In some cases (Sparc), this info is impossible
  	 * for userspace to get any other way, in others (i386) it is
  	 * merely difficult.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
  	u_platform = NULL;
  	if (k_platform) {
  		size_t len = strlen(k_platform) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
  		u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
  		if (__copy_to_user(u_platform, k_platform, len))
  			return -EFAULT;
  	}
483fad1c3   Nathan Lynch   ELF loader suppor...
184
185
186
187
188
189
190
191
192
193
194
195
  	/*
  	 * If this architecture has a "base" platform capability
  	 * string, copy it to userspace.
  	 */
  	u_base_platform = NULL;
  	if (k_base_platform) {
  		size_t len = strlen(k_base_platform) + 1;
  
  		u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
  		if (__copy_to_user(u_base_platform, k_base_platform, len))
  			return -EFAULT;
  	}
f06295b44   Kees Cook   ELF: implement AT...
196
197
198
199
200
201
202
203
  	/*
  	 * Generate 16 random bytes for userspace PRNG seeding.
  	 */
  	get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes));
  	u_rand_bytes = (elf_addr_t __user *)
  		       STACK_ALLOC(p, sizeof(k_rand_bytes));
  	if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes)))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  	/* Create the ELF interpreter info */
785d55708   Jesper Juhl   [PATCH] binflt_el...
205
  	elf_info = (elf_addr_t *)current->mm->saved_auxv;
4f9a58d75   Olaf Hering   increase AT_VECTO...
206
  	/* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  #define NEW_AUX_ENT(id, val) \
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
208
  	do { \
785d55708   Jesper Juhl   [PATCH] binflt_el...
209
210
  		elf_info[ei_index++] = id; \
  		elf_info[ei_index++] = val; \
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
211
  	} while (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
  
  #ifdef ARCH_DLINFO
  	/* 
  	 * ARCH_DLINFO must come first so PPC can do its special alignment of
  	 * AUXV.
4f9a58d75   Olaf Hering   increase AT_VECTO...
217
218
  	 * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in
  	 * ARCH_DLINFO changes
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
225
  	 */
  	ARCH_DLINFO;
  #endif
  	NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
  	NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE);
  	NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC);
  	NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff);
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
226
  	NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  	NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
  	NEW_AUX_ENT(AT_BASE, interp_load_addr);
  	NEW_AUX_ENT(AT_FLAGS, 0);
  	NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
ebc887b27   Eric W. Biederman   userns: Convert b...
231
232
233
234
  	NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));
  	NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));
  	NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));
  	NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid));
785d55708   Jesper Juhl   [PATCH] binflt_el...
235
   	NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
f06295b44   Kees Cook   ELF: implement AT...
236
  	NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);
2171364d1   Michael Neuling   powerpc: Add HWCA...
237
238
239
  #ifdef ELF_HWCAP2
  	NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2);
  #endif
651910874   John Reiser   execve filename: ...
240
  	NEW_AUX_ENT(AT_EXECFN, bprm->exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  	if (k_platform) {
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
242
  		NEW_AUX_ENT(AT_PLATFORM,
785d55708   Jesper Juhl   [PATCH] binflt_el...
243
  			    (elf_addr_t)(unsigned long)u_platform);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  	}
483fad1c3   Nathan Lynch   ELF loader suppor...
245
246
247
248
  	if (k_base_platform) {
  		NEW_AUX_ENT(AT_BASE_PLATFORM,
  			    (elf_addr_t)(unsigned long)u_base_platform);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  	if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
785d55708   Jesper Juhl   [PATCH] binflt_el...
250
  		NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
256
257
258
259
260
  	}
  #undef NEW_AUX_ENT
  	/* AT_NULL is zero; clear the rest too */
  	memset(&elf_info[ei_index], 0,
  	       sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]);
  
  	/* And advance past the AT_NULL entry.  */
  	ei_index += 2;
  
  	sp = STACK_ADD(p, ei_index);
d20894a23   Andi Kleen   Remove a.out inte...
261
  	items = (argc + 1) + (envc + 1) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
  	bprm->p = STACK_ROUND(sp, items);
  
  	/* Point sp at the lowest address on the stack */
  #ifdef CONFIG_STACK_GROWSUP
  	sp = (elf_addr_t __user *)bprm->p - items - ei_index;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
267
  	bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
  #else
  	sp = (elf_addr_t __user *)bprm->p;
  #endif
b6a2fea39   Ollie Wild   mm: variable leng...
271
272
273
274
275
276
277
278
  
  	/*
  	 * Grow the stack manually; some architectures have a limit on how
  	 * far ahead a user-space access may be in order to grow the stack.
  	 */
  	vma = find_extend_vma(current->mm, bprm->p);
  	if (!vma)
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
  	/* Now, let's put argc (and argv, envp if appropriate) on the stack */
  	if (__put_user(argc, sp++))
  		return -EFAULT;
d20894a23   Andi Kleen   Remove a.out inte...
282
283
  	argv = sp;
  	envp = argv + argc + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  
  	/* Populate argv and envp */
a84a50595   Greg Kroah-Hartman   [PATCH] fix Linux...
286
  	p = current->mm->arg_end = current->mm->arg_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  	while (argc-- > 0) {
  		size_t len;
841d5fb7c   Heiko Carstens   [PATCH] binfmt: f...
289
290
  		if (__put_user((elf_addr_t)p, argv++))
  			return -EFAULT;
b6a2fea39   Ollie Wild   mm: variable leng...
291
292
  		len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
  		if (!len || len > MAX_ARG_STRLEN)
23c4971e3   WANG Cong   [Patch] fs/binfmt...
293
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
  		p += len;
  	}
  	if (__put_user(0, argv))
  		return -EFAULT;
  	current->mm->arg_end = current->mm->env_start = p;
  	while (envc-- > 0) {
  		size_t len;
841d5fb7c   Heiko Carstens   [PATCH] binfmt: f...
301
302
  		if (__put_user((elf_addr_t)p, envp++))
  			return -EFAULT;
b6a2fea39   Ollie Wild   mm: variable leng...
303
304
  		len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
  		if (!len || len > MAX_ARG_STRLEN)
23c4971e3   WANG Cong   [Patch] fs/binfmt...
305
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
316
317
  		p += len;
  	}
  	if (__put_user(0, envp))
  		return -EFAULT;
  	current->mm->env_end = p;
  
  	/* Put the elf_info on the stack in the right place.  */
  	sp = (elf_addr_t __user *)envp + 1;
  	if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t)))
  		return -EFAULT;
  	return 0;
  }
c07380bea   James Hogan   Revert some of "b...
318
  #ifndef elf_map
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  static unsigned long elf_map(struct file *filep, unsigned long addr,
cc503c1b4   Jiri Kosina   x86: PIE executab...
320
321
  		struct elf_phdr *eppnt, int prot, int type,
  		unsigned long total_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
  {
  	unsigned long map_addr;
cc503c1b4   Jiri Kosina   x86: PIE executab...
324
325
326
327
  	unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
  	unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
  	addr = ELF_PAGESTART(addr);
  	size = ELF_PAGEALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328

dda6ebde9   David Gibson   [PATCH] Fix handl...
329
330
  	/* mmap() will return -EINVAL if given a zero size, but a
  	 * segment with zero filesize is perfectly valid */
cc503c1b4   Jiri Kosina   x86: PIE executab...
331
332
  	if (!size)
  		return addr;
cc503c1b4   Jiri Kosina   x86: PIE executab...
333
334
335
336
337
338
339
340
341
342
  	/*
  	* total_size is the size of the ELF (interpreter) image.
  	* The _first_ mmap needs to know the full size, otherwise
  	* randomization might put this image into an overlapping
  	* position with the ELF binary image. (since size < total_size)
  	* So we first map the 'big' image - and unmap the remainder at
  	* the end. (which unmap is needed for ELF images with holes.)
  	*/
  	if (total_size) {
  		total_size = ELF_PAGEALIGN(total_size);
5a5e4c2ec   Al Viro   binfmt_elf: switc...
343
  		map_addr = vm_mmap(filep, addr, total_size, prot, type, off);
cc503c1b4   Jiri Kosina   x86: PIE executab...
344
  		if (!BAD_ADDR(map_addr))
5a5e4c2ec   Al Viro   binfmt_elf: switc...
345
  			vm_munmap(map_addr+size, total_size-size);
cc503c1b4   Jiri Kosina   x86: PIE executab...
346
  	} else
5a5e4c2ec   Al Viro   binfmt_elf: switc...
347
  		map_addr = vm_mmap(filep, addr, size, prot, type, off);
cc503c1b4   Jiri Kosina   x86: PIE executab...
348

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  	return(map_addr);
  }
c07380bea   James Hogan   Revert some of "b...
351
  #endif /* !elf_map */
cc503c1b4   Jiri Kosina   x86: PIE executab...
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
  {
  	int i, first_idx = -1, last_idx = -1;
  
  	for (i = 0; i < nr; i++) {
  		if (cmds[i].p_type == PT_LOAD) {
  			last_idx = i;
  			if (first_idx == -1)
  				first_idx = i;
  		}
  	}
  	if (first_idx == -1)
  		return 0;
  
  	return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
  				ELF_PAGESTART(cmds[first_idx].p_vaddr);
  }
6a8d38945   Paul Burton   binfmt_elf: Hoist...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  /**
   * load_elf_phdrs() - load ELF program headers
   * @elf_ex:   ELF header of the binary whose program headers should be loaded
   * @elf_file: the opened ELF binary file
   *
   * Loads ELF program headers from the binary file elf_file, which has the ELF
   * header pointed to by elf_ex, into a newly allocated array. The caller is
   * responsible for freeing the allocated data. Returns an ERR_PTR upon failure.
   */
  static struct elf_phdr *load_elf_phdrs(struct elfhdr *elf_ex,
  				       struct file *elf_file)
  {
  	struct elf_phdr *elf_phdata = NULL;
  	int retval, size, err = -1;
  
  	/*
  	 * If the size of this structure has changed, then punt, since
  	 * we will be doing the wrong thing.
  	 */
  	if (elf_ex->e_phentsize != sizeof(struct elf_phdr))
  		goto out;
  
  	/* Sanity check the number of program headers... */
  	if (elf_ex->e_phnum < 1 ||
  		elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr))
  		goto out;
  
  	/* ...and their total size. */
  	size = sizeof(struct elf_phdr) * elf_ex->e_phnum;
  	if (size > ELF_MIN_ALIGN)
  		goto out;
  
  	elf_phdata = kmalloc(size, GFP_KERNEL);
  	if (!elf_phdata)
  		goto out;
  
  	/* Read in the program headers */
  	retval = kernel_read(elf_file, elf_ex->e_phoff,
  			     (char *)elf_phdata, size);
  	if (retval != size) {
  		err = (retval < 0) ? retval : -EIO;
  		goto out;
  	}
  
  	/* Success! */
  	err = 0;
  out:
  	if (err) {
  		kfree(elf_phdata);
  		elf_phdata = NULL;
  	}
  	return elf_phdata;
  }
cc503c1b4   Jiri Kosina   x86: PIE executab...
422

774c105ed   Paul Burton   binfmt_elf: allow...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
  #ifndef CONFIG_ARCH_BINFMT_ELF_STATE
  
  /**
   * struct arch_elf_state - arch-specific ELF loading state
   *
   * This structure is used to preserve architecture specific data during
   * the loading of an ELF file, throughout the checking of architecture
   * specific ELF headers & through to the point where the ELF load is
   * known to be proceeding (ie. SET_PERSONALITY).
   *
   * This implementation is a dummy for architectures which require no
   * specific state.
   */
  struct arch_elf_state {
  };
  
  #define INIT_ARCH_ELF_STATE {}
  
  /**
   * arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header
   * @ehdr:	The main ELF header
   * @phdr:	The program header to check
   * @elf:	The open ELF file
   * @is_interp:	True if the phdr is from the interpreter of the ELF being
   *		loaded, else false.
   * @state:	Architecture-specific state preserved throughout the process
   *		of loading the ELF.
   *
   * Inspects the program header phdr to validate its correctness and/or
   * suitability for the system. Called once per ELF program header in the
   * range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its
   * interpreter.
   *
   * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
   *         with that return code.
   */
  static inline int arch_elf_pt_proc(struct elfhdr *ehdr,
  				   struct elf_phdr *phdr,
  				   struct file *elf, bool is_interp,
  				   struct arch_elf_state *state)
  {
  	/* Dummy implementation, always proceed */
  	return 0;
  }
  
  /**
54d15714f   Maciej W. Rozycki   binfmt_elf: Corre...
469
   * arch_check_elf() - check an ELF executable
774c105ed   Paul Burton   binfmt_elf: allow...
470
471
   * @ehdr:	The main ELF header
   * @has_interp:	True if the ELF has an interpreter, else false.
eb4bc076f   Maciej W. Rozycki   ELF: Also pass an...
472
   * @interp_ehdr: The interpreter's ELF header
774c105ed   Paul Burton   binfmt_elf: allow...
473
474
475
476
477
478
479
480
481
482
483
   * @state:	Architecture-specific state preserved throughout the process
   *		of loading the ELF.
   *
   * Provides a final opportunity for architecture code to reject the loading
   * of the ELF & cause an exec syscall to return an error. This is called after
   * all program headers to be checked by arch_elf_pt_proc have been.
   *
   * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
   *         with that return code.
   */
  static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
eb4bc076f   Maciej W. Rozycki   ELF: Also pass an...
484
  				 struct elfhdr *interp_ehdr,
774c105ed   Paul Burton   binfmt_elf: allow...
485
486
487
488
489
490
491
  				 struct arch_elf_state *state)
  {
  	/* Dummy implementation, always proceed */
  	return 0;
  }
  
  #endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */
cc503c1b4   Jiri Kosina   x86: PIE executab...
492

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
  /* This is much more generalized than the library routine read function,
     so we keep this separate.  Technically the library read function
     is only provided so that we can read a.out libraries that have
     an ELF header */
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
497
  static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
cc503c1b4   Jiri Kosina   x86: PIE executab...
498
  		struct file *interpreter, unsigned long *interp_map_addr,
a9d9ef133   Paul Burton   binfmt_elf: load ...
499
  		unsigned long no_base, struct elf_phdr *interp_elf_phdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
  	struct elf_phdr *eppnt;
  	unsigned long load_addr = 0;
  	int load_addr_set = 0;
  	unsigned long last_bss = 0, elf_bss = 0;
  	unsigned long error = ~0UL;
cc503c1b4   Jiri Kosina   x86: PIE executab...
506
  	unsigned long total_size;
6a8d38945   Paul Burton   binfmt_elf: Hoist...
507
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
  
  	/* First of all, some simple consistency checks */
  	if (interp_elf_ex->e_type != ET_EXEC &&
  	    interp_elf_ex->e_type != ET_DYN)
  		goto out;
  	if (!elf_check_arch(interp_elf_ex))
  		goto out;
72c2d5319   Al Viro   file->f_op is nev...
515
  	if (!interpreter->f_op->mmap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  		goto out;
a9d9ef133   Paul Burton   binfmt_elf: load ...
517
518
  	total_size = total_mapping_size(interp_elf_phdata,
  					interp_elf_ex->e_phnum);
cc503c1b4   Jiri Kosina   x86: PIE executab...
519
520
  	if (!total_size) {
  		error = -EINVAL;
a9d9ef133   Paul Burton   binfmt_elf: load ...
521
  		goto out;
cc503c1b4   Jiri Kosina   x86: PIE executab...
522
  	}
a9d9ef133   Paul Burton   binfmt_elf: load ...
523
  	eppnt = interp_elf_phdata;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  	for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
  		if (eppnt->p_type == PT_LOAD) {
  			int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
  			int elf_prot = 0;
  			unsigned long vaddr = 0;
  			unsigned long k, map_addr;
  
  			if (eppnt->p_flags & PF_R)
  		    		elf_prot = PROT_READ;
  			if (eppnt->p_flags & PF_W)
  				elf_prot |= PROT_WRITE;
  			if (eppnt->p_flags & PF_X)
  				elf_prot |= PROT_EXEC;
  			vaddr = eppnt->p_vaddr;
  			if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
  				elf_type |= MAP_FIXED;
cc503c1b4   Jiri Kosina   x86: PIE executab...
540
541
  			else if (no_base && interp_elf_ex->e_type == ET_DYN)
  				load_addr = -vaddr;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
542
543
  
  			map_addr = elf_map(interpreter, load_addr + vaddr,
bb1ad8205   Andrew Morton   x86: PIE executab...
544
  					eppnt, elf_prot, elf_type, total_size);
cc503c1b4   Jiri Kosina   x86: PIE executab...
545
546
547
  			total_size = 0;
  			if (!*interp_map_addr)
  				*interp_map_addr = map_addr;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
548
549
  			error = map_addr;
  			if (BAD_ADDR(map_addr))
a9d9ef133   Paul Burton   binfmt_elf: load ...
550
  				goto out;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
551
552
553
554
555
556
557
558
559
560
561
562
563
  
  			if (!load_addr_set &&
  			    interp_elf_ex->e_type == ET_DYN) {
  				load_addr = map_addr - ELF_PAGESTART(vaddr);
  				load_addr_set = 1;
  			}
  
  			/*
  			 * Check to see if the section's size will overflow the
  			 * allowed task size. Note that p_filesz must always be
  			 * <= p_memsize so it's only necessary to check p_memsz.
  			 */
  			k = load_addr + eppnt->p_vaddr;
ce51059be   Chuck Ebbert   [PATCH] binfmt_el...
564
  			if (BAD_ADDR(k) ||
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
565
566
567
568
  			    eppnt->p_filesz > eppnt->p_memsz ||
  			    eppnt->p_memsz > TASK_SIZE ||
  			    TASK_SIZE - eppnt->p_memsz < k) {
  				error = -ENOMEM;
a9d9ef133   Paul Burton   binfmt_elf: load ...
569
  				goto out;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  			}
  
  			/*
  			 * Find the end of the file mapping for this phdr, and
  			 * keep track of the largest address we see for this.
  			 */
  			k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
  			if (k > elf_bss)
  				elf_bss = k;
  
  			/*
  			 * Do the same thing for the memory mapping - between
  			 * elf_bss and last_bss is the bss section.
  			 */
0036d1f7e   Kees Cook   binfmt_elf: fix c...
584
  			k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
585
586
587
  			if (k > last_bss)
  				last_bss = k;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  	}
0036d1f7e   Kees Cook   binfmt_elf: fix c...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  	/*
  	 * Now fill out the bss section: first pad the last page from
  	 * the file up to the page boundary, and zero it from elf_bss
  	 * up to the end of the page.
  	 */
  	if (padzero(elf_bss)) {
  		error = -EFAULT;
  		goto out;
  	}
  	/*
  	 * Next, align both the file and mem bss up to the page size,
  	 * since this is where elf_bss was just zeroed up to, and where
  	 * last_bss will end after the vm_brk() below.
  	 */
  	elf_bss = ELF_PAGEALIGN(elf_bss);
  	last_bss = ELF_PAGEALIGN(last_bss);
  	/* Finally, if there is still more bss to allocate, do it. */
752015d1b   Roland McGrath   binfmt_elf: fix P...
606
  	if (last_bss > elf_bss) {
e4eb1ff61   Linus Torvalds   VM: add "vm_brk()...
607
  		error = vm_brk(elf_bss, last_bss - elf_bss);
5d22fc25d   Linus Torvalds   mm: remove more I...
608
  		if (error)
a9d9ef133   Paul Burton   binfmt_elf: load ...
609
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  	}
cc503c1b4   Jiri Kosina   x86: PIE executab...
611
  	error = load_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
  out:
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
  /*
   * These are the functions used to load ELF style executables and shared
   * libraries.  There is no binary dependent code anywhere else.
   */
913bd9060   Andi Kleen   [PATCH] x86_64: I...
619
  #ifndef STACK_RND_MASK
d1cabd632   James Bottomley   [PATCH] fix proce...
620
  #define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12))	/* 8MB of VA */
913bd9060   Andi Kleen   [PATCH] x86_64: I...
621
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
  
  static unsigned long randomize_stack_top(unsigned long stack_top)
  {
4e7c22d44   Hector Marco-Gisbert   x86, mm/ASLR: Fix...
625
  	unsigned long random_variable = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626

c16b63e09   Andi Kleen   [PATCH] i386/x86-...
627
628
  	if ((current->flags & PF_RANDOMIZE) &&
  		!(current->personality & ADDR_NO_RANDOMIZE)) {
5ef11c35c   Daniel Cashman   mm: ASLR: use get...
629
  		random_variable = get_random_long();
4e7c22d44   Hector Marco-Gisbert   x86, mm/ASLR: Fix...
630
  		random_variable &= STACK_RND_MASK;
913bd9060   Andi Kleen   [PATCH] x86_64: I...
631
632
  		random_variable <<= PAGE_SHIFT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
  #ifdef CONFIG_STACK_GROWSUP
913bd9060   Andi Kleen   [PATCH] x86_64: I...
634
  	return PAGE_ALIGN(stack_top) + random_variable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  #else
913bd9060   Andi Kleen   [PATCH] x86_64: I...
636
  	return PAGE_ALIGN(stack_top) - random_variable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  #endif
  }
71613c3b8   Al Viro   get rid of pt_reg...
639
  static int load_elf_binary(struct linux_binprm *bprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
  {
  	struct file *interpreter = NULL; /* to shut gcc up */
   	unsigned long load_addr = 0, load_bias = 0;
  	int load_addr_set = 0;
  	char * elf_interpreter = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  	unsigned long error;
a9d9ef133   Paul Burton   binfmt_elf: load ...
646
  	struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  	unsigned long elf_bss, elf_brk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  	int retval, i;
cc503c1b4   Jiri Kosina   x86: PIE executab...
649
650
  	unsigned long elf_entry;
  	unsigned long interp_load_addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  	unsigned long start_code, end_code, start_data, end_data;
1a530a6f2   David Daney   binfmt_elf: quiet...
652
  	unsigned long reloc_func_desc __maybe_unused = 0;
8de61e69c   David Rientjes   [PATCH] fs: remov...
653
  	int executable_stack = EXSTACK_DEFAULT;
71613c3b8   Al Viro   get rid of pt_reg...
654
  	struct pt_regs *regs = current_pt_regs();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
  	struct {
  		struct elfhdr elf_ex;
  		struct elfhdr interp_elf_ex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  	} *loc;
774c105ed   Paul Burton   binfmt_elf: allow...
659
  	struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
663
664
665
666
667
  
  	loc = kmalloc(sizeof(*loc), GFP_KERNEL);
  	if (!loc) {
  		retval = -ENOMEM;
  		goto out_ret;
  	}
  	
  	/* Get the exec-header */
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
668
  	loc->elf_ex = *((struct elfhdr *)bprm->buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
676
677
678
  
  	retval = -ENOEXEC;
  	/* First of all, some simple consistency checks */
  	if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
  		goto out;
  
  	if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
  		goto out;
  	if (!elf_check_arch(&loc->elf_ex))
  		goto out;
72c2d5319   Al Viro   file->f_op is nev...
679
  	if (!bprm->file->f_op->mmap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  		goto out;
6a8d38945   Paul Burton   binfmt_elf: Hoist...
681
  	elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
  	if (!elf_phdata)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  	elf_ppnt = elf_phdata;
  	elf_bss = 0;
  	elf_brk = 0;
  
  	start_code = ~0UL;
  	end_code = 0;
  	start_data = 0;
  	end_data = 0;
  
  	for (i = 0; i < loc->elf_ex.e_phnum; i++) {
  		if (elf_ppnt->p_type == PT_INTERP) {
  			/* This is the program interpreter used for
  			 * shared libraries - for now assume that this
  			 * is an a.out format binary
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  			retval = -ENOEXEC;
  			if (elf_ppnt->p_filesz > PATH_MAX || 
  			    elf_ppnt->p_filesz < 2)
e7b9b550f   Al Viro   Don't mess with d...
702
  				goto out_free_ph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
  
  			retval = -ENOMEM;
792db3af3   Jesper Juhl   [PATCH] fs/binfmt...
705
  			elf_interpreter = kmalloc(elf_ppnt->p_filesz,
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
706
  						  GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
  			if (!elf_interpreter)
e7b9b550f   Al Viro   Don't mess with d...
708
  				goto out_free_ph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
  
  			retval = kernel_read(bprm->file, elf_ppnt->p_offset,
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
711
712
  					     elf_interpreter,
  					     elf_ppnt->p_filesz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
718
719
720
721
  			if (retval != elf_ppnt->p_filesz) {
  				if (retval >= 0)
  					retval = -EIO;
  				goto out_free_interp;
  			}
  			/* make sure path is NULL terminated */
  			retval = -ENOEXEC;
  			if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
  				goto out_free_interp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
  			interpreter = open_exec(elf_interpreter);
  			retval = PTR_ERR(interpreter);
  			if (IS_ERR(interpreter))
  				goto out_free_interp;
1fb844961   Alexey Dobriyan   [PATCH] core-dump...
726
727
728
729
730
731
  
  			/*
  			 * If the binary is not readable then enforce
  			 * mm->dumpable = 0 regardless of the interpreter's
  			 * permissions.
  			 */
1b5d783c9   Al Viro   consolidate BINPR...
732
  			would_dump(bprm, interpreter);
1fb844961   Alexey Dobriyan   [PATCH] core-dump...
733

b582ef5c5   Maciej W. Rozycki   binfmt_elf: Don't...
734
735
736
737
738
  			/* Get the exec headers */
  			retval = kernel_read(interpreter, 0,
  					     (void *)&loc->interp_elf_ex,
  					     sizeof(loc->interp_elf_ex));
  			if (retval != sizeof(loc->interp_elf_ex)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
742
  				if (retval >= 0)
  					retval = -EIO;
  				goto out_free_dentry;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
749
  			break;
  		}
  		elf_ppnt++;
  	}
  
  	elf_ppnt = elf_phdata;
  	for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
774c105ed   Paul Burton   binfmt_elf: allow...
750
751
  		switch (elf_ppnt->p_type) {
  		case PT_GNU_STACK:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
  			if (elf_ppnt->p_flags & PF_X)
  				executable_stack = EXSTACK_ENABLE_X;
  			else
  				executable_stack = EXSTACK_DISABLE_X;
  			break;
774c105ed   Paul Burton   binfmt_elf: allow...
757
758
759
760
761
762
763
764
  
  		case PT_LOPROC ... PT_HIPROC:
  			retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt,
  						  bprm->file, false,
  						  &arch_state);
  			if (retval)
  				goto out_free_dentry;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
  
  	/* Some simple consistency checks for the interpreter */
  	if (elf_interpreter) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  		retval = -ELIBBAD;
d20894a23   Andi Kleen   Remove a.out inte...
770
771
  		/* Not an ELF interpreter */
  		if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  			goto out_free_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  		/* Verify the interpreter has a valid arch */
d20894a23   Andi Kleen   Remove a.out inte...
774
  		if (!elf_check_arch(&loc->interp_elf_ex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  			goto out_free_dentry;
a9d9ef133   Paul Burton   binfmt_elf: load ...
776
777
778
779
780
781
  
  		/* Load the interpreter program headers */
  		interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex,
  						   interpreter);
  		if (!interp_elf_phdata)
  			goto out_free_dentry;
774c105ed   Paul Burton   binfmt_elf: allow...
782
783
784
785
786
787
788
789
790
791
792
793
794
  
  		/* Pass PT_LOPROC..PT_HIPROC headers to arch code */
  		elf_ppnt = interp_elf_phdata;
  		for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++)
  			switch (elf_ppnt->p_type) {
  			case PT_LOPROC ... PT_HIPROC:
  				retval = arch_elf_pt_proc(&loc->interp_elf_ex,
  							  elf_ppnt, interpreter,
  							  true, &arch_state);
  				if (retval)
  					goto out_free_dentry;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  	}
774c105ed   Paul Burton   binfmt_elf: allow...
796
797
798
799
800
  	/*
  	 * Allow arch code to reject the ELF at this point, whilst it's
  	 * still possible to return an error to the code that invoked
  	 * the exec syscall.
  	 */
eb4bc076f   Maciej W. Rozycki   ELF: Also pass an...
801
802
803
  	retval = arch_check_elf(&loc->elf_ex,
  				!!interpreter, &loc->interp_elf_ex,
  				&arch_state);
774c105ed   Paul Burton   binfmt_elf: allow...
804
805
  	if (retval)
  		goto out_free_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
  	/* Flush all traces of the currently running executable */
  	retval = flush_old_exec(bprm);
  	if (retval)
  		goto out_free_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
  	   may depend on the personality.  */
774c105ed   Paul Burton   binfmt_elf: allow...
812
  	SET_PERSONALITY2(loc->elf_ex, &arch_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
  	if (elf_read_implies_exec(loc->elf_ex, executable_stack))
  		current->personality |= READ_IMPLIES_EXEC;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
815
  	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  		current->flags |= PF_RANDOMIZE;
221af7f87   Linus Torvalds   Split 'flush_old_...
817
818
  
  	setup_new_exec(bprm);
9f834ec18   Linus Torvalds   binfmt_elf: switc...
819
  	install_exec_creds(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
  
  	/* Do this so that we can load the interpreter, if need be.  We will
  	   change some of these later */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
  	retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
  				 executable_stack);
19d860a14   Al Viro   handle suicide on...
825
  	if (retval < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  		goto out_free_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  	current->mm->start_stack = bprm->p;
af901ca18   André Goddard Rosa   tree-wide: fix as...
829
  	/* Now we do a little grungy work by mmapping the ELF image into
cc503c1b4   Jiri Kosina   x86: PIE executab...
830
  	   the correct location in memory. */
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
831
832
  	for(i = 0, elf_ppnt = elf_phdata;
  	    i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
  		int elf_prot = 0, elf_flags;
  		unsigned long k, vaddr;
a87938b2e   Michael Davidson   fs/binfmt_elf.c: ...
835
  		unsigned long total_size = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
843
844
845
  
  		if (elf_ppnt->p_type != PT_LOAD)
  			continue;
  
  		if (unlikely (elf_brk > elf_bss)) {
  			unsigned long nbyte;
  	            
  			/* There was a PT_LOAD segment with p_memsz > p_filesz
  			   before this one. Map anonymous pages, if needed,
  			   and clear the area.  */
f670d0ecd   Mikael Pettersson   binfmt_elf: cleanups
846
847
  			retval = set_brk(elf_bss + load_bias,
  					 elf_brk + load_bias);
19d860a14   Al Viro   handle suicide on...
848
  			if (retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  				goto out_free_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
852
853
854
855
856
857
858
  			nbyte = ELF_PAGEOFFSET(elf_bss);
  			if (nbyte) {
  				nbyte = ELF_MIN_ALIGN - nbyte;
  				if (nbyte > elf_brk - elf_bss)
  					nbyte = elf_brk - elf_bss;
  				if (clear_user((void __user *)elf_bss +
  							load_bias, nbyte)) {
  					/*
  					 * This bss-zeroing can fail if the ELF
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
859
  					 * file specifies odd protections. So
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
  					 * we don't check the return value
  					 */
  				}
  			}
  		}
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
865
866
867
868
869
870
  		if (elf_ppnt->p_flags & PF_R)
  			elf_prot |= PROT_READ;
  		if (elf_ppnt->p_flags & PF_W)
  			elf_prot |= PROT_WRITE;
  		if (elf_ppnt->p_flags & PF_X)
  			elf_prot |= PROT_EXEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871

f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
872
  		elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
  
  		vaddr = elf_ppnt->p_vaddr;
  		if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
  			elf_flags |= MAP_FIXED;
  		} else if (loc->elf_ex.e_type == ET_DYN) {
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
878
879
880
881
  			/* Try and get dynamic programs out of the way of the
  			 * default mmap base, as well as whatever program they
  			 * might try to exec.  This is because the brk will
  			 * follow the loader, and is not movable.  */
d1fd836dc   Kees Cook   mm: split ET_DYN ...
882
  			load_bias = ELF_ET_DYN_BASE - vaddr;
a3defbe5c   Jiri Kosina   binfmt_elf: fix P...
883
  			if (current->flags & PF_RANDOMIZE)
d1fd836dc   Kees Cook   mm: split ET_DYN ...
884
885
  				load_bias += arch_mmap_rnd();
  			load_bias = ELF_PAGESTART(load_bias);
a87938b2e   Michael Davidson   fs/binfmt_elf.c: ...
886
887
888
  			total_size = total_mapping_size(elf_phdata,
  							loc->elf_ex.e_phnum);
  			if (!total_size) {
2b1d3ae94   Andrew Morton   fs/binfmt_elf.c:l...
889
  				retval = -EINVAL;
a87938b2e   Michael Davidson   fs/binfmt_elf.c: ...
890
891
  				goto out_free_dentry;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  		}
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
893
  		error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
a87938b2e   Michael Davidson   fs/binfmt_elf.c: ...
894
  				elf_prot, elf_flags, total_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  		if (BAD_ADDR(error)) {
b140f2510   Alexey Kuznetsov   Invalid return va...
896
897
  			retval = IS_ERR((void *)error) ?
  				PTR_ERR((void*)error) : -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
902
903
904
905
906
907
908
909
910
911
  			goto out_free_dentry;
  		}
  
  		if (!load_addr_set) {
  			load_addr_set = 1;
  			load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
  			if (loc->elf_ex.e_type == ET_DYN) {
  				load_bias += error -
  				             ELF_PAGESTART(load_bias + vaddr);
  				load_addr += load_bias;
  				reloc_func_desc = load_bias;
  			}
  		}
  		k = elf_ppnt->p_vaddr;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
912
913
914
915
  		if (k < start_code)
  			start_code = k;
  		if (start_data < k)
  			start_data = k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
920
921
  
  		/*
  		 * Check to see if the section's size will overflow the
  		 * allowed task size. Note that p_filesz must always be
  		 * <= p_memsz so it is only necessary to check p_memsz.
  		 */
ce51059be   Chuck Ebbert   [PATCH] binfmt_el...
922
  		if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  		    elf_ppnt->p_memsz > TASK_SIZE ||
  		    TASK_SIZE - elf_ppnt->p_memsz < k) {
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
925
  			/* set_brk can never work. Avoid overflows. */
b140f2510   Alexey Kuznetsov   Invalid return va...
926
  			retval = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
  			goto out_free_dentry;
  		}
  
  		k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
  
  		if (k > elf_bss)
  			elf_bss = k;
  		if ((elf_ppnt->p_flags & PF_X) && end_code < k)
  			end_code = k;
  		if (end_data < k)
  			end_data = k;
  		k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
  		if (k > elf_brk)
  			elf_brk = k;
  	}
  
  	loc->elf_ex.e_entry += load_bias;
  	elf_bss += load_bias;
  	elf_brk += load_bias;
  	start_code += load_bias;
  	end_code += load_bias;
  	start_data += load_bias;
  	end_data += load_bias;
  
  	/* Calling set_brk effectively mmaps the pages that we need
  	 * for the bss and break sections.  We must do this before
  	 * mapping in the interpreter, to make sure it doesn't wind
  	 * up getting placed where the bss needs to go.
  	 */
  	retval = set_brk(elf_bss, elf_brk);
19d860a14   Al Viro   handle suicide on...
957
  	if (retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
  		goto out_free_dentry;
6de505173   Andrew Morton   [PATCH] binfmt_el...
959
  	if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
  		retval = -EFAULT; /* Nobody gets to see this, but.. */
  		goto out_free_dentry;
  	}
  
  	if (elf_interpreter) {
6eec482f4   Alan Cox   binfmt_elf: Unini...
965
  		unsigned long interp_map_addr = 0;
d20894a23   Andi Kleen   Remove a.out inte...
966
967
968
969
  
  		elf_entry = load_elf_interp(&loc->interp_elf_ex,
  					    interpreter,
  					    &interp_map_addr,
a9d9ef133   Paul Burton   binfmt_elf: load ...
970
  					    load_bias, interp_elf_phdata);
d20894a23   Andi Kleen   Remove a.out inte...
971
972
973
974
975
976
977
  		if (!IS_ERR((void *)elf_entry)) {
  			/*
  			 * load_elf_interp() returns relocation
  			 * adjustment
  			 */
  			interp_load_addr = elf_entry;
  			elf_entry += loc->interp_elf_ex.e_entry;
cc503c1b4   Jiri Kosina   x86: PIE executab...
978
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
  		if (BAD_ADDR(elf_entry)) {
ce51059be   Chuck Ebbert   [PATCH] binfmt_el...
980
981
  			retval = IS_ERR((void *)elf_entry) ?
  					(int)elf_entry : -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
985
986
987
988
989
990
  			goto out_free_dentry;
  		}
  		reloc_func_desc = interp_load_addr;
  
  		allow_write_access(interpreter);
  		fput(interpreter);
  		kfree(elf_interpreter);
  	} else {
  		elf_entry = loc->elf_ex.e_entry;
5342fba54   Suresh Siddha   [PATCH] x86_64: C...
991
  		if (BAD_ADDR(elf_entry)) {
ce51059be   Chuck Ebbert   [PATCH] binfmt_el...
992
  			retval = -EINVAL;
5342fba54   Suresh Siddha   [PATCH] x86_64: C...
993
994
  			goto out_free_dentry;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  	}
774c105ed   Paul Burton   binfmt_elf: allow...
996
  	kfree(interp_elf_phdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
  	kfree(elf_phdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
  	set_binfmt(&elf_format);
547ee84ce   Benjamin Herrenschmidt   [PATCH] ppc64: Im...
999
  #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
fc5243d98   Martin Schwidefsky   [S390] arch_setup...
1000
  	retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
19d860a14   Al Viro   handle suicide on...
1001
  	if (retval < 0)
18c8baff8   Roland McGrath   [PATCH] Fix error...
1002
  		goto out;
547ee84ce   Benjamin Herrenschmidt   [PATCH] ppc64: Im...
1003
  #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
b6a2fea39   Ollie Wild   mm: variable leng...
1004
  	retval = create_elf_tables(bprm, &loc->elf_ex,
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1005
  			  load_addr, interp_load_addr);
19d860a14   Al Viro   handle suicide on...
1006
  	if (retval < 0)
b6a2fea39   Ollie Wild   mm: variable leng...
1007
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
  	/* N.B. passed_fileno might not be initialized? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
1011
1012
1013
  	current->mm->end_code = end_code;
  	current->mm->start_code = start_code;
  	current->mm->start_data = start_data;
  	current->mm->end_data = end_data;
  	current->mm->start_stack = bprm->p;
4471a675d   Jiri Kosina   brk: COMPAT_BRK: ...
1014
  	if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
c1d171a00   Jiri Kosina   x86: randomize brk
1015
1016
  		current->mm->brk = current->mm->start_brk =
  			arch_randomize_brk(current->mm);
204db6ed1   Kees Cook   mm: fold arch_ran...
1017
  #ifdef compat_brk_randomized
4471a675d   Jiri Kosina   brk: COMPAT_BRK: ...
1018
1019
1020
  		current->brk_randomized = 1;
  #endif
  	}
c1d171a00   Jiri Kosina   x86: randomize brk
1021

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
1023
1024
1025
  	if (current->personality & MMAP_PAGE_ZERO) {
  		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
  		   and some applications "depend" upon this behavior.
  		   Since we do not have the power to recompile these, we
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1026
  		   emulate the SVr4 behavior. Sigh. */
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
1027
  		error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
  				MAP_FIXED | MAP_PRIVATE, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
  	}
  
  #ifdef ELF_PLAT_INIT
  	/*
  	 * The ABI may specify that certain registers be set up in special
  	 * ways (on i386 %edx is the address of a DT_FINI function, for
  	 * example.  In addition, it may also specify (eg, PowerPC64 ELF)
  	 * that the e_entry field is the address of the function descriptor
  	 * for the startup routine, rather than the address of the startup
  	 * routine itself.  This macro performs whatever initialization to
  	 * the regs structure is required as well as any relocations to the
  	 * function descriptor entries when executing dynamically links apps.
  	 */
  	ELF_PLAT_INIT(regs, reloc_func_desc);
  #endif
  
  	start_thread(regs, elf_entry, bprm->p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
1051
1052
1053
  	retval = 0;
  out:
  	kfree(loc);
  out_ret:
  	return retval;
  
  	/* error cleanup */
  out_free_dentry:
a9d9ef133   Paul Burton   binfmt_elf: load ...
1054
  	kfree(interp_elf_phdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
1057
1058
  	allow_write_access(interpreter);
  	if (interpreter)
  		fput(interpreter);
  out_free_interp:
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
1059
  	kfree(elf_interpreter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
  out_free_ph:
  	kfree(elf_phdata);
  	goto out;
  }
69369a700   Josh Triplett   fs, kernel: permi...
1064
  #ifdef CONFIG_USELIB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
  /* This is really simpleminded and specialized - we are loading an
     a.out library that is given an ELF header. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
1071
1072
1073
1074
1075
  static int load_elf_library(struct file *file)
  {
  	struct elf_phdr *elf_phdata;
  	struct elf_phdr *eppnt;
  	unsigned long elf_bss, bss, len;
  	int retval, error, i, j;
  	struct elfhdr elf_ex;
  
  	error = -ENOEXEC;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1076
  	retval = kernel_read(file, 0, (char *)&elf_ex, sizeof(elf_ex));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
1079
1080
1081
1082
1083
1084
  	if (retval != sizeof(elf_ex))
  		goto out;
  
  	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
  		goto out;
  
  	/* First of all, some simple consistency checks */
  	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
72c2d5319   Al Viro   file->f_op is nev...
1085
  	    !elf_check_arch(&elf_ex) || !file->f_op->mmap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
  		goto out;
  
  	/* Now read in all of the header information */
  
  	j = sizeof(struct elf_phdr) * elf_ex.e_phnum;
  	/* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */
  
  	error = -ENOMEM;
  	elf_phdata = kmalloc(j, GFP_KERNEL);
  	if (!elf_phdata)
  		goto out;
  
  	eppnt = elf_phdata;
  	error = -ENOEXEC;
  	retval = kernel_read(file, elf_ex.e_phoff, (char *)eppnt, j);
  	if (retval != j)
  		goto out_free_ph;
  
  	for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
  		if ((eppnt + i)->p_type == PT_LOAD)
  			j++;
  	if (j != 1)
  		goto out_free_ph;
  
  	while (eppnt->p_type != PT_LOAD)
  		eppnt++;
  
  	/* Now use mmap to map the library into memory. */
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
1114
  	error = vm_mmap(file,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
1117
1118
1119
1120
1121
  			ELF_PAGESTART(eppnt->p_vaddr),
  			(eppnt->p_filesz +
  			 ELF_PAGEOFFSET(eppnt->p_vaddr)),
  			PROT_READ | PROT_WRITE | PROT_EXEC,
  			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
  			(eppnt->p_offset -
  			 ELF_PAGEOFFSET(eppnt->p_vaddr)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
1123
1124
1125
1126
1127
1128
1129
  	if (error != ELF_PAGESTART(eppnt->p_vaddr))
  		goto out_free_ph;
  
  	elf_bss = eppnt->p_vaddr + eppnt->p_filesz;
  	if (padzero(elf_bss)) {
  		error = -EFAULT;
  		goto out_free_ph;
  	}
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1130
1131
  	len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr +
  			    ELF_MIN_ALIGN - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
  	bss = eppnt->p_memsz + eppnt->p_vaddr;
ecc2bc8ac   Michal Hocko   mm, elf: handle v...
1133
1134
  	if (bss > len) {
  		error = vm_brk(len, bss - len);
5d22fc25d   Linus Torvalds   mm: remove more I...
1135
  		if (error)
ecc2bc8ac   Michal Hocko   mm, elf: handle v...
1136
1137
  			goto out_free_ph;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
1142
1143
1144
  	error = 0;
  
  out_free_ph:
  	kfree(elf_phdata);
  out:
  	return error;
  }
69369a700   Josh Triplett   fs, kernel: permi...
1145
  #endif /* #ifdef CONFIG_USELIB */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146

698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
1147
  #ifdef CONFIG_ELF_CORE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
1151
1152
1153
  /*
   * ELF core dumper
   *
   * Modelled on fs/exec.c:aout_core_dump()
   * Jeremy Fitzhardinge <jeremy@sw.oz.au>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
  
  /*
909af768e   Jason Baron   coredump: remove ...
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
   * The purpose of always_dump_vma() is to make sure that special kernel mappings
   * that are useful for post-mortem analysis are included in every core dump.
   * In that way we ensure that the core dump is fully interpretable later
   * without matching up the same kernel and hardware config to see what PC values
   * meant. These special mappings include - vDSO, vsyscall, and other
   * architecture specific mappings
   */
  static bool always_dump_vma(struct vm_area_struct *vma)
  {
  	/* Any vsyscall mappings? */
  	if (vma == get_gate_vma(vma->vm_mm))
  		return true;
78d683e83   Andy Lutomirski   mm, fs: Add vm_op...
1168
1169
1170
1171
1172
1173
1174
  
  	/*
  	 * Assume that all vmas with a .name op should always be dumped.
  	 * If this changes, a new vm_ops field can easily be added.
  	 */
  	if (vma->vm_ops && vma->vm_ops->name && vma->vm_ops->name(vma))
  		return true;
909af768e   Jason Baron   coredump: remove ...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
  	/*
  	 * arch_vma_name() returns non-NULL for special architecture mappings,
  	 * such as vDSO sections.
  	 */
  	if (arch_vma_name(vma))
  		return true;
  
  	return false;
  }
  
  /*
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1186
   * Decide what to dump of a segment, part, all or none.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
   */
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1188
1189
  static unsigned long vma_dump_size(struct vm_area_struct *vma,
  				   unsigned long mm_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
  {
e575f111d   KOSAKI Motohiro   coredump_filter: ...
1191
  #define FILTER(type)	(mm_flags & (1UL << MMF_DUMP_##type))
909af768e   Jason Baron   coredump: remove ...
1192
1193
  	/* always dump the vdso and vsyscall sections */
  	if (always_dump_vma(vma))
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1194
  		goto whole;
e5b97dde5   Roland McGrath   [PATCH] Add VM_AL...
1195

0103bd16f   Konstantin Khlebnikov   mm: prepare VM_DO...
1196
  	if (vma->vm_flags & VM_DONTDUMP)
accb61fe7   Jason Baron   coredump: add VM_...
1197
  		return 0;
5037835c1   Ross Zwisler   coredump: add DAX...
1198
1199
1200
1201
1202
1203
1204
1205
  	/* support for DAX */
  	if (vma_is_dax(vma)) {
  		if ((vma->vm_flags & VM_SHARED) && FILTER(DAX_SHARED))
  			goto whole;
  		if (!(vma->vm_flags & VM_SHARED) && FILTER(DAX_PRIVATE))
  			goto whole;
  		return 0;
  	}
e575f111d   KOSAKI Motohiro   coredump_filter: ...
1206
1207
1208
1209
1210
1211
  	/* Hugetlb memory check */
  	if (vma->vm_flags & VM_HUGETLB) {
  		if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED))
  			goto whole;
  		if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE))
  			goto whole;
23d9e4821   Naoya Horiguchi   fs/binfmt_elf.c: ...
1212
  		return 0;
e575f111d   KOSAKI Motohiro   coredump_filter: ...
1213
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
  	/* Do not dump I/O mapped devices or special mappings */
314e51b98   Konstantin Khlebnikov   mm: kill vma flag...
1215
  	if (vma->vm_flags & VM_IO)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  		return 0;
a1b59e802   Kawai, Hidehiro   coredump masking:...
1217
1218
  	/* By default, dump shared memory if mapped from an anonymous file. */
  	if (vma->vm_flags & VM_SHARED) {
496ad9aa8   Al Viro   new helper: file_...
1219
  		if (file_inode(vma->vm_file)->i_nlink == 0 ?
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1220
1221
1222
  		    FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED))
  			goto whole;
  		return 0;
a1b59e802   Kawai, Hidehiro   coredump masking:...
1223
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224

82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1225
1226
1227
1228
1229
  	/* Dump segments that have been written to.  */
  	if (vma->anon_vma && FILTER(ANON_PRIVATE))
  		goto whole;
  	if (vma->vm_file == NULL)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230

82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1231
1232
1233
1234
1235
1236
1237
1238
  	if (FILTER(MAPPED_PRIVATE))
  		goto whole;
  
  	/*
  	 * If this looks like the beginning of a DSO or executable mapping,
  	 * check for an ELF header.  If we find one, dump the first page to
  	 * aid in determining what was mapped here.
  	 */
92dc07b1f   Roland McGrath   elf core dump: fi...
1239
1240
  	if (FILTER(ELF_HEADERS) &&
  	    vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) {
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1241
1242
  		u32 __user *header = (u32 __user *) vma->vm_start;
  		u32 word;
92dc07b1f   Roland McGrath   elf core dump: fi...
1243
  		mm_segment_t fs = get_fs();
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
  		/*
  		 * Doing it this way gets the constant folded by GCC.
  		 */
  		union {
  			u32 cmp;
  			char elfmag[SELFMAG];
  		} magic;
  		BUILD_BUG_ON(SELFMAG != sizeof word);
  		magic.elfmag[EI_MAG0] = ELFMAG0;
  		magic.elfmag[EI_MAG1] = ELFMAG1;
  		magic.elfmag[EI_MAG2] = ELFMAG2;
  		magic.elfmag[EI_MAG3] = ELFMAG3;
92dc07b1f   Roland McGrath   elf core dump: fi...
1256
1257
1258
1259
1260
1261
1262
1263
1264
  		/*
  		 * Switch to the user "segment" for get_user(),
  		 * then put back what elf_core_dump() had in place.
  		 */
  		set_fs(USER_DS);
  		if (unlikely(get_user(word, header)))
  			word = 0;
  		set_fs(fs);
  		if (word == magic.cmp)
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
1265
1266
1267
1268
1269
1270
1271
1272
1273
  			return PAGE_SIZE;
  	}
  
  #undef	FILTER
  
  	return 0;
  
  whole:
  	return vma->vm_end - vma->vm_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
  /* An ELF note in memory */
  struct memelfnote
  {
  	const char *name;
  	int type;
  	unsigned int datasz;
  	void *data;
  };
  
  static int notesize(struct memelfnote *en)
  {
  	int sz;
  
  	sz = sizeof(struct elf_note);
  	sz += roundup(strlen(en->name) + 1, 4);
  	sz += roundup(en->datasz, 4);
  
  	return sz;
  }
ecc8c7725   Al Viro   new helper: dump_...
1294
  static int writenote(struct memelfnote *men, struct coredump_params *cprm)
d025c9db7   Andi Kleen   [PATCH] Support p...
1295
1296
  {
  	struct elf_note en;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
1298
1299
  	en.n_namesz = strlen(men->name) + 1;
  	en.n_descsz = men->datasz;
  	en.n_type = men->type;
ecc8c7725   Al Viro   new helper: dump_...
1300
  	return dump_emit(cprm, &en, sizeof(en)) &&
22a8cb824   Al Viro   new helper: dump_...
1301
1302
  	    dump_emit(cprm, men->name, en.n_namesz) && dump_align(cprm, 4) &&
  	    dump_emit(cprm, men->data, men->datasz) && dump_align(cprm, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304

3aba481fc   Roland McGrath   elf core dump: no...
1305
  static void fill_elf_header(struct elfhdr *elf, int segs,
d3330cf08   Zhang Yanfei   binfmt_elf: remov...
1306
  			    u16 machine, u32 flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
  {
6970c8eff   Cyrill Gorcunov   BINFMT: fill_elf_...
1308
  	memset(elf, 0, sizeof(*elf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
1311
1312
1313
  	memcpy(elf->e_ident, ELFMAG, SELFMAG);
  	elf->e_ident[EI_CLASS] = ELF_CLASS;
  	elf->e_ident[EI_DATA] = ELF_DATA;
  	elf->e_ident[EI_VERSION] = EV_CURRENT;
  	elf->e_ident[EI_OSABI] = ELF_OSABI;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
  
  	elf->e_type = ET_CORE;
3aba481fc   Roland McGrath   elf core dump: no...
1316
  	elf->e_machine = machine;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
  	elf->e_version = EV_CURRENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  	elf->e_phoff = sizeof(struct elfhdr);
3aba481fc   Roland McGrath   elf core dump: no...
1319
  	elf->e_flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
1322
  	elf->e_ehsize = sizeof(struct elfhdr);
  	elf->e_phentsize = sizeof(struct elf_phdr);
  	elf->e_phnum = segs;
6970c8eff   Cyrill Gorcunov   BINFMT: fill_elf_...
1323

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324
1325
  	return;
  }
8d6b5eeea   Andrew Morton   [PATCH] binfmt_el...
1326
  static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
  {
  	phdr->p_type = PT_NOTE;
  	phdr->p_offset = offset;
  	phdr->p_vaddr = 0;
  	phdr->p_paddr = 0;
  	phdr->p_filesz = sz;
  	phdr->p_memsz = 0;
  	phdr->p_flags = 0;
  	phdr->p_align = 0;
  	return;
  }
  
  static void fill_note(struct memelfnote *note, const char *name, int type, 
  		unsigned int sz, void *data)
  {
  	note->name = name;
  	note->type = type;
  	note->datasz = sz;
  	note->data = data;
  	return;
  }
  
  /*
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1350
1351
   * fill up all the fields in prstatus from the given task struct, except
   * registers which need to be filled up separately.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
   */
  static void fill_prstatus(struct elf_prstatus *prstatus,
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1354
  		struct task_struct *p, long signr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
1358
  {
  	prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
  	prstatus->pr_sigpend = p->pending.signal.sig[0];
  	prstatus->pr_sighold = p->blocked.sig[0];
3b34fc588   Oleg Nesterov   elf_core_dump: us...
1359
1360
1361
  	rcu_read_lock();
  	prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent));
  	rcu_read_unlock();
b488893a3   Pavel Emelyanov   pid namespaces: c...
1362
  	prstatus->pr_pid = task_pid_vnr(p);
b488893a3   Pavel Emelyanov   pid namespaces: c...
1363
1364
  	prstatus->pr_pgrp = task_pgrp_vnr(p);
  	prstatus->pr_sid = task_session_vnr(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
  	if (thread_group_leader(p)) {
f06febc96   Frank Mayhar   timers: fix itime...
1366
  		struct task_cputime cputime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
  		/*
f06febc96   Frank Mayhar   timers: fix itime...
1368
1369
  		 * This is the record for the group leader.  It shows the
  		 * group-wide total, not its individual thread total.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
  		 */
f06febc96   Frank Mayhar   timers: fix itime...
1371
1372
1373
  		thread_group_cputime(p, &cputime);
  		cputime_to_timeval(cputime.utime, &prstatus->pr_utime);
  		cputime_to_timeval(cputime.stime, &prstatus->pr_stime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
  	} else {
6fac4829c   Frederic Weisbecker   cputime: Use acce...
1375
1376
1377
1378
1379
  		cputime_t utime, stime;
  
  		task_cputime(p, &utime, &stime);
  		cputime_to_timeval(utime, &prstatus->pr_utime);
  		cputime_to_timeval(stime, &prstatus->pr_stime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
1381
1382
1383
1384
1385
1386
1387
  	}
  	cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime);
  	cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime);
  }
  
  static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
  		       struct mm_struct *mm)
  {
c69e8d9c0   David Howells   CRED: Use RCU to ...
1388
  	const struct cred *cred;
a84a50595   Greg Kroah-Hartman   [PATCH] fix Linux...
1389
  	unsigned int i, len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
  	
  	/* first copy the parameters from user space */
  	memset(psinfo, 0, sizeof(struct elf_prpsinfo));
  
  	len = mm->arg_end - mm->arg_start;
  	if (len >= ELF_PRARGSZ)
  		len = ELF_PRARGSZ-1;
  	if (copy_from_user(&psinfo->pr_psargs,
  		           (const char __user *)mm->arg_start, len))
  		return -EFAULT;
  	for(i = 0; i < len; i++)
  		if (psinfo->pr_psargs[i] == 0)
  			psinfo->pr_psargs[i] = ' ';
  	psinfo->pr_psargs[len] = 0;
3b34fc588   Oleg Nesterov   elf_core_dump: us...
1404
1405
1406
  	rcu_read_lock();
  	psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent));
  	rcu_read_unlock();
b488893a3   Pavel Emelyanov   pid namespaces: c...
1407
  	psinfo->pr_pid = task_pid_vnr(p);
b488893a3   Pavel Emelyanov   pid namespaces: c...
1408
1409
  	psinfo->pr_pgrp = task_pgrp_vnr(p);
  	psinfo->pr_sid = task_session_vnr(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
1412
  
  	i = p->state ? ffz(~p->state) + 1 : 0;
  	psinfo->pr_state = i;
551485481   Carsten Otte   [PATCH] remove ne...
1413
  	psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1414
1415
1416
  	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
  	psinfo->pr_nice = task_nice(p);
  	psinfo->pr_flag = p->flags;
c69e8d9c0   David Howells   CRED: Use RCU to ...
1417
1418
  	rcu_read_lock();
  	cred = __task_cred(p);
ebc887b27   Eric W. Biederman   userns: Convert b...
1419
1420
  	SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
  	SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
c69e8d9c0   David Howells   CRED: Use RCU to ...
1421
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
1424
1425
  	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
  	
  	return 0;
  }
3aba481fc   Roland McGrath   elf core dump: no...
1426
1427
1428
1429
1430
1431
1432
1433
1434
  static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
  {
  	elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv;
  	int i = 0;
  	do
  		i += 2;
  	while (auxv[i - 2] != AT_NULL);
  	fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
  }
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1435
  static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
ce3959604   Al Viro   constify copy_sig...
1436
  		const siginfo_t *siginfo)
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1437
1438
1439
1440
1441
1442
1443
  {
  	mm_segment_t old_fs = get_fs();
  	set_fs(KERNEL_DS);
  	copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo);
  	set_fs(old_fs);
  	fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata);
  }
2aa362c49   Denys Vlasenko   coredump: extend ...
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
  #define MAX_FILE_NOTE_SIZE (4*1024*1024)
  /*
   * Format of NT_FILE note:
   *
   * long count     -- how many files are mapped
   * long page_size -- units for file_ofs
   * array of [COUNT] elements of
   *   long start
   *   long end
   *   long file_ofs
   * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
   */
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1456
  static int fill_files_note(struct memelfnote *note)
2aa362c49   Denys Vlasenko   coredump: extend ...
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
  {
  	struct vm_area_struct *vma;
  	unsigned count, size, names_ofs, remaining, n;
  	user_long_t *data;
  	user_long_t *start_end_ofs;
  	char *name_base, *name_curpos;
  
  	/* *Estimated* file count and total data size needed */
  	count = current->mm->map_count;
  	size = count * 64;
  
  	names_ofs = (2 + 3 * count) * sizeof(data[0]);
   alloc:
  	if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1471
  		return -EINVAL;
2aa362c49   Denys Vlasenko   coredump: extend ...
1472
1473
1474
  	size = round_up(size, PAGE_SIZE);
  	data = vmalloc(size);
  	if (!data)
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1475
  		return -ENOMEM;
2aa362c49   Denys Vlasenko   coredump: extend ...
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  
  	start_end_ofs = data + 2;
  	name_base = name_curpos = ((char *)data) + names_ofs;
  	remaining = size - names_ofs;
  	count = 0;
  	for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
  		struct file *file;
  		const char *filename;
  
  		file = vma->vm_file;
  		if (!file)
  			continue;
9bf39ab2a   Miklos Szeredi   vfs: add file_pat...
1488
  		filename = file_path(file, name_curpos, remaining);
2aa362c49   Denys Vlasenko   coredump: extend ...
1489
1490
1491
1492
1493
1494
1495
1496
  		if (IS_ERR(filename)) {
  			if (PTR_ERR(filename) == -ENAMETOOLONG) {
  				vfree(data);
  				size = size * 5 / 4;
  				goto alloc;
  			}
  			continue;
  		}
9bf39ab2a   Miklos Szeredi   vfs: add file_pat...
1497
  		/* file_path() fills at the end, move name down */
2aa362c49   Denys Vlasenko   coredump: extend ...
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
  		/* n = strlen(filename) + 1: */
  		n = (name_curpos + remaining) - filename;
  		remaining = filename - name_curpos;
  		memmove(name_curpos, filename, n);
  		name_curpos += n;
  
  		*start_end_ofs++ = vma->vm_start;
  		*start_end_ofs++ = vma->vm_end;
  		*start_end_ofs++ = vma->vm_pgoff;
  		count++;
  	}
  
  	/* Now we know exact count of files, can store it */
  	data[0] = count;
  	data[1] = PAGE_SIZE;
  	/*
  	 * Count usually is less than current->mm->map_count,
  	 * we need to move filenames down.
  	 */
  	n = current->mm->map_count - count;
  	if (n != 0) {
  		unsigned shift_bytes = n * 3 * sizeof(data[0]);
  		memmove(name_base - shift_bytes, name_base,
  			name_curpos - name_base);
  		name_curpos -= shift_bytes;
  	}
  
  	size = name_curpos - (char *)data;
  	fill_note(note, "CORE", NT_FILE, size, data);
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1527
  	return 0;
2aa362c49   Denys Vlasenko   coredump: extend ...
1528
  }
4206d3aa1   Roland McGrath   elf core dump: no...
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
  #ifdef CORE_DUMP_USE_REGSET
  #include <linux/regset.h>
  
  struct elf_thread_core_info {
  	struct elf_thread_core_info *next;
  	struct task_struct *task;
  	struct elf_prstatus prstatus;
  	struct memelfnote notes[0];
  };
  
  struct elf_note_info {
  	struct elf_thread_core_info *thread;
  	struct memelfnote psinfo;
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1542
  	struct memelfnote signote;
4206d3aa1   Roland McGrath   elf core dump: no...
1543
  	struct memelfnote auxv;
2aa362c49   Denys Vlasenko   coredump: extend ...
1544
  	struct memelfnote files;
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1545
  	user_siginfo_t csigdata;
4206d3aa1   Roland McGrath   elf core dump: no...
1546
1547
1548
  	size_t size;
  	int thread_notes;
  };
d31472b6d   Roland McGrath   core dump: user_r...
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
  /*
   * When a regset has a writeback hook, we call it on each thread before
   * dumping user memory.  On register window machines, this makes sure the
   * user memory backing the register data is up to date before we read it.
   */
  static void do_thread_regset_writeback(struct task_struct *task,
  				       const struct user_regset *regset)
  {
  	if (regset->writeback)
  		regset->writeback(task, regset, 1);
  }
0953f65d5   H. J. Lu   elf: Allow core d...
1560
  #ifndef PRSTATUS_SIZE
90954e7b9   Dmitry Safonov   x86/coredump: Use...
1561
  #define PRSTATUS_SIZE(S, R) sizeof(S)
0953f65d5   H. J. Lu   elf: Allow core d...
1562
1563
1564
  #endif
  
  #ifndef SET_PR_FPVALID
90954e7b9   Dmitry Safonov   x86/coredump: Use...
1565
  #define SET_PR_FPVALID(S, V, R) ((S)->pr_fpvalid = (V))
0953f65d5   H. J. Lu   elf: Allow core d...
1566
  #endif
4206d3aa1   Roland McGrath   elf core dump: no...
1567
1568
1569
1570
1571
  static int fill_thread_core_info(struct elf_thread_core_info *t,
  				 const struct user_regset_view *view,
  				 long signr, size_t *total)
  {
  	unsigned int i;
90954e7b9   Dmitry Safonov   x86/coredump: Use...
1572
  	unsigned int regset_size = view->regsets[0].n * view->regsets[0].size;
4206d3aa1   Roland McGrath   elf core dump: no...
1573
1574
1575
1576
1577
1578
1579
1580
  
  	/*
  	 * NT_PRSTATUS is the one special case, because the regset data
  	 * goes into the pr_reg field inside the note contents, rather
  	 * than being the whole note contents.  We fill the reset in here.
  	 * We assume that regset 0 is NT_PRSTATUS.
  	 */
  	fill_prstatus(&t->prstatus, t->task, signr);
90954e7b9   Dmitry Safonov   x86/coredump: Use...
1581
1582
  	(void) view->regsets[0].get(t->task, &view->regsets[0], 0, regset_size,
  				    &t->prstatus.pr_reg, NULL);
4206d3aa1   Roland McGrath   elf core dump: no...
1583
1584
  
  	fill_note(&t->notes[0], "CORE", NT_PRSTATUS,
90954e7b9   Dmitry Safonov   x86/coredump: Use...
1585
  		  PRSTATUS_SIZE(t->prstatus, regset_size), &t->prstatus);
4206d3aa1   Roland McGrath   elf core dump: no...
1586
  	*total += notesize(&t->notes[0]);
d31472b6d   Roland McGrath   core dump: user_r...
1587
  	do_thread_regset_writeback(t->task, &view->regsets[0]);
4206d3aa1   Roland McGrath   elf core dump: no...
1588
1589
1590
1591
1592
1593
1594
  	/*
  	 * Each other regset might generate a note too.  For each regset
  	 * that has no core_note_type or is inactive, we leave t->notes[i]
  	 * all zero and we'll know to skip writing it later.
  	 */
  	for (i = 1; i < view->n; ++i) {
  		const struct user_regset *regset = &view->regsets[i];
d31472b6d   Roland McGrath   core dump: user_r...
1595
  		do_thread_regset_writeback(t->task, regset);
c8e252586   H. Peter Anvin   regset: Prevent n...
1596
  		if (regset->core_note_type && regset->get &&
4206d3aa1   Roland McGrath   elf core dump: no...
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
  		    (!regset->active || regset->active(t->task, regset))) {
  			int ret;
  			size_t size = regset->n * regset->size;
  			void *data = kmalloc(size, GFP_KERNEL);
  			if (unlikely(!data))
  				return 0;
  			ret = regset->get(t->task, regset,
  					  0, size, data, NULL);
  			if (unlikely(ret))
  				kfree(data);
  			else {
  				if (regset->core_note_type != NT_PRFPREG)
  					fill_note(&t->notes[i], "LINUX",
  						  regset->core_note_type,
  						  size, data);
  				else {
90954e7b9   Dmitry Safonov   x86/coredump: Use...
1613
1614
  					SET_PR_FPVALID(&t->prstatus,
  							1, regset_size);
4206d3aa1   Roland McGrath   elf core dump: no...
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
  					fill_note(&t->notes[i], "CORE",
  						  NT_PRFPREG, size, data);
  				}
  				*total += notesize(&t->notes[i]);
  			}
  		}
  	}
  
  	return 1;
  }
  
  static int fill_note_info(struct elfhdr *elf, int phdrs,
  			  struct elf_note_info *info,
ec57941e0   Al Viro   constify do_cored...
1628
  			  const siginfo_t *siginfo, struct pt_regs *regs)
4206d3aa1   Roland McGrath   elf core dump: no...
1629
1630
1631
1632
1633
  {
  	struct task_struct *dump_task = current;
  	const struct user_regset_view *view = task_user_regset_view(dump_task);
  	struct elf_thread_core_info *t;
  	struct elf_prpsinfo *psinfo;
83914441f   Oleg Nesterov   coredump: elf_cor...
1634
  	struct core_thread *ct;
4206d3aa1   Roland McGrath   elf core dump: no...
1635
1636
1637
1638
1639
1640
  	unsigned int i;
  
  	info->size = 0;
  	info->thread = NULL;
  
  	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
6899e92d6   Alan Cox   binfmt_elf: fix c...
1641
1642
  	if (psinfo == NULL) {
  		info->psinfo.data = NULL; /* So we don't free this wrongly */
4206d3aa1   Roland McGrath   elf core dump: no...
1643
  		return 0;
6899e92d6   Alan Cox   binfmt_elf: fix c...
1644
  	}
4206d3aa1   Roland McGrath   elf core dump: no...
1645

e2dbe1255   Amerigo Wang   elf: fix one chec...
1646
  	fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
4206d3aa1   Roland McGrath   elf core dump: no...
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
  	/*
  	 * Figure out how many notes we're going to need for each thread.
  	 */
  	info->thread_notes = 0;
  	for (i = 0; i < view->n; ++i)
  		if (view->regsets[i].core_note_type != 0)
  			++info->thread_notes;
  
  	/*
  	 * Sanity check.  We rely on regset 0 being in NT_PRSTATUS,
  	 * since it is our one special case.
  	 */
  	if (unlikely(info->thread_notes == 0) ||
  	    unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) {
  		WARN_ON(1);
  		return 0;
  	}
  
  	/*
  	 * Initialize the ELF file header.
  	 */
  	fill_elf_header(elf, phdrs,
d3330cf08   Zhang Yanfei   binfmt_elf: remov...
1669
  			view->e_machine, view->e_flags);
4206d3aa1   Roland McGrath   elf core dump: no...
1670
1671
1672
1673
  
  	/*
  	 * Allocate a structure for each thread.
  	 */
83914441f   Oleg Nesterov   coredump: elf_cor...
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
  	for (ct = &dump_task->mm->core_state->dumper; ct; ct = ct->next) {
  		t = kzalloc(offsetof(struct elf_thread_core_info,
  				     notes[info->thread_notes]),
  			    GFP_KERNEL);
  		if (unlikely(!t))
  			return 0;
  
  		t->task = ct->task;
  		if (ct->task == dump_task || !info->thread) {
  			t->next = info->thread;
  			info->thread = t;
  		} else {
  			/*
  			 * Make sure to keep the original task at
  			 * the head of the list.
  			 */
  			t->next = info->thread->next;
  			info->thread->next = t;
4206d3aa1   Roland McGrath   elf core dump: no...
1692
  		}
83914441f   Oleg Nesterov   coredump: elf_cor...
1693
  	}
4206d3aa1   Roland McGrath   elf core dump: no...
1694
1695
1696
1697
1698
  
  	/*
  	 * Now fill in each thread's information.
  	 */
  	for (t = info->thread; t != NULL; t = t->next)
5ab1c309b   Denys Vlasenko   coredump: pass si...
1699
  		if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size))
4206d3aa1   Roland McGrath   elf core dump: no...
1700
1701
1702
1703
1704
1705
1706
  			return 0;
  
  	/*
  	 * Fill in the two process-wide notes.
  	 */
  	fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm);
  	info->size += notesize(&info->psinfo);
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1707
1708
  	fill_siginfo_note(&info->signote, &info->csigdata, siginfo);
  	info->size += notesize(&info->signote);
4206d3aa1   Roland McGrath   elf core dump: no...
1709
1710
  	fill_auxv_note(&info->auxv, current->mm);
  	info->size += notesize(&info->auxv);
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1711
1712
  	if (fill_files_note(&info->files) == 0)
  		info->size += notesize(&info->files);
2aa362c49   Denys Vlasenko   coredump: extend ...
1713

4206d3aa1   Roland McGrath   elf core dump: no...
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
  	return 1;
  }
  
  static size_t get_note_info_size(struct elf_note_info *info)
  {
  	return info->size;
  }
  
  /*
   * Write all the notes for each thread.  When writing the first thread, the
   * process-wide notes are interleaved after the first thread-specific note.
   */
  static int write_note_info(struct elf_note_info *info,
ecc8c7725   Al Viro   new helper: dump_...
1727
  			   struct coredump_params *cprm)
4206d3aa1   Roland McGrath   elf core dump: no...
1728
  {
b219e25f8   Fabian Frederick   fs/binfmt_elf.c: ...
1729
  	bool first = true;
4206d3aa1   Roland McGrath   elf core dump: no...
1730
1731
1732
1733
  	struct elf_thread_core_info *t = info->thread;
  
  	do {
  		int i;
ecc8c7725   Al Viro   new helper: dump_...
1734
  		if (!writenote(&t->notes[0], cprm))
4206d3aa1   Roland McGrath   elf core dump: no...
1735
  			return 0;
ecc8c7725   Al Viro   new helper: dump_...
1736
  		if (first && !writenote(&info->psinfo, cprm))
4206d3aa1   Roland McGrath   elf core dump: no...
1737
  			return 0;
ecc8c7725   Al Viro   new helper: dump_...
1738
  		if (first && !writenote(&info->signote, cprm))
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1739
  			return 0;
ecc8c7725   Al Viro   new helper: dump_...
1740
  		if (first && !writenote(&info->auxv, cprm))
4206d3aa1   Roland McGrath   elf core dump: no...
1741
  			return 0;
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1742
  		if (first && info->files.data &&
ecc8c7725   Al Viro   new helper: dump_...
1743
  				!writenote(&info->files, cprm))
2aa362c49   Denys Vlasenko   coredump: extend ...
1744
  			return 0;
4206d3aa1   Roland McGrath   elf core dump: no...
1745
1746
1747
  
  		for (i = 1; i < info->thread_notes; ++i)
  			if (t->notes[i].data &&
ecc8c7725   Al Viro   new helper: dump_...
1748
  			    !writenote(&t->notes[i], cprm))
4206d3aa1   Roland McGrath   elf core dump: no...
1749
  				return 0;
b219e25f8   Fabian Frederick   fs/binfmt_elf.c: ...
1750
  		first = false;
4206d3aa1   Roland McGrath   elf core dump: no...
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
  		t = t->next;
  	} while (t);
  
  	return 1;
  }
  
  static void free_note_info(struct elf_note_info *info)
  {
  	struct elf_thread_core_info *threads = info->thread;
  	while (threads) {
  		unsigned int i;
  		struct elf_thread_core_info *t = threads;
  		threads = t->next;
  		WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus);
  		for (i = 1; i < info->thread_notes; ++i)
  			kfree(t->notes[i].data);
  		kfree(t);
  	}
  	kfree(info->psinfo.data);
2aa362c49   Denys Vlasenko   coredump: extend ...
1770
  	vfree(info->files.data);
4206d3aa1   Roland McGrath   elf core dump: no...
1771
1772
1773
  }
  
  #else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
1775
1776
1777
1778
1779
1780
1781
  /* Here is the structure in which status of each thread is captured. */
  struct elf_thread_status
  {
  	struct list_head list;
  	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
  	elf_fpregset_t fpu;		/* NT_PRFPREG */
  	struct task_struct *thread;
  #ifdef ELF_CORE_COPY_XFPREGS
5b20cd80b   Mark Nelson   x86: replace NT_P...
1782
  	elf_fpxregset_t xfpu;		/* ELF_CORE_XFPREG_TYPE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
1784
1785
1786
1787
1788
1789
  #endif
  	struct memelfnote notes[3];
  	int num_notes;
  };
  
  /*
   * In order to add the specific thread information for the elf file format,
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1790
1791
   * we need to keep a linked list of every threads pr_status and then create
   * a single section for them in the final core file.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
   */
  static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
  {
  	int sz = 0;
  	struct task_struct *p = t->thread;
  	t->num_notes = 0;
  
  	fill_prstatus(&t->prstatus, p, signr);
  	elf_core_copy_task_regs(p, &t->prstatus.pr_reg);	
  	
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1802
1803
  	fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
  		  &(t->prstatus));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
1805
  	t->num_notes++;
  	sz += notesize(&t->notes[0]);
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
1806
1807
1808
1809
  	if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL,
  								&t->fpu))) {
  		fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu),
  			  &(t->fpu));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
1811
1812
1813
1814
1815
  		t->num_notes++;
  		sz += notesize(&t->notes[1]);
  	}
  
  #ifdef ELF_CORE_COPY_XFPREGS
  	if (elf_core_copy_task_xfpregs(p, &t->xfpu)) {
5b20cd80b   Mark Nelson   x86: replace NT_P...
1816
1817
  		fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE,
  			  sizeof(t->xfpu), &t->xfpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1818
1819
1820
1821
1822
1823
  		t->num_notes++;
  		sz += notesize(&t->notes[2]);
  	}
  #endif	
  	return sz;
  }
3aba481fc   Roland McGrath   elf core dump: no...
1824
1825
  struct elf_note_info {
  	struct memelfnote *notes;
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1826
  	struct memelfnote *notes_files;
3aba481fc   Roland McGrath   elf core dump: no...
1827
1828
1829
1830
1831
1832
1833
  	struct elf_prstatus *prstatus;	/* NT_PRSTATUS */
  	struct elf_prpsinfo *psinfo;	/* NT_PRPSINFO */
  	struct list_head thread_list;
  	elf_fpregset_t *fpu;
  #ifdef ELF_CORE_COPY_XFPREGS
  	elf_fpxregset_t *xfpu;
  #endif
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1834
  	user_siginfo_t csigdata;
3aba481fc   Roland McGrath   elf core dump: no...
1835
1836
1837
  	int thread_status_size;
  	int numnote;
  };
0cf062d0f   Amerigo Wang   elf: clean up fil...
1838
  static int elf_note_info_init(struct elf_note_info *info)
3aba481fc   Roland McGrath   elf core dump: no...
1839
  {
0cf062d0f   Amerigo Wang   elf: clean up fil...
1840
  	memset(info, 0, sizeof(*info));
3aba481fc   Roland McGrath   elf core dump: no...
1841
  	INIT_LIST_HEAD(&info->thread_list);
49ae4d4b1   Denys Vlasenko   coredump: add a n...
1842
  	/* Allocate space for ELF notes */
2aa362c49   Denys Vlasenko   coredump: extend ...
1843
  	info->notes = kmalloc(8 * sizeof(struct memelfnote), GFP_KERNEL);
3aba481fc   Roland McGrath   elf core dump: no...
1844
1845
1846
1847
  	if (!info->notes)
  		return 0;
  	info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
  	if (!info->psinfo)
f34f9d186   Denys Vlasenko   coredump: prevent...
1848
  		return 0;
3aba481fc   Roland McGrath   elf core dump: no...
1849
1850
  	info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
  	if (!info->prstatus)
f34f9d186   Denys Vlasenko   coredump: prevent...
1851
  		return 0;
3aba481fc   Roland McGrath   elf core dump: no...
1852
1853
  	info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
  	if (!info->fpu)
f34f9d186   Denys Vlasenko   coredump: prevent...
1854
  		return 0;
3aba481fc   Roland McGrath   elf core dump: no...
1855
1856
1857
  #ifdef ELF_CORE_COPY_XFPREGS
  	info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL);
  	if (!info->xfpu)
f34f9d186   Denys Vlasenko   coredump: prevent...
1858
  		return 0;
3aba481fc   Roland McGrath   elf core dump: no...
1859
  #endif
0cf062d0f   Amerigo Wang   elf: clean up fil...
1860
  	return 1;
0cf062d0f   Amerigo Wang   elf: clean up fil...
1861
1862
1863
1864
  }
  
  static int fill_note_info(struct elfhdr *elf, int phdrs,
  			  struct elf_note_info *info,
ec57941e0   Al Viro   constify do_cored...
1865
  			  const siginfo_t *siginfo, struct pt_regs *regs)
0cf062d0f   Amerigo Wang   elf: clean up fil...
1866
1867
  {
  	struct list_head *t;
afabada95   Al Viro   elf{,_fdpic} core...
1868
1869
  	struct core_thread *ct;
  	struct elf_thread_status *ets;
0cf062d0f   Amerigo Wang   elf: clean up fil...
1870
1871
1872
  
  	if (!elf_note_info_init(info))
  		return 0;
3aba481fc   Roland McGrath   elf core dump: no...
1873

afabada95   Al Viro   elf{,_fdpic} core...
1874
1875
1876
1877
1878
  	for (ct = current->mm->core_state->dumper.next;
  					ct; ct = ct->next) {
  		ets = kzalloc(sizeof(*ets), GFP_KERNEL);
  		if (!ets)
  			return 0;
83914441f   Oleg Nesterov   coredump: elf_cor...
1879

afabada95   Al Viro   elf{,_fdpic} core...
1880
1881
1882
  		ets->thread = ct->task;
  		list_add(&ets->list, &info->thread_list);
  	}
83914441f   Oleg Nesterov   coredump: elf_cor...
1883

afabada95   Al Viro   elf{,_fdpic} core...
1884
1885
  	list_for_each(t, &info->thread_list) {
  		int sz;
3aba481fc   Roland McGrath   elf core dump: no...
1886

afabada95   Al Viro   elf{,_fdpic} core...
1887
1888
1889
  		ets = list_entry(t, struct elf_thread_status, list);
  		sz = elf_dump_thread_status(siginfo->si_signo, ets);
  		info->thread_status_size += sz;
3aba481fc   Roland McGrath   elf core dump: no...
1890
1891
1892
  	}
  	/* now collect the dump for the current */
  	memset(info->prstatus, 0, sizeof(*info->prstatus));
5ab1c309b   Denys Vlasenko   coredump: pass si...
1893
  	fill_prstatus(info->prstatus, current, siginfo->si_signo);
3aba481fc   Roland McGrath   elf core dump: no...
1894
1895
1896
  	elf_core_copy_regs(&info->prstatus->pr_reg, regs);
  
  	/* Set up header */
d3330cf08   Zhang Yanfei   binfmt_elf: remov...
1897
  	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
3aba481fc   Roland McGrath   elf core dump: no...
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
  
  	/*
  	 * Set up the notes in similar form to SVR4 core dumps made
  	 * with info from their /proc.
  	 */
  
  	fill_note(info->notes + 0, "CORE", NT_PRSTATUS,
  		  sizeof(*info->prstatus), info->prstatus);
  	fill_psinfo(info->psinfo, current->group_leader, current->mm);
  	fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
  		  sizeof(*info->psinfo), info->psinfo);
2aa362c49   Denys Vlasenko   coredump: extend ...
1909
1910
  	fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo);
  	fill_auxv_note(info->notes + 3, current->mm);
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1911
  	info->numnote = 4;
3aba481fc   Roland McGrath   elf core dump: no...
1912

720236569   Dan Aloni   fs/binfmt_elf.c: ...
1913
1914
1915
1916
  	if (fill_files_note(info->notes + info->numnote) == 0) {
  		info->notes_files = info->notes + info->numnote;
  		info->numnote++;
  	}
3aba481fc   Roland McGrath   elf core dump: no...
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
  
  	/* Try to dump the FPU. */
  	info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
  							       info->fpu);
  	if (info->prstatus->pr_fpvalid)
  		fill_note(info->notes + info->numnote++,
  			  "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
  #ifdef ELF_CORE_COPY_XFPREGS
  	if (elf_core_copy_task_xfpregs(current, info->xfpu))
  		fill_note(info->notes + info->numnote++,
  			  "LINUX", ELF_CORE_XFPREG_TYPE,
  			  sizeof(*info->xfpu), info->xfpu);
  #endif
  
  	return 1;
3aba481fc   Roland McGrath   elf core dump: no...
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
  }
  
  static size_t get_note_info_size(struct elf_note_info *info)
  {
  	int sz = 0;
  	int i;
  
  	for (i = 0; i < info->numnote; i++)
  		sz += notesize(info->notes + i);
  
  	sz += info->thread_status_size;
  
  	return sz;
  }
  
  static int write_note_info(struct elf_note_info *info,
ecc8c7725   Al Viro   new helper: dump_...
1948
  			   struct coredump_params *cprm)
3aba481fc   Roland McGrath   elf core dump: no...
1949
1950
1951
1952
1953
  {
  	int i;
  	struct list_head *t;
  
  	for (i = 0; i < info->numnote; i++)
ecc8c7725   Al Viro   new helper: dump_...
1954
  		if (!writenote(info->notes + i, cprm))
3aba481fc   Roland McGrath   elf core dump: no...
1955
1956
1957
1958
1959
1960
1961
1962
  			return 0;
  
  	/* write out the thread status notes section */
  	list_for_each(t, &info->thread_list) {
  		struct elf_thread_status *tmp =
  				list_entry(t, struct elf_thread_status, list);
  
  		for (i = 0; i < tmp->num_notes; i++)
ecc8c7725   Al Viro   new helper: dump_...
1963
  			if (!writenote(&tmp->notes[i], cprm))
3aba481fc   Roland McGrath   elf core dump: no...
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
  				return 0;
  	}
  
  	return 1;
  }
  
  static void free_note_info(struct elf_note_info *info)
  {
  	while (!list_empty(&info->thread_list)) {
  		struct list_head *tmp = info->thread_list.next;
  		list_del(tmp);
  		kfree(list_entry(tmp, struct elf_thread_status, list));
  	}
720236569   Dan Aloni   fs/binfmt_elf.c: ...
1977
1978
1979
  	/* Free data possibly allocated by fill_files_note(): */
  	if (info->notes_files)
  		vfree(info->notes_files->data);
2aa362c49   Denys Vlasenko   coredump: extend ...
1980

3aba481fc   Roland McGrath   elf core dump: no...
1981
1982
1983
1984
1985
1986
1987
1988
  	kfree(info->prstatus);
  	kfree(info->psinfo);
  	kfree(info->notes);
  	kfree(info->fpu);
  #ifdef ELF_CORE_COPY_XFPREGS
  	kfree(info->xfpu);
  #endif
  }
4206d3aa1   Roland McGrath   elf core dump: no...
1989
  #endif
f47aef55d   Roland McGrath   [PATCH] i386 vDSO...
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
  static struct vm_area_struct *first_vma(struct task_struct *tsk,
  					struct vm_area_struct *gate_vma)
  {
  	struct vm_area_struct *ret = tsk->mm->mmap;
  
  	if (ret)
  		return ret;
  	return gate_vma;
  }
  /*
   * Helper function for iterating across a vma list.  It ensures that the caller
   * will visit `gate_vma' prior to terminating the search.
   */
  static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
  					struct vm_area_struct *gate_vma)
  {
  	struct vm_area_struct *ret;
  
  	ret = this_vma->vm_next;
  	if (ret)
  		return ret;
  	if (this_vma == gate_vma)
  		return NULL;
  	return gate_vma;
  }
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
  static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
  			     elf_addr_t e_shoff, int segs)
  {
  	elf->e_shoff = e_shoff;
  	elf->e_shentsize = sizeof(*shdr4extnum);
  	elf->e_shnum = 1;
  	elf->e_shstrndx = SHN_UNDEF;
  
  	memset(shdr4extnum, 0, sizeof(*shdr4extnum));
  
  	shdr4extnum->sh_type = SHT_NULL;
  	shdr4extnum->sh_size = elf->e_shnum;
  	shdr4extnum->sh_link = elf->e_shstrndx;
  	shdr4extnum->sh_info = segs;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
2031
2032
2033
2034
2035
2036
  /*
   * Actual dumper
   *
   * This is a two-pass process; first we find the offsets of the bits,
   * and then they are actually written out.  If we run out of core limit
   * we just truncate.
   */
f6151dfea   Masami Hiramatsu   mm: introduce cor...
2037
  static int elf_core_dump(struct coredump_params *cprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2038
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
2040
  	int has_dumped = 0;
  	mm_segment_t fs;
52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2041
2042
  	int segs, i;
  	size_t vma_data_size = 0;
f47aef55d   Roland McGrath   [PATCH] i386 vDSO...
2043
  	struct vm_area_struct *vma, *gate_vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
  	struct elfhdr *elf = NULL;
cdc3d5627   Al Viro   switch elf_coredu...
2045
  	loff_t offset = 0, dataoff;
720236569   Dan Aloni   fs/binfmt_elf.c: ...
2046
  	struct elf_note_info info = { };
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
2047
  	struct elf_phdr *phdr4note = NULL;
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2048
2049
2050
  	struct elf_shdr *shdr4extnum = NULL;
  	Elf_Half e_phnum;
  	elf_addr_t e_shoff;
52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2051
  	elf_addr_t *vma_filesz = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2052
2053
2054
2055
  
  	/*
  	 * We no longer stop all VM operations.
  	 * 
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
2056
2057
2058
  	 * This is because those proceses that could possibly change map_count
  	 * or the mmap / vma pages are now blocked in do_exit on current
  	 * finishing this core dump.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
2060
  	 *
  	 * Only ptrace can touch these memory addresses, but it doesn't change
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
2061
  	 * the map_count or the pages allocated. So no possibility of crashing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062
2063
2064
2065
2066
2067
  	 * exists while dumping the mm->vm_next areas to the core file.
  	 */
    
  	/* alloc memory for large data structures: too large to be on stack */
  	elf = kmalloc(sizeof(*elf), GFP_KERNEL);
  	if (!elf)
5f719558e   WANG Cong   [Patch] fs/binfmt...
2068
  		goto out;
341c87bf3   KAMEZAWA Hiroyuki   elf: limit max ma...
2069
2070
2071
2072
  	/*
  	 * The number of segs are recored into ELF header as 16bit value.
  	 * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
  	segs = current->mm->map_count;
1fcccbac8   Daisuke HATAYAMA   elf coredump: rep...
2074
  	segs += elf_core_extra_phdrs();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075

31db58b3a   Stephen Wilson   mm: arch: make ge...
2076
  	gate_vma = get_gate_vma(current->mm);
f47aef55d   Roland McGrath   [PATCH] i386 vDSO...
2077
2078
  	if (gate_vma != NULL)
  		segs++;
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2079
2080
2081
2082
2083
2084
2085
  	/* for notes section */
  	segs++;
  
  	/* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
  	 * this, kernel supports extended numbering. Have a look at
  	 * include/linux/elf.h for further information. */
  	e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2086
  	/*
3aba481fc   Roland McGrath   elf core dump: no...
2087
2088
  	 * Collect all the non-memory information about the process for the
  	 * notes.  This also sets up the file header.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2089
  	 */
5ab1c309b   Denys Vlasenko   coredump: pass si...
2090
  	if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs))
3aba481fc   Roland McGrath   elf core dump: no...
2091
  		goto cleanup;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092

3aba481fc   Roland McGrath   elf core dump: no...
2093
  	has_dumped = 1;
079148b91   Oleg Nesterov   coredump: factor ...
2094

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095
2096
  	fs = get_fs();
  	set_fs(KERNEL_DS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097
  	offset += sizeof(*elf);				/* Elf header */
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2098
  	offset += segs * sizeof(struct elf_phdr);	/* Program headers */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
2100
2101
  
  	/* Write notes phdr entry */
  	{
3aba481fc   Roland McGrath   elf core dump: no...
2102
  		size_t sz = get_note_info_size(&info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2103

e55014923   Michael Ellerman   [POWERPC] spufs: ...
2104
  		sz += elf_coredump_extra_notes_size();
bf1ab978b   Dwayne Grant McConnell   [POWERPC] coredum...
2105

93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
2106
2107
  		phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
  		if (!phdr4note)
088e7af73   Daisuke HATAYAMA   coredump: move du...
2108
  			goto end_coredump;
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
2109
2110
2111
  
  		fill_elf_note_phdr(phdr4note, sz, offset);
  		offset += sz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2112
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
  	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
  	vma_filesz = kmalloc_array(segs - 1, sizeof(*vma_filesz), GFP_KERNEL);
  	if (!vma_filesz)
  		goto end_coredump;
  
  	for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
  			vma = next_vma(vma, gate_vma)) {
  		unsigned long dump_size;
  
  		dump_size = vma_dump_size(vma, cprm->mm_flags);
  		vma_filesz[i++] = dump_size;
  		vma_data_size += dump_size;
  	}
  
  	offset += vma_data_size;
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
  	offset += elf_core_extra_data_size();
  	e_shoff = offset;
  
  	if (e_phnum == PN_XNUM) {
  		shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
  		if (!shdr4extnum)
  			goto end_coredump;
  		fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
  	}
  
  	offset = dataoff;
ecc8c7725   Al Viro   new helper: dump_...
2139
  	if (!dump_emit(cprm, elf, sizeof(*elf)))
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
2140
  		goto end_coredump;
ecc8c7725   Al Viro   new helper: dump_...
2141
  	if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
2142
  		goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
  	/* Write program headers for segments dump */
52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2144
  	for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
f47aef55d   Roland McGrath   [PATCH] i386 vDSO...
2145
  			vma = next_vma(vma, gate_vma)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146
  		struct elf_phdr phdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
2148
2149
2150
2151
  
  		phdr.p_type = PT_LOAD;
  		phdr.p_offset = offset;
  		phdr.p_vaddr = vma->vm_start;
  		phdr.p_paddr = 0;
52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2152
  		phdr.p_filesz = vma_filesz[i++];
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
2153
  		phdr.p_memsz = vma->vm_end - vma->vm_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
2155
  		offset += phdr.p_filesz;
  		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
2156
2157
2158
2159
  		if (vma->vm_flags & VM_WRITE)
  			phdr.p_flags |= PF_W;
  		if (vma->vm_flags & VM_EXEC)
  			phdr.p_flags |= PF_X;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
  		phdr.p_align = ELF_EXEC_PAGESIZE;
ecc8c7725   Al Viro   new helper: dump_...
2161
  		if (!dump_emit(cprm, &phdr, sizeof(phdr)))
088e7af73   Daisuke HATAYAMA   coredump: move du...
2162
  			goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
  	}
506f21c55   Al Viro   switch elf_core_w...
2164
  	if (!elf_core_write_extra_phdrs(cprm, offset))
1fcccbac8   Daisuke HATAYAMA   elf coredump: rep...
2165
  		goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
2167
  
   	/* write out the notes section */
ecc8c7725   Al Viro   new helper: dump_...
2168
  	if (!write_note_info(&info, cprm))
3aba481fc   Roland McGrath   elf core dump: no...
2169
  		goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170

cdc3d5627   Al Viro   switch elf_coredu...
2171
  	if (elf_coredump_extra_notes_write(cprm))
e55014923   Michael Ellerman   [POWERPC] spufs: ...
2172
  		goto end_coredump;
bf1ab978b   Dwayne Grant McConnell   [POWERPC] coredum...
2173

d025c9db7   Andi Kleen   [PATCH] Support p...
2174
  	/* Align to page */
1607f09c2   Mateusz Guzik   coredump: fix dum...
2175
  	if (!dump_skip(cprm, dataoff - cprm->pos))
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
2176
  		goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2177

52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2178
  	for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
f47aef55d   Roland McGrath   [PATCH] i386 vDSO...
2179
  			vma = next_vma(vma, gate_vma)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2180
  		unsigned long addr;
82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
2181
  		unsigned long end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182

52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2183
  		end = vma->vm_start + vma_filesz[i++];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184

82df39738   Roland McGrath   Add MMF_DUMP_ELF_...
2185
  		for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
f4e5cc2c4   Jesper Juhl   [PATCH] binfmt_el...
2186
  			struct page *page;
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
2187
2188
2189
2190
2191
  			int stop;
  
  			page = get_dump_page(addr);
  			if (page) {
  				void *kaddr = kmap(page);
13046ece9   Al Viro   binfmt_elf: conve...
2192
  				stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
2193
  				kunmap(page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
2194
  				put_page(page);
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
2195
  			} else
9b56d5438   Al Viro   dump_skip(): dump...
2196
  				stop = !dump_skip(cprm, PAGE_SIZE);
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
2197
2198
  			if (stop)
  				goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
2200
  		}
  	}
aa3e7eaf0   Al Viro   switch elf_core_w...
2201
  	if (!elf_core_write_extra_data(cprm))
1fcccbac8   Daisuke HATAYAMA   elf coredump: rep...
2202
  		goto end_coredump;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203

8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2204
  	if (e_phnum == PN_XNUM) {
13046ece9   Al Viro   binfmt_elf: conve...
2205
  		if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2206
2207
  			goto end_coredump;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
2209
2210
2211
  end_coredump:
  	set_fs(fs);
  
  cleanup:
3aba481fc   Roland McGrath   elf core dump: no...
2212
  	free_note_info(&info);
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
2213
  	kfree(shdr4extnum);
52f5592e5   Jungseung Lee   fs/binfmt_elf.c: ...
2214
  	kfree(vma_filesz);
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
2215
  	kfree(phdr4note);
5f719558e   WANG Cong   [Patch] fs/binfmt...
2216
2217
  	kfree(elf);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2218
  	return has_dumped;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219
  }
698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
2220
  #endif		/* CONFIG_ELF_CORE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
2222
2223
  
  static int __init init_elf_binfmt(void)
  {
8fc3dc5a3   Al Viro   __register_binfmt...
2224
2225
  	register_binfmt(&elf_format);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
  }
  
  static void __exit exit_elf_binfmt(void)
  {
  	/* Remove the COFF and ELF loaders. */
  	unregister_binfmt(&elf_format);
  }
  
  core_initcall(init_elf_binfmt);
  module_exit(exit_elf_binfmt);
  MODULE_LICENSE("GPL");