Blame view

fs/exec.c 43.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   *  linux/fs/exec.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
  
  /*
   * #!-checking implemented by tytso.
   */
  /*
   * Demand-loading implemented 01.12.91 - no need to read anything but
   * the header into memory. The inode of the executable is put into
   * "current->executable", and page faults do the actual loading. Clean.
   *
   * Once more I can proudly say that linux stood up to being changed: it
   * was less than 2 hours work to get demand-loading completely implemented.
   *
   * Demand loading changed July 1993 by Eric Youngdale.   Use mmap instead,
   * current->executable is only used by the procfs.  This allows a dispatch
   * table to check for several different types  of binary formats.  We keep
   * trying until we recognize the file or we run out of supported binary
   * formats. 
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include <linux/slab.h>
  #include <linux/file.h>
9f3acc314   Al Viro   [PATCH] split lin...
26
  #include <linux/fdtable.h>
ba92a43db   Hugh Dickins   exec: remove some...
27
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
  #include <linux/stat.h>
  #include <linux/fcntl.h>
  #include <linux/smp_lock.h>
ba92a43db   Hugh Dickins   exec: remove some...
31
  #include <linux/swap.h>
74aadce98   Neil Horman   core_pattern: all...
32
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include <linux/init.h>
ca5b172bd   Hugh Dickins   exec: include pag...
34
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
  #include <linux/highmem.h>
  #include <linux/spinlock.h>
  #include <linux/key.h>
  #include <linux/personality.h>
  #include <linux/binfmts.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #include <linux/utsname.h>
84d737866   Sukadev Bhattiprolu   [PATCH] add child...
41
  #include <linux/pid_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  #include <linux/module.h>
  #include <linux/namei.h>
  #include <linux/proc_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  #include <linux/mount.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
8f0ab5147   Jay Lan   [PATCH] csa: conv...
48
  #include <linux/tsacct_kern.h>
9f46080c4   Matt Helsley   [PATCH] Process E...
49
  #include <linux/cn_proc.h>
473ae30bc   Al Viro   [PATCH] execve ar...
50
  #include <linux/audit.h>
6341c393f   Roland McGrath   tracehook: exec
51
  #include <linux/tracehook.h>
5f4123be3   Johannes Berg   remove CONFIG_KMO...
52
  #include <linux/kmod.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
  
  #include <asm/uaccess.h>
  #include <asm/mmu_context.h>
b6a2fea39   Ollie Wild   mm: variable leng...
56
  #include <asm/tlb.h>
a6f76f23d   David Howells   CRED: Make execve...
57
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

702773b16   David Woodhouse   Include <asm/a.ou...
59
60
61
62
  #ifdef __alpha__
  /* for /sbin/loader handling in search_binary_handler() */
  #include <linux/a.out.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  int core_uses_pid;
71ce92f3f   Dan Aloni   make sysctl/kerne...
64
  char core_pattern[CORENAME_MAX_SIZE] = "core";
d6e711448   Alan Cox   [PATCH] setuid co...
65
  int suid_dumpable = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  /* The maximal length of core_pattern is also specified in sysctl.c */
e4dc1b14d   Alexey Dobriyan   Use list_head in ...
67
  static LIST_HEAD(formats);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
  static DEFINE_RWLOCK(binfmt_lock);
  
  int register_binfmt(struct linux_binfmt * fmt)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	if (!fmt)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  	write_lock(&binfmt_lock);
e4dc1b14d   Alexey Dobriyan   Use list_head in ...
75
  	list_add(&fmt->lh, &formats);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
  	write_unlock(&binfmt_lock);
  	return 0;	
  }
  
  EXPORT_SYMBOL(register_binfmt);
