Blame view

fs/binfmt_flat.c 27.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /****************************************************************************/
  /*
   *  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)
   */
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
18
  #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <linux/kernel.h>
  #include <linux/sched.h>
68db0cf10   Ingo Molnar   sched/headers: Pr...
21
  #include <linux/sched/task_stack.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  #include <linux/mm.h>
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/string.h>
  #include <linux/fs.h>
  #include <linux/file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
  #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>
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
36
  #include <linux/uaccess.h>
472f95f32   Nicolas Pitre   binfmt_flat: allo...
37
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
  
  #include <asm/byteorder.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  #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
  
  /****************************************************************************/
c3dc5bec0   Oskar Schirmer   flat: fix data se...
45
  /*
2e94de8ac   Mike Frysinger   fs/binfmt_flat.c:...
46
47
48
49
50
51
52
53
54
55
56
   * 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...
57
   */
2952095c6   Mike Frysinger   flat: tweak defau...
58
  #define FLAT_STACK_ALIGN	max_t(unsigned long, sizeof(void *), ARCH_SLAB_MINALIGN)
c3dc5bec0   Oskar Schirmer   flat: fix data se...
59

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
68
69
70
  #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 */
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
71
  		bool loaded;				/* Has this library been loaded? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
  	} 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...
78
  static int load_flat_binary(struct linux_binprm *);
f6151dfea   Masami Hiramatsu   mm: introduce cor...
79
  static int flat_core_dump(struct coredump_params *cprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
87
88
89
90
91
92
  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...
93
  static int flat_core_dump(struct coredump_params *cprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
95
96
97
  	pr_warn("Process %s:%d received signr %d and should have core dumped
  ",
  		current->comm, current->pid, cprm->siginfo->si_signo);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
98
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
  }
  
  /****************************************************************************/
  /*
   * create_flat_tables() parses the env- and arg-strings in new user
   * memory and creates the pointer tables from them, and puts their
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
105
   * addresses on the "stack", recording the new stack pointer value.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
   */
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
107
  static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  {
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
109
110
111
  	char __user *p;
  	unsigned long __user *sp;
  	long i, len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112

a97d157d0   Nicolas Pitre   binfmt_flat: clea...
113
114
115
116
117
118
119
120
121
122
123
124
  	p = (char __user *)arg_start;
  	sp = (unsigned long __user *)current->mm->start_stack;
  
  	sp -= bprm->envc + 1;
  	sp -= bprm->argc + 1;
  	sp -= flat_argvp_envp_on_stack() ? 2 : 0;
  	sp -= 1;  /* &argc */
  
  	current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
  	sp = (unsigned long __user *)current->mm->start_stack;
  
  	__put_user(bprm->argc, sp++);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	if (flat_argvp_envp_on_stack()) {
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  		unsigned long argv, envp;
  		argv = (unsigned long)(sp + 2);
  		envp = (unsigned long)(sp + 2 + bprm->argc + 1);
  		__put_user(argv, sp++);
  		__put_user(envp, sp++);
  	}
  
  	current->mm->arg_start = (unsigned long)p;
  	for (i = bprm->argc; i > 0; i--) {
  		__put_user((unsigned long)p, sp++);
  		len = strnlen_user(p, MAX_ARG_STRLEN);
  		if (!len || len > MAX_ARG_STRLEN)
  			return -EINVAL;
  		p += len;
  	}
  	__put_user(0, sp++);
  	current->mm->arg_end = (unsigned long)p;
  
  	current->mm->env_start = (unsigned long) p;
  	for (i = bprm->envc; i > 0; i--) {
  		__put_user((unsigned long)p, sp++);
  		len = strnlen_user(p, MAX_ARG_STRLEN);
  		if (!len || len > MAX_ARG_STRLEN)
  			return -EINVAL;
  		p += len;
  	}
  	__put_user(0, sp++);
  	current->mm->env_end = (unsigned long)p;
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  }
  
  /****************************************************************************/
  
  #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 */
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
174
175
  static int decompress_exec(struct linux_binprm *bprm, loff_t fpos, char *dst,
  		long len, int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
  {
  	unsigned char *buf;
  	z_stream strm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  	int ret, retval;
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
180
181
  	pr_debug("decompress_exec(offset=%llx,buf=%p,len=%lx)
  ", fpos, dst, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  
  	memset(&strm, 0, sizeof(strm));
  	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
9367bb730   Markus Elfring   binfmt_flat: dele...
185
  	if (!strm.workspace)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  		return -ENOMEM;
9367bb730   Markus Elfring   binfmt_flat: dele...
187

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
9367bb730   Markus Elfring   binfmt_flat: dele...
189
  	if (!buf) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
  		retval = -ENOMEM;
  		goto out_free;
  	}
  
  	/* Read in first chunk of data and parse gzip header. */
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
195
  	ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
203
204
  
  	strm.next_in = buf;
  	strm.avail_in = ret;
  	strm.total_in = 0;
  
  	retval = -ENOEXEC;
  
  	/* Check minimum size -- gzip header */
  	if (ret < 10) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
205
206
  		pr_debug("file too small?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
  		goto out_free_buf;
  	}
  
  	/* Check gzip magic number */
  	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
212
213
  		pr_debug("unknown compression magic?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
217
218
  		goto out_free_buf;
  	}
  
  	/* Check gzip method */
  	if (buf[2] != 8) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
219
220
  		pr_debug("unknown compression method?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
  		goto out_free_buf;
  	}
  	/* Check gzip flags */
  	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
  	    (buf[3] & RESERVED)) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
226
227
  		pr_debug("unknown flags?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
  		goto out_free_buf;
  	}
  
  	ret = 10;
  	if (buf[3] & EXTRA_FIELD) {
  		ret += 2 + buf[10] + (buf[11] << 8);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
234
  		if (unlikely(ret >= LBUFSIZE)) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
235
236
  			pr_debug("buffer overflow (EXTRA)?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
  			goto out_free_buf;
  		}
  	}
  	if (buf[3] & ORIG_NAME) {
f4cfb18d7   Volodymyr G. Lukiianyk   uclinux: fix gzip...
241
  		while (ret < LBUFSIZE && buf[ret++] != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  			;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
243
  		if (unlikely(ret == LBUFSIZE)) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
244
245
  			pr_debug("buffer overflow (ORIG_NAME)?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
  			goto out_free_buf;
  		}
  	}
  	if (buf[3] & COMMENT) {
f4cfb18d7   Volodymyr G. Lukiianyk   uclinux: fix gzip...
250
  		while (ret < LBUFSIZE && buf[ret++] != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  			;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
252
  		if (unlikely(ret == LBUFSIZE)) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
253
254
  			pr_debug("buffer overflow (COMMENT)?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
262
263
264
265
266
  			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) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
267
268
  		pr_debug("zlib init failed?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
  		goto out_free_buf;
  	}
  
  	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
273
  		ret = kernel_read(bprm->file, buf, LBUFSIZE, &fpos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
  		if (ret <= 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
282
283
  		len -= ret;
  
  		strm.next_in = buf;
  		strm.avail_in = ret;
  		strm.total_in = 0;
  	}
  
  	if (ret < 0) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
284
285
  		pr_debug("decompression failed (%d), %s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
294
295
296
  			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
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
  	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) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
322
  		pr_err("reference 0x%lx to shared library %d", r, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
  		goto failed;
  	}
  	if (curid != id) {
  		if (internalp) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
327
328
  			pr_err("reloc address 0x%lx not in same module "
  			       "(%d != %d)", r, curid, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  			goto failed;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
330
331
  		} else if (!p->lib_list[id].loaded &&
  			   load_flat_shared_library(id, p) < 0) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
332
  			pr_err("failed to load library %d", id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
  			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) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
338
  			pr_err("library %d is younger than %d", id, curid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
345
346
347
348
349
350
351
  			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)) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
352
  		pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
353
  		       r, start_brk-start_data+text_len, text_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
357
358
359
360
361
362
  		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...*/
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
363
  	return addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  
  failed:
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
366
367
  	pr_cont(", killing %s!
  ", current->comm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
373
  	send_sig(SIGSEGV, current, 0);
  
  	return RELOC_FAILED;
  }
  
  /****************************************************************************/
343034357   Axel Lin   fs/binfmt_flat.c:...
374
  static void old_reloc(unsigned long rl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
376
  	static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  	flat_v2_reloc_t	r;
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
378
379
  	unsigned long __user *ptr;
  	unsigned long val;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
380

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
  	r.value = rl;
  #if defined(CONFIG_COLDFIRE)
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
383
  	ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  #else
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
385
  	ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  #endif
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
387
  	get_user(val, ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
389
390
391
  	pr_debug("Relocation of variable at DATASEG+%x "
  		 "(address %p, currently %lx) into segment %s
  ",
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
392
  		 r.reloc.offset, ptr, val, segment[r.reloc.type]);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
393

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
  	switch (r.reloc.type) {
  	case OLD_FLAT_RELOC_TYPE_TEXT:
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
396
  		val += current->mm->start_code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
  		break;
  	case OLD_FLAT_RELOC_TYPE_DATA:
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
399
  		val += current->mm->start_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  		break;
  	case OLD_FLAT_RELOC_TYPE_BSS:
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
402
  		val += current->mm->end_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  		break;
  	default:
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
405
406
  		pr_err("Unknown relocation type=%x
  ", r.reloc.type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
  		break;
  	}
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
409
  	put_user(val, ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410

1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
411
412
  	pr_debug("Relocation became %lx
  ", val);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
413
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
  
  /****************************************************************************/
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
416
  static int load_flat_file(struct linux_binprm *bprm,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  		struct lib_info *libinfo, int id, unsigned long *extra_stack)
  {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
419
420
  	struct flat_hdr *hdr;
  	unsigned long textpos, datapos, realdatastart;
468138d78   Al Viro   binfmt_flat: flat...
421
  	u32 text_len, data_len, bss_len, stack_len, full_data, flags;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
422
  	unsigned long len, memp, memp_size, extra, rlim;
468138d78   Al Viro   binfmt_flat: flat...
423
  	u32 __user *reloc, *rp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	struct inode *inode;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
425
  	int i, rev, relocs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
  	loff_t fpos;
  	unsigned long start_code, end_code;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
428
  	ssize_t result;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
429
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  
  	hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
496ad9aa8   Al Viro   new helper: file_...
432
  	inode = file_inode(bprm->file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
438
439
440
441
442
443
444
  
  	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_...
445
  	full_data = data_len + relocs * sizeof(unsigned long);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446

845884d33   Greg Ungerer   [PATCH] uclinux: ...
447
  	if (strncmp(hdr->magic, "bFLT", 4)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  		/*
e2a366dc5   Mike Frysinger   FLAT binaries: dr...
449
450
451
452
  		 * 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
453
  		 * because a lot of people do not manage to produce good
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  		 */
1ad3dcc09   Luke Yang   [PATCH] flat bina...
455
456
  		ret = -ENOEXEC;
  		goto err;
845884d33   Greg Ungerer   [PATCH] uclinux: ...
457
458
459
  	}
  
  	if (flags & FLAT_FLAG_KTRACE)
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
460
461
  		pr_info("Loading file: %s
  ", bprm->filename);
845884d33   Greg Ungerer   [PATCH] uclinux: ...
462
463
  
  	if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
464
465
466
  		pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)
  ",
  		       rev, FLAT_VERSION, OLD_FLAT_VERSION);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
467
468
  		ret = -ENOEXEC;
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  	}
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
470

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
  	/* Don't allow old format executables to use shared libraries */
  	if (rev == OLD_FLAT_VERSION && id != 0) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
473
474
475
  		pr_err("shared libraries are not available before rev 0x%lx
  ",
  		       FLAT_VERSION);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
476
477
  		ret = -ENOEXEC;
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
  	}
  
  	/*
c995ee28d   Nicolas Pitre   binfmt_flat: prev...
481
482
483
484
485
486
487
488
489
490
491
492
  	 * Make sure the header params are sane.
  	 * 28 bits (256 MB) is way more than reasonable in this case.
  	 * If some top bits are set we have probable binary corruption.
  	*/
  	if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) {
  		pr_err("bad header
  ");
  		ret = -ENOEXEC;
  		goto err;
  	}
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
498
499
500
  	 * 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)) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
501
502
  		pr_err("Support for ZFLAT executables is not enabled.
  ");
1ad3dcc09   Luke Yang   [PATCH] flat bina...
503
504
  		ret = -ENOEXEC;
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
512
  	}
  #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...
513
  	rlim = rlimit(RLIMIT_DATA);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
  	if (rlim >= RLIM_INFINITY)
  		rlim = ~0;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
516
517
518
519
  	if (data_len + bss_len > rlim) {
  		ret = -ENOMEM;
  		goto err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  	/* Flush all traces of the currently running executable */
  	if (id == 0) {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
522
523
  		ret = flush_old_exec(bprm);
  		if (ret)
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
524
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
  
  		/* OK, This is the point of no return */
fcc18e83e   Malcolm Parsons   [PATCH] uclinux: ...
527
  		set_personality(PER_LINUX_32BIT);
221af7f87   Linus Torvalds   Split 'flush_old_...
528
  		setup_new_exec(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
  	}
  
  	/*
  	 * calculate the extra space we need to map in
  	 */
0e647c04f   Andrew Morton   binfmt_flat: warn...
534
535
  	extra = max_t(unsigned long, bss_len + stack_len,
  			relocs * sizeof(unsigned long));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
540
541
  
  	/*
  	 * 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.
  	 */
015feacf9   Nicolas Pitre   binfmt_flat: add ...
542
  	if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
  		/*
  		 * this should give us a ROM ptr,  but if it doesn't we don't
  		 * really care
  		 */
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
547
548
  		pr_debug("ROM mapping of file (we hope)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

6be5ceb02   Linus Torvalds   VM: add "vm_mmap(...
550
  		textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
925d1c401   Matt Helsley   procfs task exe s...
551
  				  MAP_PRIVATE|MAP_EXECUTABLE, 0);
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
552
  		if (!textpos || IS_ERR_VALUE(textpos)) {
1ad3dcc09   Luke Yang   [PATCH] flat bina...
553
  			ret = textpos;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
554
555
  			if (!textpos)
  				ret = -ENOMEM;
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
556
557
  			pr_err("Unable to mmap process text, errno %d
  ", ret);
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
558
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  		}
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
560
  		len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
0f3e442a4   David Howells   FLAT: Don't attem...
561
  		len = PAGE_ALIGN(len);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
562
  		realdatastart = vm_mmap(NULL, 0, len,
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
563
  			PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
565
  		if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
566
  			ret = realdatastart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
  			if (!realdatastart)
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
568
  				ret = -ENOMEM;
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
569
  			pr_err("Unable to allocate RAM for process data, "
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
570
571
  			       "errno %d
  ", ret);
7696e0c37   Al Viro   binfmt_flat: use ...
572
  			vm_munmap(textpos, text_len);
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
573
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  		}
c3dc5bec0   Oskar Schirmer   flat: fix data se...
575
576
577
  		datapos = ALIGN(realdatastart +
  				MAX_SHARED_LIBS * sizeof(unsigned long),
  				FLAT_DATA_ALIGN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578

a86054236   Geert Uytterhoeven   binfmt_flat: Use ...
579
580
  		pr_debug("Allocated data+bss+stack (%u bytes): %lx
  ",
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
581
  			 data_len + bss_len + stack_len, datapos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
  
  		fpos = ntohl(hdr->data_start);
  #ifdef CONFIG_BINFMT_ZFLAT
  		if (flags & FLAT_FLAG_GZDATA) {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
586
  			result = decompress_exec(bprm, fpos, (char *)datapos,
3dc20cb28   Al Viro   new helper: read_...
587
  						 full_data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
  		} else
  #endif
  		{
3dc20cb28   Al Viro   new helper: read_...
591
592
  			result = read_code(bprm->file, datapos, fpos,
  					full_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  		}
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
594
  		if (IS_ERR_VALUE(result)) {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
595
  			ret = result;
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
596
597
  			pr_err("Unable to read data+bss, errno %d
  ", ret);
7696e0c37   Al Viro   binfmt_flat: use ...
598
599
  			vm_munmap(textpos, text_len);
  			vm_munmap(realdatastart, len);
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
600
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  		}
468138d78   Al Viro   binfmt_flat: flat...
602
  		reloc = (u32 __user *)
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
603
  			(datapos + (ntohl(hdr->reloc_start) - text_len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  		memp = realdatastart;
0f3e442a4   David Howells   FLAT: Don't attem...
605
  		memp_size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  	} else {
468138d78   Al Viro   binfmt_flat: flat...
607
  		len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32);
0f3e442a4   David Howells   FLAT: Don't attem...
608
  		len = PAGE_ALIGN(len);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
609
  		textpos = vm_mmap(NULL, 0, len,
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
610
  			PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
72613e5f4   Greg Ungerer   [PATCH] uclinux: ...
611

0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
612
  		if (!textpos || IS_ERR_VALUE(textpos)) {
1ad3dcc09   Luke Yang   [PATCH] flat bina...
613
  			ret = textpos;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
614
615
  			if (!textpos)
  				ret = -ENOMEM;
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
616
  			pr_err("Unable to allocate RAM for process text/data, "
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
617
618
  			       "errno %d
  ", ret);
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
619
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
  		}
  
  		realdatastart = textpos + ntohl(hdr->data_start);
c3dc5bec0   Oskar Schirmer   flat: fix data se...
623
  		datapos = ALIGN(realdatastart +
468138d78   Al Viro   binfmt_flat: flat...
624
  				MAX_SHARED_LIBS * sizeof(u32),
c3dc5bec0   Oskar Schirmer   flat: fix data se...
625
  				FLAT_DATA_ALIGN);
468138d78   Al Viro   binfmt_flat: flat...
626
  		reloc = (u32 __user *)
c3dc5bec0   Oskar Schirmer   flat: fix data se...
627
  			(datapos + (ntohl(hdr->reloc_start) - text_len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  		memp = textpos;
0f3e442a4   David Howells   FLAT: Don't attem...
629
  		memp_size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
  #ifdef CONFIG_BINFMT_ZFLAT
  		/*
  		 * load it all in and treat it like a RAM load from now on
  		 */
  		if (flags & FLAT_FLAG_GZIP) {
472f95f32   Nicolas Pitre   binfmt_flat: allo...
635
  #ifndef CONFIG_MMU
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
636
637
  			result = decompress_exec(bprm, sizeof(struct flat_hdr),
  					 (((char *)textpos) + sizeof(struct flat_hdr)),
3dc20cb28   Al Viro   new helper: read_...
638
  					 (text_len + full_data
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
639
  						  - sizeof(struct flat_hdr)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
  					 0);
  			memmove((void *) datapos, (void *) realdatastart,
3dc20cb28   Al Viro   new helper: read_...
642
  					full_data);
472f95f32   Nicolas Pitre   binfmt_flat: allo...
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  #else
  			/*
  			 * This is used on MMU systems mainly for testing.
  			 * Let's use a kernel buffer to simplify things.
  			 */
  			long unz_text_len = text_len - sizeof(struct flat_hdr);
  			long unz_len = unz_text_len + full_data;
  			char *unz_data = vmalloc(unz_len);
  			if (!unz_data) {
  				result = -ENOMEM;
  			} else {
  				result = decompress_exec(bprm, sizeof(struct flat_hdr),
  							 unz_data, unz_len, 0);
  				if (result == 0 &&
  				    (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr),
  						  unz_data, unz_text_len) ||
  				     copy_to_user((void __user *)datapos,
  						  unz_data + unz_text_len, full_data)))
  					result = -EFAULT;
  				vfree(unz_data);
  			}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  		} else if (flags & FLAT_FLAG_GZDATA) {
3dc20cb28   Al Viro   new helper: read_...
666
  			result = read_code(bprm->file, textpos, 0, text_len);
472f95f32   Nicolas Pitre   binfmt_flat: allo...
667
668
  			if (!IS_ERR_VALUE(result)) {
  #ifndef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  				result = decompress_exec(bprm, text_len, (char *) datapos,
3dc20cb28   Al Viro   new helper: read_...
670
  						 full_data, 0);
472f95f32   Nicolas Pitre   binfmt_flat: allo...
671
672
673
674
675
676
677
678
679
680
681
682
683
  #else
  				char *unz_data = vmalloc(full_data);
  				if (!unz_data) {
  					result = -ENOMEM;
  				} else {
  					result = decompress_exec(bprm, text_len,
  						       unz_data, full_data, 0);
  					if (result == 0 &&
  					    copy_to_user((void __user *)datapos,
  							 unz_data, full_data))
  						result = -EFAULT;
  					vfree(unz_data);
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  #endif
472f95f32   Nicolas Pitre   binfmt_flat: allo...
685
686
687
  			}
  		} else
  #endif /* CONFIG_BINFMT_ZFLAT */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  		{
3dc20cb28   Al Viro   new helper: read_...
689
690
691
692
693
  			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
694
  		}
0b8c78f2b   Mike Frysinger   flat: use IS_ERR_...
695
  		if (IS_ERR_VALUE(result)) {
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
696
  			ret = result;
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
697
698
  			pr_err("Unable to read code+data+bss, errno %d
  ", ret);
7696e0c37   Al Viro   binfmt_flat: use ...
699
  			vm_munmap(textpos, text_len + data_len + extra +
468138d78   Al Viro   binfmt_flat: flat...
700
  				MAX_SHARED_LIBS * sizeof(u32));
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
701
  			goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  		}
  	}
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
704
705
706
  	start_code = textpos + sizeof(struct flat_hdr);
  	end_code = textpos + text_len;
  	text_len -= sizeof(struct flat_hdr); /* the real code len */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
  
  	/* The main program needs a little extra setup in the task structure */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
713
714
715
716
717
  	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...
718
719
  		 * 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
720
721
722
  		 */
  		current->mm->start_brk = datapos + data_len + bss_len;
  		current->mm->brk = (current->mm->start_brk + 3) & ~3;
015feacf9   Nicolas Pitre   binfmt_flat: add ...
723
  #ifndef CONFIG_MMU
0f3e442a4   David Howells   FLAT: Don't attem...
724
  		current->mm->context.end_brk = memp + memp_size - stack_len;
015feacf9   Nicolas Pitre   binfmt_flat: add ...
725
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	}
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
727
  	if (flags & FLAT_FLAG_KTRACE) {
4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
728
729
730
731
732
733
734
735
  		pr_info("Mapping is %lx, Entry point is %x, data_start is %x
  ",
  			textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
  		pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx
  ",
  			id ? "Lib" : "Load", bprm->filename,
  			start_code, end_code, datapos, datapos + data_len,
  			datapos + data_len, (datapos + data_len + bss_len + 3) & ~3);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
736
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
741
742
743
744
745
  
  	/* 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);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
746

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
  	/*
  	 * 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...
752
  	 * The first is the GOT which resides at the beginning of the data segment
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
759
  	 * 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) {
468138d78   Al Viro   binfmt_flat: flat...
760
761
  		for (rp = (u32 __user *)datapos; ; rp++) {
  			u32 addr, rp_val;
6e572ffe3   Nicolas Pitre   binfmt_flat: use ...
762
763
764
765
766
767
  			if (get_user(rp_val, rp))
  				return -EFAULT;
  			if (rp_val == 0xffffffff)
  				break;
  			if (rp_val) {
  				addr = calc_reloc(rp_val, libinfo, id, 0);
1ad3dcc09   Luke Yang   [PATCH] flat bina...
768
769
  				if (addr == RELOC_FAILED) {
  					ret = -ENOEXEC;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
770
  					goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
771
  				}
6e572ffe3   Nicolas Pitre   binfmt_flat: use ...
772
773
  				if (put_user(addr, rp))
  					return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
  			}
  		}
  	}
  
  	/*
  	 * 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) {
468138d78   Al Viro   binfmt_flat: flat...
790
  		u32 __maybe_unused persistent = 0;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
791
  		for (i = 0; i < relocs; i++) {
468138d78   Al Viro   binfmt_flat: flat...
792
  			u32 addr, relval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793

13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
794
795
796
797
798
  			/*
  			 * Get the address of the pointer to be
  			 * relocated (of course, the address has to be
  			 * relocated first).
  			 */
6e572ffe3   Nicolas Pitre   binfmt_flat: use ...
799
800
801
  			if (get_user(relval, reloc + i))
  				return -EFAULT;
  			relval = ntohl(relval);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
802
  			if (flat_set_persistent(relval, &persistent))
f9720205d   Bernd Schmidt   Binfmt_flat: Add ...
803
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  			addr = flat_get_relocate_addr(relval);
468138d78   Al Viro   binfmt_flat: flat...
805
806
  			rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1);
  			if (rp == (u32 __user *)RELOC_FAILED) {
1ad3dcc09   Luke Yang   [PATCH] flat bina...
807
  				ret = -ENOEXEC;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
808
  				goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
809
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  
  			/* Get the pointer's value.  */
468138d78   Al Viro   binfmt_flat: flat...
812
813
814
815
  			ret = flat_get_addr_from_rp(rp, relval, flags,
  							&addr, &persistent);
  			if (unlikely(ret))
  				goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
821
822
823
  			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...
824
825
  				if (addr == RELOC_FAILED) {
  					ret = -ENOEXEC;
df88912a2   Andrew Morton   [PATCH] binfmt_fl...
826
  					goto err;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
827
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
  
  				/* Write back the relocated pointer.  */
468138d78   Al Viro   binfmt_flat: flat...
830
831
832
  				ret = flat_put_addr_at_rp(rp, addr, relval);
  				if (unlikely(ret))
  					goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
  			}
  		}
  	} else {
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
836
  		for (i = 0; i < relocs; i++) {
468138d78   Al Viro   binfmt_flat: flat...
837
  			u32 relval;
1b2ce442e   Nicolas Pitre   binfmt_flat: use ...
838
839
840
841
842
  			if (get_user(relval, reloc + i))
  				return -EFAULT;
  			relval = ntohl(relval);
  			old_reloc(relval);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  	}
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
844

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
  	flush_icache_range(start_code, end_code);
  
  	/* zero the BSS,  BRK and stack areas */
467aa1465   Nicolas Pitre   binfmt_flat: use ...
848
849
850
851
852
  	if (clear_user((void __user *)(datapos + data_len), bss_len +
  		       (memp + memp_size - stack_len -		/* end brk */
  		       libinfo->lib_list[id].start_brk) +	/* start brk */
  		       stack_len))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
  
  	return 0;
1ad3dcc09   Luke Yang   [PATCH] flat bina...
855
856
  err:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
  }
  
  
  /****************************************************************************/
  #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...
873
  	memset(&bprm, 0, sizeof(bprm));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
881
882
  	/* 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...
883
884
885
886
  	bprm.cred = prepare_exec_creds();
  	res = -ENOMEM;
  	if (!bprm.cred)
  		goto out;
3a852d3bd   David Howells   CRED: Fix load_fl...
887
888
889
890
  	/* 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.
  	 */
ddb4a1442   Kees Cook   exec: Rename bprm...
891
  	bprm.called_set_creds = 1;
3a852d3bd   David Howells   CRED: Fix load_fl...
892

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  	res = prepare_binprm(&bprm);
287980e49   Arnd Bergmann   remove lots of IS...
894
  	if (!res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  		res = load_flat_file(&bprm, libs, id, NULL);
3440625d7   Linus Torvalds   flat: fix uniniti...
896
897
898
899
900
901
  
  	abort_creds(bprm.cred);
  
  out:
  	allow_write_access(bprm.file);
  	fput(bprm.file);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
902
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
907
908
909
910
911
  }
  
  #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.
   */
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
912
  static int load_flat_binary(struct linux_binprm *bprm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
  {
  	struct lib_info libinfo;
71613c3b8   Al Viro   get rid of pt_reg...
915
  	struct pt_regs *regs = current_pt_regs();
015feacf9   Nicolas Pitre   binfmt_flat: add ...
916
  	unsigned long stack_len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  	unsigned long start_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
921
  	int res;
  	int i, j;
  
  	memset(&libinfo, 0, sizeof(libinfo));
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
922

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
925
926
927
928
929
  	/*
  	 * 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.
  	 */
015feacf9   Nicolas Pitre   binfmt_flat: add ...
930
931
932
  #ifndef CONFIG_MMU
  	stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
  #endif
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
933
934
935
  	stack_len += (bprm->argc + 1) * sizeof(char *);   /* the argv array */
  	stack_len += (bprm->envc + 1) * sizeof(char *);   /* the envp array */
  	stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
936

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
  	res = load_flat_file(bprm, &libinfo, 0, &stack_len);
287980e49   Arnd Bergmann   remove lots of IS...
938
  	if (res < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  		return res;
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
940

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  	/* Update data segment pointers for all libraries */
af521f92d   Nicolas Pitre   binfmt_flat: upda...
942
943
944
945
946
947
948
949
950
951
952
953
954
  	for (i = 0; i < MAX_SHARED_LIBS; i++) {
  		if (!libinfo.lib_list[i].loaded)
  			continue;
  		for (j = 0; j < MAX_SHARED_LIBS; j++) {
  			unsigned long val = libinfo.lib_list[j].loaded ?
  				libinfo.lib_list[j].start_data : UNLOADED_LIB;
  			unsigned long __user *p = (unsigned long __user *)
  				libinfo.lib_list[i].start_data;
  			p -= j + 1;
  			if (put_user(val, p))
  				return -EFAULT;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955

a6f76f23d   David Howells   CRED: Make execve...
956
  	install_exec_creds(bprm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
  
  	set_binfmt(&flat_format);
015feacf9   Nicolas Pitre   binfmt_flat: add ...
959
960
961
962
963
  #ifdef CONFIG_MMU
  	res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
  	if (!res)
  		res = create_flat_tables(bprm, bprm->p);
  #else
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
964
965
966
967
968
  	/* Stash our initial stack pointer into the mm structure */
  	current->mm->start_stack =
  		((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
  	pr_debug("sp=%lx
  ", current->mm->start_stack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969

687fd7738   Nicolas Pitre   binfmt_flat: use ...
970
  	/* copy the arg pages onto the stack */
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
971
972
973
  	res = transfer_args_to_stack(bprm, &current->mm->start_stack);
  	if (!res)
  		res = create_flat_tables(bprm, current->mm->start_stack);
015feacf9   Nicolas Pitre   binfmt_flat: add ...
974
  #endif
687fd7738   Nicolas Pitre   binfmt_flat: use ...
975
976
  	if (res)
  		return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
979
980
981
982
983
984
  	/* 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
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
985
  	for (i = MAX_SHARED_LIBS-1; i > 0; i--) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
  		if (libinfo.lib_list[i].loaded) {
  			/* Push previos first to call address */
a97d157d0   Nicolas Pitre   binfmt_flat: clea...
988
989
990
991
  			unsigned long __user *sp;
  			current->mm->start_stack -= sizeof(unsigned long);
  			sp = (unsigned long __user *)current->mm->start_stack;
  			__put_user(start_addr, sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
994
995
  			start_addr = libinfo.lib_list[i].entry;
  		}
  	}
  #endif
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
996

74c27c43e   Takashi YOSHII   binfmt_flat: Stub...
997
998
999
  #ifdef FLAT_PLAT_INIT
  	FLAT_PLAT_INIT(regs);
  #endif
13c3f50c9   Nicolas Pitre   binfmt_flat: asso...
1000

4adbb6ac4   Nicolas Pitre   binfmt_flat: conv...
1001
1002
1003
  	pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)
  ",
  		 regs, start_addr, current->mm->start_stack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
  	start_thread(regs, start_addr, current->mm->start_stack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
1007
1008
1009
1010
1011
  	return 0;
  }
  
  /****************************************************************************/
  
  static int __init init_flat_binfmt(void)
  {
8fc3dc5a3   Al Viro   __register_binfmt...
1012
1013
  	register_binfmt(&flat_format);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
  core_initcall(init_flat_binfmt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
  
  /****************************************************************************/