Blame view

fs/binfmt_elf_fdpic.c 47.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /* binfmt_elf_fdpic.c: FDPIC ELF binary format
   *
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
3
   * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   * Written by David Howells (dhowells@redhat.com)
   * Derived from binfmt_elf.c
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  
  #include <linux/module.h>
  
  #include <linux/fs.h>
  #include <linux/stat.h>
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/mman.h>
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/binfmts.h>
  #include <linux/string.h>
  #include <linux/file.h>
  #include <linux/fcntl.h>
  #include <linux/slab.h>
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
27
  #include <linux/pagemap.h>
5edc2a512   Paul Mundt   binfmt_elf_fdpic:...
28
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/highmem.h>
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
30
  #include <linux/highuid.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  #include <linux/personality.h>
  #include <linux/ptrace.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
  #include <linux/elf.h>
  #include <linux/elf-fdpic.h>
  #include <linux/elfcore.h>
088e7af73   Daisuke HATAYAMA   coredump: move du...
37
  #include <linux/coredump.h>
ab27a8d04   Ross Zwisler   coredump: add DAX...
38
  #include <linux/dax.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
  
  #include <asm/uaccess.h>
  #include <asm/param.h>
  #include <asm/pgalloc.h>
  
  typedef char *elf_caddr_t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
  
  #if 0
  #define kdebug(fmt, ...) printk("FDPIC "fmt"
  " ,##__VA_ARGS__ )
  #else
  #define kdebug(fmt, ...) do {} while(0)
  #endif
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
52
53
54
55
56
57
  #if 0
  #define kdcore(fmt, ...) printk("FDPIC "fmt"
  " ,##__VA_ARGS__ )
  #else
  #define kdcore(fmt, ...) do {} while(0)
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  MODULE_LICENSE("GPL");
71613c3b8   Al Viro   get rid of pt_reg...
59
  static int load_elf_fdpic_binary(struct linux_binprm *);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
60
61
62
  static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *, struct file *);
  static int elf_fdpic_map_file(struct elf_fdpic_params *, struct file *,
  			      struct mm_struct *, const char *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
64
65
66
  static int create_elf_fdpic_tables(struct linux_binprm *, struct mm_struct *,
  				   struct elf_fdpic_params *,
  				   struct elf_fdpic_params *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  
  #ifndef CONFIG_MMU
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
69
70
71
72
73
  static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *,
  					    unsigned long *);
  static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *,
  						   struct file *,
  						   struct mm_struct *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  #endif
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
75
76
  static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *,
  					     struct file *, struct mm_struct *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
78
  #ifdef CONFIG_ELF_CORE
f6151dfea   Masami Hiramatsu   mm: introduce cor...
79
  static int elf_fdpic_core_dump(struct coredump_params *cprm);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
80
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  static struct linux_binfmt elf_fdpic_format = {
  	.module		= THIS_MODULE,
  	.load_binary	= load_elf_fdpic_binary,
698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
84
  #ifdef CONFIG_ELF_CORE
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
85
86
  	.core_dump	= elf_fdpic_core_dump,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
  	.min_coredump	= ELF_EXEC_PAGESIZE,
  };
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
89
90
  static int __init init_elf_fdpic_binfmt(void)
  {
8fc3dc5a3   Al Viro   __register_binfmt...
91
92
  	register_binfmt(&elf_fdpic_format);
  	return 0;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
93
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
95
96
97
98
  static void __exit exit_elf_fdpic_binfmt(void)
  {
  	unregister_binfmt(&elf_fdpic_format);
  }
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
99
  core_initcall(init_elf_fdpic_binfmt);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
100
  module_exit(exit_elf_fdpic_binfmt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
102
  static int is_elf(struct elfhdr *hdr, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
  {
  	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0)
  		return 0;
  	if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)
  		return 0;
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
108
  	if (!elf_check_arch(hdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  		return 0;
72c2d5319   Al Viro   file->f_op is nev...
110
  	if (!file->f_op->mmap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
  		return 0;
  	return 1;
  }
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  #ifndef elf_check_fdpic
  #define elf_check_fdpic(x) 0
  #endif
  
  #ifndef elf_check_const_displacement
  #define elf_check_const_displacement(x) 0
  #endif
  
  static int is_constdisp(struct elfhdr *hdr)
  {
  	if (!elf_check_fdpic(hdr))
  		return 1;
  	if (elf_check_const_displacement(hdr))
  		return 1;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
133
  /*****************************************************************************/
  /*
   * read the program headers table into memory
   */
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
134
135
  static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params,
  				 struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  {
  	struct elf32_phdr *phdr;
  	unsigned long size;
  	int retval, loop;
  
  	if (params->hdr.e_phentsize != sizeof(struct elf_phdr))
  		return -ENOMEM;
  	if (params->hdr.e_phnum > 65536U / sizeof(struct elf_phdr))
  		return -ENOMEM;
  
  	size = params->hdr.e_phnum * sizeof(struct elf_phdr);
  	params->phdrs = kmalloc(size, GFP_KERNEL);
  	if (!params->phdrs)
  		return -ENOMEM;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
150
151
  	retval = kernel_read(file, params->hdr.e_phoff,
  			     (char *) params->phdrs, size);
e1d2c8b69   David Howells   fdpic: check that...
152
153
  	if (unlikely(retval != size))
  		return retval < 0 ? retval : -ENOEXEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  
  	/* determine stack size for this binary */
  	phdr = params->phdrs;
  	for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) {
  		if (phdr->p_type != PT_GNU_STACK)
  			continue;
  
  		if (phdr->p_flags & PF_X)
  			params->flags |= ELF_FDPIC_FLAG_EXEC_STACK;
  		else
  			params->flags |= ELF_FDPIC_FLAG_NOEXEC_STACK;
  
  		params->stack_size = phdr->p_memsz;
  		break;
  	}
  
  	return 0;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
171
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
  
  /*****************************************************************************/
  /*
   * load an fdpic binary into various bits of memory
   */
