Blame view

fs/binfmt_flat.c 26.4 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
  /****************************************************************************/
  /*
   *  linux/fs/binfmt_flat.c
   *
   *	Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
   *	Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
   *	Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
   *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
   *  based heavily on:
   *
   *  linux/fs/binfmt_aout.c:
   *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
   *  linux/fs/binfmt_flat.c for 2.0 kernel
   *	    Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
   *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
   */
630d9c472   Paul Gortmaker   fs: reduce the us...
17
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/string.h>
  #include <linux/fs.h>
  #include <linux/file.h>
  #include <linux/stat.h>
  #include <linux/fcntl.h>
  #include <linux/ptrace.h>
  #include <linux/user.h>
  #include <linux/slab.h>
  #include <linux/binfmts.h>
  #include <linux/personality.h>
  #include <linux/init.h>
  #include <linux/flat.h>
1ad3dcc09   Luke Yang   [PATCH] flat bina...
36
  #include <linux/syscalls.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
  
  #include <asm/byteorder.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <asm/uaccess.h>
  #include <asm/unaligned.h>
  #include <asm/cacheflush.h>
c3dc5bec0   Oskar Schirmer   flat: fix data se...
42
  #include <asm/page.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
  
  /****************************************************************************/
  
  #if 0
  #define DEBUG 1
  #endif
  
  #ifdef DEBUG
  #define	DBG_FLT(a...)	printk(a)
  #else
  #define	DBG_FLT(a...)
  #endif
c3dc5bec0   Oskar Schirmer   flat: fix data se...
55
  /*
2e94de8ac   Mike Frysinger   fs/binfmt_flat.c:...
56
57
58
59
60
61
62
63
64
65
66
   * User data (data section and bss) needs to be aligned.
   * We pick 0x20 here because it is the max value elf2flt has always
   * used in producing FLAT files, and because it seems to be large
   * enough to make all the gcc alignment related tests happy.
   */
  #define FLAT_DATA_ALIGN	(0x20)
  
  /*
   * User data (stack) also needs to be aligned.
   * Here we can be a bit looser than the data sections since this
   * needs to only meet arch ABI requirements.
c3dc5bec0   Oskar Schirmer   flat: fix data se...
67
   */
2952095c6   Mike Frysinger   flat: tweak defau...
68
  #define FLAT_STACK_ALIGN	max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN)
c3dc5bec0   Oskar Schirmer   flat: fix data se...
69

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  #define RELOC_FAILED 0xff00ff01		/* Relocation incorrect somewhere */
  #define UNLOADED_LIB 0x7ff000ff		/* Placeholder for unused library */
  
  struct lib_info {
  	struct {
  		unsigned long start_code;		/* Start of text segment */
  		unsigned long start_data;		/* Start of data segment */
  		unsigned long start_brk;		/* End of data segment */
  		unsigned long text_len;			/* Length of text segment */
  		unsigned long entry;			/* Start address for this module */
  		unsigned long build_date;		/* When this one was compiled */
  		short loaded;				/* Has this library been loaded? */
  	} lib_list[MAX_SHARED_LIBS];
  };
  
  #ifdef CONFIG_BINFMT_SHARED_FLAT
  static int load_flat_shared_library(int id, struct lib_info *p);
  #endif
71613c3b8   Al Viro   get rid of pt_reg...
88
  static int load_flat_binary(struct linux_binprm *);