f6b450d48   Alexey Dobriyan   Make unregister_b...
81
  void unregister_binfmt(struct linux_binfmt * fmt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  	write_lock(&binfmt_lock);
e4dc1b14d   Alexey Dobriyan   Use list_head in ...
84
  	list_del(&fmt->lh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	write_unlock(&binfmt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  }
  
  EXPORT_SYMBOL(unregister_binfmt);
  
  static inline void put_binfmt(struct linux_binfmt * fmt)
  {
  	module_put(fmt->module);
  }
  
  /*
   * Note that a shared library must be both readable and executable due to
   * security reasons.
   *
   * Also note that we take the address to load from from the file itself.
   */
  asmlinkage long sys_uselib(const char __user * library)
  {
964bd1836   Al Viro   [PATCH] get rid o...
103
  	struct file *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	struct nameidata nd;
964bd1836   Al Viro   [PATCH] get rid o...
105
106
107
108
109
110
111
112
113
  	char *tmp = getname(library);
  	int error = PTR_ERR(tmp);
  
  	if (!IS_ERR(tmp)) {
  		error = path_lookup_open(AT_FDCWD, tmp,
  					 LOOKUP_FOLLOW, &nd,
  					 FMODE_READ|FMODE_EXEC);
  		putname(tmp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
  	if (error)
  		goto out;
  
  	error = -EINVAL;
4ac913785   Jan Blunck   Embed a struct pa...
118
  	if (!S_ISREG(nd.path.dentry->d_inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  		goto exit;
30524472c   Al Viro   [PATCH] take noex...
120
121
122
  	error = -EACCES;
  	if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
  		goto exit;
b77b0646e   Al Viro   [PATCH] pass MAY_...
123
  	error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  	if (error)
  		goto exit;
abe8be3ab   Andi Kleen   Allow executables...
126
  	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto out;
  
  	error = -ENOEXEC;
  	if(file->f_op) {
  		struct linux_binfmt * fmt;
  
  		read_lock(&binfmt_lock);
e4dc1b14d   Alexey Dobriyan   Use list_head in ...
136
  		list_for_each_entry(fmt, &formats, lh) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  			if (!fmt->load_shlib)
  				continue;
  			if (!try_module_get(fmt->module))
  				continue;
  			read_unlock(&binfmt_lock);
  			error = fmt->load_shlib(file);
  			read_lock(&binfmt_lock);
  			put_binfmt(fmt);
  			if (error != -ENOEXEC)
  				break;
  		}
  		read_unlock(&binfmt_lock);
  	}
  	fput(file);
  out:
    	return error;
  exit:
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
154
  	release_open_intent(&nd);
1d957f9bf   Jan Blunck   Introduce path_put()
155
  	path_put(&nd.path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  	goto out;
  }
b6a2fea39   Ollie Wild   mm: variable leng...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  #ifdef CONFIG_MMU
  
  static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
  		int write)
  {
  	struct page *page;
  	int ret;
  
  #ifdef CONFIG_STACK_GROWSUP
  	if (write) {
  		ret = expand_stack_downwards(bprm->vma, pos);
  		if (ret < 0)
  			return NULL;
  	}
  #endif
  	ret = get_user_pages(current, bprm->mm, pos,
  			1, write, 1, &page, NULL);
  	if (ret <= 0)
  		return NULL;
  
  	if (write) {
b6a2fea39   Ollie Wild   mm: variable leng...
179
  		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
a64e715fc   Linus Torvalds   Allow ARG_MAX exe...
180
181
182
183
184
185
186
187
  		struct rlimit *rlim;
  
  		/*
  		 * We've historically supported up to 32 pages (ARG_MAX)
  		 * of argument strings even with small stacks
  		 */
  		if (size <= ARG_MAX)
  			return page;
b6a2fea39   Ollie Wild   mm: variable leng...
188
189
190
191
192
193
194
195
  
  		/*
  		 * Limit to 1/4-th the stack size for the argv+env strings.
  		 * This ensures that:
  		 *  - the remaining binfmt code will not run out of stack space,
  		 *  - the program will have a reasonable amount of stack left
  		 *    to work from.
  		 */
a64e715fc   Linus Torvalds   Allow ARG_MAX exe...
196
  		rlim = current->signal->rlim;
b6a2fea39   Ollie Wild   mm: variable leng...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  		if (size > rlim[RLIMIT_STACK].rlim_cur / 4) {
  			put_page(page);
  			return NULL;
  		}
  	}
  
  	return page;
  }
  
  static void put_arg_page(struct page *page)
  {
  	put_page(page);
  }
  
  static void free_arg_page(struct linux_binprm *bprm, int i)
  {
  }
  
  static void free_arg_pages(struct linux_binprm *bprm)
  {
  }
  
  static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
  		struct page *page)
  {
  	flush_cache_page(bprm->vma, pos, page_to_pfn(page));
  }
  
  static int __bprm_mm_init(struct linux_binprm *bprm)
  {
  	int err = -ENOMEM;
  	struct vm_area_struct *vma = NULL;
  	struct mm_struct *mm = bprm->mm;
  
  	bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
  	if (!vma)
  		goto err;
  
  	down_write(&mm->mmap_sem);
  	vma->vm_mm = mm;
  
  	/*
  	 * Place the stack at the largest stack address the architecture
  	 * supports. Later, we'll move this to an appropriate place. We don't
  	 * use STACK_TOP because that can depend on attributes which aren't
  	 * configured yet.
  	 */
  	vma->vm_end = STACK_TOP_MAX;
  	vma->vm_start = vma->vm_end - PAGE_SIZE;
  
  	vma->vm_flags = VM_STACK_FLAGS;
3ed75eb8f   Coly Li   setup vma->vm_pag...
248
  	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
b6a2fea39   Ollie Wild   mm: variable leng...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  	err = insert_vm_struct(mm, vma);
  	if (err) {
  		up_write(&mm->mmap_sem);
  		goto err;
  	}
  
  	mm->stack_vm = mm->total_vm = 1;
  	up_write(&mm->mmap_sem);
  
  	bprm->p = vma->vm_end - sizeof(void *);
  
  	return 0;
  
  err:
  	if (vma) {
  		bprm->vma = NULL;
  		kmem_cache_free(vm_area_cachep, vma);
  	}
  
  	return err;
  }
  
  static bool valid_arg_len(struct linux_binprm *bprm, long len)
  {
  	return len <= MAX_ARG_STRLEN;
  }
  
  #else
  
  static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
  		int write)
  {
  	struct page *page;
  
  	page = bprm->page[pos / PAGE_SIZE];
  	if (!page && write) {
  		page = alloc_page(GFP_HIGHUSER|__GFP_ZERO);
  		if (!page)
  			return NULL;
  		bprm->page[pos / PAGE_SIZE] = page;
  	}
  
  	return page;
  }
  
  static void put_arg_page(struct page *page)
  {
  }
  
  static void free_arg_page(struct linux_binprm *bprm, int i)
  {
  	if (bprm->page[i]) {
  		__free_page(bprm->page[i]);
  		bprm->page[i] = NULL;
  	}
  }
  
  static void free_arg_pages(struct linux_binprm *bprm)
  {
  	int i;
  
  	for (i = 0; i < MAX_ARG_PAGES; i++)
  		free_arg_page(bprm, i);
  }
  
  static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
  		struct page *page)
  {
  }
  
  static int __bprm_mm_init(struct linux_binprm *bprm)
  {
  	bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *);
  	return 0;
  }
  
  static bool valid_arg_len(struct linux_binprm *bprm, long len)
  {
  	return len <= bprm->p;
  }
  
  #endif /* CONFIG_MMU */
  
  /*
   * Create a new mm_struct and populate it with a temporary stack
   * vm_area_struct.  We don't have enough context at this point to set the stack
   * flags, permissions, and offset, so we use temporary values.  We'll update
   * them later in setup_arg_pages().
   */
  int bprm_mm_init(struct linux_binprm *bprm)
  {
  	int err;
  	struct mm_struct *mm = NULL;
  
  	bprm->mm = mm = mm_alloc();
  	err = -ENOMEM;
  	if (!mm)
  		goto err;
  
  	err = init_new_context(current, mm);
  	if (err)
  		goto err;
  
  	err = __bprm_mm_init(bprm);
  	if (err)
  		goto err;
  
  	return 0;
  
  err:
  	if (mm) {
  		bprm->mm = NULL;
  		mmdrop(mm);
  	}
  
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  /*
   * count() counts the number of strings in array ARGV.
   */
  static int count(char __user * __user * argv, int max)
  {
  	int i = 0;
  
  	if (argv != NULL) {
  		for (;;) {
  			char __user * p;
  
  			if (get_user(p, argv))
  				return -EFAULT;
  			if (!p)
  				break;
  			argv++;
362e6663e   Jason Baron   exec.c, compat.c:...
382
  			if (i++ >= max)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
386
387
388
389
390
  				return -E2BIG;
  			cond_resched();
  		}
  	}
  	return i;
  }
  
  /*
b6a2fea39   Ollie Wild   mm: variable leng...
391
392
393
   * 'copy_strings()' copies argument/environment strings from the old
   * processes's memory to the new process's stack.  The call to get_user_pages()
   * ensures the destination page is created and not swapped out.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
   */
75c96f858   Adrian Bunk   [PATCH] make some...
395
396
  static int copy_strings(int argc, char __user * __user * argv,
  			struct linux_binprm *bprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
  {
  	struct page *kmapped_page = NULL;
  	char *kaddr = NULL;
b6a2fea39   Ollie Wild   mm: variable leng...
400
  	unsigned long kpos = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
404
405
406
407
408
  	int ret;
  
  	while (argc-- > 0) {
  		char __user *str;
  		int len;
  		unsigned long pos;
  
  		if (get_user(str, argv+argc) ||
b6a2fea39   Ollie Wild   mm: variable leng...
409
  				!(len = strnlen_user(str, MAX_ARG_STRLEN))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
  			ret = -EFAULT;
  			goto out;
  		}
b6a2fea39   Ollie Wild   mm: variable leng...
413
  		if (!valid_arg_len(bprm, len)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
  			ret = -E2BIG;
  			goto out;
  		}
b6a2fea39   Ollie Wild   mm: variable leng...
417
  		/* We're going to work our way backwords. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  		pos = bprm->p;
b6a2fea39   Ollie Wild   mm: variable leng...
419
420
  		str += len;
  		bprm->p -= len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
  
  		while (len > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  			int offset, bytes_to_copy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  
  			offset = pos % PAGE_SIZE;
b6a2fea39   Ollie Wild   mm: variable leng...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  			if (offset == 0)
  				offset = PAGE_SIZE;
  
  			bytes_to_copy = offset;
  			if (bytes_to_copy > len)
  				bytes_to_copy = len;
  
  			offset -= bytes_to_copy;
  			pos -= bytes_to_copy;
  			str -= bytes_to_copy;
  			len -= bytes_to_copy;
  
  			if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
  				struct page *page;
  
  				page = get_arg_page(bprm, pos, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  				if (!page) {
b6a2fea39   Ollie Wild   mm: variable leng...
443
  					ret = -E2BIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  					goto out;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446

b6a2fea39   Ollie Wild   mm: variable leng...
447
448
  				if (kmapped_page) {
  					flush_kernel_dcache_page(kmapped_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  					kunmap(kmapped_page);
b6a2fea39   Ollie Wild   mm: variable leng...
450
451
  					put_arg_page(kmapped_page);
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
  				kmapped_page = page;
  				kaddr = kmap(kmapped_page);
b6a2fea39   Ollie Wild   mm: variable leng...
454
455
  				kpos = pos & PAGE_MASK;
  				flush_arg_page(bprm, kpos, kmapped_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  			}
b6a2fea39   Ollie Wild   mm: variable leng...
457
  			if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
  				ret = -EFAULT;
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
  		}
  	}
  	ret = 0;
  out:
b6a2fea39   Ollie Wild   mm: variable leng...
465
466
  	if (kmapped_page) {
  		flush_kernel_dcache_page(kmapped_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  		kunmap(kmapped_page);
b6a2fea39   Ollie Wild   mm: variable leng...
468
469
  		put_arg_page(kmapped_page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  	return ret;
  }
  
  /*
   * Like copy_strings, but get argv and its values from kernel memory.
   */
  int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
  {
  	int r;
  	mm_segment_t oldfs = get_fs();
  	set_fs(KERNEL_DS);
  	r = copy_strings(argc, (char __user * __user *)argv, bprm);
  	set_fs(oldfs);
  	return r;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
  EXPORT_SYMBOL(copy_strings_kernel);
  
  #ifdef CONFIG_MMU
b6a2fea39   Ollie Wild   mm: variable leng...
488

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  /*
b6a2fea39   Ollie Wild   mm: variable leng...
490
491
492
   * During bprm_mm_init(), we create a temporary stack at STACK_TOP_MAX.  Once
   * the binfmt code determines where the new stack should reside, we shift it to
   * its final location.  The process proceeds as follows:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
   *
b6a2fea39   Ollie Wild   mm: variable leng...
494
495
496
497
498
499
   * 1) Use shift to calculate the new vma endpoints.
   * 2) Extend vma to cover both the old and new ranges.  This ensures the
   *    arguments passed to subsequent functions are consistent.
   * 3) Move vma's page tables to the new range.
   * 4) Free up any cleared pgd range.
   * 5) Shrink the vma to cover only the new range.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
   */
b6a2fea39   Ollie Wild   mm: variable leng...
501
  static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
  {
  	struct mm_struct *mm = vma->vm_mm;
b6a2fea39   Ollie Wild   mm: variable leng...
504
505
506
507
508
509
  	unsigned long old_start = vma->vm_start;
  	unsigned long old_end = vma->vm_end;
  	unsigned long length = old_end - old_start;
  	unsigned long new_start = old_start - shift;
  	unsigned long new_end = old_end - shift;
  	struct mmu_gather *tlb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510

b6a2fea39   Ollie Wild   mm: variable leng...
511
  	BUG_ON(new_start > new_end);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512

b6a2fea39   Ollie Wild   mm: variable leng...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  	/*
  	 * ensure there are no vmas between where we want to go
  	 * and where we are
  	 */
  	if (vma != find_vma(mm, new_start))
  		return -EFAULT;
  
  	/*
  	 * cover the whole range: [new_start, old_end)
  	 */
  	vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL);
  
  	/*
  	 * move the page tables downwards, on failure we rely on
  	 * process cleanup to remove whatever mess we made.
  	 */
  	if (length != move_page_tables(vma, old_start,
  				       vma, new_start, length))
  		return -ENOMEM;
  
  	lru_add_drain();
  	tlb = tlb_gather_mmu(mm, 0);
  	if (new_end > old_start) {
  		/*
  		 * when the old and new regions overlap clear from new_end.
  		 */
42b777281   Jan Beulich   mm: remove double...
539
  		free_pgd_range(tlb, new_end, old_end, new_end,
b6a2fea39   Ollie Wild   mm: variable leng...
540
541
542
543
544
545
546
547
  			vma->vm_next ? vma->vm_next->vm_start : 0);
  	} else {
  		/*
  		 * otherwise, clean from old_start; this is done to not touch
  		 * the address space in [new_end, old_start) some architectures
  		 * have constraints on va-space that make this illegal (IA64) -
  		 * for the others its just a little faster.
  		 */
42b777281   Jan Beulich   mm: remove double...
548
  		free_pgd_range(tlb, old_start, old_end, new_end,
b6a2fea39   Ollie Wild   mm: variable leng...
549
  			vma->vm_next ? vma->vm_next->vm_start : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	}
b6a2fea39   Ollie Wild   mm: variable leng...
551
552
553
554
555
556
557
558
  	tlb_finish_mmu(tlb, new_end, old_end);
  
  	/*
  	 * shrink the vma to just the new range.
  	 */
  	vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL);
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
  }
  
  #define EXTRA_STACK_VM_PAGES	20	/* random */
b6a2fea39   Ollie Wild   mm: variable leng...
562
563
564
565
  /*
   * Finalizes the stack vm_area_struct. The flags and permissions are updated,
   * the stack is optionally relocated, and some extra space is added.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
  int setup_arg_pages(struct linux_binprm *bprm,
  		    unsigned long stack_top,
  		    int executable_stack)
  {
b6a2fea39   Ollie Wild   mm: variable leng...
570
571
  	unsigned long ret;
  	unsigned long stack_shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  	struct mm_struct *mm = current->mm;
b6a2fea39   Ollie Wild   mm: variable leng...
573
574
575
576
  	struct vm_area_struct *vma = bprm->vma;
  	struct vm_area_struct *prev = NULL;
  	unsigned long vm_flags;
  	unsigned long stack_base;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  
  #ifdef CONFIG_STACK_GROWSUP
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
582
  	/* Limit stack size to 1GB */
  	stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max;
  	if (stack_base > (1 << 30))
  		stack_base = 1 << 30;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583

b6a2fea39   Ollie Wild   mm: variable leng...
584
585
586
  	/* Make sure we didn't let the argument array grow too large. */
  	if (vma->vm_end - vma->vm_start > stack_base)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587

b6a2fea39   Ollie Wild   mm: variable leng...
588
  	stack_base = PAGE_ALIGN(stack_top - stack_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589

b6a2fea39   Ollie Wild   mm: variable leng...
590
591
592
  	stack_shift = vma->vm_start - stack_base;
  	mm->arg_start = bprm->p - stack_shift;
  	bprm->p = vma->vm_end - stack_shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  #else
b6a2fea39   Ollie Wild   mm: variable leng...
594
595
596
597
598
  	stack_top = arch_align_stack(stack_top);
  	stack_top = PAGE_ALIGN(stack_top);
  	stack_shift = vma->vm_end - stack_top;
  
  	bprm->p -= stack_shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  	mm->arg_start = bprm->p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  	if (bprm->loader)
b6a2fea39   Ollie Wild   mm: variable leng...
602
603
  		bprm->loader -= stack_shift;
  	bprm->exec -= stack_shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
  	down_write(&mm->mmap_sem);
96a8e13ed   Hugh Dickins   exec: fix stack e...
606
  	vm_flags = VM_STACK_FLAGS;
b6a2fea39   Ollie Wild   mm: variable leng...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  
  	/*
  	 * Adjust stack execute permissions; explicitly enable for
  	 * EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X and leave alone
  	 * (arch default) otherwise.
  	 */
  	if (unlikely(executable_stack == EXSTACK_ENABLE_X))
  		vm_flags |= VM_EXEC;
  	else if (executable_stack == EXSTACK_DISABLE_X)
  		vm_flags &= ~VM_EXEC;
  	vm_flags |= mm->def_flags;
  
  	ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
  			vm_flags);
  	if (ret)
  		goto out_unlock;
  	BUG_ON(prev != vma);
  
  	/* Move stack pages down in memory. */
  	if (stack_shift) {
  		ret = shift_arg_pages(vma, stack_shift);
  		if (ret) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  			up_write(&mm->mmap_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
  			return ret;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  	}
b6a2fea39   Ollie Wild   mm: variable leng...
633
634
635
636
637
638
639
640
641
642
  #ifdef CONFIG_STACK_GROWSUP
  	stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
  #else
  	stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
  #endif
  	ret = expand_stack(vma, stack_base);
  	if (ret)
  		ret = -EFAULT;
  
  out_unlock:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  	up_write(&mm->mmap_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  EXPORT_SYMBOL(setup_arg_pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
  #endif /* CONFIG_MMU */
  
  struct file *open_exec(const char *name)
  {
  	struct nameidata nd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
  	struct file *file;
e56b6a5dd   Christoph Hellwig   Re: [PATCH 3/6] v...
653
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654

e56b6a5dd   Christoph Hellwig   Re: [PATCH 3/6] v...
655
656
657
658
659
660
661
662
  	err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd,
  				FMODE_READ|FMODE_EXEC);
  	if (err)
  		goto out;
  
  	err = -EACCES;
  	if (!S_ISREG(nd.path.dentry->d_inode->i_mode))
  		goto out_path_put;
30524472c   Al Viro   [PATCH] take noex...
663
664
  	if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
  		goto out_path_put;
e56b6a5dd   Christoph Hellwig   Re: [PATCH 3/6] v...
665
666
667
668
669
670
671
672
673
674
675
676
  	err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN);
  	if (err)
  		goto out_path_put;
  
  	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
  	if (IS_ERR(file))
  		return file;
  
  	err = deny_write_access(file);
  	if (err) {
  		fput(file);
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678

e56b6a5dd   Christoph Hellwig   Re: [PATCH 3/6] v...
679
680
681
682
683
684
685
686
  	return file;
  
   out_path_put:
  	release_open_intent(&nd);
  	path_put(&nd.path);
   out:
  	return ERR_PTR(err);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
  EXPORT_SYMBOL(open_exec);
  
  int kernel_read(struct file *file, unsigned long offset,
  	char *addr, unsigned long count)
  {
  	mm_segment_t old_fs;
  	loff_t pos = offset;
  	int result;
  
  	old_fs = get_fs();
  	set_fs(get_ds());
  	/* The cast to a user pointer is valid due to the set_fs() */
  	result = vfs_read(file, (void __user *)addr, count, &pos);
  	set_fs(old_fs);
  	return result;
  }
  
  EXPORT_SYMBOL(kernel_read);
  
  static int exec_mmap(struct mm_struct *mm)
  {
  	struct task_struct *tsk;
  	struct mm_struct * old_mm, *active_mm;
  
  	/* Notify parent that we're no longer interested in the old VM */
  	tsk = current;
  	old_mm = current->mm;
  	mm_release(tsk, old_mm);
  
  	if (old_mm) {
  		/*
  		 * Make sure that if there is a core dump in progress
  		 * for the old mm, we get out and die instead of going
  		 * through with the exec.  We must hold mmap_sem around
999d9fc16   Oleg Nesterov   coredump: move mm...
721
  		 * checking core_state and changing tsk->mm.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  		 */
  		down_read(&old_mm->mmap_sem);
999d9fc16   Oleg Nesterov   coredump: move mm...
724
  		if (unlikely(old_mm->core_state)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
729
730
731
732
733
734
735
736
737
  			up_read(&old_mm->mmap_sem);
  			return -EINTR;
  		}
  	}
  	task_lock(tsk);
  	active_mm = tsk->active_mm;
  	tsk->mm = mm;
  	tsk->active_mm = mm;
  	activate_mm(active_mm, mm);
  	task_unlock(tsk);
  	arch_pick_mmap_layout(mm);
  	if (old_mm) {
  		up_read(&old_mm->mmap_sem);
7dddb12c6   Eric Sesterhenn   BUG_ON() Conversi...
738
  		BUG_ON(active_mm != old_mm);
31a78f23b   Balbir Singh   mm owner: fix rac...
739
  		mm_update_next_owner(old_mm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
745
746
747
748
749
750
751
752
  		mmput(old_mm);
  		return 0;
  	}
  	mmdrop(active_mm);
  	return 0;
  }
  
  /*
   * This function makes sure the current process has its own signal table,
   * so that flush_signal_handlers can later reset the handlers without
   * disturbing other processes.  (Other processes might share the signal
   * table via the CLONE_SIGHAND option to clone().)
   */
858119e15   Arjan van de Ven   [PATCH] Unlinline...
753
  static int de_thread(struct task_struct *tsk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
  {
  	struct signal_struct *sig = tsk->signal;
b2c903b87   Oleg Nesterov   exec: simplify th...
756
  	struct sighand_struct *oldsighand = tsk->sighand;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  	spinlock_t *lock = &oldsighand->siglock;
  	int count;
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
759
  	if (thread_group_empty(tsk))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
762
763
  		goto no_thread_group;
  
  	/*
  	 * Kill all other threads in the thread group.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  	spin_lock_irq(lock);
ed5d2cac1   Oleg Nesterov   exec: rework the ...
766
  	if (signal_group_exit(sig)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
  		/*
  		 * Another group action in progress, just
  		 * return so that the signal is processed.
  		 */
  		spin_unlock_irq(lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
  		return -EAGAIN;
  	}
ed5d2cac1   Oleg Nesterov   exec: rework the ...
774
  	sig->group_exit_task = tsk;
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
775
  	zap_other_threads(tsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776

fea9d1755   Oleg Nesterov   ITIMER_REAL: conv...
777
778
  	/* Account for the thread group leader hanging around: */
  	count = thread_group_leader(tsk) ? 1 : 2;
6db840fa7   Oleg Nesterov   exec: RT sub-thre...
779
  	sig->notify_count = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  	while (atomic_read(&sig->count) > count) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
  		__set_current_state(TASK_UNINTERRUPTIBLE);
  		spin_unlock_irq(lock);
  		schedule();
  		spin_lock_irq(lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
  	spin_unlock_irq(lock);
  
  	/*
  	 * At this point all other threads have exited, all we have to
  	 * do is to wait for the thread group leader to become inactive,
  	 * and to assume its PID:
  	 */
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
793
  	if (!thread_group_leader(tsk)) {
8187926bd   Oleg Nesterov   posix-timers: sim...
794
  		struct task_struct *leader = tsk->group_leader;
6db840fa7   Oleg Nesterov   exec: RT sub-thre...
795

2800d8d19   Oleg Nesterov   document de_threa...
796
  		sig->notify_count = -1;	/* for exit_notify() */
6db840fa7   Oleg Nesterov   exec: RT sub-thre...
797
798
799
800
801
802
803
804
  		for (;;) {
  			write_lock_irq(&tasklist_lock);
  			if (likely(leader->exit_state))
  				break;
  			__set_current_state(TASK_UNINTERRUPTIBLE);
  			write_unlock_irq(&tasklist_lock);
  			schedule();
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805

f5e902817   Roland McGrath   [PATCH] process a...
806
807
808
809
810
811
812
813
814
815
  		/*
  		 * The only record we have of the real-time age of a
  		 * process, regardless of execs it's done, is start_time.
  		 * All the past CPU time is accumulated in signal_struct
  		 * from sister threads now dead.  But in this non-leader
  		 * exec, nothing survives from the original leader thread,
  		 * whose birth marks the true age of this process now.
  		 * When we take on its identity by switching to its PID, we
  		 * also take its birthdate (always earlier than our own).
  		 */
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
816
  		tsk->start_time = leader->start_time;
f5e902817   Roland McGrath   [PATCH] process a...
817

bac0abd61   Pavel Emelyanov   Isolate some expl...
818
819
  		BUG_ON(!same_thread_group(leader, tsk));
  		BUG_ON(has_group_leader_pid(tsk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
824
825
  		/*
  		 * An exec() starts a new thread group with the
  		 * TGID of the previous thread group. Rehash the
  		 * two threads with a switched PID, and release
  		 * the former thread group leader:
  		 */
d73d65293   Eric W. Biederman   [PATCH] pidhash: ...
826
827
  
  		/* Become a process group leader with the old leader's pid.
c18258c6f   Eric W. Biederman   [PATCH] pid: Impl...
828
829
  		 * The old leader becomes a thread of the this thread group.
  		 * Note: The old leader also uses this pid until release_task
d73d65293   Eric W. Biederman   [PATCH] pidhash: ...
830
831
  		 *       is called.  Odd but simple and correct.
  		 */
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
832
833
  		detach_pid(tsk, PIDTYPE_PID);
  		tsk->pid = leader->pid;
3743ca05f   Sukadev Bhattiprolu   pid namespaces: u...
834
  		attach_pid(tsk, PIDTYPE_PID,  task_pid(leader));
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
835
836
837
  		transfer_pid(leader, tsk, PIDTYPE_PGID);
  		transfer_pid(leader, tsk, PIDTYPE_SID);
  		list_replace_rcu(&leader->tasks, &tsk->tasks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838

aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
839
840
  		tsk->group_leader = tsk;
  		leader->group_leader = tsk;
de12a7878   Eric W. Biederman   [PATCH] de_thread...
841

aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
842
  		tsk->exit_signal = SIGCHLD;
962b564cf   Oleg Nesterov   [PATCH] fix do_wa...
843
844
845
  
  		BUG_ON(leader->exit_state != EXIT_ZOMBIE);
  		leader->exit_state = EXIT_DEAD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
  		write_unlock_irq(&tasklist_lock);
8187926bd   Oleg Nesterov   posix-timers: sim...
847
848
  
  		release_task(leader);
ed5d2cac1   Oleg Nesterov   exec: rework the ...
849
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850

6db840fa7   Oleg Nesterov   exec: RT sub-thre...
851
852
  	sig->group_exit_task = NULL;
  	sig->notify_count = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
  
  no_thread_group:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
  	exit_itimers(sig);
cbaffba12   Oleg Nesterov   posix timers: dis...
856
  	flush_itimer_signals();
329f7dba5   Oleg Nesterov   [PATCH] fix de_th...
857

b2c903b87   Oleg Nesterov   exec: simplify th...
858
859
  	if (atomic_read(&oldsighand->count) != 1) {
  		struct sighand_struct *newsighand;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  		/*
b2c903b87   Oleg Nesterov   exec: simplify th...
861
862
  		 * This ->sighand is shared with the CLONE_SIGHAND
  		 * but not CLONE_THREAD task, switch to the new one.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  		 */
b2c903b87   Oleg Nesterov   exec: simplify th...
864
865
866
  		newsighand = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
  		if (!newsighand)
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
871
872
  		atomic_set(&newsighand->count, 1);
  		memcpy(newsighand->action, oldsighand->action,
  		       sizeof(newsighand->action));
  
  		write_lock_irq(&tasklist_lock);
  		spin_lock(&oldsighand->siglock);
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
873
  		rcu_assign_pointer(tsk->sighand, newsighand);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
  		spin_unlock(&oldsighand->siglock);
  		write_unlock_irq(&tasklist_lock);
fba2afaae   Davide Libenzi   signal/timer/even...
876
  		__cleanup_sighand(oldsighand);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  	}
aafe6c2a2   Eric W. Biederman   [PATCH] de_thread...
878
  	BUG_ON(!thread_group_leader(tsk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
  	return 0;
  }
0840a90d9   Oleg Nesterov   exec: simplify ->...
881

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
  /*
   * These functions flushes out all traces of the currently running executable
   * so that a new one can be started
   */
858119e15   Arjan van de Ven   [PATCH] Unlinline...
886
  static void flush_old_files(struct files_struct * files)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
888
  {
  	long j = -1;
badf16621   Dipankar Sarma   [PATCH] files: br...
889
  	struct fdtable *fdt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
893
894
895
896
  
  	spin_lock(&files->file_lock);
  	for (;;) {
  		unsigned long set, i;
  
  		j++;
  		i = j * __NFDBITS;
badf16621   Dipankar Sarma   [PATCH] files: br...
897
  		fdt = files_fdtable(files);
bbea9f696   Vadim Lobanov   [PATCH] fdtable: ...
898
  		if (i >= fdt->max_fds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
  			break;
badf16621   Dipankar Sarma   [PATCH] files: br...
900
  		set = fdt->close_on_exec->fds_bits[j];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
902
  		if (!set)
  			continue;
badf16621   Dipankar Sarma   [PATCH] files: br...
903
  		fdt->close_on_exec->fds_bits[j] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
906
907
908
909
910
911
912
913
914
  		spin_unlock(&files->file_lock);
  		for ( ; set ; i++,set >>= 1) {
  			if (set & 1) {
  				sys_close(i);
  			}
  		}
  		spin_lock(&files->file_lock);
  
  	}
  	spin_unlock(&files->file_lock);
  }
59714d65d   Andrew Morton   get_task_comm(): ...
915
  char *get_task_comm(char *buf, struct task_struct *tsk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
920
  {
  	/* buf must be at least sizeof(tsk->comm) in size */
  	task_lock(tsk);
  	strncpy(buf, tsk->comm, sizeof(tsk->comm));
  	task_unlock(tsk);
59714d65d   Andrew Morton   get_task_comm(): ...
921
  	return buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
925
926
927
928
929
930
931
932
933
934
  }
  
  void set_task_comm(struct task_struct *tsk, char *buf)
  {
  	task_lock(tsk);
  	strlcpy(tsk->comm, buf, sizeof(tsk->comm));
  	task_unlock(tsk);
  }
  
  int flush_old_exec(struct linux_binprm * bprm)
  {
  	char * name;
  	int i, ch, retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
937
938
939
940
941
942
943
  	char tcomm[sizeof(current->comm)];
  
  	/*
  	 * Make sure we have a private signal table and that
  	 * we are unassociated from the previous thread group.
  	 */
  	retval = de_thread(current);
  	if (retval)
  		goto out;
925d1c401   Matt Helsley   procfs task exe s...
944
  	set_mm_exe_file(bprm->mm, bprm->file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
949
  	 * Release all of the old mmap stuff
  	 */
  	retval = exec_mmap(bprm->mm);
  	if (retval)
fd8328be8   Al Viro   [PATCH] sanitize ...
950
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
  
  	bprm->mm = NULL;		/* We're using it now */
  
  	/* This is the point of no return */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
  	current->sas_ss_sp = current->sas_ss_size = 0;
da9592ede   David Howells   CRED: Wrap task c...
956
  	if (current_euid() == current_uid() && current_egid() == current_gid())
6c5d52382   Kawai, Hidehiro   coredump masking:...
957
  		set_dumpable(current->mm, 1);
d6e711448   Alan Cox   [PATCH] setuid co...
958
  	else
6c5d52382   Kawai, Hidehiro   coredump masking:...
959
  		set_dumpable(current->mm, suid_dumpable);
d6e711448   Alan Cox   [PATCH] setuid co...
960

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
  	name = bprm->filename;
367720923   Paolo 'Blaisorblade' Giarrusso   [PATCH] comments ...
962
963
  
  	/* Copies the binary name from after last slash */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
  	for (i=0; (ch = *(name++)) != '\0';) {
  		if (ch == '/')
367720923   Paolo 'Blaisorblade' Giarrusso   [PATCH] comments ...
966
  			i = 0; /* overwrite what we wrote */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
972
973
974
975
  		else
  			if (i < (sizeof(tcomm) - 1))
  				tcomm[i++] = ch;
  	}
  	tcomm[i] = '\0';
  	set_task_comm(current, tcomm);
  
  	current->flags &= ~PF_RANDOMIZE;
  	flush_thread();
0551fbd29   Benjamin Herrenschmidt   [PATCH] Add mm->t...
976
977
978
979
980
  	/* Set the new mm task size. We have to do that late because it may
  	 * depend on TIF_32BIT which is only updated in flush_thread() on
  	 * some architectures like powerpc
  	 */
  	current->mm->task_size = TASK_SIZE;
a6f76f23d   David Howells   CRED: Make execve...
981
982
983
  	/* install the new credentials */
  	if (bprm->cred->uid != current_euid() ||
  	    bprm->cred->gid != current_egid()) {
d2d56c5f5   Marcel Holtmann   Reset current->pd...
984
985
  		current->pdeath_signal = 0;
  	} else if (file_permission(bprm->file, MAY_READ) ||
a6f76f23d   David Howells   CRED: Make execve...
986
  		   bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
6c5d52382   Kawai, Hidehiro   coredump masking:...
987
  		set_dumpable(current->mm, suid_dumpable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
  	}
a6f76f23d   David Howells   CRED: Make execve...
989
  	current->personality &= ~bprm->per_clear;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
991
992
993
994
995
996
997
998
  	/* An exec changes our domain. We are no longer part of the thread
  	   group */
  
  	current->self_exec_id++;
  			
  	flush_signal_handlers(current, 0);
  	flush_old_files(current->files);
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
1003
  out:
  	return retval;
  }
  
  EXPORT_SYMBOL(flush_old_exec);
a6f76f23d   David Howells   CRED: Make execve...
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
  /*
   * install the new credentials for this executable
   */
  void install_exec_creds(struct linux_binprm *bprm)
  {
  	security_bprm_committing_creds(bprm);
  
  	commit_creds(bprm->cred);
  	bprm->cred = NULL;
  
  	/* cred_exec_mutex must be held at least to this point to prevent
  	 * ptrace_attach() from altering our determination of the task's
  	 * credentials; any time after this it may be unlocked */
  
  	security_bprm_committed_creds(bprm);
  }
  EXPORT_SYMBOL(install_exec_creds);
  
  /*
   * determine how safe it is to execute the proposed program
   * - the caller must hold current->cred_exec_mutex to protect against
   *   PTRACE_ATTACH
   */
  void check_unsafe_exec(struct linux_binprm *bprm)
  {
  	struct task_struct *p = current;
  
  	bprm->unsafe = tracehook_unsafe_exec(p);
  
  	if (atomic_read(&p->fs->count) > 1 ||
  	    atomic_read(&p->files->count) > 1 ||
  	    atomic_read(&p->sighand->count) > 1)
  		bprm->unsafe |= LSM_UNSAFE_SHARE;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
  /* 
   * Fill the binprm structure from the inode. 
   * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
a6f76f23d   David Howells   CRED: Make execve...
1041
1042
   *
   * This may be called multiple times for binary chains (scripts for example).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
1045
   */
  int prepare_binprm(struct linux_binprm *bprm)
  {
a6f76f23d   David Howells   CRED: Make execve...
1046
  	umode_t mode;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
1047
  	struct inode * inode = bprm->file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
  	int retval;
  
  	mode = inode->i_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
  	if (bprm->file->f_op == NULL)
  		return -EACCES;
a6f76f23d   David Howells   CRED: Make execve...
1053
1054
1055
  	/* clear any previous set[ug]id data from a previous binary */
  	bprm->cred->euid = current_euid();
  	bprm->cred->egid = current_egid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056

a6f76f23d   David Howells   CRED: Make execve...
1057
  	if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
  		/* Set-uid? */
  		if (mode & S_ISUID) {
a6f76f23d   David Howells   CRED: Make execve...
1060
1061
  			bprm->per_clear |= PER_CLEAR_ON_SETID;
  			bprm->cred->euid = inode->i_uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
1064
1065
1066
1067
1068
1069
1070
  		}
  
  		/* Set-gid? */
  		/*
  		 * If setgid is set but no group execute bit then this
  		 * is a candidate for mandatory locking, not a setgid
  		 * executable.
  		 */
  		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
a6f76f23d   David Howells   CRED: Make execve...
1071
1072
  			bprm->per_clear |= PER_CLEAR_ON_SETID;
  			bprm->cred->egid = inode->i_gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
1075
1076
  		}
  	}
  
  	/* fill in binprm security blob */
a6f76f23d   David Howells   CRED: Make execve...
1077
  	retval = security_bprm_set_creds(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
  	if (retval)
  		return retval;
a6f76f23d   David Howells   CRED: Make execve...
1080
  	bprm->cred_prepared = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081

a6f76f23d   David Howells   CRED: Make execve...
1082
1083
  	memset(bprm->buf, 0, BINPRM_BUF_SIZE);
  	return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
1086
  }
  
  EXPORT_SYMBOL(prepare_binprm);
4fc75ff48   Nick Piggin   exec: fix remove_...
1087
1088
1089
1090
1091
  /*
   * Arguments are '\0' separated strings found at the location bprm->p
   * points to; chop off the first by relocating brpm->p to right after
   * the first '\0' encountered.
   */
b6a2fea39   Ollie Wild   mm: variable leng...
1092
  int remove_arg_zero(struct linux_binprm *bprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  {
b6a2fea39   Ollie Wild   mm: variable leng...
1094
1095
1096
1097
  	int ret = 0;
  	unsigned long offset;
  	char *kaddr;
  	struct page *page;
4fc75ff48   Nick Piggin   exec: fix remove_...
1098

b6a2fea39   Ollie Wild   mm: variable leng...
1099
1100
  	if (!bprm->argc)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101

b6a2fea39   Ollie Wild   mm: variable leng...
1102
1103
1104
1105
1106
1107
1108
1109
  	do {
  		offset = bprm->p & ~PAGE_MASK;
  		page = get_arg_page(bprm, bprm->p, 0);
  		if (!page) {
  			ret = -EFAULT;
  			goto out;
  		}
  		kaddr = kmap_atomic(page, KM_USER0);
4fc75ff48   Nick Piggin   exec: fix remove_...
1110

b6a2fea39   Ollie Wild   mm: variable leng...
1111
1112
1113
  		for (; offset < PAGE_SIZE && kaddr[offset];
  				offset++, bprm->p++)
  			;
4fc75ff48   Nick Piggin   exec: fix remove_...
1114

b6a2fea39   Ollie Wild   mm: variable leng...
1115
1116
  		kunmap_atomic(kaddr, KM_USER0);
  		put_arg_page(page);
4fc75ff48   Nick Piggin   exec: fix remove_...
1117

b6a2fea39   Ollie Wild   mm: variable leng...
1118
1119
1120
  		if (offset == PAGE_SIZE)
  			free_arg_page(bprm, (bprm->p >> PAGE_SHIFT) - 1);
  	} while (offset == PAGE_SIZE);
4fc75ff48   Nick Piggin   exec: fix remove_...
1121

b6a2fea39   Ollie Wild   mm: variable leng...
1122
1123
1124
  	bprm->p++;
  	bprm->argc--;
  	ret = 0;
4fc75ff48   Nick Piggin   exec: fix remove_...
1125

b6a2fea39   Ollie Wild   mm: variable leng...
1126
1127
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
1132
1133
1134
1135
  EXPORT_SYMBOL(remove_arg_zero);
  
  /*
   * cycle the list of binary formats handler, until one recognizes the image
   */
  int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
  {
85f334666   Roland McGrath   tracehook: exec d...
1136
  	unsigned int depth = bprm->recursion_depth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
  	int try,retval;
  	struct linux_binfmt *fmt;
702773b16   David Woodhouse   Include <asm/a.ou...
1139
  #ifdef __alpha__
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  	/* handle /sbin/loader.. */
  	{
  	    struct exec * eh = (struct exec *) bprm->buf;
  
  	    if (!bprm->loader && eh->fh.f_magic == 0x183 &&
  		(eh->fh.f_flags & 0x3000) == 0x3000)
  	    {
  		struct file * file;
  		unsigned long loader;
  
  		allow_write_access(bprm->file);
  		fput(bprm->file);
  		bprm->file = NULL;
b6a2fea39   Ollie Wild   mm: variable leng...
1153
  		loader = bprm->vma->vm_end - sizeof(void *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
1157
1158
1159
1160
  
  		file = open_exec("/sbin/loader");
  		retval = PTR_ERR(file);
  		if (IS_ERR(file))
  			return retval;
  
  		/* Remember if the application is TASO.  */
53112488b   Kirill A. Shutemov   alpha: introduce ...
1161
  		bprm->taso = eh->ah.entry < 0x100000000UL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
  
  		bprm->file = file;
  		bprm->loader = loader;
  		retval = prepare_binprm(bprm);
  		if (retval<0)
  			return retval;
  		/* should call search_binary_handler recursively here,
  		   but it does not matter */
  	    }
  	}
  #endif
  	retval = security_bprm_check(bprm);
  	if (retval)
  		return retval;
  
  	/* kernel module loader fixup */
  	/* so we don't try to load run modprobe in kernel space. */
  	set_fs(USER_DS);
473ae30bc   Al Viro   [PATCH] execve ar...
1180
1181
1182
1183
  
  	retval = audit_bprm(bprm);
  	if (retval)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
1185
1186
  	retval = -ENOENT;
  	for (try=0; try<2; try++) {
  		read_lock(&binfmt_lock);
e4dc1b14d   Alexey Dobriyan   Use list_head in ...
1187
  		list_for_each_entry(fmt, &formats, lh) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
1189
1190
1191
1192
1193
1194
  			int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
  			if (!fn)
  				continue;
  			if (!try_module_get(fmt->module))
  				continue;
  			read_unlock(&binfmt_lock);
  			retval = fn(bprm, regs);
85f334666   Roland McGrath   tracehook: exec d...
1195
1196
1197
1198
1199
1200
  			/*
  			 * Restore the depth counter to its starting value
  			 * in this call, so we don't have to rely on every
  			 * load_binary function to restore it on return.
  			 */
  			bprm->recursion_depth = depth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
  			if (retval >= 0) {
85f334666   Roland McGrath   tracehook: exec d...
1202
1203
  				if (depth == 0)
  					tracehook_report_exec(fmt, bprm, regs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
1207
1208
1209
  				put_binfmt(fmt);
  				allow_write_access(bprm->file);
  				if (bprm->file)
  					fput(bprm->file);
  				bprm->file = NULL;
  				current->did_exec = 1;
9f46080c4   Matt Helsley   [PATCH] Process E...
1210
  				proc_exec_connector(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  				return retval;
  			}
  			read_lock(&binfmt_lock);
  			put_binfmt(fmt);
  			if (retval != -ENOEXEC || bprm->mm == NULL)
  				break;
  			if (!bprm->file) {
  				read_unlock(&binfmt_lock);
  				return retval;
  			}
  		}
  		read_unlock(&binfmt_lock);
  		if (retval != -ENOEXEC || bprm->mm == NULL) {
  			break;
5f4123be3   Johannes Berg   remove CONFIG_KMO...
1225
1226
  #ifdef CONFIG_MODULES
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  #define printable(c) (((c)=='\t') || ((c)=='
  ') || (0x20<=(c) && (c)<=0x7e))
  			if (printable(bprm->buf[0]) &&
  			    printable(bprm->buf[1]) &&
  			    printable(bprm->buf[2]) &&
  			    printable(bprm->buf[3]))
  				break; /* -ENOEXEC */
  			request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
  #endif
  		}
  	}
  	return retval;
  }
  
  EXPORT_SYMBOL(search_binary_handler);
08a6fac1c   Al Viro   [PATCH] get rid o...
1242
1243
1244
  void free_bprm(struct linux_binprm *bprm)
  {
  	free_arg_pages(bprm);
a6f76f23d   David Howells   CRED: Make execve...
1245
1246
  	if (bprm->cred)
  		abort_creds(bprm->cred);
08a6fac1c   Al Viro   [PATCH] get rid o...
1247
1248
  	kfree(bprm);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
  /*
   * sys_execve() executes a new program.
   */
  int do_execve(char * filename,
  	char __user *__user *argv,
  	char __user *__user *envp,
  	struct pt_regs * regs)
  {
  	struct linux_binprm *bprm;
  	struct file *file;
3b1253880   Al Viro   [PATCH] sanitize ...
1259
  	struct files_struct *displaced;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261

3b1253880   Al Viro   [PATCH] sanitize ...
1262
  	retval = unshare_files(&displaced);
fd8328be8   Al Viro   [PATCH] sanitize ...
1263
1264
  	if (retval)
  		goto out_ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
  	retval = -ENOMEM;
11b0b5abb   Oliver Neukum   [PATCH] use kzall...
1266
  	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
  	if (!bprm)
fd8328be8   Al Viro   [PATCH] sanitize ...
1268
  		goto out_files;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269

a6f76f23d   David Howells   CRED: Make execve...
1270
1271
1272
1273
1274
1275
1276
1277
1278
  	retval = mutex_lock_interruptible(&current->cred_exec_mutex);
  	if (retval < 0)
  		goto out_free;
  
  	retval = -ENOMEM;
  	bprm->cred = prepare_exec_creds();
  	if (!bprm->cred)
  		goto out_unlock;
  	check_unsafe_exec(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
1281
  	file = open_exec(filename);
  	retval = PTR_ERR(file);
  	if (IS_ERR(file))
a6f76f23d   David Howells   CRED: Make execve...
1282
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
  
  	sched_exec();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
1287
  	bprm->file = file;
  	bprm->filename = filename;
  	bprm->interp = filename;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288

b6a2fea39   Ollie Wild   mm: variable leng...
1289
1290
1291
  	retval = bprm_mm_init(bprm);
  	if (retval)
  		goto out_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292

b6a2fea39   Ollie Wild   mm: variable leng...
1293
  	bprm->argc = count(argv, MAX_ARG_STRINGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  	if ((retval = bprm->argc) < 0)
a6f76f23d   David Howells   CRED: Make execve...
1295
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296

b6a2fea39   Ollie Wild   mm: variable leng...
1297
  	bprm->envc = count(envp, MAX_ARG_STRINGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
  	if ((retval = bprm->envc) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
  		goto out;
  
  	retval = prepare_binprm(bprm);
  	if (retval < 0)
  		goto out;
  
  	retval = copy_strings_kernel(1, &bprm->filename, bprm);
  	if (retval < 0)
  		goto out;
  
  	bprm->exec = bprm->p;
  	retval = copy_strings(bprm->envc, envp, bprm);
  	if (retval < 0)
  		goto out;
  
  	retval = copy_strings(bprm->argc, argv, bprm);
  	if (retval < 0)
  		goto out;
7b34e4283   Oleg Nesterov   introduce PF_KTHR...
1317
  	current->flags &= ~PF_KTHREAD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  	retval = search_binary_handler(bprm,regs);
a6f76f23d   David Howells   CRED: Make execve...
1319
1320
  	if (retval < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321

a6f76f23d   David Howells   CRED: Make execve...
1322
1323
1324
1325
1326
1327
1328
  	/* execve succeeded */
  	mutex_unlock(&current->cred_exec_mutex);
  	acct_update_integrals(current);
  	free_bprm(bprm);
  	if (displaced)
  		put_files_struct(displaced);
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329

a6f76f23d   David Howells   CRED: Make execve...
1330
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
  	if (bprm->mm)
b6a2fea39   Ollie Wild   mm: variable leng...
1332
  		mmput (bprm->mm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
1335
1336
1337
1338
  
  out_file:
  	if (bprm->file) {
  		allow_write_access(bprm->file);
  		fput(bprm->file);
  	}
a6f76f23d   David Howells   CRED: Make execve...
1339
1340
1341
1342
1343
  
  out_unlock:
  	mutex_unlock(&current->cred_exec_mutex);
  
  out_free:
08a6fac1c   Al Viro   [PATCH] get rid o...
1344
  	free_bprm(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345

fd8328be8   Al Viro   [PATCH] sanitize ...
1346
  out_files:
3b1253880   Al Viro   [PATCH] sanitize ...
1347
1348
  	if (displaced)
  		reset_files_struct(displaced);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  out_ret:
  	return retval;
  }
  
  int set_binfmt(struct linux_binfmt *new)
  {
  	struct linux_binfmt *old = current->binfmt;
  
  	if (new) {
  		if (!try_module_get(new->module))
  			return -1;
  	}
  	current->binfmt = new;
  	if (old)
  		module_put(old->module);
  	return 0;
  }
  
  EXPORT_SYMBOL(set_binfmt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
1369
1370
1371
  /* format_corename will inspect the pattern parameter, and output a
   * name into corename, which must have space for at least
   * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
   */
6409324b3   Oleg Nesterov   coredump: format_...
1372
  static int format_corename(char *corename, long signr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
  {
86a264abe   David Howells   CRED: Wrap curren...
1374
  	const struct cred *cred = current_cred();
565b9b14e   Oleg Nesterov   coredump: format_...
1375
1376
  	const char *pat_ptr = core_pattern;
  	int ispipe = (*pat_ptr == '|');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  	char *out_ptr = corename;
  	char *const out_end = corename + CORENAME_MAX_SIZE;
  	int rc;
  	int pid_in_pattern = 0;
  
  	/* Repeat as long as we have more pattern to process and more output
  	   space */
  	while (*pat_ptr) {
  		if (*pat_ptr != '%') {
  			if (out_ptr == out_end)
  				goto out;
  			*out_ptr++ = *pat_ptr++;
  		} else {
  			switch (*++pat_ptr) {
  			case 0:
  				goto out;
  			/* Double percent, output one percent */
  			case '%':
  				if (out_ptr == out_end)
  					goto out;
  				*out_ptr++ = '%';
  				break;
  			/* pid */
  			case 'p':
  				pid_in_pattern = 1;
  				rc = snprintf(out_ptr, out_end - out_ptr,
b488893a3   Pavel Emelyanov   pid namespaces: c...
1403
  					      "%d", task_tgid_vnr(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
1408
1409
1410
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
  			/* uid */
  			case 'u':
  				rc = snprintf(out_ptr, out_end - out_ptr,
86a264abe   David Howells   CRED: Wrap curren...
1411
  					      "%d", cred->uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
1416
1417
1418
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
  			/* gid */
  			case 'g':
  				rc = snprintf(out_ptr, out_end - out_ptr,
86a264abe   David Howells   CRED: Wrap curren...
1419
  					      "%d", cred->gid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
  			/* signal that caused the coredump */
  			case 's':
  				rc = snprintf(out_ptr, out_end - out_ptr,
  					      "%ld", signr);
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
  			/* UNIX time of coredump */
  			case 't': {
  				struct timeval tv;
  				do_gettimeofday(&tv);
  				rc = snprintf(out_ptr, out_end - out_ptr,
  					      "%lu", tv.tv_sec);
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
  			}
  			/* hostname */
  			case 'h':
  				down_read(&uts_sem);
  				rc = snprintf(out_ptr, out_end - out_ptr,
e9ff3990f   Serge E. Hallyn   [PATCH] namespace...
1447
  					      "%s", utsname()->nodename);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
  				up_read(&uts_sem);
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
  			/* executable */
  			case 'e':
  				rc = snprintf(out_ptr, out_end - out_ptr,
  					      "%s", current->comm);
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
74aadce98   Neil Horman   core_pattern: all...
1461
1462
1463
1464
1465
1466
1467
1468
  			/* core limit size */
  			case 'c':
  				rc = snprintf(out_ptr, out_end - out_ptr,
  					      "%lu", current->signal->rlim[RLIMIT_CORE].rlim_cur);
  				if (rc > out_end - out_ptr)
  					goto out;
  				out_ptr += rc;
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
  			default:
  				break;
  			}
  			++pat_ptr;
  		}
  	}
  	/* Backward compatibility with core_uses_pid:
  	 *
  	 * If core_pattern does not include a %p (as is the default)
  	 * and core_uses_pid is set, then .%pid will be appended to
c4bbafda7   Alan Cox   exec.c: fix cored...
1479
  	 * the filename. Do not do this for piped commands. */
6409324b3   Oleg Nesterov   coredump: format_...
1480
  	if (!ispipe && !pid_in_pattern && core_uses_pid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481
  		rc = snprintf(out_ptr, out_end - out_ptr,
b488893a3   Pavel Emelyanov   pid namespaces: c...
1482
  			      ".%d", task_tgid_vnr(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
1484
1485
1486
  		if (rc > out_end - out_ptr)
  			goto out;
  		out_ptr += rc;
  	}
c4bbafda7   Alan Cox   exec.c: fix cored...
1487
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1488
  	*out_ptr = 0;
c4bbafda7   Alan Cox   exec.c: fix cored...
1489
  	return ispipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
  }
8cd9c2491   Oleg Nesterov   coredump: simplif...
1491
  static int zap_process(struct task_struct *start)
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1492
1493
  {
  	struct task_struct *t;
8cd9c2491   Oleg Nesterov   coredump: simplif...
1494
  	int nr = 0;
281de339c   Oleg Nesterov   [PATCH] coredump:...
1495

d5f70c00a   Oleg Nesterov   [PATCH] coredump:...
1496
1497
  	start->signal->flags = SIGNAL_GROUP_EXIT;
  	start->signal->group_stop_count = 0;
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1498
1499
1500
1501
  
  	t = start;
  	do {
  		if (t != current && t->mm) {
281de339c   Oleg Nesterov   [PATCH] coredump:...
1502
1503
  			sigaddset(&t->pending.signal, SIGKILL);
  			signal_wake_up(t, 1);
8cd9c2491   Oleg Nesterov   coredump: simplif...
1504
  			nr++;
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1505
  		}
e4901f92a   Oleg Nesterov   coredump: zap_thr...
1506
  	} while_each_thread(start, t);
8cd9c2491   Oleg Nesterov   coredump: simplif...
1507
1508
  
  	return nr;
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1509
  }
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1510
  static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
8cd9c2491   Oleg Nesterov   coredump: simplif...
1511
  				struct core_state *core_state, int exit_code)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
  {
  	struct task_struct *g, *p;
5debfa6da   Oleg Nesterov   [PATCH] coredump:...
1514
  	unsigned long flags;
8cd9c2491   Oleg Nesterov   coredump: simplif...
1515
  	int nr = -EAGAIN;
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1516
1517
  
  	spin_lock_irq(&tsk->sighand->siglock);
ed5d2cac1   Oleg Nesterov   exec: rework the ...
1518
  	if (!signal_group_exit(tsk->signal)) {
8cd9c2491   Oleg Nesterov   coredump: simplif...
1519
  		mm->core_state = core_state;
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1520
  		tsk->signal->group_exit_code = exit_code;
8cd9c2491   Oleg Nesterov   coredump: simplif...
1521
  		nr = zap_process(tsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
  	}
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1523
  	spin_unlock_irq(&tsk->sighand->siglock);
8cd9c2491   Oleg Nesterov   coredump: simplif...
1524
1525
  	if (unlikely(nr < 0))
  		return nr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526

8cd9c2491   Oleg Nesterov   coredump: simplif...
1527
  	if (atomic_read(&mm->mm_users) == nr + 1)
5debfa6da   Oleg Nesterov   [PATCH] coredump:...
1528
  		goto done;
e4901f92a   Oleg Nesterov   coredump: zap_thr...
1529
1530
  	/*
  	 * We should find and kill all tasks which use this mm, and we should
999d9fc16   Oleg Nesterov   coredump: move mm...
1531
  	 * count them correctly into ->nr_threads. We don't take tasklist
e4901f92a   Oleg Nesterov   coredump: zap_thr...
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
  	 * lock, but this is safe wrt:
  	 *
  	 * fork:
  	 *	None of sub-threads can fork after zap_process(leader). All
  	 *	processes which were created before this point should be
  	 *	visible to zap_threads() because copy_process() adds the new
  	 *	process to the tail of init_task.tasks list, and lock/unlock
  	 *	of ->siglock provides a memory barrier.
  	 *
  	 * do_exit:
  	 *	The caller holds mm->mmap_sem. This means that the task which
  	 *	uses this mm can't pass exit_mm(), so it can't exit or clear
  	 *	its ->mm.
  	 *
  	 * de_thread:
  	 *	It does list_replace_rcu(&leader->tasks, &current->tasks),
  	 *	we must see either old or new leader, this does not matter.
  	 *	However, it can change p->sighand, so lock_task_sighand(p)
  	 *	must be used. Since p->mm != NULL and we hold ->mmap_sem
  	 *	it can't fail.
  	 *
  	 *	Note also that "g" can be the old leader with ->mm == NULL
  	 *	and already unhashed and thus removed from ->thread_group.
  	 *	This is OK, __unhash_process()->list_del_rcu() does not
  	 *	clear the ->next pointer, we will find the new leader via
  	 *	next_thread().
  	 */
7b1c6154f   Oleg Nesterov   [PATCH] coredump:...
1559
  	rcu_read_lock();
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1560
  	for_each_process(g) {
5debfa6da   Oleg Nesterov   [PATCH] coredump:...
1561
1562
  		if (g == tsk->group_leader)
  			continue;
15b9f360c   Oleg Nesterov   coredump: zap_thr...
1563
1564
  		if (g->flags & PF_KTHREAD)
  			continue;
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1565
1566
1567
  		p = g;
  		do {
  			if (p->mm) {
15b9f360c   Oleg Nesterov   coredump: zap_thr...
1568
  				if (unlikely(p->mm == mm)) {
5debfa6da   Oleg Nesterov   [PATCH] coredump:...
1569
  					lock_task_sighand(p, &flags);
8cd9c2491   Oleg Nesterov   coredump: simplif...
1570
  					nr += zap_process(p);
5debfa6da   Oleg Nesterov   [PATCH] coredump:...
1571
1572
  					unlock_task_sighand(p, &flags);
  				}
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1573
1574
  				break;
  			}
e4901f92a   Oleg Nesterov   coredump: zap_thr...
1575
  		} while_each_thread(g, p);
aceecc041   Oleg Nesterov   [PATCH] coredump:...
1576
  	}
7b1c6154f   Oleg Nesterov   [PATCH] coredump:...
1577
  	rcu_read_unlock();
5debfa6da   Oleg Nesterov   [PATCH] coredump:...
1578
  done:
c5f1cc8c1   Oleg Nesterov   coredump: turn co...
1579
  	atomic_set(&core_state->nr_threads, nr);
8cd9c2491   Oleg Nesterov   coredump: simplif...
1580
  	return nr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581
  }
9d5b327bf   Oleg Nesterov   coredump: make mm...
1582
  static int coredump_wait(int exit_code, struct core_state *core_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
  {
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1584
1585
  	struct task_struct *tsk = current;
  	struct mm_struct *mm = tsk->mm;
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1586
  	struct completion *vfork_done;
2384f55f8   Oleg Nesterov   [PATCH] coredump_...
1587
  	int core_waiters;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588

9d5b327bf   Oleg Nesterov   coredump: make mm...
1589
  	init_completion(&core_state->startup);
b564daf80   Oleg Nesterov   coredump: constru...
1590
1591
  	core_state->dumper.task = tsk;
  	core_state->dumper.next = NULL;
9d5b327bf   Oleg Nesterov   coredump: make mm...
1592
  	core_waiters = zap_threads(tsk, mm, core_state, exit_code);
2384f55f8   Oleg Nesterov   [PATCH] coredump_...
1593
  	up_write(&mm->mmap_sem);
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
  	if (unlikely(core_waiters < 0))
  		goto fail;
  
  	/*
  	 * Make sure nobody is waiting for us to release the VM,
  	 * otherwise we can deadlock when we wait on each other
  	 */
  	vfork_done = tsk->vfork_done;
  	if (vfork_done) {
  		tsk->vfork_done = NULL;
  		complete(vfork_done);
  	}
2384f55f8   Oleg Nesterov   [PATCH] coredump_...
1606
  	if (core_waiters)
9d5b327bf   Oleg Nesterov   coredump: make mm...
1607
  		wait_for_completion(&core_state->startup);
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1608
  fail:
dcf560c59   Oleg Nesterov   [PATCH] coredump:...
1609
  	return core_waiters;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
  }
a94e2d408   Oleg Nesterov   coredump: kill mm...
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
  static void coredump_finish(struct mm_struct *mm)
  {
  	struct core_thread *curr, *next;
  	struct task_struct *task;
  
  	next = mm->core_state->dumper.next;
  	while ((curr = next) != NULL) {
  		next = curr->next;
  		task = curr->task;
  		/*
  		 * see exit_mm(), curr->task must not see
  		 * ->task == NULL before we read ->next.
  		 */
  		smp_mb();
  		curr->task = NULL;
  		wake_up_process(task);
  	}
  
  	mm->core_state = NULL;
  }
6c5d52382   Kawai, Hidehiro   coredump masking:...
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
  /*
   * set_dumpable converts traditional three-value dumpable to two flags and
   * stores them into mm->flags.  It modifies lower two bits of mm->flags, but
   * these bits are not changed atomically.  So get_dumpable can observe the
   * intermediate state.  To avoid doing unexpected behavior, get get_dumpable
   * return either old dumpable or new one by paying attention to the order of
   * modifying the bits.
   *
   * dumpable |   mm->flags (binary)
   * old  new | initial interim  final
   * ---------+-----------------------
   *  0    1  |   00      01      01
   *  0    2  |   00      10(*)   11
   *  1    0  |   01      00      00
   *  1    2  |   01      11      11
   *  2    0  |   11      10(*)   00
   *  2    1  |   11      11      01
   *
   * (*) get_dumpable regards interim value of 10 as 11.
   */
  void set_dumpable(struct mm_struct *mm, int value)
  {
  	switch (value) {
  	case 0:
  		clear_bit(MMF_DUMPABLE, &mm->flags);
  		smp_wmb();
  		clear_bit(MMF_DUMP_SECURELY, &mm->flags);
  		break;
  	case 1:
  		set_bit(MMF_DUMPABLE, &mm->flags);
  		smp_wmb();
  		clear_bit(MMF_DUMP_SECURELY, &mm->flags);
  		break;
  	case 2:
  		set_bit(MMF_DUMP_SECURELY, &mm->flags);
  		smp_wmb();
  		set_bit(MMF_DUMPABLE, &mm->flags);
  		break;
  	}
  }
6c5d52382   Kawai, Hidehiro   coredump masking:...
1671
1672
1673
1674
1675
1676
1677
1678
  
  int get_dumpable(struct mm_struct *mm)
  {
  	int ret;
  
  	ret = mm->flags & 0x3;
  	return (ret >= 2) ? 2 : ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
1680
  int do_coredump(long signr, int exit_code, struct pt_regs * regs)
  {
9d5b327bf   Oleg Nesterov   coredump: make mm...
1681
  	struct core_state core_state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
1684
1685
1686
  	char corename[CORENAME_MAX_SIZE + 1];
  	struct mm_struct *mm = current->mm;
  	struct linux_binfmt * binfmt;
  	struct inode * inode;
  	struct file * file;
d84f4f992   David Howells   CRED: Inaugurate ...
1687
1688
  	const struct cred *old_cred;
  	struct cred *cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
  	int retval = 0;
d6e711448   Alan Cox   [PATCH] setuid co...
1690
  	int flag = 0;
d025c9db7   Andi Kleen   [PATCH] Support p...
1691
  	int ispipe = 0;
7dc0b22e3   Neil Horman   core_pattern: ign...
1692
  	unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
74aadce98   Neil Horman   core_pattern: all...
1693
1694
1695
  	char **helper_argv = NULL;
  	int helper_argc = 0;
  	char *delimit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696

0a4ff8c25   Steve Grubb   [PATCH] Abnormal ...
1697
  	audit_core_dumps(signr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1698
1699
1700
  	binfmt = current->binfmt;
  	if (!binfmt || !binfmt->core_dump)
  		goto fail;
d84f4f992   David Howells   CRED: Inaugurate ...
1701
1702
1703
1704
1705
1706
  
  	cred = prepare_creds();
  	if (!cred) {
  		retval = -ENOMEM;
  		goto fail;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707
  	down_write(&mm->mmap_sem);
00ec99da4   Roland McGrath   core dump: remain...
1708
1709
1710
  	/*
  	 * If another thread got here first, or we are not dumpable, bail out.
  	 */
999d9fc16   Oleg Nesterov   coredump: move mm...
1711
  	if (mm->core_state || !get_dumpable(mm)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
  		up_write(&mm->mmap_sem);
d84f4f992   David Howells   CRED: Inaugurate ...
1713
  		put_cred(cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
1715
  		goto fail;
  	}
d6e711448   Alan Cox   [PATCH] setuid co...
1716
1717
1718
1719
1720
1721
  
  	/*
  	 *	We cannot trust fsuid as being the "true" uid of the
  	 *	process nor do we know its entire history. We only know it
  	 *	was tainted so we dump it as root in mode 2.
  	 */
6c5d52382   Kawai, Hidehiro   coredump masking:...
1722
  	if (get_dumpable(mm) == 2) {	/* Setuid core dump mode */
d6e711448   Alan Cox   [PATCH] setuid co...
1723
  		flag = O_EXCL;		/* Stop rewrite attacks */
d84f4f992   David Howells   CRED: Inaugurate ...
1724
  		cred->fsuid = 0;	/* Dump root private */
d6e711448   Alan Cox   [PATCH] setuid co...
1725
  	}
1291cf416   Oleg Nesterov   [PATCH] fix de_th...
1726

9d5b327bf   Oleg Nesterov   coredump: make mm...
1727
  	retval = coredump_wait(exit_code, &core_state);
d84f4f992   David Howells   CRED: Inaugurate ...
1728
1729
  	if (retval < 0) {
  		put_cred(cred);
1291cf416   Oleg Nesterov   [PATCH] fix de_th...
1730
  		goto fail;
d84f4f992   David Howells   CRED: Inaugurate ...
1731
1732
1733
  	}
  
  	old_cred = override_creds(cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
1735
1736
1737
1738
  
  	/*
  	 * Clear any false indication of pending signals that might
  	 * be seen by the filesystem code called to write the core file.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739
  	clear_thread_flag(TIF_SIGPENDING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1740
1741
1742
1743
1744
  	/*
  	 * lock_kernel() because format_corename() is controlled by sysctl, which
  	 * uses lock_kernel()
  	 */
   	lock_kernel();
6409324b3   Oleg Nesterov   coredump: format_...
1745
  	ispipe = format_corename(corename, signr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1746
  	unlock_kernel();
7dc0b22e3   Neil Horman   core_pattern: ign...
1747
1748
1749
1750
1751
1752
1753
1754
  	/*
  	 * Don't bother to check the RLIMIT_CORE value if core_pattern points
  	 * to a pipe.  Since we're not writing directly to the filesystem
  	 * RLIMIT_CORE doesn't really apply, as no actual core file will be
  	 * created unless the pipe reader choses to write out the core file
  	 * at which point file size limits and permissions will be imposed
  	 * as it does with any other process
  	 */
74aadce98   Neil Horman   core_pattern: all...
1755
  	if ((!ispipe) && (core_limit < binfmt->min_coredump))
7dc0b22e3   Neil Horman   core_pattern: ign...
1756
  		goto fail_unlock;
c4bbafda7   Alan Cox   exec.c: fix cored...
1757
   	if (ispipe) {
74aadce98   Neil Horman   core_pattern: all...
1758
1759
1760
1761
1762
  		helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
  		/* Terminate the string before the first option */
  		delimit = strchr(corename, ' ');
  		if (delimit)
  			*delimit = '\0';
323211371   Neil Horman   core_pattern: fix...
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  		delimit = strrchr(helper_argv[0], '/');
  		if (delimit)
  			delimit++;
  		else
  			delimit = helper_argv[0];
  		if (!strcmp(delimit, current->comm)) {
  			printk(KERN_NOTICE "Recursive core dump detected, "
  					"aborting
  ");
  			goto fail_unlock;
  		}
  
  		core_limit = RLIM_INFINITY;
d025c9db7   Andi Kleen   [PATCH] Support p...
1776
  		/* SIGPIPE can happen, but it's just never processed */
323211371   Neil Horman   core_pattern: fix...
1777
1778
   		if (call_usermodehelper_pipe(corename+1, helper_argv, NULL,
  				&file)) {
d025c9db7   Andi Kleen   [PATCH] Support p...
1779
1780
1781
1782
1783
   			printk(KERN_INFO "Core dump to %s pipe failed
  ",
  			       corename);
   			goto fail_unlock;
   		}
d025c9db7   Andi Kleen   [PATCH] Support p...
1784
1785
   	} else
   		file = filp_open(corename,
6d4df677f   Alexey Dobriyan   [PATCH] do_coredu...
1786
1787
  				 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
  				 0600);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1788
1789
  	if (IS_ERR(file))
  		goto fail_unlock;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
1790
  	inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1791
1792
  	if (inode->i_nlink > 1)
  		goto close_fail;	/* multiple links - don't dump */
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
1793
  	if (!ispipe && d_unhashed(file->f_path.dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
  		goto close_fail;
d025c9db7   Andi Kleen   [PATCH] Support p...
1795
1796
1797
  	/* AK: actually i see no reason to not allow this for named pipes etc.,
  	   but keep the previous behaviour for now. */
  	if (!ispipe && !S_ISREG(inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1798
  		goto close_fail;
c46f739dd   Ingo Molnar   vfs: coredumping fix
1799
1800
1801
1802
  	/*
  	 * Dont allow local users get cute and trick others to coredump
  	 * into their pre-created files:
  	 */
da9592ede   David Howells   CRED: Wrap task c...
1803
  	if (inode->i_uid != current_fsuid())
c46f739dd   Ingo Molnar   vfs: coredumping fix
1804
  		goto close_fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1805
1806
1807
1808
  	if (!file->f_op)
  		goto close_fail;
  	if (!file->f_op->write)
  		goto close_fail;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
1809
  	if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  		goto close_fail;
7dc0b22e3   Neil Horman   core_pattern: ign...
1811
  	retval = binfmt->core_dump(signr, regs, file, core_limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1812
1813
1814
1815
1816
1817
  
  	if (retval)
  		current->signal->group_exit_code |= 0x80;
  close_fail:
  	filp_close(file, NULL);
  fail_unlock:
74aadce98   Neil Horman   core_pattern: all...
1818
1819
  	if (helper_argv)
  		argv_free(helper_argv);
d84f4f992   David Howells   CRED: Inaugurate ...
1820
1821
  	revert_creds(old_cred);
  	put_cred(cred);
a94e2d408   Oleg Nesterov   coredump: kill mm...
1822
  	coredump_finish(mm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1823
1824
1825
  fail:
  	return retval;
  }