71613c3b8   Al Viro   get rid of pt_reg...
177
  static int load_elf_fdpic_binary(struct linux_binprm *bprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  {
  	struct elf_fdpic_params exec_params, interp_params;
71613c3b8   Al Viro   get rid of pt_reg...
180
  	struct pt_regs *regs = current_pt_regs();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  	struct elf_phdr *phdr;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
182
  	unsigned long stack_size, entryaddr;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
183
184
185
  #ifdef ELF_FDPIC_PLAT_INIT
  	unsigned long dynaddr;
  #endif
04e4f2b18   Mike Frysinger   FDPIC: Respect PT...
186
187
188
  #ifndef CONFIG_MMU
  	unsigned long stack_prot;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
  	struct file *interpreter = NULL; /* to shut gcc up */
  	char *interpreter_name = NULL;
  	int executable_stack;
  	int retval, i;
aa289b472   David Howells   [PATCH] FDPIC: fi...
193
  	kdebug("____ LOAD %d ____", current->pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
  	memset(&exec_params, 0, sizeof(exec_params));
  	memset(&interp_params, 0, sizeof(interp_params));
  
  	exec_params.hdr = *(struct elfhdr *) bprm->buf;
  	exec_params.flags = ELF_FDPIC_FLAG_PRESENT | ELF_FDPIC_FLAG_EXECUTABLE;
  
  	/* check that this is a binary we know how to deal with */
  	retval = -ENOEXEC;
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
202
  	if (!is_elf(&exec_params.hdr, bprm->file))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  		goto error;
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
204
205
206
207
208
209
210
211
212
213
  	if (!elf_check_fdpic(&exec_params.hdr)) {
  #ifdef CONFIG_MMU
  		/* binfmt_elf handles non-fdpic elf except on nommu */
  		goto error;
  #else
  		/* nommu can only load ET_DYN (PIE) ELF */
  		if (exec_params.hdr.e_type != ET_DYN)
  			goto error;
  #endif
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  
  	/* read the program header table */
  	retval = elf_fdpic_fetch_phdrs(&exec_params, bprm->file);
  	if (retval < 0)
  		goto error;
  
  	/* scan for a program header that specifies an interpreter */
  	phdr = exec_params.phdrs;
  
  	for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) {
  		switch (phdr->p_type) {
  		case PT_INTERP:
  			retval = -ENOMEM;
  			if (phdr->p_filesz > PATH_MAX)
  				goto error;
  			retval = -ENOENT;
  			if (phdr->p_filesz < 2)
  				goto error;
  
  			/* read the name of the interpreter into memory */
792db3af3   Jesper Juhl   [PATCH] fs/binfmt...
234
  			interpreter_name = kmalloc(phdr->p_filesz, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
  			if (!interpreter_name)
  				goto error;
  
  			retval = kernel_read(bprm->file,
  					     phdr->p_offset,
  					     interpreter_name,
  					     phdr->p_filesz);
e1d2c8b69   David Howells   fdpic: check that...
242
243
244
  			if (unlikely(retval != phdr->p_filesz)) {
  				if (retval >= 0)
  					retval = -ENOEXEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  				goto error;
e1d2c8b69   David Howells   fdpic: check that...
246
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  
  			retval = -ENOENT;
  			if (interpreter_name[phdr->p_filesz - 1] != '\0')
  				goto error;
  
  			kdebug("Using ELF interpreter %s", interpreter_name);
  
  			/* replace the program with the interpreter */
  			interpreter = open_exec(interpreter_name);
  			retval = PTR_ERR(interpreter);
  			if (IS_ERR(interpreter)) {
  				interpreter = NULL;
  				goto error;
  			}
1fb844961   Alexey Dobriyan   [PATCH] core-dump...
261
262
263
264
265
  			/*
  			 * If the binary is not readable then enforce
  			 * mm->dumpable = 0 regardless of the interpreter's
  			 * permissions.
  			 */
1b5d783c9   Al Viro   consolidate BINPR...
266
  			would_dump(bprm, interpreter);
1fb844961   Alexey Dobriyan   [PATCH] core-dump...
267

8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
268
269
  			retval = kernel_read(interpreter, 0, bprm->buf,
  					     BINPRM_BUF_SIZE);
e1d2c8b69   David Howells   fdpic: check that...
270
271
272
  			if (unlikely(retval != BINPRM_BUF_SIZE)) {
  				if (retval >= 0)
  					retval = -ENOEXEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  				goto error;
e1d2c8b69   David Howells   fdpic: check that...
274
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
280
281
282
283
284
285
286
287
  
  			interp_params.hdr = *((struct elfhdr *) bprm->buf);
  			break;
  
  		case PT_LOAD:
  #ifdef CONFIG_MMU
  			if (exec_params.load_addr == 0)
  				exec_params.load_addr = phdr->p_vaddr;
  #endif
  			break;
  		}
  
  	}
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
288
  	if (is_constdisp(&exec_params.hdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
  		exec_params.flags |= ELF_FDPIC_FLAG_CONSTDISP;
  
  	/* perform insanity checks on the interpreter */
  	if (interpreter_name) {
  		retval = -ELIBBAD;
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
294
  		if (!is_elf(&interp_params.hdr, interpreter))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
303
304
305
  			goto error;
  
  		interp_params.flags = ELF_FDPIC_FLAG_PRESENT;
  
  		/* read the interpreter's program header table */
  		retval = elf_fdpic_fetch_phdrs(&interp_params, interpreter);
  		if (retval < 0)
  			goto error;
  	}
  
  	stack_size = exec_params.stack_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
  	if (exec_params.flags & ELF_FDPIC_FLAG_EXEC_STACK)
  		executable_stack = EXSTACK_ENABLE_X;
  	else if (exec_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK)
  		executable_stack = EXSTACK_DISABLE_X;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  	else
  		executable_stack = EXSTACK_DEFAULT;
8e8b63a68   David Howells   fdpic: ignore the...
312
313
314
315
316
317
318
319
320
  	if (stack_size == 0) {
  		stack_size = interp_params.stack_size;
  		if (interp_params.flags & ELF_FDPIC_FLAG_EXEC_STACK)
  			executable_stack = EXSTACK_ENABLE_X;
  		else if (interp_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK)
  			executable_stack = EXSTACK_DISABLE_X;
  		else
  			executable_stack = EXSTACK_DEFAULT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
  	retval = -ENOEXEC;
  	if (stack_size == 0)
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
323
  		stack_size = 131072UL; /* same as exec.c's default commit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324

1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
325
  	if (is_constdisp(&interp_params.hdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
  		interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP;
  
  	/* flush all traces of the currently running executable */
  	retval = flush_old_exec(bprm);
  	if (retval)
  		goto error;
  
  	/* there's now no turning back... the old userspace image is dead,
19d860a14   Al Viro   handle suicide on...
334
335
  	 * defunct, deceased, etc.
  	 */
1bde925d2   Rich Felker   fs/binfmt_elf_fdp...
336
337
338
339
  	if (elf_check_fdpic(&exec_params.hdr))
  		set_personality(PER_LINUX_FDPIC);
  	else
  		set_personality(PER_LINUX);
04e4f2b18   Mike Frysinger   FDPIC: Respect PT...
340
341
  	if (elf_read_implies_exec(&exec_params.hdr, executable_stack))
  		current->personality |= READ_IMPLIES_EXEC;
221af7f87   Linus Torvalds   Split 'flush_old_...
342
343
  
  	setup_new_exec(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
  	set_binfmt(&elf_fdpic_format);
  
  	current->mm->start_code = 0;
  	current->mm->end_code = 0;
  	current->mm->start_stack = 0;
  	current->mm->start_data = 0;
  	current->mm->end_data = 0;
  	current->mm->context.exec_fdpic_loadmap = 0;
  	current->mm->context.interp_fdpic_loadmap = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
  #ifdef CONFIG_MMU
  	elf_fdpic_arch_lay_out_mm(&exec_params,
  				  &interp_params,
  				  &current->mm->start_stack,
  				  &current->mm->start_brk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
359
360
  	retval = setup_arg_pages(bprm, current->mm->start_stack,
  				 executable_stack);
19d860a14   Al Viro   handle suicide on...
361
362
  	if (retval < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
  #endif
  
  	/* load the executable and interpreter into memory */
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
366
367
  	retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm,
  				    "executable");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  	if (retval < 0)
19d860a14   Al Viro   handle suicide on...
369
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
  
  	if (interpreter_name) {
  		retval = elf_fdpic_map_file(&interp_params, interpreter,
  					    current->mm, "interpreter");
  		if (retval < 0) {
  			printk(KERN_ERR "Unable to load interpreter
  ");
19d860a14   Al Viro   handle suicide on...
377
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
386
387
  		}
  
  		allow_write_access(interpreter);
  		fput(interpreter);
  		interpreter = NULL;
  	}
  
  #ifdef CONFIG_MMU
  	if (!current->mm->start_brk)
  		current->mm->start_brk = current->mm->end_data;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
388
389
  	current->mm->brk = current->mm->start_brk =
  		PAGE_ALIGN(current->mm->start_brk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  
  #else
4ac313111   Rich Felker   fs/binfmt_elf_fdp...
392
  	/* create a stack area and zero-size brk area */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  	stack_size = (stack_size + PAGE_SIZE - 1) & PAGE_MASK;
  	if (stack_size < PAGE_SIZE * 2)
  		stack_size = PAGE_SIZE * 2;
04e4f2b18   Mike Frysinger   FDPIC: Respect PT...
396
397
398
399
  	stack_prot = PROT_READ | PROT_WRITE;
  	if (executable_stack == EXSTACK_ENABLE_X ||
  	    (executable_stack == EXSTACK_DEFAULT && VM_STACK_FLAGS & VM_EXEC))
  		stack_prot |= PROT_EXEC;
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
400
  	current->mm->start_brk = vm_mmap(NULL, 0, stack_size, stack_prot,
ea6376395   Jie Zhang   nommu: fix malloc...
401
402
  					 MAP_PRIVATE | MAP_ANONYMOUS |
  					 MAP_UNINITIALIZED | MAP_GROWSDOWN,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  					 0);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
404
  	if (IS_ERR_VALUE(current->mm->start_brk)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  		retval = current->mm->start_brk;
  		current->mm->start_brk = 0;
19d860a14   Al Viro   handle suicide on...
407
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  	current->mm->brk = current->mm->start_brk;
  	current->mm->context.end_brk = current->mm->start_brk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
  	current->mm->start_stack = current->mm->start_brk + stack_size;
  #endif
a6f76f23d   David Howells   CRED: Make execve...
413
  	install_exec_creds(bprm);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
414
415
  	if (create_elf_fdpic_tables(bprm, current->mm,
  				    &exec_params, &interp_params) < 0)
19d860a14   Al Viro   handle suicide on...
416
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417

8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
418
419
420
421
422
423
424
  	kdebug("- start_code  %lx", current->mm->start_code);
  	kdebug("- end_code    %lx", current->mm->end_code);
  	kdebug("- start_data  %lx", current->mm->start_data);
  	kdebug("- end_data    %lx", current->mm->end_data);
  	kdebug("- start_brk   %lx", current->mm->start_brk);
  	kdebug("- brk         %lx", current->mm->brk);
  	kdebug("- start_stack %lx", current->mm->start_stack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
429
430
431
432
  
  #ifdef ELF_FDPIC_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.  This macro performs whatever initialization to
  	 * the regs structure is required.
  	 */
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
433
434
435
  	dynaddr = interp_params.dynamic_addr ?: exec_params.dynamic_addr;
  	ELF_FDPIC_PLAT_INIT(regs, exec_params.map_addr, interp_params.map_addr,
  			    dynaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
  #endif
  
  	/* everything is now ready... get the userspace context ready to roll */
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
439
440
  	entryaddr = interp_params.entry_addr ?: exec_params.entry_addr;
  	start_thread(regs, entryaddr, current->mm->start_stack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
  	retval = 0;
  
  error:
  	if (interpreter) {
  		allow_write_access(interpreter);
  		fput(interpreter);
  	}
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
449
450
451
452
453
  	kfree(interpreter_name);
  	kfree(exec_params.phdrs);
  	kfree(exec_params.loadmap);
  	kfree(interp_params.phdrs);
  	kfree(interp_params.loadmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  	return retval;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
455
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  
  /*****************************************************************************/
ec23847d6   Paul Mundt   binfmt_elf_fdpic:...
458
459
460
461
462
463
464
465
466
  
  #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
467
  /*
c7637941d   Paul Mundt   binfmt_elf_fdpic:...
468
469
   * present useful information to the program by shovelling it onto the new
   * process's stack
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
   */
  static int create_elf_fdpic_tables(struct linux_binprm *bprm,
  				   struct mm_struct *mm,
  				   struct elf_fdpic_params *exec_params,
  				   struct elf_fdpic_params *interp_params)
  {
86a264abe   David Howells   CRED: Wrap curren...
476
  	const struct cred *cred = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  	unsigned long sp, csp, nitems;
530018bf3   Al Viro   [PATCH] frv: binf...
478
  	elf_caddr_t __user *argv, *envp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	size_t platform_len = 0, len;
ec23847d6   Paul Mundt   binfmt_elf_fdpic:...
480
481
  	char *k_platform, *k_base_platform;
  	char __user *u_platform, *u_base_platform, *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  	int loop;
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
483
  	int nr;	/* reset for each csp adjustment */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  #ifdef CONFIG_MMU
c7637941d   Paul Mundt   binfmt_elf_fdpic:...
486
487
488
489
490
491
  	/* 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, so we give the architecture
  	 * an opportunity to do so here.
  	 */
  	sp = arch_align_stack(bprm->p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
495
496
497
498
  #else
  	sp = mm->start_stack;
  
  	/* stack the program arguments and environment */
  	if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0)
  		return -EFAULT;
  #endif
ec23847d6   Paul Mundt   binfmt_elf_fdpic:...
499
500
501
502
503
504
  	/*
  	 * 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
505
  	k_platform = ELF_PLATFORM;
1aeb21d62   David Howells   [PATCH] FDPIC: Fi...
506
  	u_platform = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
  
  	if (k_platform) {
  		platform_len = strlen(k_platform) + 1;
  		sp -= platform_len;
530018bf3   Al Viro   [PATCH] frv: binf...
511
  		u_platform = (char __user *) sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
  		if (__copy_to_user(u_platform, k_platform, platform_len) != 0)
  			return -EFAULT;
  	}
ec23847d6   Paul Mundt   binfmt_elf_fdpic:...
515
516
517
518
519
520
521
522
523
524
525
526
527
528
  	/*
  	 * If this architecture has a "base" platform capability
  	 * string, copy it to userspace.
  	 */
  	k_base_platform = ELF_BASE_PLATFORM;
  	u_base_platform = NULL;
  
  	if (k_base_platform) {
  		platform_len = strlen(k_base_platform) + 1;
  		sp -= platform_len;
  		u_base_platform = (char __user *) sp;
  		if (__copy_to_user(u_base_platform, k_base_platform, platform_len) != 0)
  			return -EFAULT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
534
535
  	sp &= ~7UL;
  
  	/* stack the load map(s) */
  	len = sizeof(struct elf32_fdpic_loadmap);
  	len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs;
  	sp = (sp - len) & ~7UL;
  	exec_params->map_addr = sp;
530018bf3   Al Viro   [PATCH] frv: binf...
536
  	if (copy_to_user((void __user *) sp, exec_params->loadmap, len) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
542
  		return -EFAULT;
  
  	current->mm->context.exec_fdpic_loadmap = (unsigned long) sp;
  
  	if (interp_params->loadmap) {
  		len = sizeof(struct elf32_fdpic_loadmap);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
543
544
  		len += sizeof(struct elf32_fdpic_loadseg) *
  			interp_params->loadmap->nsegs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
  		sp = (sp - len) & ~7UL;
  		interp_params->map_addr = sp;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
547
548
  		if (copy_to_user((void __user *) sp, interp_params->loadmap,
  				 len) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
552
553
554
  			return -EFAULT;
  
  		current->mm->context.interp_fdpic_loadmap = (unsigned long) sp;
  	}
  
  	/* force 16 byte _final_ alignment here for generality */
5edc2a512   Paul Mundt   binfmt_elf_fdpic:...
555
  #define DLINFO_ITEMS 15
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

ec23847d6   Paul Mundt   binfmt_elf_fdpic:...
557
558
  	nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) +
  		(k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

5edc2a512   Paul Mundt   binfmt_elf_fdpic:...
560
561
  	if (bprm->interp_flags & BINPRM_FLAGS_EXECFD)
  		nitems++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
566
567
568
569
570
571
  	csp = sp;
  	sp -= nitems * 2 * sizeof(unsigned long);
  	sp -= (bprm->envc + 1) * sizeof(char *);	/* envv[] */
  	sp -= (bprm->argc + 1) * sizeof(char *);	/* argv[] */
  	sp -= 1 * sizeof(unsigned long);		/* argc */
  
  	csp -= sp & 15UL;
  	sp -= sp & 15UL;
  
  	/* put the ELF interpreter info on the stack */
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
572
  #define NEW_AUX_ENT(id, val)						\
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
573
574
575
576
577
578
  	do {								\
  		struct { unsigned long _id, _val; } __user *ent;	\
  									\
  		ent = (void __user *) csp;				\
  		__put_user((id), &ent[nr]._id);				\
  		__put_user((val), &ent[nr]._val);			\
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
579
  		nr++;							\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	} while (0)
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
581
  	nr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  	csp -= 2 * sizeof(unsigned long);
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
583
  	NEW_AUX_ENT(AT_NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
  	if (k_platform) {
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
585
  		nr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  		csp -= 2 * sizeof(unsigned long);
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
587
  		NEW_AUX_ENT(AT_PLATFORM,
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
588
  			    (elf_addr_t) (unsigned long) u_platform);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  	}
ec23847d6   Paul Mundt   binfmt_elf_fdpic:...
590
591
592
593
594
595
  	if (k_base_platform) {
  		nr = 0;
  		csp -= 2 * sizeof(unsigned long);
  		NEW_AUX_ENT(AT_BASE_PLATFORM,
  			    (elf_addr_t) (unsigned long) u_base_platform);
  	}
5edc2a512   Paul Mundt   binfmt_elf_fdpic:...
596
597
598
599
600
  	if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
  		nr = 0;
  		csp -= 2 * sizeof(unsigned long);
  		NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
  	}
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
601
  	nr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  	csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
2171364d1   Michael Neuling   powerpc: Add HWCA...
603
604
605
606
  	NEW_AUX_ENT(AT_HWCAP,	ELF_HWCAP);
  #ifdef ELF_HWCAP2
  	NEW_AUX_ENT(AT_HWCAP2,	ELF_HWCAP2);
  #endif
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
607
608
609
610
611
612
613
614
  	NEW_AUX_ENT(AT_PAGESZ,	PAGE_SIZE);
  	NEW_AUX_ENT(AT_CLKTCK,	CLOCKS_PER_SEC);
  	NEW_AUX_ENT(AT_PHDR,	exec_params->ph_addr);
  	NEW_AUX_ENT(AT_PHENT,	sizeof(struct elf_phdr));
  	NEW_AUX_ENT(AT_PHNUM,	exec_params->hdr.e_phnum);
  	NEW_AUX_ENT(AT_BASE,	interp_params->elfhdr_addr);
  	NEW_AUX_ENT(AT_FLAGS,	0);
  	NEW_AUX_ENT(AT_ENTRY,	exec_params->entry_addr);
ebc887b27   Eric W. Biederman   userns: Convert b...
615
616
617
618
  	NEW_AUX_ENT(AT_UID,	(elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid));
  	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid));
  	NEW_AUX_ENT(AT_GID,	(elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid));
  	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));
5edc2a512   Paul Mundt   binfmt_elf_fdpic:...
619
620
  	NEW_AUX_ENT(AT_SECURE,	security_bprm_secureexec(bprm));
  	NEW_AUX_ENT(AT_EXECFN,	bprm->exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
  
  #ifdef ARCH_DLINFO
9b14ec35f   Paul Mundt   binfmt_elf_fdpic:...
623
624
  	nr = 0;
  	csp -= AT_VECTOR_SIZE_ARCH * 2 * sizeof(unsigned long);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
632
633
  	/* ARCH_DLINFO must come last so platform specific code can enforce
  	 * special alignment requirements on the AUXV if necessary (eg. PPC).
  	 */
  	ARCH_DLINFO;
  #endif
  #undef NEW_AUX_ENT
  
  	/* allocate room for argv[] and envv[] */
  	csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
530018bf3   Al Viro   [PATCH] frv: binf...
634
  	envp = (elf_caddr_t __user *) csp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  	csp -= (bprm->argc + 1) * sizeof(elf_caddr_t);
530018bf3   Al Viro   [PATCH] frv: binf...
636
  	argv = (elf_caddr_t __user *) csp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
  
  	/* stack argc */
  	csp -= sizeof(unsigned long);
530018bf3   Al Viro   [PATCH] frv: binf...
640
  	__put_user(bprm->argc, (unsigned long __user *) csp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641

88bcd5126   Eric Sesterhenn   BUG_ON() Conversi...
642
  	BUG_ON(csp != sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
  
  	/* fill in the argv[] array */
  #ifdef CONFIG_MMU
  	current->mm->arg_start = bprm->p;
  #else
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
648
649
  	current->mm->arg_start = current->mm->start_stack -
  		(MAX_ARG_PAGES * PAGE_SIZE - bprm->p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  #endif
530018bf3   Al Viro   [PATCH] frv: binf...
651
  	p = (char __user *) current->mm->arg_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
  	for (loop = bprm->argc; loop > 0; loop--) {
  		__put_user((elf_caddr_t) p, argv++);
b6a2fea39   Ollie Wild   mm: variable leng...
654
655
  		len = strnlen_user(p, MAX_ARG_STRLEN);
  		if (!len || len > MAX_ARG_STRLEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
661
662
663
664
665
  			return -EINVAL;
  		p += len;
  	}
  	__put_user(NULL, argv);
  	current->mm->arg_end = (unsigned long) p;
  
  	/* fill in the envv[] array */
  	current->mm->env_start = (unsigned long) p;
  	for (loop = bprm->envc; loop > 0; loop--) {
  		__put_user((elf_caddr_t)(unsigned long) p, envp++);
b6a2fea39   Ollie Wild   mm: variable leng...
666
667
  		len = strnlen_user(p, MAX_ARG_STRLEN);
  		if (!len || len > MAX_ARG_STRLEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
673
674
675
  			return -EINVAL;
  		p += len;
  	}
  	__put_user(NULL, envp);
  	current->mm->env_end = (unsigned long) p;
  
  	mm->start_stack = (unsigned long) sp;
  	return 0;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
676
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
  
  /*****************************************************************************/
  /*
   * transfer the program arguments and environment from the holding pages onto
   * the stack
   */
  #ifndef CONFIG_MMU
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
684
685
  static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *bprm,
  					    unsigned long *_sp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  {
  	unsigned long index, stop, sp;
  	char *src;
  	int ret = 0;
  
  	stop = bprm->p >> PAGE_SHIFT;
  	sp = *_sp;
  
  	for (index = MAX_ARG_PAGES - 1; index >= stop; index--) {
  		src = kmap(bprm->page[index]);
  		sp -= PAGE_SIZE;
  		if (copy_to_user((void *) sp, src, PAGE_SIZE) != 0)
  			ret = -EFAULT;
  		kunmap(bprm->page[index]);
  		if (ret < 0)
  			goto out;
  	}
  
  	*_sp = (*_sp - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p)) & ~15;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
705
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  	return ret;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
707
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  #endif
  
  /*****************************************************************************/
  /*
   * load the appropriate binary image (executable or interpreter) into memory
   * - we assume no MMU is available
   * - if no other PIC bits are set in params->hdr->e_flags
   *   - we assume that the LOADable segments in the binary are independently relocatable
   *   - we assume R/O executable segments are shareable
   * - else
   *   - we assume the loadable parts of the image to require fixed displacement
   *   - the image is not shareable
   */
  static int elf_fdpic_map_file(struct elf_fdpic_params *params,
  			      struct file *file,
  			      struct mm_struct *mm,
  			      const char *what)
  {
  	struct elf32_fdpic_loadmap *loadmap;
  #ifdef CONFIG_MMU
  	struct elf32_fdpic_loadseg *mseg;
  #endif
  	struct elf32_fdpic_loadseg *seg;
  	struct elf32_phdr *phdr;
  	unsigned long load_addr, stop;
  	unsigned nloads, tmp;
  	size_t size;
  	int loop, ret;
  
  	/* allocate a load map table */
  	nloads = 0;
  	for (loop = 0; loop < params->hdr.e_phnum; loop++)
  		if (params->phdrs[loop].p_type == PT_LOAD)
  			nloads++;
  
  	if (nloads == 0)
  		return -ELIBBAD;
  
  	size = sizeof(*loadmap) + nloads * sizeof(*seg);
b87576d59   Robert P. J. Day   fs: Convert kmall...
747
  	loadmap = kzalloc(size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
751
  	if (!loadmap)
  		return -ENOMEM;
  
  	params->loadmap = loadmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  
  	loadmap->version = ELF32_FDPIC_LOADMAP_VERSION;
  	loadmap->nsegs = nloads;
  
  	load_addr = params->load_addr;
  	seg = loadmap->segs;
  
  	/* map the requested LOADs into the memory space */
  	switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) {
  	case ELF_FDPIC_FLAG_CONSTDISP:
  	case ELF_FDPIC_FLAG_CONTIGUOUS:
  #ifndef CONFIG_MMU
  		ret = elf_fdpic_map_file_constdisp_on_uclinux(params, file, mm);
  		if (ret < 0)
  			return ret;
  		break;
  #endif
  	default:
  		ret = elf_fdpic_map_file_by_direct_mmap(params, file, mm);
  		if (ret < 0)
  			return ret;
  		break;
  	}
  
  	/* map the entry point */
  	if (params->hdr.e_entry) {
  		seg = loadmap->segs;
  		for (loop = loadmap->nsegs; loop > 0; loop--, seg++) {
  			if (params->hdr.e_entry >= seg->p_vaddr &&
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
781
  			    params->hdr.e_entry < seg->p_vaddr + seg->p_memsz) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
  				params->entry_addr =
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
783
784
  					(params->hdr.e_entry - seg->p_vaddr) +
  					seg->addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
  				break;
  			}
  		}
  	}
  
  	/* determine where the program header table has wound up if mapped */
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
791
792
  	stop = params->hdr.e_phoff;
  	stop += params->hdr.e_phnum * sizeof (struct elf_phdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
794
795
796
797
798
799
800
801
802
803
804
805
  	phdr = params->phdrs;
  
  	for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) {
  		if (phdr->p_type != PT_LOAD)
  			continue;
  
  		if (phdr->p_offset > params->hdr.e_phoff ||
  		    phdr->p_offset + phdr->p_filesz < stop)
  			continue;
  
  		seg = loadmap->segs;
  		for (loop = loadmap->nsegs; loop > 0; loop--, seg++) {
  			if (phdr->p_vaddr >= seg->p_vaddr &&
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
806
807
808
809
810
  			    phdr->p_vaddr + phdr->p_filesz <=
  			    seg->p_vaddr + seg->p_memsz) {
  				params->ph_addr =
  					(phdr->p_vaddr - seg->p_vaddr) +
  					seg->addr +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  					params->hdr.e_phoff - phdr->p_offset;
  				break;
  			}
  		}
  		break;
  	}
  
  	/* determine where the dynamic section has wound up if there is one */
  	phdr = params->phdrs;
  	for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) {
  		if (phdr->p_type != PT_DYNAMIC)
  			continue;
  
  		seg = loadmap->segs;
  		for (loop = loadmap->nsegs; loop > 0; loop--, seg++) {
  			if (phdr->p_vaddr >= seg->p_vaddr &&
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
827
828
829
830
831
832
833
834
835
  			    phdr->p_vaddr + phdr->p_memsz <=
  			    seg->p_vaddr + seg->p_memsz) {
  				params->dynamic_addr =
  					(phdr->p_vaddr - seg->p_vaddr) +
  					seg->addr;
  
  				/* check the dynamic section contains at least
  				 * one item, and that the last item is a NULL
  				 * entry */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
  				if (phdr->p_memsz == 0 ||
  				    phdr->p_memsz % sizeof(Elf32_Dyn) != 0)
  					goto dynamic_error;
  
  				tmp = phdr->p_memsz / sizeof(Elf32_Dyn);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
841
842
  				if (((Elf32_Dyn *)
  				     params->dynamic_addr)[tmp - 1].d_tag != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
849
850
  					goto dynamic_error;
  				break;
  			}
  		}
  		break;
  	}
  
  	/* now elide adjacent segments in the load map on MMU linux
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
851
852
  	 * - on uClinux the holes between may actually be filled with system
  	 *   stuff or stuff from other processes
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
859
860
861
862
  	 */
  #ifdef CONFIG_MMU
  	nloads = loadmap->nsegs;
  	mseg = loadmap->segs;
  	seg = mseg + 1;
  	for (loop = 1; loop < nloads; loop++) {
  		/* see if we have a candidate for merging */
  		if (seg->p_vaddr - mseg->p_vaddr == seg->addr - mseg->addr) {
  			load_addr = PAGE_ALIGN(mseg->addr + mseg->p_memsz);
  			if (load_addr == (seg->addr & PAGE_MASK)) {
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
863
864
865
  				mseg->p_memsz +=
  					load_addr -
  					(mseg->addr + mseg->p_memsz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
  				mseg->p_memsz += seg->addr & ~PAGE_MASK;
  				mseg->p_memsz += seg->p_memsz;
  				loadmap->nsegs--;
  				continue;
  			}
  		}
  
  		mseg++;
  		if (mseg != seg)
  			*mseg = *seg;
  	}
  #endif
  
  	kdebug("Mapped Object [%s]:", what);
  	kdebug("- elfhdr   : %lx", params->elfhdr_addr);
  	kdebug("- entry    : %lx", params->entry_addr);
  	kdebug("- PHDR[]   : %lx", params->ph_addr);
  	kdebug("- DYNAMIC[]: %lx", params->dynamic_addr);
  	seg = loadmap->segs;
  	for (loop = 0; loop < loadmap->nsegs; loop++, seg++)
  		kdebug("- LOAD[%d] : %08x-%08x [va=%x ms=%x]",
  		       loop,
  		       seg->addr, seg->addr + seg->p_memsz - 1,
  		       seg->p_vaddr, seg->p_memsz);
  
  	return 0;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
892
  dynamic_error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
  	printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)
  ",
496ad9aa8   Al Viro   new helper: file_...
895
  	       what, file_inode(file)->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  	return -ELIBBAD;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
897
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
902
903
  
  /*****************************************************************************/
  /*
   * map a file with constant displacement under uClinux
   */
  #ifndef CONFIG_MMU
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
904
905
906
907
  static int elf_fdpic_map_file_constdisp_on_uclinux(
  	struct elf_fdpic_params *params,
  	struct file *file,
  	struct mm_struct *mm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
  {
  	struct elf32_fdpic_loadseg *seg;
  	struct elf32_phdr *phdr;
  	unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0, mflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
  	int loop, ret;
  
  	load_addr = params->load_addr;
  	seg = params->loadmap->segs;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
916
917
  	/* determine the bounds of the contiguous overall allocation we must
  	 * make */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
  	phdr = params->phdrs;
  	for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) {
  		if (params->phdrs[loop].p_type != PT_LOAD)
  			continue;
  
  		if (base > phdr->p_vaddr)
  			base = phdr->p_vaddr;
  		if (top < phdr->p_vaddr + phdr->p_memsz)
  			top = phdr->p_vaddr + phdr->p_memsz;
  	}
  
  	/* allocate one big anon block for everything */
  	mflags = MAP_PRIVATE;
  	if (params->flags & ELF_FDPIC_FLAG_EXECUTABLE)
  		mflags |= MAP_EXECUTABLE;
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
933
  	maddr = vm_mmap(NULL, load_addr, top - base,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  			PROT_READ | PROT_WRITE | PROT_EXEC, mflags, 0);
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
935
  	if (IS_ERR_VALUE(maddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
940
941
942
943
944
945
  		return (int) maddr;
  
  	if (load_addr != 0)
  		load_addr += PAGE_ALIGN(top - base);
  
  	/* and then load the file segments into it */
  	phdr = params->phdrs;
  	for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) {
  		if (params->phdrs[loop].p_type != PT_LOAD)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
  		seg->addr = maddr + (phdr->p_vaddr - base);
  		seg->p_vaddr = phdr->p_vaddr;
  		seg->p_memsz = phdr->p_memsz;
3dc20cb28   Al Viro   new helper: read_...
949
950
  		ret = read_code(file, seg->addr, phdr->p_offset,
  				       phdr->p_filesz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
955
956
957
958
  		if (ret < 0)
  			return ret;
  
  		/* map the ELF header address if in this segment */
  		if (phdr->p_offset == 0)
  			params->elfhdr_addr = seg->addr;
  
  		/* clear any space allocated but not loaded */
ab4ad5551   Mike Frysinger   bin_elf_fdpic: ch...
959
  		if (phdr->p_filesz < phdr->p_memsz) {
e30c7c3b3   Takuya Yoshikawa   binfmt_elf_fdpic:...
960
961
962
  			if (clear_user((void *) (seg->addr + phdr->p_filesz),
  				       phdr->p_memsz - phdr->p_filesz))
  				return -EFAULT;
ab4ad5551   Mike Frysinger   bin_elf_fdpic: ch...
963
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
966
  
  		if (mm) {
  			if (phdr->p_flags & PF_X) {
aa289b472   David Howells   [PATCH] FDPIC: fi...
967
968
969
970
971
  				if (!mm->start_code) {
  					mm->start_code = seg->addr;
  					mm->end_code = seg->addr +
  						phdr->p_memsz;
  				}
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
972
  			} else if (!mm->start_data) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
  				mm->start_data = seg->addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  				mm->end_data = seg->addr + phdr->p_memsz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
  		}
  
  		seg++;
  	}
  
  	return 0;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
982
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
986
987
988
989
990
991
992
993
994
995
  #endif
  
  /*****************************************************************************/
  /*
   * map a binary by direct mmap() of the individual PT_LOAD segments
   */
  static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
  					     struct file *file,
  					     struct mm_struct *mm)
  {
  	struct elf32_fdpic_loadseg *seg;
  	struct elf32_phdr *phdr;
  	unsigned long load_addr, delta_vaddr;
e30c7c3b3   Takuya Yoshikawa   binfmt_elf_fdpic:...
996
  	int loop, dvset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  
  	load_addr = params->load_addr;
  	delta_vaddr = 0;
  	dvset = 0;
  
  	seg = params->loadmap->segs;
  
  	/* deal with each load segment separately */
  	phdr = params->phdrs;
  	for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) {
  		unsigned long maddr, disp, excess, excess1;
  		int prot = 0, flags;
  
  		if (phdr->p_type != PT_LOAD)
  			continue;
  
  		kdebug("[LOAD] va=%lx of=%lx fs=%lx ms=%lx",
  		       (unsigned long) phdr->p_vaddr,
  		       (unsigned long) phdr->p_offset,
  		       (unsigned long) phdr->p_filesz,
  		       (unsigned long) phdr->p_memsz);
  
  		/* determine the mapping parameters */
  		if (phdr->p_flags & PF_R) prot |= PROT_READ;
  		if (phdr->p_flags & PF_W) prot |= PROT_WRITE;
  		if (phdr->p_flags & PF_X) prot |= PROT_EXEC;
  
  		flags = MAP_PRIVATE | MAP_DENYWRITE;
  		if (params->flags & ELF_FDPIC_FLAG_EXECUTABLE)
  			flags |= MAP_EXECUTABLE;
  
  		maddr = 0;
  
  		switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) {
  		case ELF_FDPIC_FLAG_INDEPENDENT:
  			/* PT_LOADs are independently locatable */
  			break;
  
  		case ELF_FDPIC_FLAG_HONOURVADDR:
  			/* the specified virtual address must be honoured */
  			maddr = phdr->p_vaddr;
  			flags |= MAP_FIXED;
  			break;
  
  		case ELF_FDPIC_FLAG_CONSTDISP:
  			/* constant displacement
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1043
1044
  			 * - can be mapped anywhere, but must be mapped as a
  			 *   unit
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
1047
1048
1049
  			 */
  			if (!dvset) {
  				maddr = load_addr;
  				delta_vaddr = phdr->p_vaddr;
  				dvset = 1;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1050
  			} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  				maddr = load_addr + phdr->p_vaddr - delta_vaddr;
  				flags |= MAP_FIXED;
  			}
  			break;
  
  		case ELF_FDPIC_FLAG_CONTIGUOUS:
  			/* contiguity handled later */
  			break;
  
  		default:
  			BUG();
  		}
  
  		maddr &= PAGE_MASK;
  
  		/* create the mapping */
  		disp = phdr->p_vaddr & ~PAGE_MASK;
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
1068
  		maddr = vm_mmap(file, maddr, phdr->p_memsz + disp, prot, flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
  				phdr->p_offset - disp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
  
  		kdebug("mmap[%d] <file> sz=%lx pr=%x fl=%x of=%lx --> %08lx",
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1072
1073
  		       loop, phdr->p_memsz + disp, prot, flags,
  		       phdr->p_offset - disp, maddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074

8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1075
  		if (IS_ERR_VALUE(maddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  			return (int) maddr;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1077
1078
  		if ((params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) ==
  		    ELF_FDPIC_FLAG_CONTIGUOUS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
1081
1082
1083
1084
1085
1086
1087
  			load_addr += PAGE_ALIGN(phdr->p_memsz + disp);
  
  		seg->addr = maddr + disp;
  		seg->p_vaddr = phdr->p_vaddr;
  		seg->p_memsz = phdr->p_memsz;
  
  		/* map the ELF header address if in this segment */
  		if (phdr->p_offset == 0)
  			params->elfhdr_addr = seg->addr;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1088
1089
  		/* clear the bit between beginning of mapping and beginning of
  		 * PT_LOAD */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
1091
  		if (prot & PROT_WRITE && disp > 0) {
  			kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp);
e30c7c3b3   Takuya Yoshikawa   binfmt_elf_fdpic:...
1092
1093
  			if (clear_user((void __user *) maddr, disp))
  				return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
  			maddr += disp;
  		}
  
  		/* clear any space allocated but not loaded
  		 * - on uClinux we can just clear the lot
  		 * - on MMU linux we'll get a SIGBUS beyond the last page
  		 *   extant in the file
  		 */
  		excess = phdr->p_memsz - phdr->p_filesz;
  		excess1 = PAGE_SIZE - ((maddr + phdr->p_filesz) & ~PAGE_MASK);
  
  #ifdef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
1108
1109
1110
  		if (excess > excess1) {
  			unsigned long xaddr = maddr + phdr->p_filesz + excess1;
  			unsigned long xmaddr;
  
  			flags |= MAP_FIXED | MAP_ANONYMOUS;
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
1111
  			xmaddr = vm_mmap(NULL, xaddr, excess - excess1,
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1112
  					 prot, flags, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
  
  			kdebug("mmap[%d] <anon>"
  			       " ad=%lx sz=%lx pr=%x fl=%x of=0 --> %08lx",
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1116
1117
  			       loop, xaddr, excess - excess1, prot, flags,
  			       xmaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
1124
1125
  
  			if (xmaddr != xaddr)
  				return -ENOMEM;
  		}
  
  		if (prot & PROT_WRITE && excess1 > 0) {
  			kdebug("clear[%d] ad=%lx sz=%lx",
  			       loop, maddr + phdr->p_filesz, excess1);
e30c7c3b3   Takuya Yoshikawa   binfmt_elf_fdpic:...
1126
1127
1128
  			if (clear_user((void __user *) maddr + phdr->p_filesz,
  				       excess1))
  				return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
1132
1133
1134
  		}
  
  #else
  		if (excess > 0) {
  			kdebug("clear[%d] ad=%lx sz=%lx",
  			       loop, maddr + phdr->p_filesz, excess);
e30c7c3b3   Takuya Yoshikawa   binfmt_elf_fdpic:...
1135
1136
  			if (clear_user((void *) maddr + phdr->p_filesz, excess))
  				return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
1140
1141
  		}
  #endif
  
  		if (mm) {
  			if (phdr->p_flags & PF_X) {
aa289b472   David Howells   [PATCH] FDPIC: fi...
1142
1143
1144
1145
  				if (!mm->start_code) {
  					mm->start_code = maddr;
  					mm->end_code = maddr + phdr->p_memsz;
  				}
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1146
  			} else if (!mm->start_data) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
1150
1151
1152
1153
1154
1155
  				mm->start_data = maddr;
  				mm->end_data = maddr + phdr->p_memsz;
  			}
  		}
  
  		seg++;
  	}
  
  	return 0;
8a2ab7f5d   David Howells   [PATCH] FDPIC: Ad...
1156
  }
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  
  /*****************************************************************************/
  /*
   * ELF-FDPIC core dumper
   *
   * Modelled on fs/exec.c:aout_core_dump()
   * Jeremy Fitzhardinge <jeremy@sw.oz.au>
   *
   * Modelled on fs/binfmt_elf.c core dumper
   */
698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
1167
  #ifdef CONFIG_ELF_CORE
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1168
1169
  
  /*
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1170
1171
1172
1173
1174
1175
   * Decide whether a segment is worth dumping; default is yes to be
   * sure (missing info is worse than too much; etc).
   * Personally I'd include everything, and use the coredump limit...
   *
   * I think we should skip something. But I am not sure how. H.J.
   */
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1176
  static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1177
  {
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1178
  	int dump_ok;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1179
  	/* Do not dump I/O mapped devices or special mappings */
314e51b98   Konstantin Khlebnikov   mm: kill vma flag...
1180
  	if (vma->vm_flags & VM_IO) {
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  		kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags);
  		return 0;
  	}
  
  	/* If we may not read the contents, don't allow us to dump
  	 * them either. "dump_write()" can't handle it anyway.
  	 */
  	if (!(vma->vm_flags & VM_READ)) {
  		kdcore("%08lx: %08lx: no (!read)", vma->vm_start, vma->vm_flags);
  		return 0;
  	}
ab27a8d04   Ross Zwisler   coredump: add DAX...
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
  	/* support for DAX */
  	if (vma_is_dax(vma)) {
  		if (vma->vm_flags & VM_SHARED) {
  			dump_ok = test_bit(MMF_DUMP_DAX_SHARED, &mm_flags);
  			kdcore("%08lx: %08lx: %s (DAX shared)", vma->vm_start,
  			       vma->vm_flags, dump_ok ? "yes" : "no");
  		} else {
  			dump_ok = test_bit(MMF_DUMP_DAX_PRIVATE, &mm_flags);
  			kdcore("%08lx: %08lx: %s (DAX private)", vma->vm_start,
  			       vma->vm_flags, dump_ok ? "yes" : "no");
  		}
  		return dump_ok;
  	}
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1205
  	/* By default, dump shared memory if mapped from an anonymous file. */
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1206
  	if (vma->vm_flags & VM_SHARED) {
496ad9aa8   Al Viro   new helper: file_...
1207
  		if (file_inode(vma->vm_file)->i_nlink == 0) {
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1208
1209
1210
1211
  			dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags);
  			kdcore("%08lx: %08lx: %s (share)", vma->vm_start,
  			       vma->vm_flags, dump_ok ? "yes" : "no");
  			return dump_ok;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1212
  		}
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1213
1214
1215
1216
  		dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags);
  		kdcore("%08lx: %08lx: %s (share)", vma->vm_start,
  		       vma->vm_flags, dump_ok ? "yes" : "no");
  		return dump_ok;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1217
1218
1219
  	}
  
  #ifdef CONFIG_MMU
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1220
  	/* By default, if it hasn't been written to, don't write it out */
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1221
  	if (!vma->anon_vma) {
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1222
1223
1224
1225
  		dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags);
  		kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start,
  		       vma->vm_flags, dump_ok ? "yes" : "no");
  		return dump_ok;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1226
1227
  	}
  #endif
ee78b0a61   Kawai, Hidehiro   coredump masking:...
1228
1229
1230
1231
  	dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags);
  	kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags,
  	       dump_ok ? "yes" : "no");
  	return dump_ok;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
  }
  
  /* 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;
  }
  
  /* #define DEBUG */
e6c1baa9b   Al Viro   convert the rest ...
1255
  static int writenote(struct memelfnote *men, struct coredump_params *cprm)
05f47fda9   Daisuke HATAYAMA   coredump: unify d...
1256
1257
  {
  	struct elf_note en;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1258
1259
1260
  	en.n_namesz = strlen(men->name) + 1;
  	en.n_descsz = men->datasz;
  	en.n_type = men->type;
e6c1baa9b   Al Viro   convert the rest ...
1261
  	return dump_emit(cprm, &en, sizeof(en)) &&
22a8cb824   Al Viro   new helper: dump_...
1262
1263
  		dump_emit(cprm, men->name, en.n_namesz) && dump_align(cprm, 4) &&
  		dump_emit(cprm, men->data, men->datasz) && dump_align(cprm, 4);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1264
  }
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1265

6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
  static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs)
  {
  	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;
  	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
  
  	elf->e_type = ET_CORE;
  	elf->e_machine = ELF_ARCH;
  	elf->e_version = EV_CURRENT;
  	elf->e_entry = 0;
  	elf->e_phoff = sizeof(struct elfhdr);
  	elf->e_shoff = 0;
  	elf->e_flags = ELF_FDPIC_CORE_EFLAGS;
  	elf->e_ehsize = sizeof(struct elfhdr);
  	elf->e_phentsize = sizeof(struct elf_phdr);
  	elf->e_phnum = segs;
  	elf->e_shentsize = 0;
  	elf->e_shnum = 0;
  	elf->e_shstrndx = 0;
  	return;
  }
  
  static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
  {
  	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 inline 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;
  }
  
  /*
   * fill up all the fields in prstatus from the given task struct, except
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
1316
   * registers which need to be filled up separately.
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1317
1318
1319
1320
1321
1322
1323
   */
  static void fill_prstatus(struct elf_prstatus *prstatus,
  			  struct task_struct *p, long signr)
  {
  	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...
1324
1325
1326
  	rcu_read_lock();
  	prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent));
  	rcu_read_unlock();
b488893a3   Pavel Emelyanov   pid namespaces: c...
1327
  	prstatus->pr_pid = task_pid_vnr(p);
b488893a3   Pavel Emelyanov   pid namespaces: c...
1328
1329
  	prstatus->pr_pgrp = task_pgrp_vnr(p);
  	prstatus->pr_sid = task_session_vnr(p);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1330
  	if (thread_group_leader(p)) {
2515ddc6d   Paul Mundt   binfmt_elf_fdpic:...
1331
  		struct task_cputime cputime;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1332
  		/*
2515ddc6d   Paul Mundt   binfmt_elf_fdpic:...
1333
1334
  		 * This is the record for the group leader.  It shows the
  		 * group-wide total, not its individual thread total.
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1335
  		 */
2515ddc6d   Paul Mundt   binfmt_elf_fdpic:...
1336
1337
1338
  		thread_group_cputime(p, &cputime);
  		cputime_to_timeval(cputime.utime, &prstatus->pr_utime);
  		cputime_to_timeval(cputime.stime, &prstatus->pr_stime);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1339
  	} else {
6fac4829c   Frederic Weisbecker   cputime: Use acce...
1340
1341
1342
1343
1344
  		cputime_t utime, stime;
  
  		task_cputime(p, &utime, &stime);
  		cputime_to_timeval(utime, &prstatus->pr_utime);
  		cputime_to_timeval(stime, &prstatus->pr_stime);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
  	}
  	cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime);
  	cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime);
  
  	prstatus->pr_exec_fdpic_loadmap = p->mm->context.exec_fdpic_loadmap;
  	prstatus->pr_interp_fdpic_loadmap = p->mm->context.interp_fdpic_loadmap;
  }
  
  static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
  		       struct mm_struct *mm)
  {
c69e8d9c0   David Howells   CRED: Use RCU to ...
1356
  	const struct cred *cred;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
  	unsigned int i, len;
  
  	/* 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...
1372
1373
1374
  	rcu_read_lock();
  	psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent));
  	rcu_read_unlock();
b488893a3   Pavel Emelyanov   pid namespaces: c...
1375
  	psinfo->pr_pid = task_pid_vnr(p);
b488893a3   Pavel Emelyanov   pid namespaces: c...
1376
1377
  	psinfo->pr_pgrp = task_pgrp_vnr(p);
  	psinfo->pr_sid = task_session_vnr(p);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1378
1379
1380
1381
1382
1383
1384
  
  	i = p->state ? ffz(~p->state) + 1 : 0;
  	psinfo->pr_state = i;
  	psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];
  	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 ...
1385
1386
  	rcu_read_lock();
  	cred = __task_cred(p);
ebc887b27   Eric W. Biederman   userns: Convert b...
1387
1388
  	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 ...
1389
  	rcu_read_unlock();
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
  
  	return 0;
  }
  
  /* 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...
1403
  	elf_fpxregset_t xfpu;		/* ELF_CORE_XFPREG_TYPE */
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
  #endif
  	struct memelfnote notes[3];
  	int num_notes;
  };
  
  /*
   * In order to add the specific thread information for the elf file format,
   * we need to keep a linked list of every thread's pr_status and then create
   * a single section for them in the final core file.
   */
  static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
  {
  	struct task_struct *p = t->thread;
  	int sz = 0;
  
  	t->num_notes = 0;
  
  	fill_prstatus(&t->prstatus, p, signr);
  	elf_core_copy_task_regs(p, &t->prstatus.pr_reg);
  
  	fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
  		  &t->prstatus);
  	t->num_notes++;
  	sz += notesize(&t->notes[0]);
  
  	t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu);
  	if (t->prstatus.pr_fpvalid) {
  		fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu),
  			  &t->fpu);
  		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...
1439
1440
  		fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE,
  			  sizeof(t->xfpu), &t->xfpu);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1441
1442
1443
1444
1445
1446
  		t->num_notes++;
  		sz += notesize(&t->notes[2]);
  	}
  #endif
  	return sz;
  }
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  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;
  }
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1462
1463
1464
  /*
   * dump the segments for an MMU process
   */
e6c1baa9b   Al Viro   convert the rest ...
1465
  static bool elf_fdpic_dump_segments(struct coredump_params *cprm)
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1466
1467
1468
1469
1470
  {
  	struct vm_area_struct *vma;
  
  	for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
  		unsigned long addr;
e6c1baa9b   Al Viro   convert the rest ...
1471
  		if (!maydump(vma, cprm->mm_flags))
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1472
  			continue;
e6c1baa9b   Al Viro   convert the rest ...
1473
  #ifdef CONFIG_MMU
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
1474
1475
  		for (addr = vma->vm_start; addr < vma->vm_end;
  							addr += PAGE_SIZE) {
e6c1baa9b   Al Viro   convert the rest ...
1476
  			bool res;
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
1477
1478
1479
  			struct page *page = get_dump_page(addr);
  			if (page) {
  				void *kaddr = kmap(page);
e6c1baa9b   Al Viro   convert the rest ...
1480
  				res = dump_emit(cprm, kaddr, PAGE_SIZE);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1481
1482
  				kunmap(page);
  				page_cache_release(page);
e6c1baa9b   Al Viro   convert the rest ...
1483
  			} else {
9b56d5438   Al Viro   dump_skip(): dump...
1484
  				res = dump_skip(cprm, PAGE_SIZE);
e6c1baa9b   Al Viro   convert the rest ...
1485
1486
1487
  			}
  			if (!res)
  				return false;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1488
  		}
e6c1baa9b   Al Viro   convert the rest ...
1489
1490
  #else
  		if (!dump_emit(cprm, (void *) vma->vm_start,
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1491
  				vma->vm_end - vma->vm_start))
e6c1baa9b   Al Viro   convert the rest ...
1492
1493
  			return false;
  #endif
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1494
  	}
e6c1baa9b   Al Viro   convert the rest ...
1495
  	return true;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1496
  }
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1497

8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1498
1499
1500
1501
  static size_t elf_core_vma_data_size(unsigned long mm_flags)
  {
  	struct vm_area_struct *vma;
  	size_t size = 0;
47568d4c5   David Howells   FDPIC: For-loop i...
1502
  	for (vma = current->mm->mmap; vma; vma = vma->vm_next)
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1503
1504
1505
1506
  		if (maydump(vma, mm_flags))
  			size += vma->vm_end - vma->vm_start;
  	return size;
  }
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1507
1508
1509
1510
1511
1512
1513
  /*
   * 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...
1514
  static int elf_fdpic_core_dump(struct coredump_params *cprm)
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1515
1516
1517
1518
1519
  {
  #define	NUM_NOTES	6
  	int has_dumped = 0;
  	mm_segment_t fs;
  	int segs;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1520
1521
1522
  	int i;
  	struct vm_area_struct *vma;
  	struct elfhdr *elf = NULL;
9b56d5438   Al Viro   dump_skip(): dump...
1523
  	loff_t offset = 0, dataoff;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1524
1525
1526
1527
  	int numnote;
  	struct memelfnote *notes = NULL;
  	struct elf_prstatus *prstatus = NULL;	/* NT_PRSTATUS */
  	struct elf_prpsinfo *psinfo = NULL;	/* NT_PRPSINFO */
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1528
1529
1530
1531
1532
1533
1534
   	LIST_HEAD(thread_list);
   	struct list_head *t;
  	elf_fpregset_t *fpu = NULL;
  #ifdef ELF_CORE_COPY_XFPREGS
  	elf_fpxregset_t *xfpu = NULL;
  #endif
  	int thread_status_size = 0;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1535
  	elf_addr_t *auxv;
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
1536
  	struct elf_phdr *phdr4note = NULL;
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1537
1538
1539
  	struct elf_shdr *shdr4extnum = NULL;
  	Elf_Half e_phnum;
  	elf_addr_t e_shoff;
afabada95   Al Viro   elf{,_fdpic} core...
1540
1541
  	struct core_thread *ct;
  	struct elf_thread_status *tmp;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
  
  	/*
  	 * We no longer stop all VM operations.
  	 *
  	 * 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.
  	 *
  	 * Only ptrace can touch these memory addresses, but it doesn't change
  	 * the map_count or the pages allocated. So no possibility of crashing
  	 * 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)
  		goto cleanup;
  	prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL);
  	if (!prstatus)
  		goto cleanup;
  	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
  	if (!psinfo)
  		goto cleanup;
  	notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL);
  	if (!notes)
  		goto cleanup;
  	fpu = kmalloc(sizeof(*fpu), GFP_KERNEL);
  	if (!fpu)
  		goto cleanup;
  #ifdef ELF_CORE_COPY_XFPREGS
  	xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL);
  	if (!xfpu)
  		goto cleanup;
  #endif
afabada95   Al Viro   elf{,_fdpic} core...
1576
1577
1578
1579
1580
  	for (ct = current->mm->core_state->dumper.next;
  					ct; ct = ct->next) {
  		tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
  		if (!tmp)
  			goto cleanup;
182c515fd   Oleg Nesterov   coredump: elf_fdp...
1581

afabada95   Al Viro   elf{,_fdpic} core...
1582
1583
1584
  		tmp->thread = ct->task;
  		list_add(&tmp->list, &thread_list);
  	}
182c515fd   Oleg Nesterov   coredump: elf_fdp...
1585

afabada95   Al Viro   elf{,_fdpic} core...
1586
1587
1588
  	list_for_each(t, &thread_list) {
  		struct elf_thread_status *tmp;
  		int sz;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1589

afabada95   Al Viro   elf{,_fdpic} core...
1590
1591
1592
  		tmp = list_entry(t, struct elf_thread_status, list);
  		sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp);
  		thread_status_size += sz;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1593
1594
1595
  	}
  
  	/* now collect the dump for the current */
5ab1c309b   Denys Vlasenko   coredump: pass si...
1596
  	fill_prstatus(prstatus, current, cprm->siginfo->si_signo);
f6151dfea   Masami Hiramatsu   mm: introduce cor...
1597
  	elf_core_copy_regs(&prstatus->pr_reg, cprm->regs);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1598

6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1599
  	segs = current->mm->map_count;
1fcccbac8   Daisuke HATAYAMA   elf coredump: rep...
1600
  	segs += elf_core_extra_phdrs();
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1601

8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1602
1603
1604
1605
1606
1607
1608
  	/* 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;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1609
  	/* Set up header */
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1610
  	fill_elf_fdpic_header(elf, e_phnum);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1611
1612
  
  	has_dumped = 1;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
  	/*
  	 * Set up the notes in similar form to SVR4 core dumps made
  	 * with info from their /proc.
  	 */
  
  	fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus);
  	fill_psinfo(psinfo, current->group_leader, current->mm);
  	fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
  
  	numnote = 2;
  
  	auxv = (elf_addr_t *) current->mm->saved_auxv;
  
  	i = 0;
  	do
  		i += 2;
  	while (auxv[i - 2] != AT_NULL);
  	fill_note(&notes[numnote++], "CORE", NT_AUXV,
  		  i * sizeof(elf_addr_t), auxv);
  
    	/* Try to dump the FPU. */
  	if ((prstatus->pr_fpvalid =
f6151dfea   Masami Hiramatsu   mm: introduce cor...
1635
  	     elf_core_copy_task_fpregs(current, cprm->regs, fpu)))
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1636
1637
1638
1639
1640
  		fill_note(notes + numnote++,
  			  "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
  #ifdef ELF_CORE_COPY_XFPREGS
  	if (elf_core_copy_task_xfpregs(current, xfpu))
  		fill_note(notes + numnote++,
5b20cd80b   Mark Nelson   x86: replace NT_P...
1641
  			  "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1642
1643
1644
1645
  #endif
  
  	fs = get_fs();
  	set_fs(KERNEL_DS);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1646
  	offset += sizeof(*elf);				/* Elf header */
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1647
  	offset += segs * sizeof(struct elf_phdr);	/* Program headers */
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1648
1649
1650
  
  	/* Write notes phdr entry */
  	{
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1651
1652
1653
1654
1655
1656
  		int sz = 0;
  
  		for (i = 0; i < numnote; i++)
  			sz += notesize(notes + i);
  
  		sz += thread_status_size;
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
1657
1658
  		phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
  		if (!phdr4note)
088e7af73   Daisuke HATAYAMA   coredump: move du...
1659
  			goto end_coredump;
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
1660
1661
1662
  
  		fill_elf_note_phdr(phdr4note, sz, offset);
  		offset += sz;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1663
1664
1665
1666
  	}
  
  	/* Page-align dumped data */
  	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
30736a4d4   Masami Hiramatsu   coredump: pass mm...
1667
  	offset += elf_core_vma_data_size(cprm->mm_flags);
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
  	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;
e6c1baa9b   Al Viro   convert the rest ...
1679
  	if (!dump_emit(cprm, elf, sizeof(*elf)))
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
1680
  		goto end_coredump;
e6c1baa9b   Al Viro   convert the rest ...
1681
  	if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
1682
  		goto end_coredump;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1683
  	/* write program headers for segments dump */
8feae1311   David Howells   NOMMU: Make VMAs ...
1684
  	for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1685
1686
  		struct elf_phdr phdr;
  		size_t sz;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1687
1688
1689
1690
1691
1692
  		sz = vma->vm_end - vma->vm_start;
  
  		phdr.p_type = PT_LOAD;
  		phdr.p_offset = offset;
  		phdr.p_vaddr = vma->vm_start;
  		phdr.p_paddr = 0;
30736a4d4   Masami Hiramatsu   coredump: pass mm...
1693
  		phdr.p_filesz = maydump(vma, cprm->mm_flags) ? sz : 0;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1694
1695
1696
1697
1698
1699
1700
1701
  		phdr.p_memsz = sz;
  		offset += phdr.p_filesz;
  		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
  		if (vma->vm_flags & VM_WRITE)
  			phdr.p_flags |= PF_W;
  		if (vma->vm_flags & VM_EXEC)
  			phdr.p_flags |= PF_X;
  		phdr.p_align = ELF_EXEC_PAGESIZE;
e6c1baa9b   Al Viro   convert the rest ...
1702
  		if (!dump_emit(cprm, &phdr, sizeof(phdr)))
088e7af73   Daisuke HATAYAMA   coredump: move du...
1703
  			goto end_coredump;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1704
  	}
506f21c55   Al Viro   switch elf_core_w...
1705
  	if (!elf_core_write_extra_phdrs(cprm, offset))
1fcccbac8   Daisuke HATAYAMA   elf coredump: rep...
1706
  		goto end_coredump;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1707
1708
1709
  
   	/* write out the notes section */
  	for (i = 0; i < numnote; i++)
e6c1baa9b   Al Viro   convert the rest ...
1710
  		if (!writenote(notes + i, cprm))
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1711
1712
1713
1714
1715
1716
1717
1718
  			goto end_coredump;
  
  	/* write out the thread status notes section */
  	list_for_each(t, &thread_list) {
  		struct elf_thread_status *tmp =
  				list_entry(t, struct elf_thread_status, list);
  
  		for (i = 0; i < tmp->num_notes; i++)
e6c1baa9b   Al Viro   convert the rest ...
1719
  			if (!writenote(&tmp->notes[i], cprm))
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1720
1721
  				goto end_coredump;
  	}
9b56d5438   Al Viro   dump_skip(): dump...
1722
  	if (!dump_skip(cprm, dataoff - cprm->written))
f3e8fccd0   Hugh Dickins   mm: add get_dump_...
1723
  		goto end_coredump;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1724

e6c1baa9b   Al Viro   convert the rest ...
1725
  	if (!elf_fdpic_dump_segments(cprm))
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1726
  		goto end_coredump;
aa3e7eaf0   Al Viro   switch elf_core_w...
1727
  	if (!elf_core_write_extra_data(cprm))
1fcccbac8   Daisuke HATAYAMA   elf coredump: rep...
1728
  		goto end_coredump;
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1729

8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1730
  	if (e_phnum == PN_XNUM) {
e6c1baa9b   Al Viro   convert the rest ...
1731
  		if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
8d9032bbe   Daisuke HATAYAMA   elf coredump: add...
1732
1733
  			goto end_coredump;
  	}
2f48912d1   Daisuke HATAYAMA   binfmt_elf_fdpic:...
1734
  	if (cprm->file->f_pos != offset) {
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1735
1736
1737
1738
  		/* Sanity check */
  		printk(KERN_WARNING
  		       "elf_core_dump: file->f_pos (%lld) != offset (%lld)
  ",
2f48912d1   Daisuke HATAYAMA   binfmt_elf_fdpic:...
1739
  		       cprm->file->f_pos, offset);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
  	}
  
  end_coredump:
  	set_fs(fs);
  
  cleanup:
  	while (!list_empty(&thread_list)) {
  		struct list_head *tmp = thread_list.next;
  		list_del(tmp);
  		kfree(list_entry(tmp, struct elf_thread_status, list));
  	}
93eb211e6   Daisuke HATAYAMA   elf coredump: mak...
1751
  	kfree(phdr4note);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1752
1753
1754
1755
1756
  	kfree(elf);
  	kfree(prstatus);
  	kfree(psinfo);
  	kfree(notes);
  	kfree(fpu);
bcb65a797   Davidlohr Bueso   FDPIC: Fix memory...
1757
  	kfree(shdr4extnum);
6d8c4e3b0   David Howells   [PATCH] FDPIC: Ad...
1758
1759
1760
1761
1762
1763
  #ifdef ELF_CORE_COPY_XFPREGS
  	kfree(xfpu);
  #endif
  	return has_dumped;
  #undef NUM_NOTES
  }
698ba7b5a   Christoph Hellwig   elf: kill USE_ELF...
1764
  #endif		/* CONFIG_ELF_CORE */