f6151dfea   Masami Hiramatsu   mm: introduce cor...
89
  static int flat_core_dump(struct coredump_params *cprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
  static struct linux_binfmt flat_format = {
  	.module		= THIS_MODULE,
  	.load_binary	= load_flat_binary,
  	.core_dump	= flat_core_dump,
  	.min_coredump	= PAGE_SIZE
  };
  
  /****************************************************************************/
  /*
   * Routine writes a core dump image in the current directory.
   * Currently only a stub-function.
   */
f6151dfea   Masami Hiramatsu   mm: introduce cor...
103
  static int flat_core_dump(struct coredump_params *cprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
  {
  	printk("Process %s:%d received signr %d and should have core dumped
  ",
5ab1c309b   Denys Vlasenko   coredump: pass si...
107
  			current->comm, current->pid, (int) cprm->siginfo->si_signo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  	return(1);
  }
  
  /****************************************************************************/
  /*
   * create_flat_tables() parses the env- and arg-strings in new user
   * memory and creates the pointer tables from them, and puts their
   * addresses on the "stack", returning the new stack pointer value.
   */
  
  static unsigned long create_flat_tables(
  	unsigned long pp,
  	struct linux_binprm * bprm)
  {
  	unsigned long *argv,*envp;
  	unsigned long * sp;
  	char * p = (char*)pp;
  	int argc = bprm->argc;
  	int envc = bprm->envc;
0e647c04f   Andrew Morton   binfmt_flat: warn...
127
  	char uninitialized_var(dummy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

c3dc5bec0   Oskar Schirmer   flat: fix data se...
129
130
  	sp = (unsigned long *)p;
  	sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
2e94de8ac   Mike Frysinger   fs/binfmt_flat.c:...
131
  	sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
c3dc5bec0   Oskar Schirmer   flat: fix data se...
132
133
  	argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
  	envp = argv + (argc + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  	if (flat_argvp_envp_on_stack()) {
c3dc5bec0   Oskar Schirmer   flat: fix data se...
136
137
  		put_user((unsigned long) envp, sp + 2);
  		put_user((unsigned long) argv, sp + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  	}
c3dc5bec0   Oskar Schirmer   flat: fix data se...
139
  	put_user(argc, sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  	current->mm->arg_start = (unsigned long) p;
  	while (argc-->0) {
  		put_user((unsigned long) p, argv++);
  		do {
  			get_user(dummy, p); p++;
  		} while (dummy);
  	}
  	put_user((unsigned long) NULL, argv);
  	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
  	while (envc-->0) {
  		put_user((unsigned long)p, envp); envp++;
  		do {
  			get_user(dummy, p); p++;
  		} while (dummy);
  	}
  	put_user((unsigned long) NULL, envp);
  	current->mm->env_end = (unsigned long) p;
  	return (unsigned long)sp;
  }
  
  /****************************************************************************/
  
  #ifdef CONFIG_BINFMT_ZFLAT
  
  #include <linux/zlib.h>
  
  #define LBUFSIZE	4000
  
  /* gzip flag byte */
  #define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
  #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
  #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
  #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
  #define COMMENT      0x10 /* bit 4 set: file comment present */
  #define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
  #define RESERVED     0xC0 /* bit 6,7:   reserved */
  
  static int decompress_exec(
  	struct linux_binprm *bprm,
  	unsigned long offset,
  	char *dst,
  	long len,
  	int fd)
  {
  	unsigned char *buf;
  	z_stream strm;
  	loff_t fpos;
  	int ret, retval;
  
  	DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)
  ",(int)offset, (int)dst, (int)len);
  
  	memset(&strm, 0, sizeof(strm));
  	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
  	if (strm.workspace == NULL) {
  		DBG_FLT("binfmt_flat: no memory for decompress workspace
  ");
  		return -ENOMEM;
  	}
  	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
  	if (buf == NULL) {
  		DBG_FLT("binfmt_flat: no memory for read buffer
  ");
  		retval = -ENOMEM;
  		goto out_free;
  	}
  
  	/* Read in first chunk of data and parse gzip header. */
  	fpos = offset;
3dc20cb28   Al Viro   new helper: read_...
209
  	ret = kernel_read(bprm->file, offset, buf, LBUFSIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
  
  	strm.next_in = buf;
  	strm.avail_in = ret;
  	strm.total_in = 0;
3dc20cb28   Al Viro   new helper: read_...
214
  	fpos += ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
248
  
  	retval = -ENOEXEC;
  
  	/* Check minimum size -- gzip header */
  	if (ret < 10) {
  		DBG_FLT("binfmt_flat: file too small?
  ");
  		goto out_free_buf;
  	}
  
  	/* Check gzip magic number */
  	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
  		DBG_FLT("binfmt_flat: unknown compression magic?
  ");
  		goto out_free_buf;
  	}
  
  	/* Check gzip method */
  	if (buf[2] != 8) {
  		DBG_FLT("binfmt_flat: unknown compression method?
  ");
  		goto out_free_buf;
  	}
  	/* Check gzip flags */
  	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
  	    (buf[3] & RESERVED)) {
  		DBG_FLT("binfmt_flat: unknown flags?
  ");
  		goto out_free_buf;
  	}
  
  	ret = 10;
  	if (buf[3] & EXTRA_FIELD) {
  		ret += 2 + buf[10] + (buf[11] << 8);
f4cfb18d7   Volodymyr G. Lukiianyk   uclinux: fix gzip...
249
  		if (unlikely(LBUFSIZE <= ret)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
  			DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?
  ");
  			goto out_free_buf;
  		}
  	}
  	if (buf[3] & ORIG_NAME) {
f4cfb18d7   Volodymyr G. Lukiianyk   uclinux: fix gzip...
256
  		while (ret < LBUFSIZE && buf[ret++] != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
263
264
  			;
  		if (unlikely(LBUFSIZE == ret)) {
  			DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?
  ");
  			goto out_free_buf;
  		}
  	}
  	if (buf[3] & COMMENT) {
f4cfb18d7   Volodymyr G. Lukiianyk   uclinux: fix gzip...
265
  		while (ret < LBUFSIZE && buf[ret++] != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  			;
  		if (unlikely(LBUFSIZE == ret)) {
  			DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?
  ");
  			goto out_free_buf;
  		}
  	}
  
  	strm.next_in += ret;
  	strm.avail_in -= ret;
  
  	strm.next_out = dst;
  	strm.avail_out = len;
  	strm.total_out = 0;
  
  	if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
  		DBG_FLT("binfmt_flat: zlib init failed?
  ");
  		goto out_free_buf;
  	}
  
  	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
3dc20cb28   Al Viro   new helper: read_...
288
  		ret = kernel_read(bprm->file, fpos, buf, LBUFSIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  		if (ret <= 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
  		len -= ret;
  
  		strm.next_in = buf;
  		strm.avail_in = ret;
  		strm.total_in = 0;
3dc20cb28   Al Viro   new helper: read_...
296
  		fpos += ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  	}
  
  	if (ret < 0) {
  		DBG_FLT("binfmt_flat: decompression failed (%d), %s
  ",
  			ret, strm.msg);
  		goto out_zlib;
  	}
  
  	retval = 0;
  out_zlib:
  	zlib_inflateEnd(&strm);
  out_free_buf:
  	kfree(buf);
  out_free:
  	kfree(strm.workspace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	return retval;
  }
  
  #endif /* CONFIG_BINFMT_ZFLAT */
  
  /****************************************************************************/
  
  static unsigned long
  calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
  {
  	unsigned long addr;
  	int id;
  	unsigned long start_brk;
  	unsigned long start_data;
  	unsigned long text_len;
  	unsigned long start_code;
  
  #ifdef CONFIG_BINFMT_SHARED_FLAT
  	if (r == 0)
  		id = curid;	/* Relocs of 0 are always self referring */
  	else {
  		id = (r >> 24) & 0xff;	/* Find ID for this reloc */
  		r &= 0x00ffffff;	/* Trim ID off here */
  	}
  	if (id >= MAX_SHARED_LIBS) {
  		printk("BINFMT_FLAT: reference 0x%x to shared library %d",
  				(unsigned) r, id);
  		goto failed;
  	}
  	if (curid != id) {
  		if (internalp) {
  			printk("BINFMT_FLAT: reloc address 0x%x not in same module "
  					"(%d != %d)", (unsigned) r, curid, id);
  			goto failed;
  		} else if ( ! p->lib_list[id].loaded &&
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
348
  				IS_ERR_VALUE(load_flat_shared_library(id, p))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  			printk("BINFMT_FLAT: failed to load library %d", id);
  			goto failed;
  		}
  		/* Check versioning information (i.e. time stamps) */
  		if (p->lib_list[id].build_date && p->lib_list[curid].build_date &&
  				p->lib_list[curid].build_date < p->lib_list[id].build_date) {
  			printk("BINFMT_FLAT: library %d is younger than %d", id, curid);
  			goto failed;
  		}
  	}
  #else
  	id = 0;
  #endif
  
  	start_brk = p->lib_list[id].start_brk;
  	start_data = p->lib_list[id].start_data;
  	start_code = p->lib_list[id].start_code;
  	text_len = p->lib_list[id].text_len;
  
  	if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
  		printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)",
d7dfee3f5   Jun Sun   uclinux: error me...
370
  		       (int) r,(int)(start_brk-start_data+text_len),(int)text_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  		goto failed;
  	}
  
  	if (r < text_len)			/* In text segment */
  		addr = r + start_code;
  	else					/* In data segment */
  		addr = r - text_len + start_data;
  
  	/* Range checked already above so doing the range tests is redundant...*/
  	return(addr);
  
  failed:
  	printk(", killing %s!
  ", current->comm);
  	send_sig(SIGSEGV, current, 0);
  
  	return RELOC_FAILED;
  }
  
  /****************************************************************************/
  
  void old_reloc(unsigned long rl)
  {
  #ifdef DEBUG
  	char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
  #endif
  	flat_v2_reloc_t	r;
  	unsigned long *ptr;
  	
  	r.value = rl;
  #if defined(CONFIG_COLDFIRE)
  	ptr = (unsigned long *) (current->mm->start_code + r.reloc.offset);
  #else
  	ptr = (unsigned long *) (current->mm->start_data + r.reloc.offset);
  #endif
  
  #ifdef DEBUG
  	printk("Relocation of variable at DATASEG+%x "
  		"(address %p, currently %x) into segment %s
  ",
  		r.reloc.offset, ptr, (int)*ptr, segment[r.reloc.type]);
  #endif
  	
  	switch (r.reloc.type) {
  	case OLD_FLAT_RELOC_TYPE_TEXT:
  		*ptr += current->mm->start_code;
  		break;
  	case OLD_FLAT_RELOC_TYPE_DATA:
  		*ptr += current->mm->start_data;
  		break;
  	case OLD_FLAT_RELOC_TYPE_BSS:
  		*ptr += current->mm->end_data;
  		break;
  	default:
  		printk("BINFMT_FLAT: Unknown relocation type=%x
  ", r.reloc.type);
  		break;
  	}
  
  #ifdef DEBUG
  	printk("Relocation became %x
  ", (int)*ptr);
  #endif
  }		
  
  /****************************************************************************/
  
  static int load_flat_file(struct linux_binprm * bprm,
  		struct lib_info *libinfo, int id, unsigned long *extra_stack)
  {
  	struct flat_hdr * hdr;
  	unsigned long textpos = 0, datapos = 0, result;
  	unsigned long realdatastart = 0;
  	unsigned long text_len, data_len, bss_len, stack_len, flags;
3dc20cb28   Al Viro   new helper: read_...
445
  	unsigned long full_data;
0f3e442a4   David Howells   FLAT: Don't attem...
446
447
  	unsigned long len, memp = 0;
  	unsigned long memp_size, extra, rlim;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
  	unsigned long *reloc = 0, *rp;
  	struct inode *inode;
  	int i, rev, relocs = 0;
  	loff_t fpos;
  	unsigned long start_code, end_code;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
453
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  
  	hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
496ad9aa8   Al Viro   new helper: file_...
456
  	inode = file_inode(bprm->file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
461
462
463
464
465
466
467
468
  
  	text_len  = ntohl(hdr->data_start);
  	data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
  	bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
  	stack_len = ntohl(hdr->stack_size);
  	if (extra_stack) {
  		stack_len += *extra_stack;
  		*extra_stack = stack_len;
  	}
  	relocs    = ntohl(hdr->reloc_count);
  	flags     = ntohl(hdr->flags);
  	rev       = ntohl(hdr->rev);
3dc20cb28   Al Viro   new helper: read_...
469
  	full_data = data_len + relocs * sizeof(unsigned long);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470

845884d33   Greg Ungerer   [PATCH] uclinux: ...
471
  	if (strncmp(hdr->magic, "bFLT", 4)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  		/*
e2a366dc5   Mike Frysinger   FLAT binaries: dr...
473
474
475
476
  		 * Previously, here was a printk to tell people
  		 *   "BINFMT_FLAT: bad header magic".
  		 * But for the kernel which also use ELF FD-PIC format, this
  		 * error message is confusing.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  		 * because a lot of people do not manage to produce good
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  		 */
1ad3dcc09   Luke Yang   [PATCH] flat bina...
479
480
  		ret = -ENOEXEC;
  		goto err;
845884d33   Greg Ungerer   [PATCH] uclinux: ...
481
482
483
484
485
486
487
  	}
  
  	if (flags & FLAT_FLAG_KTRACE)
  		printk("BINFMT_FLAT: Loading file: %s
  ", bprm->filename);
  
  	if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
0e647c04f   Andrew Morton   binfmt_flat: warn...
488
489
490
491
  		printk("BINFMT_FLAT: bad flat file version 0x%x (supported "
  			"0x%lx and 0x%lx)
  ",
  			rev, FLAT_VERSION, OLD_FLAT_VERSION);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
492
493
  		ret = -ENOEXEC;
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
  	}
  	
  	/* Don't allow old format executables to use shared libraries */
  	if (rev == OLD_FLAT_VERSION && id != 0) {
  		printk("BINFMT_FLAT: shared libraries are not available before rev 0x%x
  ",
  				(int) FLAT_VERSION);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
501
502
  		ret = -ENOEXEC;
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
509
510
511
512
513
514
515
  	}
  
  	/*
  	 * fix up the flags for the older format,  there were all kinds
  	 * of endian hacks,  this only works for the simple cases
  	 */
  	if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
  		flags = FLAT_FLAG_RAM;
  
  #ifndef CONFIG_BINFMT_ZFLAT
  	if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
  		printk("Support for ZFLAT executables is not enabled.
  ");
1ad3dcc09   Luke Yang   [PATCH] flat bina...
516
517
  		ret = -ENOEXEC;
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
522
523
524
525
  	}
  #endif
  
  	/*
  	 * Check initial limits. This avoids letting people circumvent
  	 * size limits imposed on them by creating programs with large
  	 * arrays in the data or bss.
  	 */
d554ed895   Jiri Slaby   fs: use rlimit he...
526
  	rlim = rlimit(RLIMIT_DATA);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
  	if (rlim >= RLIM_INFINITY)
  		rlim = ~0;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
529
530
531
532
  	if (data_len + bss_len > rlim) {
  		ret = -ENOMEM;
  		goto err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
  	/* Flush all traces of the currently running executable */
  	if (id == 0) {
  		result = flush_old_exec(bprm);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
536
537
  		if (result) {
  			ret = result;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
538
  			goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
539
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
  
  		/* OK, This is the point of no return */
fcc18e83e   Malcolm Parsons   [PATCH] uclinux: ...
542
  		set_personality(PER_LINUX_32BIT);
221af7f87   Linus Torvalds   Split 'flush_old_...
543
  		setup_new_exec(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
  	}
  
  	/*
  	 * calculate the extra space we need to map in
  	 */
0e647c04f   Andrew Morton   binfmt_flat: warn...
549
550
  	extra = max_t(unsigned long, bss_len + stack_len,
  			relocs * sizeof(unsigned long));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
555
556
557
558
559
560
561
562
563
  
  	/*
  	 * there are a couple of cases here,  the separate code/data
  	 * case,  and then the fully copied to RAM case which lumps
  	 * it all together.
  	 */
  	if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
  		/*
  		 * this should give us a ROM ptr,  but if it doesn't we don't
  		 * really care
  		 */
  		DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)
  ");
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
564
  		textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
925d1c401   Matt Helsley   procfs task exe s...
565
  				  MAP_PRIVATE|MAP_EXECUTABLE, 0);
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
566
  		if (!textpos || IS_ERR_VALUE(textpos)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
570
  			if (!textpos)
  				textpos = (unsigned long) -ENOMEM;
  			printk("Unable to mmap process text, errno %d
  ", (int)-textpos);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
571
  			ret = textpos;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
572
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  		}
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
574
  		len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
0f3e442a4   David Howells   FLAT: Don't attem...
575
  		len = PAGE_ALIGN(len);
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
576
  		realdatastart = vm_mmap(0, 0, len,
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
577
  			PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578

0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
579
  		if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
  			if (!realdatastart)
  				realdatastart = (unsigned long) -ENOMEM;
  			printk("Unable to allocate RAM for process data, errno %d
  ",
c287ef1ff   Greg Ungerer   nommu: report cor...
584
  					(int)-realdatastart);
7696e0c37   Al Viro   binfmt_flat: use ...
585
  			vm_munmap(textpos, text_len);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
586
  			ret = realdatastart;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
587
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  		}
c3dc5bec0   Oskar Schirmer   flat: fix data se...
589
590
591
  		datapos = ALIGN(realdatastart +
  				MAX_SHARED_LIBS * sizeof(unsigned long),
  				FLAT_DATA_ALIGN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
598
599
600
  
  		DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x
  ",
  				(int)(data_len + bss_len + stack_len), (int)datapos);
  
  		fpos = ntohl(hdr->data_start);
  #ifdef CONFIG_BINFMT_ZFLAT
  		if (flags & FLAT_FLAG_GZDATA) {
  			result = decompress_exec(bprm, fpos, (char *) datapos, 
3dc20cb28   Al Viro   new helper: read_...
601
  						 full_data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  		} else
  #endif
  		{
3dc20cb28   Al Viro   new helper: read_...
605
606
  			result = read_code(bprm->file, datapos, fpos,
  					full_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  		}
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
608
  		if (IS_ERR_VALUE(result)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  			printk("Unable to read data+bss, errno %d
  ", (int)-result);
7696e0c37   Al Viro   binfmt_flat: use ...
611
612
  			vm_munmap(textpos, text_len);
  			vm_munmap(realdatastart, len);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
613
  			ret = result;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
614
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
  		}
  
  		reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len));
  		memp = realdatastart;
0f3e442a4   David Howells   FLAT: Don't attem...
619
  		memp_size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  	} else {
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
621
  		len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
0f3e442a4   David Howells   FLAT: Don't attem...
622
  		len = PAGE_ALIGN(len);
6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
623
  		textpos = vm_mmap(0, 0, len,
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
624
  			PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
625

0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
626
  		if (!textpos || IS_ERR_VALUE(textpos)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
  			if (!textpos)
  				textpos = (unsigned long) -ENOMEM;
  			printk("Unable to allocate RAM for process text/data, errno %d
  ",
  					(int)-textpos);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
632
  			ret = textpos;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
633
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
  		}
  
  		realdatastart = textpos + ntohl(hdr->data_start);
c3dc5bec0   Oskar Schirmer   flat: fix data se...
637
638
639
640
641
642
  		datapos = ALIGN(realdatastart +
  				MAX_SHARED_LIBS * sizeof(unsigned long),
  				FLAT_DATA_ALIGN);
  
  		reloc = (unsigned long *)
  			(datapos + (ntohl(hdr->reloc_start) - text_len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  		memp = textpos;
0f3e442a4   David Howells   FLAT: Don't attem...
644
  		memp_size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
650
651
  #ifdef CONFIG_BINFMT_ZFLAT
  		/*
  		 * load it all in and treat it like a RAM load from now on
  		 */
  		if (flags & FLAT_FLAG_GZIP) {
  			result = decompress_exec(bprm, sizeof (struct flat_hdr),
  					 (((char *) textpos) + sizeof (struct flat_hdr)),
3dc20cb28   Al Viro   new helper: read_...
652
  					 (text_len + full_data
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
655
  						  - sizeof (struct flat_hdr)),
  					 0);
  			memmove((void *) datapos, (void *) realdatastart,
3dc20cb28   Al Viro   new helper: read_...
656
  					full_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  		} else if (flags & FLAT_FLAG_GZDATA) {
3dc20cb28   Al Viro   new helper: read_...
658
  			result = read_code(bprm->file, textpos, 0, text_len);
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
659
  			if (!IS_ERR_VALUE(result))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  				result = decompress_exec(bprm, text_len, (char *) datapos,
3dc20cb28   Al Viro   new helper: read_...
661
  						 full_data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
  		}
  		else
  #endif
  		{
3dc20cb28   Al Viro   new helper: read_...
666
667
668
669
670
  			result = read_code(bprm->file, textpos, 0, text_len);
  			if (!IS_ERR_VALUE(result))
  				result = read_code(bprm->file, datapos,
  						   ntohl(hdr->data_start),
  						   full_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  		}
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
672
  		if (IS_ERR_VALUE(result)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  			printk("Unable to read code+data+bss, errno %d
  ",(int)-result);
7696e0c37   Al Viro   binfmt_flat: use ...
675
  			vm_munmap(textpos, text_len + data_len + extra +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
  				MAX_SHARED_LIBS * sizeof(unsigned long));
1ad3dcc09   Luke Yang   [PATCH] flat bina...
677
  			ret = result;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
678
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  		}
  	}
  
  	if (flags & FLAT_FLAG_KTRACE)
  		printk("Mapping is %x, Entry point is %x, data_start is %x
  ",
  			(int)textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
  
  	/* The main program needs a little extra setup in the task structure */
  	start_code = textpos + sizeof (struct flat_hdr);
  	end_code = textpos + text_len;
  	if (id == 0) {
  		current->mm->start_code = start_code;
  		current->mm->end_code = end_code;
  		current->mm->start_data = datapos;
  		current->mm->end_data = datapos + data_len;
  		/*
  		 * set up the brk stuff, uses any slack left in data/bss/stack
  		 * allocation.  We put the brk after the bss (between the bss
  		 * and stack) like other platforms.
0f3e442a4   David Howells   FLAT: Don't attem...
699
700
  		 * Userspace code relies on the stack pointer starting out at
  		 * an address right at the end of a page.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
  		 */
  		current->mm->start_brk = datapos + data_len + bss_len;
  		current->mm->brk = (current->mm->start_brk + 3) & ~3;
0f3e442a4   David Howells   FLAT: Don't attem...
704
  		current->mm->context.end_brk = memp + memp_size - stack_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
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
  	}
  
  	if (flags & FLAT_FLAG_KTRACE)
  		printk("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x
  ",
  			id ? "Lib" : "Load", bprm->filename,
  			(int) start_code, (int) end_code,
  			(int) datapos,
  			(int) (datapos + data_len),
  			(int) (datapos + data_len),
  			(int) (((datapos + data_len + bss_len) + 3) & ~3));
  
  	text_len -= sizeof(struct flat_hdr); /* the real code len */
  
  	/* Store the current module values into the global library structure */
  	libinfo->lib_list[id].start_code = start_code;
  	libinfo->lib_list[id].start_data = datapos;
  	libinfo->lib_list[id].start_brk = datapos + data_len + bss_len;
  	libinfo->lib_list[id].text_len = text_len;
  	libinfo->lib_list[id].loaded = 1;
  	libinfo->lib_list[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
  	libinfo->lib_list[id].build_date = ntohl(hdr->build_date);
  	
  	/*
  	 * We just load the allocations into some temporary memory to
  	 * help simplify all this mumbo jumbo
  	 *
  	 * We've got two different sections of relocation entries.
25985edce   Lucas De Marchi   Fix common misspe...
733
  	 * The first is the GOT which resides at the beginning of the data segment
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
739
740
741
742
743
744
  	 * and is terminated with a -1.  This one can be relocated in place.
  	 * The second is the extra relocation entries tacked after the image's
  	 * data segment. These require a little more processing as the entry is
  	 * really an offset into the image which contains an offset into the
  	 * image.
  	 */
  	if (flags & FLAT_FLAG_GOTPIC) {
  		for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) {
  			unsigned long addr;
  			if (*rp) {
  				addr = calc_reloc(*rp, libinfo, id, 0);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
745
746
  				if (addr == RELOC_FAILED) {
  					ret = -ENOEXEC;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
747
  					goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
748
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
  				*rp = addr;
  			}
  		}
  	}
  
  	/*
  	 * Now run through the relocation entries.
  	 * We've got to be careful here as C++ produces relocatable zero
  	 * entries in the constructor and destructor tables which are then
  	 * tested for being not zero (which will always occur unless we're
  	 * based from address zero).  This causes an endless loop as __start
  	 * is at zero.  The solution used is to not relocate zero addresses.
  	 * This has the negative side effect of not allowing a global data
  	 * reference to be statically initialised to _stext (I've moved
  	 * __start to address 4 so that is okay).
  	 */
  	if (rev > OLD_FLAT_VERSION) {
f9720205d   Bernd Schmidt   Binfmt_flat: Add ...
766
  		unsigned long persistent = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
  		for (i=0; i < relocs; i++) {
  			unsigned long addr, relval;
  
  			/* Get the address of the pointer to be
  			   relocated (of course, the address has to be
  			   relocated first).  */
  			relval = ntohl(reloc[i]);
f9720205d   Bernd Schmidt   Binfmt_flat: Add ...
774
775
  			if (flat_set_persistent (relval, &persistent))
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
  			addr = flat_get_relocate_addr(relval);
  			rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
778
779
  			if (rp == (unsigned long *)RELOC_FAILED) {
  				ret = -ENOEXEC;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
780
  				goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
781
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
  
  			/* Get the pointer's value.  */
576bb9ced   Andrew Morton   binfmt_flat: chec...
784
785
  			addr = flat_get_addr_from_rp(rp, relval, flags,
  							&persistent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
793
  			if (addr != 0) {
  				/*
  				 * Do the relocation.  PIC relocs in the data section are
  				 * already in target order
  				 */
  				if ((flags & FLAT_FLAG_GOTPIC) == 0)
  					addr = ntohl(addr);
  				addr = calc_reloc(addr, libinfo, id, 0);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
794
795
  				if (addr == RELOC_FAILED) {
  					ret = -ENOEXEC;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
796
  					goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
797
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
801
802
803
804
805
806
807
808
809
810
811
  
  				/* Write back the relocated pointer.  */
  				flat_put_addr_at_rp(rp, addr, relval);
  			}
  		}
  	} else {
  		for (i=0; i < relocs; i++)
  			old_reloc(ntohl(reloc[i]));
  	}
  	
  	flush_icache_range(start_code, end_code);
  
  	/* zero the BSS,  BRK and stack areas */
  	memset((void*)(datapos + data_len), 0, bss_len + 
0f3e442a4   David Howells   FLAT: Don't attem...
812
813
  			(memp + memp_size - stack_len -		/* end brk */
  			libinfo->lib_list[id].start_brk) +	/* start brk */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
  			stack_len);
  
  	return 0;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
817
818
  err:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
  }
  
  
  /****************************************************************************/
  #ifdef CONFIG_BINFMT_SHARED_FLAT
  
  /*
   * Load a shared library into memory.  The library gets its own data
   * segment (including bss) but not argv/argc/environ.
   */
  
  static int load_flat_shared_library(int id, struct lib_info *libs)
  {
  	struct linux_binprm bprm;
  	int res;
  	char buf[16];
3a852d3bd   David Howells   CRED: Fix load_fl...
835
  	memset(&bprm, 0, sizeof(bprm));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
843
844
  	/* Create the file name */
  	sprintf(buf, "/lib/lib%d.so", id);
  
  	/* Open the file up */
  	bprm.filename = buf;
  	bprm.file = open_exec(bprm.filename);
  	res = PTR_ERR(bprm.file);
  	if (IS_ERR(bprm.file))
  		return res;
3440625d7   Linus Torvalds   flat: fix uniniti...
845
846
847
848
  	bprm.cred = prepare_exec_creds();
  	res = -ENOMEM;
  	if (!bprm.cred)
  		goto out;
3a852d3bd   David Howells   CRED: Fix load_fl...
849
850
851
852
853
  	/* We don't really care about recalculating credentials at this point
  	 * as we're past the point of no return and are dealing with shared
  	 * libraries.
  	 */
  	bprm.cred_prepared = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  	res = prepare_binprm(&bprm);
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
855
  	if (!IS_ERR_VALUE(res))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  		res = load_flat_file(&bprm, libs, id, NULL);
3440625d7   Linus Torvalds   flat: fix uniniti...
857
858
859
860
861
862
  
  	abort_creds(bprm.cred);
  
  out:
  	allow_write_access(bprm.file);
  	fput(bprm.file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
866
867
868
869
870
871
872
  	return(res);
  }
  
  #endif /* CONFIG_BINFMT_SHARED_FLAT */
  /****************************************************************************/
  
  /*
   * These are the functions used to load flat style executables and shared
   * libraries.  There is no binary dependent code anywhere else.
   */
71613c3b8   Al Viro   get rid of pt_reg...
873
  static int load_flat_binary(struct linux_binprm * bprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
  {
  	struct lib_info libinfo;
71613c3b8   Al Viro   get rid of pt_reg...
876
  	struct pt_regs *regs = current_pt_regs();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
  	unsigned long p = bprm->p;
  	unsigned long stack_len;
  	unsigned long start_addr;
  	unsigned long *sp;
  	int res;
  	int i, j;
  
  	memset(&libinfo, 0, sizeof(libinfo));
  	/*
  	 * We have to add the size of our arguments to our stack size
  	 * otherwise it's too easy for users to create stack overflows
  	 * by passing in a huge argument list.  And yes,  we have to be
  	 * pedantic and include space for the argv/envp array as it may have
  	 * a lot of entries.
  	 */
  #define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
  	stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
  	stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
  	stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
2e94de8ac   Mike Frysinger   fs/binfmt_flat.c:...
896
  	stack_len += FLAT_STACK_ALIGN - 1;  /* reserve for upcoming alignment */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
  	
  	res = load_flat_file(bprm, &libinfo, 0, &stack_len);
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
899
  	if (IS_ERR_VALUE(res))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
902
903
904
905
906
907
908
  		return res;
  	
  	/* Update data segment pointers for all libraries */
  	for (i=0; i<MAX_SHARED_LIBS; i++)
  		if (libinfo.lib_list[i].loaded)
  			for (j=0; j<MAX_SHARED_LIBS; j++)
  				(-(j+1))[(unsigned long *)(libinfo.lib_list[i].start_data)] =
  					(libinfo.lib_list[j].loaded)?
  						libinfo.lib_list[j].start_data:UNLOADED_LIB;
a6f76f23d   David Howells   CRED: Make execve...
909
  	install_exec_creds(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
  
  	set_binfmt(&flat_format);
  
  	p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
  	DBG_FLT("p=%x
  ", (int)p);
  
  	/* copy the arg pages onto the stack, this could be more efficient :-) */
  	for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--)
  		* (char *) --p =
  			((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE];
  
  	sp = (unsigned long *) create_flat_tables(p, bprm);
  	
  	/* Fake some return addresses to ensure the call chain will
  	 * initialise library in order for us.  We are required to call
  	 * lib 1 first, then 2, ... and finally the main program (id 0).
  	 */
  	start_addr = libinfo.lib_list[0].entry;
  
  #ifdef CONFIG_BINFMT_SHARED_FLAT
  	for (i = MAX_SHARED_LIBS-1; i>0; i--) {
  		if (libinfo.lib_list[i].loaded) {
  			/* Push previos first to call address */
  			--sp;	put_user(start_addr, sp);
  			start_addr = libinfo.lib_list[i].entry;
  		}
  	}
  #endif
  	
  	/* Stash our initial stack pointer into the mm structure */
  	current->mm->start_stack = (unsigned long )sp;
74c27c43e   Takashi YOSHII   binfmt_flat: Stub...
942
943
944
  #ifdef FLAT_PLAT_INIT
  	FLAT_PLAT_INIT(regs);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
  	DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)
  ",
  		(int)regs, (int)start_addr, (int)current->mm->start_stack);
  	
  	start_thread(regs, start_addr, current->mm->start_stack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
955
956
  	return 0;
  }
  
  /****************************************************************************/
  
  static int __init init_flat_binfmt(void)
  {
8fc3dc5a3   Al Viro   __register_binfmt...
957
958
  	register_binfmt(&flat_format);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
  /****************************************************************************/
  
  core_initcall(init_flat_binfmt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
964
  
  /****************************************************************************/