Commit 079148b919d0c58b796f9ae98bdb53028dbcd5e7
Committed by
Linus Torvalds
1 parent
528f827ee0
Exists in
master
and in
20 other branches
coredump: factor out the setting of PF_DUMPCORE
Cleanup. Every linux_binfmt->core_dump() sets PF_DUMPCORE, move this into zap_threads() called by do_coredump(). Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Mandeep Singh Baines <msb@chromium.org> Cc: Neil Horman <nhorman@redhat.com> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Cc: Tejun Heo <tj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 5 changed files with 2 additions and 6 deletions Inline Diff
arch/x86/ia32/ia32_aout.c
1 | /* | 1 | /* |
2 | * a.out loader for x86-64 | 2 | * a.out loader for x86-64 |
3 | * | 3 | * |
4 | * Copyright (C) 1991, 1992, 1996 Linus Torvalds | 4 | * Copyright (C) 1991, 1992, 1996 Linus Torvalds |
5 | * Hacked together by Andi Kleen | 5 | * Hacked together by Andi Kleen |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | 9 | ||
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/mman.h> | 13 | #include <linux/mman.h> |
14 | #include <linux/a.out.h> | 14 | #include <linux/a.out.h> |
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/signal.h> | 16 | #include <linux/signal.h> |
17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/file.h> | 19 | #include <linux/file.h> |
20 | #include <linux/stat.h> | 20 | #include <linux/stat.h> |
21 | #include <linux/fcntl.h> | 21 | #include <linux/fcntl.h> |
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/user.h> | 23 | #include <linux/user.h> |
24 | #include <linux/binfmts.h> | 24 | #include <linux/binfmts.h> |
25 | #include <linux/personality.h> | 25 | #include <linux/personality.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/jiffies.h> | 27 | #include <linux/jiffies.h> |
28 | 28 | ||
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | #include <asm/pgalloc.h> | 30 | #include <asm/pgalloc.h> |
31 | #include <asm/cacheflush.h> | 31 | #include <asm/cacheflush.h> |
32 | #include <asm/user32.h> | 32 | #include <asm/user32.h> |
33 | #include <asm/ia32.h> | 33 | #include <asm/ia32.h> |
34 | 34 | ||
35 | #undef WARN_OLD | 35 | #undef WARN_OLD |
36 | #undef CORE_DUMP /* definitely broken */ | 36 | #undef CORE_DUMP /* definitely broken */ |
37 | 37 | ||
38 | static int load_aout_binary(struct linux_binprm *); | 38 | static int load_aout_binary(struct linux_binprm *); |
39 | static int load_aout_library(struct file *); | 39 | static int load_aout_library(struct file *); |
40 | 40 | ||
41 | #ifdef CORE_DUMP | 41 | #ifdef CORE_DUMP |
42 | static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, | 42 | static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, |
43 | unsigned long limit); | 43 | unsigned long limit); |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * fill in the user structure for a core dump.. | 46 | * fill in the user structure for a core dump.. |
47 | */ | 47 | */ |
48 | static void dump_thread32(struct pt_regs *regs, struct user32 *dump) | 48 | static void dump_thread32(struct pt_regs *regs, struct user32 *dump) |
49 | { | 49 | { |
50 | u32 fs, gs; | 50 | u32 fs, gs; |
51 | 51 | ||
52 | /* changed the size calculations - should hopefully work better. lbt */ | 52 | /* changed the size calculations - should hopefully work better. lbt */ |
53 | dump->magic = CMAGIC; | 53 | dump->magic = CMAGIC; |
54 | dump->start_code = 0; | 54 | dump->start_code = 0; |
55 | dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); | 55 | dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); |
56 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; | 56 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; |
57 | dump->u_dsize = ((unsigned long) | 57 | dump->u_dsize = ((unsigned long) |
58 | (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; | 58 | (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; |
59 | dump->u_dsize -= dump->u_tsize; | 59 | dump->u_dsize -= dump->u_tsize; |
60 | dump->u_ssize = 0; | 60 | dump->u_ssize = 0; |
61 | dump->u_debugreg[0] = current->thread.debugreg0; | 61 | dump->u_debugreg[0] = current->thread.debugreg0; |
62 | dump->u_debugreg[1] = current->thread.debugreg1; | 62 | dump->u_debugreg[1] = current->thread.debugreg1; |
63 | dump->u_debugreg[2] = current->thread.debugreg2; | 63 | dump->u_debugreg[2] = current->thread.debugreg2; |
64 | dump->u_debugreg[3] = current->thread.debugreg3; | 64 | dump->u_debugreg[3] = current->thread.debugreg3; |
65 | dump->u_debugreg[4] = 0; | 65 | dump->u_debugreg[4] = 0; |
66 | dump->u_debugreg[5] = 0; | 66 | dump->u_debugreg[5] = 0; |
67 | dump->u_debugreg[6] = current->thread.debugreg6; | 67 | dump->u_debugreg[6] = current->thread.debugreg6; |
68 | dump->u_debugreg[7] = current->thread.debugreg7; | 68 | dump->u_debugreg[7] = current->thread.debugreg7; |
69 | 69 | ||
70 | if (dump->start_stack < 0xc0000000) { | 70 | if (dump->start_stack < 0xc0000000) { |
71 | unsigned long tmp; | 71 | unsigned long tmp; |
72 | 72 | ||
73 | tmp = (unsigned long) (0xc0000000 - dump->start_stack); | 73 | tmp = (unsigned long) (0xc0000000 - dump->start_stack); |
74 | dump->u_ssize = tmp >> PAGE_SHIFT; | 74 | dump->u_ssize = tmp >> PAGE_SHIFT; |
75 | } | 75 | } |
76 | 76 | ||
77 | dump->regs.bx = regs->bx; | 77 | dump->regs.bx = regs->bx; |
78 | dump->regs.cx = regs->cx; | 78 | dump->regs.cx = regs->cx; |
79 | dump->regs.dx = regs->dx; | 79 | dump->regs.dx = regs->dx; |
80 | dump->regs.si = regs->si; | 80 | dump->regs.si = regs->si; |
81 | dump->regs.di = regs->di; | 81 | dump->regs.di = regs->di; |
82 | dump->regs.bp = regs->bp; | 82 | dump->regs.bp = regs->bp; |
83 | dump->regs.ax = regs->ax; | 83 | dump->regs.ax = regs->ax; |
84 | dump->regs.ds = current->thread.ds; | 84 | dump->regs.ds = current->thread.ds; |
85 | dump->regs.es = current->thread.es; | 85 | dump->regs.es = current->thread.es; |
86 | savesegment(fs, fs); | 86 | savesegment(fs, fs); |
87 | dump->regs.fs = fs; | 87 | dump->regs.fs = fs; |
88 | savesegment(gs, gs); | 88 | savesegment(gs, gs); |
89 | dump->regs.gs = gs; | 89 | dump->regs.gs = gs; |
90 | dump->regs.orig_ax = regs->orig_ax; | 90 | dump->regs.orig_ax = regs->orig_ax; |
91 | dump->regs.ip = regs->ip; | 91 | dump->regs.ip = regs->ip; |
92 | dump->regs.cs = regs->cs; | 92 | dump->regs.cs = regs->cs; |
93 | dump->regs.flags = regs->flags; | 93 | dump->regs.flags = regs->flags; |
94 | dump->regs.sp = regs->sp; | 94 | dump->regs.sp = regs->sp; |
95 | dump->regs.ss = regs->ss; | 95 | dump->regs.ss = regs->ss; |
96 | 96 | ||
97 | #if 1 /* FIXME */ | 97 | #if 1 /* FIXME */ |
98 | dump->u_fpvalid = 0; | 98 | dump->u_fpvalid = 0; |
99 | #else | 99 | #else |
100 | dump->u_fpvalid = dump_fpu(regs, &dump->i387); | 100 | dump->u_fpvalid = dump_fpu(regs, &dump->i387); |
101 | #endif | 101 | #endif |
102 | } | 102 | } |
103 | 103 | ||
104 | #endif | 104 | #endif |
105 | 105 | ||
106 | static struct linux_binfmt aout_format = { | 106 | static struct linux_binfmt aout_format = { |
107 | .module = THIS_MODULE, | 107 | .module = THIS_MODULE, |
108 | .load_binary = load_aout_binary, | 108 | .load_binary = load_aout_binary, |
109 | .load_shlib = load_aout_library, | 109 | .load_shlib = load_aout_library, |
110 | #ifdef CORE_DUMP | 110 | #ifdef CORE_DUMP |
111 | .core_dump = aout_core_dump, | 111 | .core_dump = aout_core_dump, |
112 | #endif | 112 | #endif |
113 | .min_coredump = PAGE_SIZE | 113 | .min_coredump = PAGE_SIZE |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static void set_brk(unsigned long start, unsigned long end) | 116 | static void set_brk(unsigned long start, unsigned long end) |
117 | { | 117 | { |
118 | start = PAGE_ALIGN(start); | 118 | start = PAGE_ALIGN(start); |
119 | end = PAGE_ALIGN(end); | 119 | end = PAGE_ALIGN(end); |
120 | if (end <= start) | 120 | if (end <= start) |
121 | return; | 121 | return; |
122 | vm_brk(start, end - start); | 122 | vm_brk(start, end - start); |
123 | } | 123 | } |
124 | 124 | ||
125 | #ifdef CORE_DUMP | 125 | #ifdef CORE_DUMP |
126 | /* | 126 | /* |
127 | * These are the only things you should do on a core-file: use only these | 127 | * These are the only things you should do on a core-file: use only these |
128 | * macros to write out all the necessary info. | 128 | * macros to write out all the necessary info. |
129 | */ | 129 | */ |
130 | 130 | ||
131 | #include <linux/coredump.h> | 131 | #include <linux/coredump.h> |
132 | 132 | ||
133 | #define DUMP_WRITE(addr, nr) \ | 133 | #define DUMP_WRITE(addr, nr) \ |
134 | if (!dump_write(file, (void *)(addr), (nr))) \ | 134 | if (!dump_write(file, (void *)(addr), (nr))) \ |
135 | goto end_coredump; | 135 | goto end_coredump; |
136 | 136 | ||
137 | #define DUMP_SEEK(offset) \ | 137 | #define DUMP_SEEK(offset) \ |
138 | if (!dump_seek(file, offset)) \ | 138 | if (!dump_seek(file, offset)) \ |
139 | goto end_coredump; | 139 | goto end_coredump; |
140 | 140 | ||
141 | #define START_DATA() (u.u_tsize << PAGE_SHIFT) | 141 | #define START_DATA() (u.u_tsize << PAGE_SHIFT) |
142 | #define START_STACK(u) (u.start_stack) | 142 | #define START_STACK(u) (u.start_stack) |
143 | 143 | ||
144 | /* | 144 | /* |
145 | * Routine writes a core dump image in the current directory. | 145 | * Routine writes a core dump image in the current directory. |
146 | * Currently only a stub-function. | 146 | * Currently only a stub-function. |
147 | * | 147 | * |
148 | * Note that setuid/setgid files won't make a core-dump if the uid/gid | 148 | * Note that setuid/setgid files won't make a core-dump if the uid/gid |
149 | * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable" | 149 | * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable" |
150 | * field, which also makes sure the core-dumps won't be recursive if the | 150 | * field, which also makes sure the core-dumps won't be recursive if the |
151 | * dumping of the process results in another error.. | 151 | * dumping of the process results in another error.. |
152 | */ | 152 | */ |
153 | 153 | ||
154 | static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, | 154 | static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, |
155 | unsigned long limit) | 155 | unsigned long limit) |
156 | { | 156 | { |
157 | mm_segment_t fs; | 157 | mm_segment_t fs; |
158 | int has_dumped = 0; | 158 | int has_dumped = 0; |
159 | unsigned long dump_start, dump_size; | 159 | unsigned long dump_start, dump_size; |
160 | struct user32 dump; | 160 | struct user32 dump; |
161 | 161 | ||
162 | fs = get_fs(); | 162 | fs = get_fs(); |
163 | set_fs(KERNEL_DS); | 163 | set_fs(KERNEL_DS); |
164 | has_dumped = 1; | 164 | has_dumped = 1; |
165 | current->flags |= PF_DUMPCORE; | ||
166 | strncpy(dump.u_comm, current->comm, sizeof(current->comm)); | 165 | strncpy(dump.u_comm, current->comm, sizeof(current->comm)); |
167 | dump.u_ar0 = offsetof(struct user32, regs); | 166 | dump.u_ar0 = offsetof(struct user32, regs); |
168 | dump.signal = signr; | 167 | dump.signal = signr; |
169 | dump_thread32(regs, &dump); | 168 | dump_thread32(regs, &dump); |
170 | 169 | ||
171 | /* | 170 | /* |
172 | * If the size of the dump file exceeds the rlimit, then see | 171 | * If the size of the dump file exceeds the rlimit, then see |
173 | * what would happen if we wrote the stack, but not the data | 172 | * what would happen if we wrote the stack, but not the data |
174 | * area. | 173 | * area. |
175 | */ | 174 | */ |
176 | if ((dump.u_dsize + dump.u_ssize + 1) * PAGE_SIZE > limit) | 175 | if ((dump.u_dsize + dump.u_ssize + 1) * PAGE_SIZE > limit) |
177 | dump.u_dsize = 0; | 176 | dump.u_dsize = 0; |
178 | 177 | ||
179 | /* Make sure we have enough room to write the stack and data areas. */ | 178 | /* Make sure we have enough room to write the stack and data areas. */ |
180 | if ((dump.u_ssize + 1) * PAGE_SIZE > limit) | 179 | if ((dump.u_ssize + 1) * PAGE_SIZE > limit) |
181 | dump.u_ssize = 0; | 180 | dump.u_ssize = 0; |
182 | 181 | ||
183 | /* make sure we actually have a data and stack area to dump */ | 182 | /* make sure we actually have a data and stack area to dump */ |
184 | set_fs(USER_DS); | 183 | set_fs(USER_DS); |
185 | if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_DATA(dump), | 184 | if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_DATA(dump), |
186 | dump.u_dsize << PAGE_SHIFT)) | 185 | dump.u_dsize << PAGE_SHIFT)) |
187 | dump.u_dsize = 0; | 186 | dump.u_dsize = 0; |
188 | if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_STACK(dump), | 187 | if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_STACK(dump), |
189 | dump.u_ssize << PAGE_SHIFT)) | 188 | dump.u_ssize << PAGE_SHIFT)) |
190 | dump.u_ssize = 0; | 189 | dump.u_ssize = 0; |
191 | 190 | ||
192 | set_fs(KERNEL_DS); | 191 | set_fs(KERNEL_DS); |
193 | /* struct user */ | 192 | /* struct user */ |
194 | DUMP_WRITE(&dump, sizeof(dump)); | 193 | DUMP_WRITE(&dump, sizeof(dump)); |
195 | /* Now dump all of the user data. Include malloced stuff as well */ | 194 | /* Now dump all of the user data. Include malloced stuff as well */ |
196 | DUMP_SEEK(PAGE_SIZE); | 195 | DUMP_SEEK(PAGE_SIZE); |
197 | /* now we start writing out the user space info */ | 196 | /* now we start writing out the user space info */ |
198 | set_fs(USER_DS); | 197 | set_fs(USER_DS); |
199 | /* Dump the data area */ | 198 | /* Dump the data area */ |
200 | if (dump.u_dsize != 0) { | 199 | if (dump.u_dsize != 0) { |
201 | dump_start = START_DATA(dump); | 200 | dump_start = START_DATA(dump); |
202 | dump_size = dump.u_dsize << PAGE_SHIFT; | 201 | dump_size = dump.u_dsize << PAGE_SHIFT; |
203 | DUMP_WRITE(dump_start, dump_size); | 202 | DUMP_WRITE(dump_start, dump_size); |
204 | } | 203 | } |
205 | /* Now prepare to dump the stack area */ | 204 | /* Now prepare to dump the stack area */ |
206 | if (dump.u_ssize != 0) { | 205 | if (dump.u_ssize != 0) { |
207 | dump_start = START_STACK(dump); | 206 | dump_start = START_STACK(dump); |
208 | dump_size = dump.u_ssize << PAGE_SHIFT; | 207 | dump_size = dump.u_ssize << PAGE_SHIFT; |
209 | DUMP_WRITE(dump_start, dump_size); | 208 | DUMP_WRITE(dump_start, dump_size); |
210 | } | 209 | } |
211 | end_coredump: | 210 | end_coredump: |
212 | set_fs(fs); | 211 | set_fs(fs); |
213 | return has_dumped; | 212 | return has_dumped; |
214 | } | 213 | } |
215 | #endif | 214 | #endif |
216 | 215 | ||
217 | /* | 216 | /* |
218 | * create_aout_tables() parses the env- and arg-strings in new user | 217 | * create_aout_tables() parses the env- and arg-strings in new user |
219 | * memory and creates the pointer tables from them, and puts their | 218 | * memory and creates the pointer tables from them, and puts their |
220 | * addresses on the "stack", returning the new stack pointer value. | 219 | * addresses on the "stack", returning the new stack pointer value. |
221 | */ | 220 | */ |
222 | static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm) | 221 | static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm) |
223 | { | 222 | { |
224 | u32 __user *argv, *envp, *sp; | 223 | u32 __user *argv, *envp, *sp; |
225 | int argc = bprm->argc, envc = bprm->envc; | 224 | int argc = bprm->argc, envc = bprm->envc; |
226 | 225 | ||
227 | sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p); | 226 | sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p); |
228 | sp -= envc+1; | 227 | sp -= envc+1; |
229 | envp = sp; | 228 | envp = sp; |
230 | sp -= argc+1; | 229 | sp -= argc+1; |
231 | argv = sp; | 230 | argv = sp; |
232 | put_user((unsigned long) envp, --sp); | 231 | put_user((unsigned long) envp, --sp); |
233 | put_user((unsigned long) argv, --sp); | 232 | put_user((unsigned long) argv, --sp); |
234 | put_user(argc, --sp); | 233 | put_user(argc, --sp); |
235 | current->mm->arg_start = (unsigned long) p; | 234 | current->mm->arg_start = (unsigned long) p; |
236 | while (argc-- > 0) { | 235 | while (argc-- > 0) { |
237 | char c; | 236 | char c; |
238 | 237 | ||
239 | put_user((u32)(unsigned long)p, argv++); | 238 | put_user((u32)(unsigned long)p, argv++); |
240 | do { | 239 | do { |
241 | get_user(c, p++); | 240 | get_user(c, p++); |
242 | } while (c); | 241 | } while (c); |
243 | } | 242 | } |
244 | put_user(0, argv); | 243 | put_user(0, argv); |
245 | current->mm->arg_end = current->mm->env_start = (unsigned long) p; | 244 | current->mm->arg_end = current->mm->env_start = (unsigned long) p; |
246 | while (envc-- > 0) { | 245 | while (envc-- > 0) { |
247 | char c; | 246 | char c; |
248 | 247 | ||
249 | put_user((u32)(unsigned long)p, envp++); | 248 | put_user((u32)(unsigned long)p, envp++); |
250 | do { | 249 | do { |
251 | get_user(c, p++); | 250 | get_user(c, p++); |
252 | } while (c); | 251 | } while (c); |
253 | } | 252 | } |
254 | put_user(0, envp); | 253 | put_user(0, envp); |
255 | current->mm->env_end = (unsigned long) p; | 254 | current->mm->env_end = (unsigned long) p; |
256 | return sp; | 255 | return sp; |
257 | } | 256 | } |
258 | 257 | ||
259 | /* | 258 | /* |
260 | * These are the functions used to load a.out style executables and shared | 259 | * These are the functions used to load a.out style executables and shared |
261 | * libraries. There is no binary dependent code anywhere else. | 260 | * libraries. There is no binary dependent code anywhere else. |
262 | */ | 261 | */ |
263 | static int load_aout_binary(struct linux_binprm *bprm) | 262 | static int load_aout_binary(struct linux_binprm *bprm) |
264 | { | 263 | { |
265 | unsigned long error, fd_offset, rlim; | 264 | unsigned long error, fd_offset, rlim; |
266 | struct pt_regs *regs = current_pt_regs(); | 265 | struct pt_regs *regs = current_pt_regs(); |
267 | struct exec ex; | 266 | struct exec ex; |
268 | int retval; | 267 | int retval; |
269 | 268 | ||
270 | ex = *((struct exec *) bprm->buf); /* exec-header */ | 269 | ex = *((struct exec *) bprm->buf); /* exec-header */ |
271 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && | 270 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && |
272 | N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || | 271 | N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || |
273 | N_TRSIZE(ex) || N_DRSIZE(ex) || | 272 | N_TRSIZE(ex) || N_DRSIZE(ex) || |
274 | i_size_read(file_inode(bprm->file)) < | 273 | i_size_read(file_inode(bprm->file)) < |
275 | ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { | 274 | ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { |
276 | return -ENOEXEC; | 275 | return -ENOEXEC; |
277 | } | 276 | } |
278 | 277 | ||
279 | fd_offset = N_TXTOFF(ex); | 278 | fd_offset = N_TXTOFF(ex); |
280 | 279 | ||
281 | /* Check initial limits. This avoids letting people circumvent | 280 | /* Check initial limits. This avoids letting people circumvent |
282 | * size limits imposed on them by creating programs with large | 281 | * size limits imposed on them by creating programs with large |
283 | * arrays in the data or bss. | 282 | * arrays in the data or bss. |
284 | */ | 283 | */ |
285 | rlim = rlimit(RLIMIT_DATA); | 284 | rlim = rlimit(RLIMIT_DATA); |
286 | if (rlim >= RLIM_INFINITY) | 285 | if (rlim >= RLIM_INFINITY) |
287 | rlim = ~0; | 286 | rlim = ~0; |
288 | if (ex.a_data + ex.a_bss > rlim) | 287 | if (ex.a_data + ex.a_bss > rlim) |
289 | return -ENOMEM; | 288 | return -ENOMEM; |
290 | 289 | ||
291 | /* Flush all traces of the currently running executable */ | 290 | /* Flush all traces of the currently running executable */ |
292 | retval = flush_old_exec(bprm); | 291 | retval = flush_old_exec(bprm); |
293 | if (retval) | 292 | if (retval) |
294 | return retval; | 293 | return retval; |
295 | 294 | ||
296 | /* OK, This is the point of no return */ | 295 | /* OK, This is the point of no return */ |
297 | set_personality(PER_LINUX); | 296 | set_personality(PER_LINUX); |
298 | set_personality_ia32(false); | 297 | set_personality_ia32(false); |
299 | 298 | ||
300 | setup_new_exec(bprm); | 299 | setup_new_exec(bprm); |
301 | 300 | ||
302 | regs->cs = __USER32_CS; | 301 | regs->cs = __USER32_CS; |
303 | regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = | 302 | regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = |
304 | regs->r13 = regs->r14 = regs->r15 = 0; | 303 | regs->r13 = regs->r14 = regs->r15 = 0; |
305 | 304 | ||
306 | current->mm->end_code = ex.a_text + | 305 | current->mm->end_code = ex.a_text + |
307 | (current->mm->start_code = N_TXTADDR(ex)); | 306 | (current->mm->start_code = N_TXTADDR(ex)); |
308 | current->mm->end_data = ex.a_data + | 307 | current->mm->end_data = ex.a_data + |
309 | (current->mm->start_data = N_DATADDR(ex)); | 308 | (current->mm->start_data = N_DATADDR(ex)); |
310 | current->mm->brk = ex.a_bss + | 309 | current->mm->brk = ex.a_bss + |
311 | (current->mm->start_brk = N_BSSADDR(ex)); | 310 | (current->mm->start_brk = N_BSSADDR(ex)); |
312 | current->mm->free_area_cache = TASK_UNMAPPED_BASE; | 311 | current->mm->free_area_cache = TASK_UNMAPPED_BASE; |
313 | current->mm->cached_hole_size = 0; | 312 | current->mm->cached_hole_size = 0; |
314 | 313 | ||
315 | retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT); | 314 | retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT); |
316 | if (retval < 0) { | 315 | if (retval < 0) { |
317 | /* Someone check-me: is this error path enough? */ | 316 | /* Someone check-me: is this error path enough? */ |
318 | send_sig(SIGKILL, current, 0); | 317 | send_sig(SIGKILL, current, 0); |
319 | return retval; | 318 | return retval; |
320 | } | 319 | } |
321 | 320 | ||
322 | install_exec_creds(bprm); | 321 | install_exec_creds(bprm); |
323 | 322 | ||
324 | if (N_MAGIC(ex) == OMAGIC) { | 323 | if (N_MAGIC(ex) == OMAGIC) { |
325 | unsigned long text_addr, map_size; | 324 | unsigned long text_addr, map_size; |
326 | loff_t pos; | 325 | loff_t pos; |
327 | 326 | ||
328 | text_addr = N_TXTADDR(ex); | 327 | text_addr = N_TXTADDR(ex); |
329 | 328 | ||
330 | pos = 32; | 329 | pos = 32; |
331 | map_size = ex.a_text+ex.a_data; | 330 | map_size = ex.a_text+ex.a_data; |
332 | 331 | ||
333 | error = vm_brk(text_addr & PAGE_MASK, map_size); | 332 | error = vm_brk(text_addr & PAGE_MASK, map_size); |
334 | 333 | ||
335 | if (error != (text_addr & PAGE_MASK)) { | 334 | if (error != (text_addr & PAGE_MASK)) { |
336 | send_sig(SIGKILL, current, 0); | 335 | send_sig(SIGKILL, current, 0); |
337 | return error; | 336 | return error; |
338 | } | 337 | } |
339 | 338 | ||
340 | error = bprm->file->f_op->read(bprm->file, | 339 | error = bprm->file->f_op->read(bprm->file, |
341 | (char __user *)text_addr, | 340 | (char __user *)text_addr, |
342 | ex.a_text+ex.a_data, &pos); | 341 | ex.a_text+ex.a_data, &pos); |
343 | if ((signed long)error < 0) { | 342 | if ((signed long)error < 0) { |
344 | send_sig(SIGKILL, current, 0); | 343 | send_sig(SIGKILL, current, 0); |
345 | return error; | 344 | return error; |
346 | } | 345 | } |
347 | 346 | ||
348 | flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); | 347 | flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); |
349 | } else { | 348 | } else { |
350 | #ifdef WARN_OLD | 349 | #ifdef WARN_OLD |
351 | static unsigned long error_time, error_time2; | 350 | static unsigned long error_time, error_time2; |
352 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && | 351 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && |
353 | (N_MAGIC(ex) != NMAGIC) && | 352 | (N_MAGIC(ex) != NMAGIC) && |
354 | time_after(jiffies, error_time2 + 5*HZ)) { | 353 | time_after(jiffies, error_time2 + 5*HZ)) { |
355 | printk(KERN_NOTICE "executable not page aligned\n"); | 354 | printk(KERN_NOTICE "executable not page aligned\n"); |
356 | error_time2 = jiffies; | 355 | error_time2 = jiffies; |
357 | } | 356 | } |
358 | 357 | ||
359 | if ((fd_offset & ~PAGE_MASK) != 0 && | 358 | if ((fd_offset & ~PAGE_MASK) != 0 && |
360 | time_after(jiffies, error_time + 5*HZ)) { | 359 | time_after(jiffies, error_time + 5*HZ)) { |
361 | printk(KERN_WARNING | 360 | printk(KERN_WARNING |
362 | "fd_offset is not page aligned. Please convert " | 361 | "fd_offset is not page aligned. Please convert " |
363 | "program: %s\n", | 362 | "program: %s\n", |
364 | bprm->file->f_path.dentry->d_name.name); | 363 | bprm->file->f_path.dentry->d_name.name); |
365 | error_time = jiffies; | 364 | error_time = jiffies; |
366 | } | 365 | } |
367 | #endif | 366 | #endif |
368 | 367 | ||
369 | if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) { | 368 | if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) { |
370 | loff_t pos = fd_offset; | 369 | loff_t pos = fd_offset; |
371 | 370 | ||
372 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); | 371 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); |
373 | bprm->file->f_op->read(bprm->file, | 372 | bprm->file->f_op->read(bprm->file, |
374 | (char __user *)N_TXTADDR(ex), | 373 | (char __user *)N_TXTADDR(ex), |
375 | ex.a_text+ex.a_data, &pos); | 374 | ex.a_text+ex.a_data, &pos); |
376 | flush_icache_range((unsigned long) N_TXTADDR(ex), | 375 | flush_icache_range((unsigned long) N_TXTADDR(ex), |
377 | (unsigned long) N_TXTADDR(ex) + | 376 | (unsigned long) N_TXTADDR(ex) + |
378 | ex.a_text+ex.a_data); | 377 | ex.a_text+ex.a_data); |
379 | goto beyond_if; | 378 | goto beyond_if; |
380 | } | 379 | } |
381 | 380 | ||
382 | error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, | 381 | error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, |
383 | PROT_READ | PROT_EXEC, | 382 | PROT_READ | PROT_EXEC, |
384 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | | 383 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | |
385 | MAP_EXECUTABLE | MAP_32BIT, | 384 | MAP_EXECUTABLE | MAP_32BIT, |
386 | fd_offset); | 385 | fd_offset); |
387 | 386 | ||
388 | if (error != N_TXTADDR(ex)) { | 387 | if (error != N_TXTADDR(ex)) { |
389 | send_sig(SIGKILL, current, 0); | 388 | send_sig(SIGKILL, current, 0); |
390 | return error; | 389 | return error; |
391 | } | 390 | } |
392 | 391 | ||
393 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, | 392 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, |
394 | PROT_READ | PROT_WRITE | PROT_EXEC, | 393 | PROT_READ | PROT_WRITE | PROT_EXEC, |
395 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | | 394 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | |
396 | MAP_EXECUTABLE | MAP_32BIT, | 395 | MAP_EXECUTABLE | MAP_32BIT, |
397 | fd_offset + ex.a_text); | 396 | fd_offset + ex.a_text); |
398 | if (error != N_DATADDR(ex)) { | 397 | if (error != N_DATADDR(ex)) { |
399 | send_sig(SIGKILL, current, 0); | 398 | send_sig(SIGKILL, current, 0); |
400 | return error; | 399 | return error; |
401 | } | 400 | } |
402 | } | 401 | } |
403 | beyond_if: | 402 | beyond_if: |
404 | set_binfmt(&aout_format); | 403 | set_binfmt(&aout_format); |
405 | 404 | ||
406 | set_brk(current->mm->start_brk, current->mm->brk); | 405 | set_brk(current->mm->start_brk, current->mm->brk); |
407 | 406 | ||
408 | current->mm->start_stack = | 407 | current->mm->start_stack = |
409 | (unsigned long)create_aout_tables((char __user *)bprm->p, bprm); | 408 | (unsigned long)create_aout_tables((char __user *)bprm->p, bprm); |
410 | /* start thread */ | 409 | /* start thread */ |
411 | loadsegment(fs, 0); | 410 | loadsegment(fs, 0); |
412 | loadsegment(ds, __USER32_DS); | 411 | loadsegment(ds, __USER32_DS); |
413 | loadsegment(es, __USER32_DS); | 412 | loadsegment(es, __USER32_DS); |
414 | load_gs_index(0); | 413 | load_gs_index(0); |
415 | (regs)->ip = ex.a_entry; | 414 | (regs)->ip = ex.a_entry; |
416 | (regs)->sp = current->mm->start_stack; | 415 | (regs)->sp = current->mm->start_stack; |
417 | (regs)->flags = 0x200; | 416 | (regs)->flags = 0x200; |
418 | (regs)->cs = __USER32_CS; | 417 | (regs)->cs = __USER32_CS; |
419 | (regs)->ss = __USER32_DS; | 418 | (regs)->ss = __USER32_DS; |
420 | regs->r8 = regs->r9 = regs->r10 = regs->r11 = | 419 | regs->r8 = regs->r9 = regs->r10 = regs->r11 = |
421 | regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0; | 420 | regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0; |
422 | set_fs(USER_DS); | 421 | set_fs(USER_DS); |
423 | return 0; | 422 | return 0; |
424 | } | 423 | } |
425 | 424 | ||
426 | static int load_aout_library(struct file *file) | 425 | static int load_aout_library(struct file *file) |
427 | { | 426 | { |
428 | unsigned long bss, start_addr, len, error; | 427 | unsigned long bss, start_addr, len, error; |
429 | int retval; | 428 | int retval; |
430 | struct exec ex; | 429 | struct exec ex; |
431 | 430 | ||
432 | 431 | ||
433 | retval = -ENOEXEC; | 432 | retval = -ENOEXEC; |
434 | error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); | 433 | error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); |
435 | if (error != sizeof(ex)) | 434 | if (error != sizeof(ex)) |
436 | goto out; | 435 | goto out; |
437 | 436 | ||
438 | /* We come in here for the regular a.out style of shared libraries */ | 437 | /* We come in here for the regular a.out style of shared libraries */ |
439 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || | 438 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || |
440 | N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || | 439 | N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || |
441 | i_size_read(file_inode(file)) < | 440 | i_size_read(file_inode(file)) < |
442 | ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { | 441 | ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { |
443 | goto out; | 442 | goto out; |
444 | } | 443 | } |
445 | 444 | ||
446 | if (N_FLAGS(ex)) | 445 | if (N_FLAGS(ex)) |
447 | goto out; | 446 | goto out; |
448 | 447 | ||
449 | /* For QMAGIC, the starting address is 0x20 into the page. We mask | 448 | /* For QMAGIC, the starting address is 0x20 into the page. We mask |
450 | this off to get the starting address for the page */ | 449 | this off to get the starting address for the page */ |
451 | 450 | ||
452 | start_addr = ex.a_entry & 0xfffff000; | 451 | start_addr = ex.a_entry & 0xfffff000; |
453 | 452 | ||
454 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { | 453 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { |
455 | loff_t pos = N_TXTOFF(ex); | 454 | loff_t pos = N_TXTOFF(ex); |
456 | 455 | ||
457 | #ifdef WARN_OLD | 456 | #ifdef WARN_OLD |
458 | static unsigned long error_time; | 457 | static unsigned long error_time; |
459 | if (time_after(jiffies, error_time + 5*HZ)) { | 458 | if (time_after(jiffies, error_time + 5*HZ)) { |
460 | printk(KERN_WARNING | 459 | printk(KERN_WARNING |
461 | "N_TXTOFF is not page aligned. Please convert " | 460 | "N_TXTOFF is not page aligned. Please convert " |
462 | "library: %s\n", | 461 | "library: %s\n", |
463 | file->f_path.dentry->d_name.name); | 462 | file->f_path.dentry->d_name.name); |
464 | error_time = jiffies; | 463 | error_time = jiffies; |
465 | } | 464 | } |
466 | #endif | 465 | #endif |
467 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); | 466 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); |
468 | 467 | ||
469 | file->f_op->read(file, (char __user *)start_addr, | 468 | file->f_op->read(file, (char __user *)start_addr, |
470 | ex.a_text + ex.a_data, &pos); | 469 | ex.a_text + ex.a_data, &pos); |
471 | flush_icache_range((unsigned long) start_addr, | 470 | flush_icache_range((unsigned long) start_addr, |
472 | (unsigned long) start_addr + ex.a_text + | 471 | (unsigned long) start_addr + ex.a_text + |
473 | ex.a_data); | 472 | ex.a_data); |
474 | 473 | ||
475 | retval = 0; | 474 | retval = 0; |
476 | goto out; | 475 | goto out; |
477 | } | 476 | } |
478 | /* Now use mmap to map the library into memory. */ | 477 | /* Now use mmap to map the library into memory. */ |
479 | error = vm_mmap(file, start_addr, ex.a_text + ex.a_data, | 478 | error = vm_mmap(file, start_addr, ex.a_text + ex.a_data, |
480 | PROT_READ | PROT_WRITE | PROT_EXEC, | 479 | PROT_READ | PROT_WRITE | PROT_EXEC, |
481 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT, | 480 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT, |
482 | N_TXTOFF(ex)); | 481 | N_TXTOFF(ex)); |
483 | retval = error; | 482 | retval = error; |
484 | if (error != start_addr) | 483 | if (error != start_addr) |
485 | goto out; | 484 | goto out; |
486 | 485 | ||
487 | len = PAGE_ALIGN(ex.a_text + ex.a_data); | 486 | len = PAGE_ALIGN(ex.a_text + ex.a_data); |
488 | bss = ex.a_text + ex.a_data + ex.a_bss; | 487 | bss = ex.a_text + ex.a_data + ex.a_bss; |
489 | if (bss > len) { | 488 | if (bss > len) { |
490 | error = vm_brk(start_addr + len, bss - len); | 489 | error = vm_brk(start_addr + len, bss - len); |
491 | retval = error; | 490 | retval = error; |
492 | if (error != start_addr + len) | 491 | if (error != start_addr + len) |
493 | goto out; | 492 | goto out; |
494 | } | 493 | } |
495 | retval = 0; | 494 | retval = 0; |
496 | out: | 495 | out: |
497 | return retval; | 496 | return retval; |
498 | } | 497 | } |
499 | 498 | ||
500 | static int __init init_aout_binfmt(void) | 499 | static int __init init_aout_binfmt(void) |
501 | { | 500 | { |
502 | register_binfmt(&aout_format); | 501 | register_binfmt(&aout_format); |
503 | return 0; | 502 | return 0; |
504 | } | 503 | } |
505 | 504 | ||
506 | static void __exit exit_aout_binfmt(void) | 505 | static void __exit exit_aout_binfmt(void) |
507 | { | 506 | { |
508 | unregister_binfmt(&aout_format); | 507 | unregister_binfmt(&aout_format); |
509 | } | 508 | } |
510 | 509 | ||
511 | module_init(init_aout_binfmt); | 510 | module_init(init_aout_binfmt); |
512 | module_exit(exit_aout_binfmt); | 511 | module_exit(exit_aout_binfmt); |
513 | MODULE_LICENSE("GPL"); | 512 | MODULE_LICENSE("GPL"); |
514 | 513 |
fs/binfmt_aout.c
1 | /* | 1 | /* |
2 | * linux/fs/binfmt_aout.c | 2 | * linux/fs/binfmt_aout.c |
3 | * | 3 | * |
4 | * Copyright (C) 1991, 1992, 1996 Linus Torvalds | 4 | * Copyright (C) 1991, 1992, 1996 Linus Torvalds |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | 8 | ||
9 | #include <linux/time.h> | 9 | #include <linux/time.h> |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/mman.h> | 12 | #include <linux/mman.h> |
13 | #include <linux/a.out.h> | 13 | #include <linux/a.out.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/signal.h> | 15 | #include <linux/signal.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/file.h> | 18 | #include <linux/file.h> |
19 | #include <linux/stat.h> | 19 | #include <linux/stat.h> |
20 | #include <linux/fcntl.h> | 20 | #include <linux/fcntl.h> |
21 | #include <linux/ptrace.h> | 21 | #include <linux/ptrace.h> |
22 | #include <linux/user.h> | 22 | #include <linux/user.h> |
23 | #include <linux/binfmts.h> | 23 | #include <linux/binfmts.h> |
24 | #include <linux/personality.h> | 24 | #include <linux/personality.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/coredump.h> | 26 | #include <linux/coredump.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | 28 | ||
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | #include <asm/a.out-core.h> | 31 | #include <asm/a.out-core.h> |
32 | 32 | ||
33 | static int load_aout_binary(struct linux_binprm *); | 33 | static int load_aout_binary(struct linux_binprm *); |
34 | static int load_aout_library(struct file*); | 34 | static int load_aout_library(struct file*); |
35 | 35 | ||
36 | #ifdef CONFIG_COREDUMP | 36 | #ifdef CONFIG_COREDUMP |
37 | /* | 37 | /* |
38 | * Routine writes a core dump image in the current directory. | 38 | * Routine writes a core dump image in the current directory. |
39 | * Currently only a stub-function. | 39 | * Currently only a stub-function. |
40 | * | 40 | * |
41 | * Note that setuid/setgid files won't make a core-dump if the uid/gid | 41 | * Note that setuid/setgid files won't make a core-dump if the uid/gid |
42 | * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable" | 42 | * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable" |
43 | * field, which also makes sure the core-dumps won't be recursive if the | 43 | * field, which also makes sure the core-dumps won't be recursive if the |
44 | * dumping of the process results in another error.. | 44 | * dumping of the process results in another error.. |
45 | */ | 45 | */ |
46 | static int aout_core_dump(struct coredump_params *cprm) | 46 | static int aout_core_dump(struct coredump_params *cprm) |
47 | { | 47 | { |
48 | struct file *file = cprm->file; | 48 | struct file *file = cprm->file; |
49 | mm_segment_t fs; | 49 | mm_segment_t fs; |
50 | int has_dumped = 0; | 50 | int has_dumped = 0; |
51 | void __user *dump_start; | 51 | void __user *dump_start; |
52 | int dump_size; | 52 | int dump_size; |
53 | struct user dump; | 53 | struct user dump; |
54 | #ifdef __alpha__ | 54 | #ifdef __alpha__ |
55 | # define START_DATA(u) ((void __user *)u.start_data) | 55 | # define START_DATA(u) ((void __user *)u.start_data) |
56 | #else | 56 | #else |
57 | # define START_DATA(u) ((void __user *)((u.u_tsize << PAGE_SHIFT) + \ | 57 | # define START_DATA(u) ((void __user *)((u.u_tsize << PAGE_SHIFT) + \ |
58 | u.start_code)) | 58 | u.start_code)) |
59 | #endif | 59 | #endif |
60 | # define START_STACK(u) ((void __user *)u.start_stack) | 60 | # define START_STACK(u) ((void __user *)u.start_stack) |
61 | 61 | ||
62 | fs = get_fs(); | 62 | fs = get_fs(); |
63 | set_fs(KERNEL_DS); | 63 | set_fs(KERNEL_DS); |
64 | has_dumped = 1; | 64 | has_dumped = 1; |
65 | current->flags |= PF_DUMPCORE; | ||
66 | strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); | 65 | strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); |
67 | dump.u_ar0 = offsetof(struct user, regs); | 66 | dump.u_ar0 = offsetof(struct user, regs); |
68 | dump.signal = cprm->siginfo->si_signo; | 67 | dump.signal = cprm->siginfo->si_signo; |
69 | aout_dump_thread(cprm->regs, &dump); | 68 | aout_dump_thread(cprm->regs, &dump); |
70 | 69 | ||
71 | /* If the size of the dump file exceeds the rlimit, then see what would happen | 70 | /* If the size of the dump file exceeds the rlimit, then see what would happen |
72 | if we wrote the stack, but not the data area. */ | 71 | if we wrote the stack, but not the data area. */ |
73 | if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > cprm->limit) | 72 | if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > cprm->limit) |
74 | dump.u_dsize = 0; | 73 | dump.u_dsize = 0; |
75 | 74 | ||
76 | /* Make sure we have enough room to write the stack and data areas. */ | 75 | /* Make sure we have enough room to write the stack and data areas. */ |
77 | if ((dump.u_ssize + 1) * PAGE_SIZE > cprm->limit) | 76 | if ((dump.u_ssize + 1) * PAGE_SIZE > cprm->limit) |
78 | dump.u_ssize = 0; | 77 | dump.u_ssize = 0; |
79 | 78 | ||
80 | /* make sure we actually have a data and stack area to dump */ | 79 | /* make sure we actually have a data and stack area to dump */ |
81 | set_fs(USER_DS); | 80 | set_fs(USER_DS); |
82 | if (!access_ok(VERIFY_READ, START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) | 81 | if (!access_ok(VERIFY_READ, START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) |
83 | dump.u_dsize = 0; | 82 | dump.u_dsize = 0; |
84 | if (!access_ok(VERIFY_READ, START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) | 83 | if (!access_ok(VERIFY_READ, START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) |
85 | dump.u_ssize = 0; | 84 | dump.u_ssize = 0; |
86 | 85 | ||
87 | set_fs(KERNEL_DS); | 86 | set_fs(KERNEL_DS); |
88 | /* struct user */ | 87 | /* struct user */ |
89 | if (!dump_write(file, &dump, sizeof(dump))) | 88 | if (!dump_write(file, &dump, sizeof(dump))) |
90 | goto end_coredump; | 89 | goto end_coredump; |
91 | /* Now dump all of the user data. Include malloced stuff as well */ | 90 | /* Now dump all of the user data. Include malloced stuff as well */ |
92 | if (!dump_seek(cprm->file, PAGE_SIZE - sizeof(dump))) | 91 | if (!dump_seek(cprm->file, PAGE_SIZE - sizeof(dump))) |
93 | goto end_coredump; | 92 | goto end_coredump; |
94 | /* now we start writing out the user space info */ | 93 | /* now we start writing out the user space info */ |
95 | set_fs(USER_DS); | 94 | set_fs(USER_DS); |
96 | /* Dump the data area */ | 95 | /* Dump the data area */ |
97 | if (dump.u_dsize != 0) { | 96 | if (dump.u_dsize != 0) { |
98 | dump_start = START_DATA(dump); | 97 | dump_start = START_DATA(dump); |
99 | dump_size = dump.u_dsize << PAGE_SHIFT; | 98 | dump_size = dump.u_dsize << PAGE_SHIFT; |
100 | if (!dump_write(file, dump_start, dump_size)) | 99 | if (!dump_write(file, dump_start, dump_size)) |
101 | goto end_coredump; | 100 | goto end_coredump; |
102 | } | 101 | } |
103 | /* Now prepare to dump the stack area */ | 102 | /* Now prepare to dump the stack area */ |
104 | if (dump.u_ssize != 0) { | 103 | if (dump.u_ssize != 0) { |
105 | dump_start = START_STACK(dump); | 104 | dump_start = START_STACK(dump); |
106 | dump_size = dump.u_ssize << PAGE_SHIFT; | 105 | dump_size = dump.u_ssize << PAGE_SHIFT; |
107 | if (!dump_write(file, dump_start, dump_size)) | 106 | if (!dump_write(file, dump_start, dump_size)) |
108 | goto end_coredump; | 107 | goto end_coredump; |
109 | } | 108 | } |
110 | end_coredump: | 109 | end_coredump: |
111 | set_fs(fs); | 110 | set_fs(fs); |
112 | return has_dumped; | 111 | return has_dumped; |
113 | } | 112 | } |
114 | #else | 113 | #else |
115 | #define aout_core_dump NULL | 114 | #define aout_core_dump NULL |
116 | #endif | 115 | #endif |
117 | 116 | ||
118 | static struct linux_binfmt aout_format = { | 117 | static struct linux_binfmt aout_format = { |
119 | .module = THIS_MODULE, | 118 | .module = THIS_MODULE, |
120 | .load_binary = load_aout_binary, | 119 | .load_binary = load_aout_binary, |
121 | .load_shlib = load_aout_library, | 120 | .load_shlib = load_aout_library, |
122 | .core_dump = aout_core_dump, | 121 | .core_dump = aout_core_dump, |
123 | .min_coredump = PAGE_SIZE | 122 | .min_coredump = PAGE_SIZE |
124 | }; | 123 | }; |
125 | 124 | ||
126 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) | 125 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) |
127 | 126 | ||
128 | static int set_brk(unsigned long start, unsigned long end) | 127 | static int set_brk(unsigned long start, unsigned long end) |
129 | { | 128 | { |
130 | start = PAGE_ALIGN(start); | 129 | start = PAGE_ALIGN(start); |
131 | end = PAGE_ALIGN(end); | 130 | end = PAGE_ALIGN(end); |
132 | if (end > start) { | 131 | if (end > start) { |
133 | unsigned long addr; | 132 | unsigned long addr; |
134 | addr = vm_brk(start, end - start); | 133 | addr = vm_brk(start, end - start); |
135 | if (BAD_ADDR(addr)) | 134 | if (BAD_ADDR(addr)) |
136 | return addr; | 135 | return addr; |
137 | } | 136 | } |
138 | return 0; | 137 | return 0; |
139 | } | 138 | } |
140 | 139 | ||
141 | /* | 140 | /* |
142 | * create_aout_tables() parses the env- and arg-strings in new user | 141 | * create_aout_tables() parses the env- and arg-strings in new user |
143 | * memory and creates the pointer tables from them, and puts their | 142 | * memory and creates the pointer tables from them, and puts their |
144 | * addresses on the "stack", returning the new stack pointer value. | 143 | * addresses on the "stack", returning the new stack pointer value. |
145 | */ | 144 | */ |
146 | static unsigned long __user *create_aout_tables(char __user *p, struct linux_binprm * bprm) | 145 | static unsigned long __user *create_aout_tables(char __user *p, struct linux_binprm * bprm) |
147 | { | 146 | { |
148 | char __user * __user *argv; | 147 | char __user * __user *argv; |
149 | char __user * __user *envp; | 148 | char __user * __user *envp; |
150 | unsigned long __user *sp; | 149 | unsigned long __user *sp; |
151 | int argc = bprm->argc; | 150 | int argc = bprm->argc; |
152 | int envc = bprm->envc; | 151 | int envc = bprm->envc; |
153 | 152 | ||
154 | sp = (void __user *)((-(unsigned long)sizeof(char *)) & (unsigned long) p); | 153 | sp = (void __user *)((-(unsigned long)sizeof(char *)) & (unsigned long) p); |
155 | #ifdef __alpha__ | 154 | #ifdef __alpha__ |
156 | /* whee.. test-programs are so much fun. */ | 155 | /* whee.. test-programs are so much fun. */ |
157 | put_user(0, --sp); | 156 | put_user(0, --sp); |
158 | put_user(0, --sp); | 157 | put_user(0, --sp); |
159 | if (bprm->loader) { | 158 | if (bprm->loader) { |
160 | put_user(0, --sp); | 159 | put_user(0, --sp); |
161 | put_user(1003, --sp); | 160 | put_user(1003, --sp); |
162 | put_user(bprm->loader, --sp); | 161 | put_user(bprm->loader, --sp); |
163 | put_user(1002, --sp); | 162 | put_user(1002, --sp); |
164 | } | 163 | } |
165 | put_user(bprm->exec, --sp); | 164 | put_user(bprm->exec, --sp); |
166 | put_user(1001, --sp); | 165 | put_user(1001, --sp); |
167 | #endif | 166 | #endif |
168 | sp -= envc+1; | 167 | sp -= envc+1; |
169 | envp = (char __user * __user *) sp; | 168 | envp = (char __user * __user *) sp; |
170 | sp -= argc+1; | 169 | sp -= argc+1; |
171 | argv = (char __user * __user *) sp; | 170 | argv = (char __user * __user *) sp; |
172 | #ifndef __alpha__ | 171 | #ifndef __alpha__ |
173 | put_user((unsigned long) envp,--sp); | 172 | put_user((unsigned long) envp,--sp); |
174 | put_user((unsigned long) argv,--sp); | 173 | put_user((unsigned long) argv,--sp); |
175 | #endif | 174 | #endif |
176 | put_user(argc,--sp); | 175 | put_user(argc,--sp); |
177 | current->mm->arg_start = (unsigned long) p; | 176 | current->mm->arg_start = (unsigned long) p; |
178 | while (argc-->0) { | 177 | while (argc-->0) { |
179 | char c; | 178 | char c; |
180 | put_user(p,argv++); | 179 | put_user(p,argv++); |
181 | do { | 180 | do { |
182 | get_user(c,p++); | 181 | get_user(c,p++); |
183 | } while (c); | 182 | } while (c); |
184 | } | 183 | } |
185 | put_user(NULL,argv); | 184 | put_user(NULL,argv); |
186 | current->mm->arg_end = current->mm->env_start = (unsigned long) p; | 185 | current->mm->arg_end = current->mm->env_start = (unsigned long) p; |
187 | while (envc-->0) { | 186 | while (envc-->0) { |
188 | char c; | 187 | char c; |
189 | put_user(p,envp++); | 188 | put_user(p,envp++); |
190 | do { | 189 | do { |
191 | get_user(c,p++); | 190 | get_user(c,p++); |
192 | } while (c); | 191 | } while (c); |
193 | } | 192 | } |
194 | put_user(NULL,envp); | 193 | put_user(NULL,envp); |
195 | current->mm->env_end = (unsigned long) p; | 194 | current->mm->env_end = (unsigned long) p; |
196 | return sp; | 195 | return sp; |
197 | } | 196 | } |
198 | 197 | ||
199 | /* | 198 | /* |
200 | * These are the functions used to load a.out style executables and shared | 199 | * These are the functions used to load a.out style executables and shared |
201 | * libraries. There is no binary dependent code anywhere else. | 200 | * libraries. There is no binary dependent code anywhere else. |
202 | */ | 201 | */ |
203 | 202 | ||
204 | static int load_aout_binary(struct linux_binprm * bprm) | 203 | static int load_aout_binary(struct linux_binprm * bprm) |
205 | { | 204 | { |
206 | struct pt_regs *regs = current_pt_regs(); | 205 | struct pt_regs *regs = current_pt_regs(); |
207 | struct exec ex; | 206 | struct exec ex; |
208 | unsigned long error; | 207 | unsigned long error; |
209 | unsigned long fd_offset; | 208 | unsigned long fd_offset; |
210 | unsigned long rlim; | 209 | unsigned long rlim; |
211 | int retval; | 210 | int retval; |
212 | 211 | ||
213 | ex = *((struct exec *) bprm->buf); /* exec-header */ | 212 | ex = *((struct exec *) bprm->buf); /* exec-header */ |
214 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && | 213 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && |
215 | N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || | 214 | N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || |
216 | N_TRSIZE(ex) || N_DRSIZE(ex) || | 215 | N_TRSIZE(ex) || N_DRSIZE(ex) || |
217 | i_size_read(file_inode(bprm->file)) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { | 216 | i_size_read(file_inode(bprm->file)) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { |
218 | return -ENOEXEC; | 217 | return -ENOEXEC; |
219 | } | 218 | } |
220 | 219 | ||
221 | /* | 220 | /* |
222 | * Requires a mmap handler. This prevents people from using a.out | 221 | * Requires a mmap handler. This prevents people from using a.out |
223 | * as part of an exploit attack against /proc-related vulnerabilities. | 222 | * as part of an exploit attack against /proc-related vulnerabilities. |
224 | */ | 223 | */ |
225 | if (!bprm->file->f_op || !bprm->file->f_op->mmap) | 224 | if (!bprm->file->f_op || !bprm->file->f_op->mmap) |
226 | return -ENOEXEC; | 225 | return -ENOEXEC; |
227 | 226 | ||
228 | fd_offset = N_TXTOFF(ex); | 227 | fd_offset = N_TXTOFF(ex); |
229 | 228 | ||
230 | /* Check initial limits. This avoids letting people circumvent | 229 | /* Check initial limits. This avoids letting people circumvent |
231 | * size limits imposed on them by creating programs with large | 230 | * size limits imposed on them by creating programs with large |
232 | * arrays in the data or bss. | 231 | * arrays in the data or bss. |
233 | */ | 232 | */ |
234 | rlim = rlimit(RLIMIT_DATA); | 233 | rlim = rlimit(RLIMIT_DATA); |
235 | if (rlim >= RLIM_INFINITY) | 234 | if (rlim >= RLIM_INFINITY) |
236 | rlim = ~0; | 235 | rlim = ~0; |
237 | if (ex.a_data + ex.a_bss > rlim) | 236 | if (ex.a_data + ex.a_bss > rlim) |
238 | return -ENOMEM; | 237 | return -ENOMEM; |
239 | 238 | ||
240 | /* Flush all traces of the currently running executable */ | 239 | /* Flush all traces of the currently running executable */ |
241 | retval = flush_old_exec(bprm); | 240 | retval = flush_old_exec(bprm); |
242 | if (retval) | 241 | if (retval) |
243 | return retval; | 242 | return retval; |
244 | 243 | ||
245 | /* OK, This is the point of no return */ | 244 | /* OK, This is the point of no return */ |
246 | #ifdef __alpha__ | 245 | #ifdef __alpha__ |
247 | SET_AOUT_PERSONALITY(bprm, ex); | 246 | SET_AOUT_PERSONALITY(bprm, ex); |
248 | #else | 247 | #else |
249 | set_personality(PER_LINUX); | 248 | set_personality(PER_LINUX); |
250 | #endif | 249 | #endif |
251 | setup_new_exec(bprm); | 250 | setup_new_exec(bprm); |
252 | 251 | ||
253 | current->mm->end_code = ex.a_text + | 252 | current->mm->end_code = ex.a_text + |
254 | (current->mm->start_code = N_TXTADDR(ex)); | 253 | (current->mm->start_code = N_TXTADDR(ex)); |
255 | current->mm->end_data = ex.a_data + | 254 | current->mm->end_data = ex.a_data + |
256 | (current->mm->start_data = N_DATADDR(ex)); | 255 | (current->mm->start_data = N_DATADDR(ex)); |
257 | current->mm->brk = ex.a_bss + | 256 | current->mm->brk = ex.a_bss + |
258 | (current->mm->start_brk = N_BSSADDR(ex)); | 257 | (current->mm->start_brk = N_BSSADDR(ex)); |
259 | current->mm->free_area_cache = current->mm->mmap_base; | 258 | current->mm->free_area_cache = current->mm->mmap_base; |
260 | current->mm->cached_hole_size = 0; | 259 | current->mm->cached_hole_size = 0; |
261 | 260 | ||
262 | retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); | 261 | retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); |
263 | if (retval < 0) { | 262 | if (retval < 0) { |
264 | /* Someone check-me: is this error path enough? */ | 263 | /* Someone check-me: is this error path enough? */ |
265 | send_sig(SIGKILL, current, 0); | 264 | send_sig(SIGKILL, current, 0); |
266 | return retval; | 265 | return retval; |
267 | } | 266 | } |
268 | 267 | ||
269 | install_exec_creds(bprm); | 268 | install_exec_creds(bprm); |
270 | 269 | ||
271 | if (N_MAGIC(ex) == OMAGIC) { | 270 | if (N_MAGIC(ex) == OMAGIC) { |
272 | unsigned long text_addr, map_size; | 271 | unsigned long text_addr, map_size; |
273 | loff_t pos; | 272 | loff_t pos; |
274 | 273 | ||
275 | text_addr = N_TXTADDR(ex); | 274 | text_addr = N_TXTADDR(ex); |
276 | 275 | ||
277 | #ifdef __alpha__ | 276 | #ifdef __alpha__ |
278 | pos = fd_offset; | 277 | pos = fd_offset; |
279 | map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1; | 278 | map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1; |
280 | #else | 279 | #else |
281 | pos = 32; | 280 | pos = 32; |
282 | map_size = ex.a_text+ex.a_data; | 281 | map_size = ex.a_text+ex.a_data; |
283 | #endif | 282 | #endif |
284 | error = vm_brk(text_addr & PAGE_MASK, map_size); | 283 | error = vm_brk(text_addr & PAGE_MASK, map_size); |
285 | if (error != (text_addr & PAGE_MASK)) { | 284 | if (error != (text_addr & PAGE_MASK)) { |
286 | send_sig(SIGKILL, current, 0); | 285 | send_sig(SIGKILL, current, 0); |
287 | return error; | 286 | return error; |
288 | } | 287 | } |
289 | 288 | ||
290 | error = bprm->file->f_op->read(bprm->file, | 289 | error = bprm->file->f_op->read(bprm->file, |
291 | (char __user *)text_addr, | 290 | (char __user *)text_addr, |
292 | ex.a_text+ex.a_data, &pos); | 291 | ex.a_text+ex.a_data, &pos); |
293 | if ((signed long)error < 0) { | 292 | if ((signed long)error < 0) { |
294 | send_sig(SIGKILL, current, 0); | 293 | send_sig(SIGKILL, current, 0); |
295 | return error; | 294 | return error; |
296 | } | 295 | } |
297 | 296 | ||
298 | flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); | 297 | flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); |
299 | } else { | 298 | } else { |
300 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && | 299 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && |
301 | (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) | 300 | (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) |
302 | { | 301 | { |
303 | printk(KERN_NOTICE "executable not page aligned\n"); | 302 | printk(KERN_NOTICE "executable not page aligned\n"); |
304 | } | 303 | } |
305 | 304 | ||
306 | if ((fd_offset & ~PAGE_MASK) != 0 && printk_ratelimit()) | 305 | if ((fd_offset & ~PAGE_MASK) != 0 && printk_ratelimit()) |
307 | { | 306 | { |
308 | printk(KERN_WARNING | 307 | printk(KERN_WARNING |
309 | "fd_offset is not page aligned. Please convert program: %s\n", | 308 | "fd_offset is not page aligned. Please convert program: %s\n", |
310 | bprm->file->f_path.dentry->d_name.name); | 309 | bprm->file->f_path.dentry->d_name.name); |
311 | } | 310 | } |
312 | 311 | ||
313 | if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { | 312 | if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { |
314 | loff_t pos = fd_offset; | 313 | loff_t pos = fd_offset; |
315 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); | 314 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); |
316 | bprm->file->f_op->read(bprm->file, | 315 | bprm->file->f_op->read(bprm->file, |
317 | (char __user *)N_TXTADDR(ex), | 316 | (char __user *)N_TXTADDR(ex), |
318 | ex.a_text+ex.a_data, &pos); | 317 | ex.a_text+ex.a_data, &pos); |
319 | flush_icache_range((unsigned long) N_TXTADDR(ex), | 318 | flush_icache_range((unsigned long) N_TXTADDR(ex), |
320 | (unsigned long) N_TXTADDR(ex) + | 319 | (unsigned long) N_TXTADDR(ex) + |
321 | ex.a_text+ex.a_data); | 320 | ex.a_text+ex.a_data); |
322 | goto beyond_if; | 321 | goto beyond_if; |
323 | } | 322 | } |
324 | 323 | ||
325 | error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, | 324 | error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, |
326 | PROT_READ | PROT_EXEC, | 325 | PROT_READ | PROT_EXEC, |
327 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, | 326 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, |
328 | fd_offset); | 327 | fd_offset); |
329 | 328 | ||
330 | if (error != N_TXTADDR(ex)) { | 329 | if (error != N_TXTADDR(ex)) { |
331 | send_sig(SIGKILL, current, 0); | 330 | send_sig(SIGKILL, current, 0); |
332 | return error; | 331 | return error; |
333 | } | 332 | } |
334 | 333 | ||
335 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, | 334 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, |
336 | PROT_READ | PROT_WRITE | PROT_EXEC, | 335 | PROT_READ | PROT_WRITE | PROT_EXEC, |
337 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, | 336 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, |
338 | fd_offset + ex.a_text); | 337 | fd_offset + ex.a_text); |
339 | if (error != N_DATADDR(ex)) { | 338 | if (error != N_DATADDR(ex)) { |
340 | send_sig(SIGKILL, current, 0); | 339 | send_sig(SIGKILL, current, 0); |
341 | return error; | 340 | return error; |
342 | } | 341 | } |
343 | } | 342 | } |
344 | beyond_if: | 343 | beyond_if: |
345 | set_binfmt(&aout_format); | 344 | set_binfmt(&aout_format); |
346 | 345 | ||
347 | retval = set_brk(current->mm->start_brk, current->mm->brk); | 346 | retval = set_brk(current->mm->start_brk, current->mm->brk); |
348 | if (retval < 0) { | 347 | if (retval < 0) { |
349 | send_sig(SIGKILL, current, 0); | 348 | send_sig(SIGKILL, current, 0); |
350 | return retval; | 349 | return retval; |
351 | } | 350 | } |
352 | 351 | ||
353 | current->mm->start_stack = | 352 | current->mm->start_stack = |
354 | (unsigned long) create_aout_tables((char __user *) bprm->p, bprm); | 353 | (unsigned long) create_aout_tables((char __user *) bprm->p, bprm); |
355 | #ifdef __alpha__ | 354 | #ifdef __alpha__ |
356 | regs->gp = ex.a_gpvalue; | 355 | regs->gp = ex.a_gpvalue; |
357 | #endif | 356 | #endif |
358 | start_thread(regs, ex.a_entry, current->mm->start_stack); | 357 | start_thread(regs, ex.a_entry, current->mm->start_stack); |
359 | return 0; | 358 | return 0; |
360 | } | 359 | } |
361 | 360 | ||
362 | static int load_aout_library(struct file *file) | 361 | static int load_aout_library(struct file *file) |
363 | { | 362 | { |
364 | struct inode * inode; | 363 | struct inode * inode; |
365 | unsigned long bss, start_addr, len; | 364 | unsigned long bss, start_addr, len; |
366 | unsigned long error; | 365 | unsigned long error; |
367 | int retval; | 366 | int retval; |
368 | struct exec ex; | 367 | struct exec ex; |
369 | 368 | ||
370 | inode = file_inode(file); | 369 | inode = file_inode(file); |
371 | 370 | ||
372 | retval = -ENOEXEC; | 371 | retval = -ENOEXEC; |
373 | error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); | 372 | error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); |
374 | if (error != sizeof(ex)) | 373 | if (error != sizeof(ex)) |
375 | goto out; | 374 | goto out; |
376 | 375 | ||
377 | /* We come in here for the regular a.out style of shared libraries */ | 376 | /* We come in here for the regular a.out style of shared libraries */ |
378 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || | 377 | if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || |
379 | N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || | 378 | N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || |
380 | i_size_read(inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { | 379 | i_size_read(inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { |
381 | goto out; | 380 | goto out; |
382 | } | 381 | } |
383 | 382 | ||
384 | /* | 383 | /* |
385 | * Requires a mmap handler. This prevents people from using a.out | 384 | * Requires a mmap handler. This prevents people from using a.out |
386 | * as part of an exploit attack against /proc-related vulnerabilities. | 385 | * as part of an exploit attack against /proc-related vulnerabilities. |
387 | */ | 386 | */ |
388 | if (!file->f_op || !file->f_op->mmap) | 387 | if (!file->f_op || !file->f_op->mmap) |
389 | goto out; | 388 | goto out; |
390 | 389 | ||
391 | if (N_FLAGS(ex)) | 390 | if (N_FLAGS(ex)) |
392 | goto out; | 391 | goto out; |
393 | 392 | ||
394 | /* For QMAGIC, the starting address is 0x20 into the page. We mask | 393 | /* For QMAGIC, the starting address is 0x20 into the page. We mask |
395 | this off to get the starting address for the page */ | 394 | this off to get the starting address for the page */ |
396 | 395 | ||
397 | start_addr = ex.a_entry & 0xfffff000; | 396 | start_addr = ex.a_entry & 0xfffff000; |
398 | 397 | ||
399 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { | 398 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { |
400 | loff_t pos = N_TXTOFF(ex); | 399 | loff_t pos = N_TXTOFF(ex); |
401 | 400 | ||
402 | if (printk_ratelimit()) | 401 | if (printk_ratelimit()) |
403 | { | 402 | { |
404 | printk(KERN_WARNING | 403 | printk(KERN_WARNING |
405 | "N_TXTOFF is not page aligned. Please convert library: %s\n", | 404 | "N_TXTOFF is not page aligned. Please convert library: %s\n", |
406 | file->f_path.dentry->d_name.name); | 405 | file->f_path.dentry->d_name.name); |
407 | } | 406 | } |
408 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); | 407 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); |
409 | 408 | ||
410 | file->f_op->read(file, (char __user *)start_addr, | 409 | file->f_op->read(file, (char __user *)start_addr, |
411 | ex.a_text + ex.a_data, &pos); | 410 | ex.a_text + ex.a_data, &pos); |
412 | flush_icache_range((unsigned long) start_addr, | 411 | flush_icache_range((unsigned long) start_addr, |
413 | (unsigned long) start_addr + ex.a_text + ex.a_data); | 412 | (unsigned long) start_addr + ex.a_text + ex.a_data); |
414 | 413 | ||
415 | retval = 0; | 414 | retval = 0; |
416 | goto out; | 415 | goto out; |
417 | } | 416 | } |
418 | /* Now use mmap to map the library into memory. */ | 417 | /* Now use mmap to map the library into memory. */ |
419 | error = vm_mmap(file, start_addr, ex.a_text + ex.a_data, | 418 | error = vm_mmap(file, start_addr, ex.a_text + ex.a_data, |
420 | PROT_READ | PROT_WRITE | PROT_EXEC, | 419 | PROT_READ | PROT_WRITE | PROT_EXEC, |
421 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, | 420 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, |
422 | N_TXTOFF(ex)); | 421 | N_TXTOFF(ex)); |
423 | retval = error; | 422 | retval = error; |
424 | if (error != start_addr) | 423 | if (error != start_addr) |
425 | goto out; | 424 | goto out; |
426 | 425 | ||
427 | len = PAGE_ALIGN(ex.a_text + ex.a_data); | 426 | len = PAGE_ALIGN(ex.a_text + ex.a_data); |
428 | bss = ex.a_text + ex.a_data + ex.a_bss; | 427 | bss = ex.a_text + ex.a_data + ex.a_bss; |
429 | if (bss > len) { | 428 | if (bss > len) { |
430 | error = vm_brk(start_addr + len, bss - len); | 429 | error = vm_brk(start_addr + len, bss - len); |
431 | retval = error; | 430 | retval = error; |
432 | if (error != start_addr + len) | 431 | if (error != start_addr + len) |
433 | goto out; | 432 | goto out; |
434 | } | 433 | } |
435 | retval = 0; | 434 | retval = 0; |
436 | out: | 435 | out: |
437 | return retval; | 436 | return retval; |
438 | } | 437 | } |
439 | 438 | ||
440 | static int __init init_aout_binfmt(void) | 439 | static int __init init_aout_binfmt(void) |
441 | { | 440 | { |
442 | register_binfmt(&aout_format); | 441 | register_binfmt(&aout_format); |
443 | return 0; | 442 | return 0; |
444 | } | 443 | } |
445 | 444 | ||
446 | static void __exit exit_aout_binfmt(void) | 445 | static void __exit exit_aout_binfmt(void) |
447 | { | 446 | { |
448 | unregister_binfmt(&aout_format); | 447 | unregister_binfmt(&aout_format); |
449 | } | 448 | } |
450 | 449 | ||
451 | core_initcall(init_aout_binfmt); | 450 | core_initcall(init_aout_binfmt); |
452 | module_exit(exit_aout_binfmt); | 451 | module_exit(exit_aout_binfmt); |
453 | MODULE_LICENSE("GPL"); | 452 | MODULE_LICENSE("GPL"); |
454 | 453 |
fs/binfmt_elf.c
1 | /* | 1 | /* |
2 | * linux/fs/binfmt_elf.c | 2 | * linux/fs/binfmt_elf.c |
3 | * | 3 | * |
4 | * These are the functions used to load ELF format executables as used | 4 | * These are the functions used to load ELF format executables as used |
5 | * on SVr4 machines. Information on the format may be found in the book | 5 | * on SVr4 machines. Information on the format may be found in the book |
6 | * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support | 6 | * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support |
7 | * Tools". | 7 | * Tools". |
8 | * | 8 | * |
9 | * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). | 9 | * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/mman.h> | 16 | #include <linux/mman.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/signal.h> | 18 | #include <linux/signal.h> |
19 | #include <linux/binfmts.h> | 19 | #include <linux/binfmts.h> |
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/file.h> | 21 | #include <linux/file.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/personality.h> | 23 | #include <linux/personality.h> |
24 | #include <linux/elfcore.h> | 24 | #include <linux/elfcore.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/highuid.h> | 26 | #include <linux/highuid.h> |
27 | #include <linux/compiler.h> | 27 | #include <linux/compiler.h> |
28 | #include <linux/highmem.h> | 28 | #include <linux/highmem.h> |
29 | #include <linux/pagemap.h> | 29 | #include <linux/pagemap.h> |
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | #include <linux/security.h> | 31 | #include <linux/security.h> |
32 | #include <linux/random.h> | 32 | #include <linux/random.h> |
33 | #include <linux/elf.h> | 33 | #include <linux/elf.h> |
34 | #include <linux/utsname.h> | 34 | #include <linux/utsname.h> |
35 | #include <linux/coredump.h> | 35 | #include <linux/coredump.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/param.h> | 38 | #include <asm/param.h> |
39 | #include <asm/page.h> | 39 | #include <asm/page.h> |
40 | 40 | ||
41 | #ifndef user_long_t | 41 | #ifndef user_long_t |
42 | #define user_long_t long | 42 | #define user_long_t long |
43 | #endif | 43 | #endif |
44 | #ifndef user_siginfo_t | 44 | #ifndef user_siginfo_t |
45 | #define user_siginfo_t siginfo_t | 45 | #define user_siginfo_t siginfo_t |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | static int load_elf_binary(struct linux_binprm *bprm); | 48 | static int load_elf_binary(struct linux_binprm *bprm); |
49 | static int load_elf_library(struct file *); | 49 | static int load_elf_library(struct file *); |
50 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, | 50 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, |
51 | int, int, unsigned long); | 51 | int, int, unsigned long); |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * If we don't support core dumping, then supply a NULL so we | 54 | * If we don't support core dumping, then supply a NULL so we |
55 | * don't even try. | 55 | * don't even try. |
56 | */ | 56 | */ |
57 | #ifdef CONFIG_ELF_CORE | 57 | #ifdef CONFIG_ELF_CORE |
58 | static int elf_core_dump(struct coredump_params *cprm); | 58 | static int elf_core_dump(struct coredump_params *cprm); |
59 | #else | 59 | #else |
60 | #define elf_core_dump NULL | 60 | #define elf_core_dump NULL |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | #if ELF_EXEC_PAGESIZE > PAGE_SIZE | 63 | #if ELF_EXEC_PAGESIZE > PAGE_SIZE |
64 | #define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE | 64 | #define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE |
65 | #else | 65 | #else |
66 | #define ELF_MIN_ALIGN PAGE_SIZE | 66 | #define ELF_MIN_ALIGN PAGE_SIZE |
67 | #endif | 67 | #endif |
68 | 68 | ||
69 | #ifndef ELF_CORE_EFLAGS | 69 | #ifndef ELF_CORE_EFLAGS |
70 | #define ELF_CORE_EFLAGS 0 | 70 | #define ELF_CORE_EFLAGS 0 |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) | 73 | #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) |
74 | #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) | 74 | #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) |
75 | #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) | 75 | #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) |
76 | 76 | ||
77 | static struct linux_binfmt elf_format = { | 77 | static struct linux_binfmt elf_format = { |
78 | .module = THIS_MODULE, | 78 | .module = THIS_MODULE, |
79 | .load_binary = load_elf_binary, | 79 | .load_binary = load_elf_binary, |
80 | .load_shlib = load_elf_library, | 80 | .load_shlib = load_elf_library, |
81 | .core_dump = elf_core_dump, | 81 | .core_dump = elf_core_dump, |
82 | .min_coredump = ELF_EXEC_PAGESIZE, | 82 | .min_coredump = ELF_EXEC_PAGESIZE, |
83 | }; | 83 | }; |
84 | 84 | ||
85 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) | 85 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) |
86 | 86 | ||
87 | static int set_brk(unsigned long start, unsigned long end) | 87 | static int set_brk(unsigned long start, unsigned long end) |
88 | { | 88 | { |
89 | start = ELF_PAGEALIGN(start); | 89 | start = ELF_PAGEALIGN(start); |
90 | end = ELF_PAGEALIGN(end); | 90 | end = ELF_PAGEALIGN(end); |
91 | if (end > start) { | 91 | if (end > start) { |
92 | unsigned long addr; | 92 | unsigned long addr; |
93 | addr = vm_brk(start, end - start); | 93 | addr = vm_brk(start, end - start); |
94 | if (BAD_ADDR(addr)) | 94 | if (BAD_ADDR(addr)) |
95 | return addr; | 95 | return addr; |
96 | } | 96 | } |
97 | current->mm->start_brk = current->mm->brk = end; | 97 | current->mm->start_brk = current->mm->brk = end; |
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | /* We need to explicitly zero any fractional pages | 101 | /* We need to explicitly zero any fractional pages |
102 | after the data section (i.e. bss). This would | 102 | after the data section (i.e. bss). This would |
103 | contain the junk from the file that should not | 103 | contain the junk from the file that should not |
104 | be in memory | 104 | be in memory |
105 | */ | 105 | */ |
106 | static int padzero(unsigned long elf_bss) | 106 | static int padzero(unsigned long elf_bss) |
107 | { | 107 | { |
108 | unsigned long nbyte; | 108 | unsigned long nbyte; |
109 | 109 | ||
110 | nbyte = ELF_PAGEOFFSET(elf_bss); | 110 | nbyte = ELF_PAGEOFFSET(elf_bss); |
111 | if (nbyte) { | 111 | if (nbyte) { |
112 | nbyte = ELF_MIN_ALIGN - nbyte; | 112 | nbyte = ELF_MIN_ALIGN - nbyte; |
113 | if (clear_user((void __user *) elf_bss, nbyte)) | 113 | if (clear_user((void __user *) elf_bss, nbyte)) |
114 | return -EFAULT; | 114 | return -EFAULT; |
115 | } | 115 | } |
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | 118 | ||
119 | /* Let's use some macros to make this stack manipulation a little clearer */ | 119 | /* Let's use some macros to make this stack manipulation a little clearer */ |
120 | #ifdef CONFIG_STACK_GROWSUP | 120 | #ifdef CONFIG_STACK_GROWSUP |
121 | #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) | 121 | #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) |
122 | #define STACK_ROUND(sp, items) \ | 122 | #define STACK_ROUND(sp, items) \ |
123 | ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) | 123 | ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) |
124 | #define STACK_ALLOC(sp, len) ({ \ | 124 | #define STACK_ALLOC(sp, len) ({ \ |
125 | elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \ | 125 | elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \ |
126 | old_sp; }) | 126 | old_sp; }) |
127 | #else | 127 | #else |
128 | #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) | 128 | #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) |
129 | #define STACK_ROUND(sp, items) \ | 129 | #define STACK_ROUND(sp, items) \ |
130 | (((unsigned long) (sp - items)) &~ 15UL) | 130 | (((unsigned long) (sp - items)) &~ 15UL) |
131 | #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) | 131 | #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) |
132 | #endif | 132 | #endif |
133 | 133 | ||
134 | #ifndef ELF_BASE_PLATFORM | 134 | #ifndef ELF_BASE_PLATFORM |
135 | /* | 135 | /* |
136 | * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. | 136 | * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. |
137 | * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value | 137 | * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value |
138 | * will be copied to the user stack in the same manner as AT_PLATFORM. | 138 | * will be copied to the user stack in the same manner as AT_PLATFORM. |
139 | */ | 139 | */ |
140 | #define ELF_BASE_PLATFORM NULL | 140 | #define ELF_BASE_PLATFORM NULL |
141 | #endif | 141 | #endif |
142 | 142 | ||
143 | static int | 143 | static int |
144 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | 144 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, |
145 | unsigned long load_addr, unsigned long interp_load_addr) | 145 | unsigned long load_addr, unsigned long interp_load_addr) |
146 | { | 146 | { |
147 | unsigned long p = bprm->p; | 147 | unsigned long p = bprm->p; |
148 | int argc = bprm->argc; | 148 | int argc = bprm->argc; |
149 | int envc = bprm->envc; | 149 | int envc = bprm->envc; |
150 | elf_addr_t __user *argv; | 150 | elf_addr_t __user *argv; |
151 | elf_addr_t __user *envp; | 151 | elf_addr_t __user *envp; |
152 | elf_addr_t __user *sp; | 152 | elf_addr_t __user *sp; |
153 | elf_addr_t __user *u_platform; | 153 | elf_addr_t __user *u_platform; |
154 | elf_addr_t __user *u_base_platform; | 154 | elf_addr_t __user *u_base_platform; |
155 | elf_addr_t __user *u_rand_bytes; | 155 | elf_addr_t __user *u_rand_bytes; |
156 | const char *k_platform = ELF_PLATFORM; | 156 | const char *k_platform = ELF_PLATFORM; |
157 | const char *k_base_platform = ELF_BASE_PLATFORM; | 157 | const char *k_base_platform = ELF_BASE_PLATFORM; |
158 | unsigned char k_rand_bytes[16]; | 158 | unsigned char k_rand_bytes[16]; |
159 | int items; | 159 | int items; |
160 | elf_addr_t *elf_info; | 160 | elf_addr_t *elf_info; |
161 | int ei_index = 0; | 161 | int ei_index = 0; |
162 | const struct cred *cred = current_cred(); | 162 | const struct cred *cred = current_cred(); |
163 | struct vm_area_struct *vma; | 163 | struct vm_area_struct *vma; |
164 | 164 | ||
165 | /* | 165 | /* |
166 | * In some cases (e.g. Hyper-Threading), we want to avoid L1 | 166 | * In some cases (e.g. Hyper-Threading), we want to avoid L1 |
167 | * evictions by the processes running on the same package. One | 167 | * evictions by the processes running on the same package. One |
168 | * thing we can do is to shuffle the initial stack for them. | 168 | * thing we can do is to shuffle the initial stack for them. |
169 | */ | 169 | */ |
170 | 170 | ||
171 | p = arch_align_stack(p); | 171 | p = arch_align_stack(p); |
172 | 172 | ||
173 | /* | 173 | /* |
174 | * If this architecture has a platform capability string, copy it | 174 | * If this architecture has a platform capability string, copy it |
175 | * to userspace. In some cases (Sparc), this info is impossible | 175 | * to userspace. In some cases (Sparc), this info is impossible |
176 | * for userspace to get any other way, in others (i386) it is | 176 | * for userspace to get any other way, in others (i386) it is |
177 | * merely difficult. | 177 | * merely difficult. |
178 | */ | 178 | */ |
179 | u_platform = NULL; | 179 | u_platform = NULL; |
180 | if (k_platform) { | 180 | if (k_platform) { |
181 | size_t len = strlen(k_platform) + 1; | 181 | size_t len = strlen(k_platform) + 1; |
182 | 182 | ||
183 | u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); | 183 | u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); |
184 | if (__copy_to_user(u_platform, k_platform, len)) | 184 | if (__copy_to_user(u_platform, k_platform, len)) |
185 | return -EFAULT; | 185 | return -EFAULT; |
186 | } | 186 | } |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * If this architecture has a "base" platform capability | 189 | * If this architecture has a "base" platform capability |
190 | * string, copy it to userspace. | 190 | * string, copy it to userspace. |
191 | */ | 191 | */ |
192 | u_base_platform = NULL; | 192 | u_base_platform = NULL; |
193 | if (k_base_platform) { | 193 | if (k_base_platform) { |
194 | size_t len = strlen(k_base_platform) + 1; | 194 | size_t len = strlen(k_base_platform) + 1; |
195 | 195 | ||
196 | u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); | 196 | u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); |
197 | if (__copy_to_user(u_base_platform, k_base_platform, len)) | 197 | if (__copy_to_user(u_base_platform, k_base_platform, len)) |
198 | return -EFAULT; | 198 | return -EFAULT; |
199 | } | 199 | } |
200 | 200 | ||
201 | /* | 201 | /* |
202 | * Generate 16 random bytes for userspace PRNG seeding. | 202 | * Generate 16 random bytes for userspace PRNG seeding. |
203 | */ | 203 | */ |
204 | get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); | 204 | get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); |
205 | u_rand_bytes = (elf_addr_t __user *) | 205 | u_rand_bytes = (elf_addr_t __user *) |
206 | STACK_ALLOC(p, sizeof(k_rand_bytes)); | 206 | STACK_ALLOC(p, sizeof(k_rand_bytes)); |
207 | if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) | 207 | if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) |
208 | return -EFAULT; | 208 | return -EFAULT; |
209 | 209 | ||
210 | /* Create the ELF interpreter info */ | 210 | /* Create the ELF interpreter info */ |
211 | elf_info = (elf_addr_t *)current->mm->saved_auxv; | 211 | elf_info = (elf_addr_t *)current->mm->saved_auxv; |
212 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ | 212 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ |
213 | #define NEW_AUX_ENT(id, val) \ | 213 | #define NEW_AUX_ENT(id, val) \ |
214 | do { \ | 214 | do { \ |
215 | elf_info[ei_index++] = id; \ | 215 | elf_info[ei_index++] = id; \ |
216 | elf_info[ei_index++] = val; \ | 216 | elf_info[ei_index++] = val; \ |
217 | } while (0) | 217 | } while (0) |
218 | 218 | ||
219 | #ifdef ARCH_DLINFO | 219 | #ifdef ARCH_DLINFO |
220 | /* | 220 | /* |
221 | * ARCH_DLINFO must come first so PPC can do its special alignment of | 221 | * ARCH_DLINFO must come first so PPC can do its special alignment of |
222 | * AUXV. | 222 | * AUXV. |
223 | * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in | 223 | * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in |
224 | * ARCH_DLINFO changes | 224 | * ARCH_DLINFO changes |
225 | */ | 225 | */ |
226 | ARCH_DLINFO; | 226 | ARCH_DLINFO; |
227 | #endif | 227 | #endif |
228 | NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); | 228 | NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); |
229 | NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); | 229 | NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); |
230 | NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); | 230 | NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); |
231 | NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); | 231 | NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); |
232 | NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); | 232 | NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); |
233 | NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); | 233 | NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); |
234 | NEW_AUX_ENT(AT_BASE, interp_load_addr); | 234 | NEW_AUX_ENT(AT_BASE, interp_load_addr); |
235 | NEW_AUX_ENT(AT_FLAGS, 0); | 235 | NEW_AUX_ENT(AT_FLAGS, 0); |
236 | NEW_AUX_ENT(AT_ENTRY, exec->e_entry); | 236 | NEW_AUX_ENT(AT_ENTRY, exec->e_entry); |
237 | NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); | 237 | NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); |
238 | NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); | 238 | NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); |
239 | NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); | 239 | NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); |
240 | NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); | 240 | NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); |
241 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); | 241 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); |
242 | NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); | 242 | NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); |
243 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); | 243 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); |
244 | if (k_platform) { | 244 | if (k_platform) { |
245 | NEW_AUX_ENT(AT_PLATFORM, | 245 | NEW_AUX_ENT(AT_PLATFORM, |
246 | (elf_addr_t)(unsigned long)u_platform); | 246 | (elf_addr_t)(unsigned long)u_platform); |
247 | } | 247 | } |
248 | if (k_base_platform) { | 248 | if (k_base_platform) { |
249 | NEW_AUX_ENT(AT_BASE_PLATFORM, | 249 | NEW_AUX_ENT(AT_BASE_PLATFORM, |
250 | (elf_addr_t)(unsigned long)u_base_platform); | 250 | (elf_addr_t)(unsigned long)u_base_platform); |
251 | } | 251 | } |
252 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { | 252 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { |
253 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); | 253 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); |
254 | } | 254 | } |
255 | #undef NEW_AUX_ENT | 255 | #undef NEW_AUX_ENT |
256 | /* AT_NULL is zero; clear the rest too */ | 256 | /* AT_NULL is zero; clear the rest too */ |
257 | memset(&elf_info[ei_index], 0, | 257 | memset(&elf_info[ei_index], 0, |
258 | sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); | 258 | sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); |
259 | 259 | ||
260 | /* And advance past the AT_NULL entry. */ | 260 | /* And advance past the AT_NULL entry. */ |
261 | ei_index += 2; | 261 | ei_index += 2; |
262 | 262 | ||
263 | sp = STACK_ADD(p, ei_index); | 263 | sp = STACK_ADD(p, ei_index); |
264 | 264 | ||
265 | items = (argc + 1) + (envc + 1) + 1; | 265 | items = (argc + 1) + (envc + 1) + 1; |
266 | bprm->p = STACK_ROUND(sp, items); | 266 | bprm->p = STACK_ROUND(sp, items); |
267 | 267 | ||
268 | /* Point sp at the lowest address on the stack */ | 268 | /* Point sp at the lowest address on the stack */ |
269 | #ifdef CONFIG_STACK_GROWSUP | 269 | #ifdef CONFIG_STACK_GROWSUP |
270 | sp = (elf_addr_t __user *)bprm->p - items - ei_index; | 270 | sp = (elf_addr_t __user *)bprm->p - items - ei_index; |
271 | bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */ | 271 | bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */ |
272 | #else | 272 | #else |
273 | sp = (elf_addr_t __user *)bprm->p; | 273 | sp = (elf_addr_t __user *)bprm->p; |
274 | #endif | 274 | #endif |
275 | 275 | ||
276 | 276 | ||
277 | /* | 277 | /* |
278 | * Grow the stack manually; some architectures have a limit on how | 278 | * Grow the stack manually; some architectures have a limit on how |
279 | * far ahead a user-space access may be in order to grow the stack. | 279 | * far ahead a user-space access may be in order to grow the stack. |
280 | */ | 280 | */ |
281 | vma = find_extend_vma(current->mm, bprm->p); | 281 | vma = find_extend_vma(current->mm, bprm->p); |
282 | if (!vma) | 282 | if (!vma) |
283 | return -EFAULT; | 283 | return -EFAULT; |
284 | 284 | ||
285 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ | 285 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ |
286 | if (__put_user(argc, sp++)) | 286 | if (__put_user(argc, sp++)) |
287 | return -EFAULT; | 287 | return -EFAULT; |
288 | argv = sp; | 288 | argv = sp; |
289 | envp = argv + argc + 1; | 289 | envp = argv + argc + 1; |
290 | 290 | ||
291 | /* Populate argv and envp */ | 291 | /* Populate argv and envp */ |
292 | p = current->mm->arg_end = current->mm->arg_start; | 292 | p = current->mm->arg_end = current->mm->arg_start; |
293 | while (argc-- > 0) { | 293 | while (argc-- > 0) { |
294 | size_t len; | 294 | size_t len; |
295 | if (__put_user((elf_addr_t)p, argv++)) | 295 | if (__put_user((elf_addr_t)p, argv++)) |
296 | return -EFAULT; | 296 | return -EFAULT; |
297 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); | 297 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); |
298 | if (!len || len > MAX_ARG_STRLEN) | 298 | if (!len || len > MAX_ARG_STRLEN) |
299 | return -EINVAL; | 299 | return -EINVAL; |
300 | p += len; | 300 | p += len; |
301 | } | 301 | } |
302 | if (__put_user(0, argv)) | 302 | if (__put_user(0, argv)) |
303 | return -EFAULT; | 303 | return -EFAULT; |
304 | current->mm->arg_end = current->mm->env_start = p; | 304 | current->mm->arg_end = current->mm->env_start = p; |
305 | while (envc-- > 0) { | 305 | while (envc-- > 0) { |
306 | size_t len; | 306 | size_t len; |
307 | if (__put_user((elf_addr_t)p, envp++)) | 307 | if (__put_user((elf_addr_t)p, envp++)) |
308 | return -EFAULT; | 308 | return -EFAULT; |
309 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); | 309 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); |
310 | if (!len || len > MAX_ARG_STRLEN) | 310 | if (!len || len > MAX_ARG_STRLEN) |
311 | return -EINVAL; | 311 | return -EINVAL; |
312 | p += len; | 312 | p += len; |
313 | } | 313 | } |
314 | if (__put_user(0, envp)) | 314 | if (__put_user(0, envp)) |
315 | return -EFAULT; | 315 | return -EFAULT; |
316 | current->mm->env_end = p; | 316 | current->mm->env_end = p; |
317 | 317 | ||
318 | /* Put the elf_info on the stack in the right place. */ | 318 | /* Put the elf_info on the stack in the right place. */ |
319 | sp = (elf_addr_t __user *)envp + 1; | 319 | sp = (elf_addr_t __user *)envp + 1; |
320 | if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) | 320 | if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) |
321 | return -EFAULT; | 321 | return -EFAULT; |
322 | return 0; | 322 | return 0; |
323 | } | 323 | } |
324 | 324 | ||
325 | #ifndef elf_map | 325 | #ifndef elf_map |
326 | 326 | ||
327 | static unsigned long elf_map(struct file *filep, unsigned long addr, | 327 | static unsigned long elf_map(struct file *filep, unsigned long addr, |
328 | struct elf_phdr *eppnt, int prot, int type, | 328 | struct elf_phdr *eppnt, int prot, int type, |
329 | unsigned long total_size) | 329 | unsigned long total_size) |
330 | { | 330 | { |
331 | unsigned long map_addr; | 331 | unsigned long map_addr; |
332 | unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); | 332 | unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); |
333 | unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); | 333 | unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); |
334 | addr = ELF_PAGESTART(addr); | 334 | addr = ELF_PAGESTART(addr); |
335 | size = ELF_PAGEALIGN(size); | 335 | size = ELF_PAGEALIGN(size); |
336 | 336 | ||
337 | /* mmap() will return -EINVAL if given a zero size, but a | 337 | /* mmap() will return -EINVAL if given a zero size, but a |
338 | * segment with zero filesize is perfectly valid */ | 338 | * segment with zero filesize is perfectly valid */ |
339 | if (!size) | 339 | if (!size) |
340 | return addr; | 340 | return addr; |
341 | 341 | ||
342 | /* | 342 | /* |
343 | * total_size is the size of the ELF (interpreter) image. | 343 | * total_size is the size of the ELF (interpreter) image. |
344 | * The _first_ mmap needs to know the full size, otherwise | 344 | * The _first_ mmap needs to know the full size, otherwise |
345 | * randomization might put this image into an overlapping | 345 | * randomization might put this image into an overlapping |
346 | * position with the ELF binary image. (since size < total_size) | 346 | * position with the ELF binary image. (since size < total_size) |
347 | * So we first map the 'big' image - and unmap the remainder at | 347 | * So we first map the 'big' image - and unmap the remainder at |
348 | * the end. (which unmap is needed for ELF images with holes.) | 348 | * the end. (which unmap is needed for ELF images with holes.) |
349 | */ | 349 | */ |
350 | if (total_size) { | 350 | if (total_size) { |
351 | total_size = ELF_PAGEALIGN(total_size); | 351 | total_size = ELF_PAGEALIGN(total_size); |
352 | map_addr = vm_mmap(filep, addr, total_size, prot, type, off); | 352 | map_addr = vm_mmap(filep, addr, total_size, prot, type, off); |
353 | if (!BAD_ADDR(map_addr)) | 353 | if (!BAD_ADDR(map_addr)) |
354 | vm_munmap(map_addr+size, total_size-size); | 354 | vm_munmap(map_addr+size, total_size-size); |
355 | } else | 355 | } else |
356 | map_addr = vm_mmap(filep, addr, size, prot, type, off); | 356 | map_addr = vm_mmap(filep, addr, size, prot, type, off); |
357 | 357 | ||
358 | return(map_addr); | 358 | return(map_addr); |
359 | } | 359 | } |
360 | 360 | ||
361 | #endif /* !elf_map */ | 361 | #endif /* !elf_map */ |
362 | 362 | ||
363 | static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) | 363 | static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) |
364 | { | 364 | { |
365 | int i, first_idx = -1, last_idx = -1; | 365 | int i, first_idx = -1, last_idx = -1; |
366 | 366 | ||
367 | for (i = 0; i < nr; i++) { | 367 | for (i = 0; i < nr; i++) { |
368 | if (cmds[i].p_type == PT_LOAD) { | 368 | if (cmds[i].p_type == PT_LOAD) { |
369 | last_idx = i; | 369 | last_idx = i; |
370 | if (first_idx == -1) | 370 | if (first_idx == -1) |
371 | first_idx = i; | 371 | first_idx = i; |
372 | } | 372 | } |
373 | } | 373 | } |
374 | if (first_idx == -1) | 374 | if (first_idx == -1) |
375 | return 0; | 375 | return 0; |
376 | 376 | ||
377 | return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - | 377 | return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - |
378 | ELF_PAGESTART(cmds[first_idx].p_vaddr); | 378 | ELF_PAGESTART(cmds[first_idx].p_vaddr); |
379 | } | 379 | } |
380 | 380 | ||
381 | 381 | ||
382 | /* This is much more generalized than the library routine read function, | 382 | /* This is much more generalized than the library routine read function, |
383 | so we keep this separate. Technically the library read function | 383 | so we keep this separate. Technically the library read function |
384 | is only provided so that we can read a.out libraries that have | 384 | is only provided so that we can read a.out libraries that have |
385 | an ELF header */ | 385 | an ELF header */ |
386 | 386 | ||
387 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | 387 | static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, |
388 | struct file *interpreter, unsigned long *interp_map_addr, | 388 | struct file *interpreter, unsigned long *interp_map_addr, |
389 | unsigned long no_base) | 389 | unsigned long no_base) |
390 | { | 390 | { |
391 | struct elf_phdr *elf_phdata; | 391 | struct elf_phdr *elf_phdata; |
392 | struct elf_phdr *eppnt; | 392 | struct elf_phdr *eppnt; |
393 | unsigned long load_addr = 0; | 393 | unsigned long load_addr = 0; |
394 | int load_addr_set = 0; | 394 | int load_addr_set = 0; |
395 | unsigned long last_bss = 0, elf_bss = 0; | 395 | unsigned long last_bss = 0, elf_bss = 0; |
396 | unsigned long error = ~0UL; | 396 | unsigned long error = ~0UL; |
397 | unsigned long total_size; | 397 | unsigned long total_size; |
398 | int retval, i, size; | 398 | int retval, i, size; |
399 | 399 | ||
400 | /* First of all, some simple consistency checks */ | 400 | /* First of all, some simple consistency checks */ |
401 | if (interp_elf_ex->e_type != ET_EXEC && | 401 | if (interp_elf_ex->e_type != ET_EXEC && |
402 | interp_elf_ex->e_type != ET_DYN) | 402 | interp_elf_ex->e_type != ET_DYN) |
403 | goto out; | 403 | goto out; |
404 | if (!elf_check_arch(interp_elf_ex)) | 404 | if (!elf_check_arch(interp_elf_ex)) |
405 | goto out; | 405 | goto out; |
406 | if (!interpreter->f_op || !interpreter->f_op->mmap) | 406 | if (!interpreter->f_op || !interpreter->f_op->mmap) |
407 | goto out; | 407 | goto out; |
408 | 408 | ||
409 | /* | 409 | /* |
410 | * If the size of this structure has changed, then punt, since | 410 | * If the size of this structure has changed, then punt, since |
411 | * we will be doing the wrong thing. | 411 | * we will be doing the wrong thing. |
412 | */ | 412 | */ |
413 | if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) | 413 | if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) |
414 | goto out; | 414 | goto out; |
415 | if (interp_elf_ex->e_phnum < 1 || | 415 | if (interp_elf_ex->e_phnum < 1 || |
416 | interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) | 416 | interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) |
417 | goto out; | 417 | goto out; |
418 | 418 | ||
419 | /* Now read in all of the header information */ | 419 | /* Now read in all of the header information */ |
420 | size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum; | 420 | size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum; |
421 | if (size > ELF_MIN_ALIGN) | 421 | if (size > ELF_MIN_ALIGN) |
422 | goto out; | 422 | goto out; |
423 | elf_phdata = kmalloc(size, GFP_KERNEL); | 423 | elf_phdata = kmalloc(size, GFP_KERNEL); |
424 | if (!elf_phdata) | 424 | if (!elf_phdata) |
425 | goto out; | 425 | goto out; |
426 | 426 | ||
427 | retval = kernel_read(interpreter, interp_elf_ex->e_phoff, | 427 | retval = kernel_read(interpreter, interp_elf_ex->e_phoff, |
428 | (char *)elf_phdata, size); | 428 | (char *)elf_phdata, size); |
429 | error = -EIO; | 429 | error = -EIO; |
430 | if (retval != size) { | 430 | if (retval != size) { |
431 | if (retval < 0) | 431 | if (retval < 0) |
432 | error = retval; | 432 | error = retval; |
433 | goto out_close; | 433 | goto out_close; |
434 | } | 434 | } |
435 | 435 | ||
436 | total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); | 436 | total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); |
437 | if (!total_size) { | 437 | if (!total_size) { |
438 | error = -EINVAL; | 438 | error = -EINVAL; |
439 | goto out_close; | 439 | goto out_close; |
440 | } | 440 | } |
441 | 441 | ||
442 | eppnt = elf_phdata; | 442 | eppnt = elf_phdata; |
443 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { | 443 | for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { |
444 | if (eppnt->p_type == PT_LOAD) { | 444 | if (eppnt->p_type == PT_LOAD) { |
445 | int elf_type = MAP_PRIVATE | MAP_DENYWRITE; | 445 | int elf_type = MAP_PRIVATE | MAP_DENYWRITE; |
446 | int elf_prot = 0; | 446 | int elf_prot = 0; |
447 | unsigned long vaddr = 0; | 447 | unsigned long vaddr = 0; |
448 | unsigned long k, map_addr; | 448 | unsigned long k, map_addr; |
449 | 449 | ||
450 | if (eppnt->p_flags & PF_R) | 450 | if (eppnt->p_flags & PF_R) |
451 | elf_prot = PROT_READ; | 451 | elf_prot = PROT_READ; |
452 | if (eppnt->p_flags & PF_W) | 452 | if (eppnt->p_flags & PF_W) |
453 | elf_prot |= PROT_WRITE; | 453 | elf_prot |= PROT_WRITE; |
454 | if (eppnt->p_flags & PF_X) | 454 | if (eppnt->p_flags & PF_X) |
455 | elf_prot |= PROT_EXEC; | 455 | elf_prot |= PROT_EXEC; |
456 | vaddr = eppnt->p_vaddr; | 456 | vaddr = eppnt->p_vaddr; |
457 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) | 457 | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) |
458 | elf_type |= MAP_FIXED; | 458 | elf_type |= MAP_FIXED; |
459 | else if (no_base && interp_elf_ex->e_type == ET_DYN) | 459 | else if (no_base && interp_elf_ex->e_type == ET_DYN) |
460 | load_addr = -vaddr; | 460 | load_addr = -vaddr; |
461 | 461 | ||
462 | map_addr = elf_map(interpreter, load_addr + vaddr, | 462 | map_addr = elf_map(interpreter, load_addr + vaddr, |
463 | eppnt, elf_prot, elf_type, total_size); | 463 | eppnt, elf_prot, elf_type, total_size); |
464 | total_size = 0; | 464 | total_size = 0; |
465 | if (!*interp_map_addr) | 465 | if (!*interp_map_addr) |
466 | *interp_map_addr = map_addr; | 466 | *interp_map_addr = map_addr; |
467 | error = map_addr; | 467 | error = map_addr; |
468 | if (BAD_ADDR(map_addr)) | 468 | if (BAD_ADDR(map_addr)) |
469 | goto out_close; | 469 | goto out_close; |
470 | 470 | ||
471 | if (!load_addr_set && | 471 | if (!load_addr_set && |
472 | interp_elf_ex->e_type == ET_DYN) { | 472 | interp_elf_ex->e_type == ET_DYN) { |
473 | load_addr = map_addr - ELF_PAGESTART(vaddr); | 473 | load_addr = map_addr - ELF_PAGESTART(vaddr); |
474 | load_addr_set = 1; | 474 | load_addr_set = 1; |
475 | } | 475 | } |
476 | 476 | ||
477 | /* | 477 | /* |
478 | * Check to see if the section's size will overflow the | 478 | * Check to see if the section's size will overflow the |
479 | * allowed task size. Note that p_filesz must always be | 479 | * allowed task size. Note that p_filesz must always be |
480 | * <= p_memsize so it's only necessary to check p_memsz. | 480 | * <= p_memsize so it's only necessary to check p_memsz. |
481 | */ | 481 | */ |
482 | k = load_addr + eppnt->p_vaddr; | 482 | k = load_addr + eppnt->p_vaddr; |
483 | if (BAD_ADDR(k) || | 483 | if (BAD_ADDR(k) || |
484 | eppnt->p_filesz > eppnt->p_memsz || | 484 | eppnt->p_filesz > eppnt->p_memsz || |
485 | eppnt->p_memsz > TASK_SIZE || | 485 | eppnt->p_memsz > TASK_SIZE || |
486 | TASK_SIZE - eppnt->p_memsz < k) { | 486 | TASK_SIZE - eppnt->p_memsz < k) { |
487 | error = -ENOMEM; | 487 | error = -ENOMEM; |
488 | goto out_close; | 488 | goto out_close; |
489 | } | 489 | } |
490 | 490 | ||
491 | /* | 491 | /* |
492 | * Find the end of the file mapping for this phdr, and | 492 | * Find the end of the file mapping for this phdr, and |
493 | * keep track of the largest address we see for this. | 493 | * keep track of the largest address we see for this. |
494 | */ | 494 | */ |
495 | k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; | 495 | k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; |
496 | if (k > elf_bss) | 496 | if (k > elf_bss) |
497 | elf_bss = k; | 497 | elf_bss = k; |
498 | 498 | ||
499 | /* | 499 | /* |
500 | * Do the same thing for the memory mapping - between | 500 | * Do the same thing for the memory mapping - between |
501 | * elf_bss and last_bss is the bss section. | 501 | * elf_bss and last_bss is the bss section. |
502 | */ | 502 | */ |
503 | k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; | 503 | k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; |
504 | if (k > last_bss) | 504 | if (k > last_bss) |
505 | last_bss = k; | 505 | last_bss = k; |
506 | } | 506 | } |
507 | } | 507 | } |
508 | 508 | ||
509 | if (last_bss > elf_bss) { | 509 | if (last_bss > elf_bss) { |
510 | /* | 510 | /* |
511 | * Now fill out the bss section. First pad the last page up | 511 | * Now fill out the bss section. First pad the last page up |
512 | * to the page boundary, and then perform a mmap to make sure | 512 | * to the page boundary, and then perform a mmap to make sure |
513 | * that there are zero-mapped pages up to and including the | 513 | * that there are zero-mapped pages up to and including the |
514 | * last bss page. | 514 | * last bss page. |
515 | */ | 515 | */ |
516 | if (padzero(elf_bss)) { | 516 | if (padzero(elf_bss)) { |
517 | error = -EFAULT; | 517 | error = -EFAULT; |
518 | goto out_close; | 518 | goto out_close; |
519 | } | 519 | } |
520 | 520 | ||
521 | /* What we have mapped so far */ | 521 | /* What we have mapped so far */ |
522 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); | 522 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); |
523 | 523 | ||
524 | /* Map the last of the bss segment */ | 524 | /* Map the last of the bss segment */ |
525 | error = vm_brk(elf_bss, last_bss - elf_bss); | 525 | error = vm_brk(elf_bss, last_bss - elf_bss); |
526 | if (BAD_ADDR(error)) | 526 | if (BAD_ADDR(error)) |
527 | goto out_close; | 527 | goto out_close; |
528 | } | 528 | } |
529 | 529 | ||
530 | error = load_addr; | 530 | error = load_addr; |
531 | 531 | ||
532 | out_close: | 532 | out_close: |
533 | kfree(elf_phdata); | 533 | kfree(elf_phdata); |
534 | out: | 534 | out: |
535 | return error; | 535 | return error; |
536 | } | 536 | } |
537 | 537 | ||
538 | /* | 538 | /* |
539 | * These are the functions used to load ELF style executables and shared | 539 | * These are the functions used to load ELF style executables and shared |
540 | * libraries. There is no binary dependent code anywhere else. | 540 | * libraries. There is no binary dependent code anywhere else. |
541 | */ | 541 | */ |
542 | 542 | ||
543 | #define INTERPRETER_NONE 0 | 543 | #define INTERPRETER_NONE 0 |
544 | #define INTERPRETER_ELF 2 | 544 | #define INTERPRETER_ELF 2 |
545 | 545 | ||
546 | #ifndef STACK_RND_MASK | 546 | #ifndef STACK_RND_MASK |
547 | #define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12)) /* 8MB of VA */ | 547 | #define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12)) /* 8MB of VA */ |
548 | #endif | 548 | #endif |
549 | 549 | ||
550 | static unsigned long randomize_stack_top(unsigned long stack_top) | 550 | static unsigned long randomize_stack_top(unsigned long stack_top) |
551 | { | 551 | { |
552 | unsigned int random_variable = 0; | 552 | unsigned int random_variable = 0; |
553 | 553 | ||
554 | if ((current->flags & PF_RANDOMIZE) && | 554 | if ((current->flags & PF_RANDOMIZE) && |
555 | !(current->personality & ADDR_NO_RANDOMIZE)) { | 555 | !(current->personality & ADDR_NO_RANDOMIZE)) { |
556 | random_variable = get_random_int() & STACK_RND_MASK; | 556 | random_variable = get_random_int() & STACK_RND_MASK; |
557 | random_variable <<= PAGE_SHIFT; | 557 | random_variable <<= PAGE_SHIFT; |
558 | } | 558 | } |
559 | #ifdef CONFIG_STACK_GROWSUP | 559 | #ifdef CONFIG_STACK_GROWSUP |
560 | return PAGE_ALIGN(stack_top) + random_variable; | 560 | return PAGE_ALIGN(stack_top) + random_variable; |
561 | #else | 561 | #else |
562 | return PAGE_ALIGN(stack_top) - random_variable; | 562 | return PAGE_ALIGN(stack_top) - random_variable; |
563 | #endif | 563 | #endif |
564 | } | 564 | } |
565 | 565 | ||
566 | static int load_elf_binary(struct linux_binprm *bprm) | 566 | static int load_elf_binary(struct linux_binprm *bprm) |
567 | { | 567 | { |
568 | struct file *interpreter = NULL; /* to shut gcc up */ | 568 | struct file *interpreter = NULL; /* to shut gcc up */ |
569 | unsigned long load_addr = 0, load_bias = 0; | 569 | unsigned long load_addr = 0, load_bias = 0; |
570 | int load_addr_set = 0; | 570 | int load_addr_set = 0; |
571 | char * elf_interpreter = NULL; | 571 | char * elf_interpreter = NULL; |
572 | unsigned long error; | 572 | unsigned long error; |
573 | struct elf_phdr *elf_ppnt, *elf_phdata; | 573 | struct elf_phdr *elf_ppnt, *elf_phdata; |
574 | unsigned long elf_bss, elf_brk; | 574 | unsigned long elf_bss, elf_brk; |
575 | int retval, i; | 575 | int retval, i; |
576 | unsigned int size; | 576 | unsigned int size; |
577 | unsigned long elf_entry; | 577 | unsigned long elf_entry; |
578 | unsigned long interp_load_addr = 0; | 578 | unsigned long interp_load_addr = 0; |
579 | unsigned long start_code, end_code, start_data, end_data; | 579 | unsigned long start_code, end_code, start_data, end_data; |
580 | unsigned long reloc_func_desc __maybe_unused = 0; | 580 | unsigned long reloc_func_desc __maybe_unused = 0; |
581 | int executable_stack = EXSTACK_DEFAULT; | 581 | int executable_stack = EXSTACK_DEFAULT; |
582 | unsigned long def_flags = 0; | 582 | unsigned long def_flags = 0; |
583 | struct pt_regs *regs = current_pt_regs(); | 583 | struct pt_regs *regs = current_pt_regs(); |
584 | struct { | 584 | struct { |
585 | struct elfhdr elf_ex; | 585 | struct elfhdr elf_ex; |
586 | struct elfhdr interp_elf_ex; | 586 | struct elfhdr interp_elf_ex; |
587 | } *loc; | 587 | } *loc; |
588 | 588 | ||
589 | loc = kmalloc(sizeof(*loc), GFP_KERNEL); | 589 | loc = kmalloc(sizeof(*loc), GFP_KERNEL); |
590 | if (!loc) { | 590 | if (!loc) { |
591 | retval = -ENOMEM; | 591 | retval = -ENOMEM; |
592 | goto out_ret; | 592 | goto out_ret; |
593 | } | 593 | } |
594 | 594 | ||
595 | /* Get the exec-header */ | 595 | /* Get the exec-header */ |
596 | loc->elf_ex = *((struct elfhdr *)bprm->buf); | 596 | loc->elf_ex = *((struct elfhdr *)bprm->buf); |
597 | 597 | ||
598 | retval = -ENOEXEC; | 598 | retval = -ENOEXEC; |
599 | /* First of all, some simple consistency checks */ | 599 | /* First of all, some simple consistency checks */ |
600 | if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) | 600 | if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
601 | goto out; | 601 | goto out; |
602 | 602 | ||
603 | if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) | 603 | if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) |
604 | goto out; | 604 | goto out; |
605 | if (!elf_check_arch(&loc->elf_ex)) | 605 | if (!elf_check_arch(&loc->elf_ex)) |
606 | goto out; | 606 | goto out; |
607 | if (!bprm->file->f_op || !bprm->file->f_op->mmap) | 607 | if (!bprm->file->f_op || !bprm->file->f_op->mmap) |
608 | goto out; | 608 | goto out; |
609 | 609 | ||
610 | /* Now read in all of the header information */ | 610 | /* Now read in all of the header information */ |
611 | if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) | 611 | if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) |
612 | goto out; | 612 | goto out; |
613 | if (loc->elf_ex.e_phnum < 1 || | 613 | if (loc->elf_ex.e_phnum < 1 || |
614 | loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) | 614 | loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) |
615 | goto out; | 615 | goto out; |
616 | size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr); | 616 | size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr); |
617 | retval = -ENOMEM; | 617 | retval = -ENOMEM; |
618 | elf_phdata = kmalloc(size, GFP_KERNEL); | 618 | elf_phdata = kmalloc(size, GFP_KERNEL); |
619 | if (!elf_phdata) | 619 | if (!elf_phdata) |
620 | goto out; | 620 | goto out; |
621 | 621 | ||
622 | retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, | 622 | retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, |
623 | (char *)elf_phdata, size); | 623 | (char *)elf_phdata, size); |
624 | if (retval != size) { | 624 | if (retval != size) { |
625 | if (retval >= 0) | 625 | if (retval >= 0) |
626 | retval = -EIO; | 626 | retval = -EIO; |
627 | goto out_free_ph; | 627 | goto out_free_ph; |
628 | } | 628 | } |
629 | 629 | ||
630 | elf_ppnt = elf_phdata; | 630 | elf_ppnt = elf_phdata; |
631 | elf_bss = 0; | 631 | elf_bss = 0; |
632 | elf_brk = 0; | 632 | elf_brk = 0; |
633 | 633 | ||
634 | start_code = ~0UL; | 634 | start_code = ~0UL; |
635 | end_code = 0; | 635 | end_code = 0; |
636 | start_data = 0; | 636 | start_data = 0; |
637 | end_data = 0; | 637 | end_data = 0; |
638 | 638 | ||
639 | for (i = 0; i < loc->elf_ex.e_phnum; i++) { | 639 | for (i = 0; i < loc->elf_ex.e_phnum; i++) { |
640 | if (elf_ppnt->p_type == PT_INTERP) { | 640 | if (elf_ppnt->p_type == PT_INTERP) { |
641 | /* This is the program interpreter used for | 641 | /* This is the program interpreter used for |
642 | * shared libraries - for now assume that this | 642 | * shared libraries - for now assume that this |
643 | * is an a.out format binary | 643 | * is an a.out format binary |
644 | */ | 644 | */ |
645 | retval = -ENOEXEC; | 645 | retval = -ENOEXEC; |
646 | if (elf_ppnt->p_filesz > PATH_MAX || | 646 | if (elf_ppnt->p_filesz > PATH_MAX || |
647 | elf_ppnt->p_filesz < 2) | 647 | elf_ppnt->p_filesz < 2) |
648 | goto out_free_ph; | 648 | goto out_free_ph; |
649 | 649 | ||
650 | retval = -ENOMEM; | 650 | retval = -ENOMEM; |
651 | elf_interpreter = kmalloc(elf_ppnt->p_filesz, | 651 | elf_interpreter = kmalloc(elf_ppnt->p_filesz, |
652 | GFP_KERNEL); | 652 | GFP_KERNEL); |
653 | if (!elf_interpreter) | 653 | if (!elf_interpreter) |
654 | goto out_free_ph; | 654 | goto out_free_ph; |
655 | 655 | ||
656 | retval = kernel_read(bprm->file, elf_ppnt->p_offset, | 656 | retval = kernel_read(bprm->file, elf_ppnt->p_offset, |
657 | elf_interpreter, | 657 | elf_interpreter, |
658 | elf_ppnt->p_filesz); | 658 | elf_ppnt->p_filesz); |
659 | if (retval != elf_ppnt->p_filesz) { | 659 | if (retval != elf_ppnt->p_filesz) { |
660 | if (retval >= 0) | 660 | if (retval >= 0) |
661 | retval = -EIO; | 661 | retval = -EIO; |
662 | goto out_free_interp; | 662 | goto out_free_interp; |
663 | } | 663 | } |
664 | /* make sure path is NULL terminated */ | 664 | /* make sure path is NULL terminated */ |
665 | retval = -ENOEXEC; | 665 | retval = -ENOEXEC; |
666 | if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') | 666 | if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') |
667 | goto out_free_interp; | 667 | goto out_free_interp; |
668 | 668 | ||
669 | interpreter = open_exec(elf_interpreter); | 669 | interpreter = open_exec(elf_interpreter); |
670 | retval = PTR_ERR(interpreter); | 670 | retval = PTR_ERR(interpreter); |
671 | if (IS_ERR(interpreter)) | 671 | if (IS_ERR(interpreter)) |
672 | goto out_free_interp; | 672 | goto out_free_interp; |
673 | 673 | ||
674 | /* | 674 | /* |
675 | * If the binary is not readable then enforce | 675 | * If the binary is not readable then enforce |
676 | * mm->dumpable = 0 regardless of the interpreter's | 676 | * mm->dumpable = 0 regardless of the interpreter's |
677 | * permissions. | 677 | * permissions. |
678 | */ | 678 | */ |
679 | would_dump(bprm, interpreter); | 679 | would_dump(bprm, interpreter); |
680 | 680 | ||
681 | retval = kernel_read(interpreter, 0, bprm->buf, | 681 | retval = kernel_read(interpreter, 0, bprm->buf, |
682 | BINPRM_BUF_SIZE); | 682 | BINPRM_BUF_SIZE); |
683 | if (retval != BINPRM_BUF_SIZE) { | 683 | if (retval != BINPRM_BUF_SIZE) { |
684 | if (retval >= 0) | 684 | if (retval >= 0) |
685 | retval = -EIO; | 685 | retval = -EIO; |
686 | goto out_free_dentry; | 686 | goto out_free_dentry; |
687 | } | 687 | } |
688 | 688 | ||
689 | /* Get the exec headers */ | 689 | /* Get the exec headers */ |
690 | loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); | 690 | loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); |
691 | break; | 691 | break; |
692 | } | 692 | } |
693 | elf_ppnt++; | 693 | elf_ppnt++; |
694 | } | 694 | } |
695 | 695 | ||
696 | elf_ppnt = elf_phdata; | 696 | elf_ppnt = elf_phdata; |
697 | for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) | 697 | for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) |
698 | if (elf_ppnt->p_type == PT_GNU_STACK) { | 698 | if (elf_ppnt->p_type == PT_GNU_STACK) { |
699 | if (elf_ppnt->p_flags & PF_X) | 699 | if (elf_ppnt->p_flags & PF_X) |
700 | executable_stack = EXSTACK_ENABLE_X; | 700 | executable_stack = EXSTACK_ENABLE_X; |
701 | else | 701 | else |
702 | executable_stack = EXSTACK_DISABLE_X; | 702 | executable_stack = EXSTACK_DISABLE_X; |
703 | break; | 703 | break; |
704 | } | 704 | } |
705 | 705 | ||
706 | /* Some simple consistency checks for the interpreter */ | 706 | /* Some simple consistency checks for the interpreter */ |
707 | if (elf_interpreter) { | 707 | if (elf_interpreter) { |
708 | retval = -ELIBBAD; | 708 | retval = -ELIBBAD; |
709 | /* Not an ELF interpreter */ | 709 | /* Not an ELF interpreter */ |
710 | if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) | 710 | if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
711 | goto out_free_dentry; | 711 | goto out_free_dentry; |
712 | /* Verify the interpreter has a valid arch */ | 712 | /* Verify the interpreter has a valid arch */ |
713 | if (!elf_check_arch(&loc->interp_elf_ex)) | 713 | if (!elf_check_arch(&loc->interp_elf_ex)) |
714 | goto out_free_dentry; | 714 | goto out_free_dentry; |
715 | } | 715 | } |
716 | 716 | ||
717 | /* Flush all traces of the currently running executable */ | 717 | /* Flush all traces of the currently running executable */ |
718 | retval = flush_old_exec(bprm); | 718 | retval = flush_old_exec(bprm); |
719 | if (retval) | 719 | if (retval) |
720 | goto out_free_dentry; | 720 | goto out_free_dentry; |
721 | 721 | ||
722 | /* OK, This is the point of no return */ | 722 | /* OK, This is the point of no return */ |
723 | current->mm->def_flags = def_flags; | 723 | current->mm->def_flags = def_flags; |
724 | 724 | ||
725 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages | 725 | /* Do this immediately, since STACK_TOP as used in setup_arg_pages |
726 | may depend on the personality. */ | 726 | may depend on the personality. */ |
727 | SET_PERSONALITY(loc->elf_ex); | 727 | SET_PERSONALITY(loc->elf_ex); |
728 | if (elf_read_implies_exec(loc->elf_ex, executable_stack)) | 728 | if (elf_read_implies_exec(loc->elf_ex, executable_stack)) |
729 | current->personality |= READ_IMPLIES_EXEC; | 729 | current->personality |= READ_IMPLIES_EXEC; |
730 | 730 | ||
731 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) | 731 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) |
732 | current->flags |= PF_RANDOMIZE; | 732 | current->flags |= PF_RANDOMIZE; |
733 | 733 | ||
734 | setup_new_exec(bprm); | 734 | setup_new_exec(bprm); |
735 | 735 | ||
736 | /* Do this so that we can load the interpreter, if need be. We will | 736 | /* Do this so that we can load the interpreter, if need be. We will |
737 | change some of these later */ | 737 | change some of these later */ |
738 | current->mm->free_area_cache = current->mm->mmap_base; | 738 | current->mm->free_area_cache = current->mm->mmap_base; |
739 | current->mm->cached_hole_size = 0; | 739 | current->mm->cached_hole_size = 0; |
740 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), | 740 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), |
741 | executable_stack); | 741 | executable_stack); |
742 | if (retval < 0) { | 742 | if (retval < 0) { |
743 | send_sig(SIGKILL, current, 0); | 743 | send_sig(SIGKILL, current, 0); |
744 | goto out_free_dentry; | 744 | goto out_free_dentry; |
745 | } | 745 | } |
746 | 746 | ||
747 | current->mm->start_stack = bprm->p; | 747 | current->mm->start_stack = bprm->p; |
748 | 748 | ||
749 | /* Now we do a little grungy work by mmapping the ELF image into | 749 | /* Now we do a little grungy work by mmapping the ELF image into |
750 | the correct location in memory. */ | 750 | the correct location in memory. */ |
751 | for(i = 0, elf_ppnt = elf_phdata; | 751 | for(i = 0, elf_ppnt = elf_phdata; |
752 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { | 752 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { |
753 | int elf_prot = 0, elf_flags; | 753 | int elf_prot = 0, elf_flags; |
754 | unsigned long k, vaddr; | 754 | unsigned long k, vaddr; |
755 | 755 | ||
756 | if (elf_ppnt->p_type != PT_LOAD) | 756 | if (elf_ppnt->p_type != PT_LOAD) |
757 | continue; | 757 | continue; |
758 | 758 | ||
759 | if (unlikely (elf_brk > elf_bss)) { | 759 | if (unlikely (elf_brk > elf_bss)) { |
760 | unsigned long nbyte; | 760 | unsigned long nbyte; |
761 | 761 | ||
762 | /* There was a PT_LOAD segment with p_memsz > p_filesz | 762 | /* There was a PT_LOAD segment with p_memsz > p_filesz |
763 | before this one. Map anonymous pages, if needed, | 763 | before this one. Map anonymous pages, if needed, |
764 | and clear the area. */ | 764 | and clear the area. */ |
765 | retval = set_brk(elf_bss + load_bias, | 765 | retval = set_brk(elf_bss + load_bias, |
766 | elf_brk + load_bias); | 766 | elf_brk + load_bias); |
767 | if (retval) { | 767 | if (retval) { |
768 | send_sig(SIGKILL, current, 0); | 768 | send_sig(SIGKILL, current, 0); |
769 | goto out_free_dentry; | 769 | goto out_free_dentry; |
770 | } | 770 | } |
771 | nbyte = ELF_PAGEOFFSET(elf_bss); | 771 | nbyte = ELF_PAGEOFFSET(elf_bss); |
772 | if (nbyte) { | 772 | if (nbyte) { |
773 | nbyte = ELF_MIN_ALIGN - nbyte; | 773 | nbyte = ELF_MIN_ALIGN - nbyte; |
774 | if (nbyte > elf_brk - elf_bss) | 774 | if (nbyte > elf_brk - elf_bss) |
775 | nbyte = elf_brk - elf_bss; | 775 | nbyte = elf_brk - elf_bss; |
776 | if (clear_user((void __user *)elf_bss + | 776 | if (clear_user((void __user *)elf_bss + |
777 | load_bias, nbyte)) { | 777 | load_bias, nbyte)) { |
778 | /* | 778 | /* |
779 | * This bss-zeroing can fail if the ELF | 779 | * This bss-zeroing can fail if the ELF |
780 | * file specifies odd protections. So | 780 | * file specifies odd protections. So |
781 | * we don't check the return value | 781 | * we don't check the return value |
782 | */ | 782 | */ |
783 | } | 783 | } |
784 | } | 784 | } |
785 | } | 785 | } |
786 | 786 | ||
787 | if (elf_ppnt->p_flags & PF_R) | 787 | if (elf_ppnt->p_flags & PF_R) |
788 | elf_prot |= PROT_READ; | 788 | elf_prot |= PROT_READ; |
789 | if (elf_ppnt->p_flags & PF_W) | 789 | if (elf_ppnt->p_flags & PF_W) |
790 | elf_prot |= PROT_WRITE; | 790 | elf_prot |= PROT_WRITE; |
791 | if (elf_ppnt->p_flags & PF_X) | 791 | if (elf_ppnt->p_flags & PF_X) |
792 | elf_prot |= PROT_EXEC; | 792 | elf_prot |= PROT_EXEC; |
793 | 793 | ||
794 | elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; | 794 | elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; |
795 | 795 | ||
796 | vaddr = elf_ppnt->p_vaddr; | 796 | vaddr = elf_ppnt->p_vaddr; |
797 | if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { | 797 | if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { |
798 | elf_flags |= MAP_FIXED; | 798 | elf_flags |= MAP_FIXED; |
799 | } else if (loc->elf_ex.e_type == ET_DYN) { | 799 | } else if (loc->elf_ex.e_type == ET_DYN) { |
800 | /* Try and get dynamic programs out of the way of the | 800 | /* Try and get dynamic programs out of the way of the |
801 | * default mmap base, as well as whatever program they | 801 | * default mmap base, as well as whatever program they |
802 | * might try to exec. This is because the brk will | 802 | * might try to exec. This is because the brk will |
803 | * follow the loader, and is not movable. */ | 803 | * follow the loader, and is not movable. */ |
804 | #ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE | 804 | #ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE |
805 | /* Memory randomization might have been switched off | 805 | /* Memory randomization might have been switched off |
806 | * in runtime via sysctl or explicit setting of | 806 | * in runtime via sysctl or explicit setting of |
807 | * personality flags. | 807 | * personality flags. |
808 | * If that is the case, retain the original non-zero | 808 | * If that is the case, retain the original non-zero |
809 | * load_bias value in order to establish proper | 809 | * load_bias value in order to establish proper |
810 | * non-randomized mappings. | 810 | * non-randomized mappings. |
811 | */ | 811 | */ |
812 | if (current->flags & PF_RANDOMIZE) | 812 | if (current->flags & PF_RANDOMIZE) |
813 | load_bias = 0; | 813 | load_bias = 0; |
814 | else | 814 | else |
815 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); | 815 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); |
816 | #else | 816 | #else |
817 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); | 817 | load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); |
818 | #endif | 818 | #endif |
819 | } | 819 | } |
820 | 820 | ||
821 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, | 821 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, |
822 | elf_prot, elf_flags, 0); | 822 | elf_prot, elf_flags, 0); |
823 | if (BAD_ADDR(error)) { | 823 | if (BAD_ADDR(error)) { |
824 | send_sig(SIGKILL, current, 0); | 824 | send_sig(SIGKILL, current, 0); |
825 | retval = IS_ERR((void *)error) ? | 825 | retval = IS_ERR((void *)error) ? |
826 | PTR_ERR((void*)error) : -EINVAL; | 826 | PTR_ERR((void*)error) : -EINVAL; |
827 | goto out_free_dentry; | 827 | goto out_free_dentry; |
828 | } | 828 | } |
829 | 829 | ||
830 | if (!load_addr_set) { | 830 | if (!load_addr_set) { |
831 | load_addr_set = 1; | 831 | load_addr_set = 1; |
832 | load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); | 832 | load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); |
833 | if (loc->elf_ex.e_type == ET_DYN) { | 833 | if (loc->elf_ex.e_type == ET_DYN) { |
834 | load_bias += error - | 834 | load_bias += error - |
835 | ELF_PAGESTART(load_bias + vaddr); | 835 | ELF_PAGESTART(load_bias + vaddr); |
836 | load_addr += load_bias; | 836 | load_addr += load_bias; |
837 | reloc_func_desc = load_bias; | 837 | reloc_func_desc = load_bias; |
838 | } | 838 | } |
839 | } | 839 | } |
840 | k = elf_ppnt->p_vaddr; | 840 | k = elf_ppnt->p_vaddr; |
841 | if (k < start_code) | 841 | if (k < start_code) |
842 | start_code = k; | 842 | start_code = k; |
843 | if (start_data < k) | 843 | if (start_data < k) |
844 | start_data = k; | 844 | start_data = k; |
845 | 845 | ||
846 | /* | 846 | /* |
847 | * Check to see if the section's size will overflow the | 847 | * Check to see if the section's size will overflow the |
848 | * allowed task size. Note that p_filesz must always be | 848 | * allowed task size. Note that p_filesz must always be |
849 | * <= p_memsz so it is only necessary to check p_memsz. | 849 | * <= p_memsz so it is only necessary to check p_memsz. |
850 | */ | 850 | */ |
851 | if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || | 851 | if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || |
852 | elf_ppnt->p_memsz > TASK_SIZE || | 852 | elf_ppnt->p_memsz > TASK_SIZE || |
853 | TASK_SIZE - elf_ppnt->p_memsz < k) { | 853 | TASK_SIZE - elf_ppnt->p_memsz < k) { |
854 | /* set_brk can never work. Avoid overflows. */ | 854 | /* set_brk can never work. Avoid overflows. */ |
855 | send_sig(SIGKILL, current, 0); | 855 | send_sig(SIGKILL, current, 0); |
856 | retval = -EINVAL; | 856 | retval = -EINVAL; |
857 | goto out_free_dentry; | 857 | goto out_free_dentry; |
858 | } | 858 | } |
859 | 859 | ||
860 | k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; | 860 | k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; |
861 | 861 | ||
862 | if (k > elf_bss) | 862 | if (k > elf_bss) |
863 | elf_bss = k; | 863 | elf_bss = k; |
864 | if ((elf_ppnt->p_flags & PF_X) && end_code < k) | 864 | if ((elf_ppnt->p_flags & PF_X) && end_code < k) |
865 | end_code = k; | 865 | end_code = k; |
866 | if (end_data < k) | 866 | if (end_data < k) |
867 | end_data = k; | 867 | end_data = k; |
868 | k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; | 868 | k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; |
869 | if (k > elf_brk) | 869 | if (k > elf_brk) |
870 | elf_brk = k; | 870 | elf_brk = k; |
871 | } | 871 | } |
872 | 872 | ||
873 | loc->elf_ex.e_entry += load_bias; | 873 | loc->elf_ex.e_entry += load_bias; |
874 | elf_bss += load_bias; | 874 | elf_bss += load_bias; |
875 | elf_brk += load_bias; | 875 | elf_brk += load_bias; |
876 | start_code += load_bias; | 876 | start_code += load_bias; |
877 | end_code += load_bias; | 877 | end_code += load_bias; |
878 | start_data += load_bias; | 878 | start_data += load_bias; |
879 | end_data += load_bias; | 879 | end_data += load_bias; |
880 | 880 | ||
881 | /* Calling set_brk effectively mmaps the pages that we need | 881 | /* Calling set_brk effectively mmaps the pages that we need |
882 | * for the bss and break sections. We must do this before | 882 | * for the bss and break sections. We must do this before |
883 | * mapping in the interpreter, to make sure it doesn't wind | 883 | * mapping in the interpreter, to make sure it doesn't wind |
884 | * up getting placed where the bss needs to go. | 884 | * up getting placed where the bss needs to go. |
885 | */ | 885 | */ |
886 | retval = set_brk(elf_bss, elf_brk); | 886 | retval = set_brk(elf_bss, elf_brk); |
887 | if (retval) { | 887 | if (retval) { |
888 | send_sig(SIGKILL, current, 0); | 888 | send_sig(SIGKILL, current, 0); |
889 | goto out_free_dentry; | 889 | goto out_free_dentry; |
890 | } | 890 | } |
891 | if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { | 891 | if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { |
892 | send_sig(SIGSEGV, current, 0); | 892 | send_sig(SIGSEGV, current, 0); |
893 | retval = -EFAULT; /* Nobody gets to see this, but.. */ | 893 | retval = -EFAULT; /* Nobody gets to see this, but.. */ |
894 | goto out_free_dentry; | 894 | goto out_free_dentry; |
895 | } | 895 | } |
896 | 896 | ||
897 | if (elf_interpreter) { | 897 | if (elf_interpreter) { |
898 | unsigned long interp_map_addr = 0; | 898 | unsigned long interp_map_addr = 0; |
899 | 899 | ||
900 | elf_entry = load_elf_interp(&loc->interp_elf_ex, | 900 | elf_entry = load_elf_interp(&loc->interp_elf_ex, |
901 | interpreter, | 901 | interpreter, |
902 | &interp_map_addr, | 902 | &interp_map_addr, |
903 | load_bias); | 903 | load_bias); |
904 | if (!IS_ERR((void *)elf_entry)) { | 904 | if (!IS_ERR((void *)elf_entry)) { |
905 | /* | 905 | /* |
906 | * load_elf_interp() returns relocation | 906 | * load_elf_interp() returns relocation |
907 | * adjustment | 907 | * adjustment |
908 | */ | 908 | */ |
909 | interp_load_addr = elf_entry; | 909 | interp_load_addr = elf_entry; |
910 | elf_entry += loc->interp_elf_ex.e_entry; | 910 | elf_entry += loc->interp_elf_ex.e_entry; |
911 | } | 911 | } |
912 | if (BAD_ADDR(elf_entry)) { | 912 | if (BAD_ADDR(elf_entry)) { |
913 | force_sig(SIGSEGV, current); | 913 | force_sig(SIGSEGV, current); |
914 | retval = IS_ERR((void *)elf_entry) ? | 914 | retval = IS_ERR((void *)elf_entry) ? |
915 | (int)elf_entry : -EINVAL; | 915 | (int)elf_entry : -EINVAL; |
916 | goto out_free_dentry; | 916 | goto out_free_dentry; |
917 | } | 917 | } |
918 | reloc_func_desc = interp_load_addr; | 918 | reloc_func_desc = interp_load_addr; |
919 | 919 | ||
920 | allow_write_access(interpreter); | 920 | allow_write_access(interpreter); |
921 | fput(interpreter); | 921 | fput(interpreter); |
922 | kfree(elf_interpreter); | 922 | kfree(elf_interpreter); |
923 | } else { | 923 | } else { |
924 | elf_entry = loc->elf_ex.e_entry; | 924 | elf_entry = loc->elf_ex.e_entry; |
925 | if (BAD_ADDR(elf_entry)) { | 925 | if (BAD_ADDR(elf_entry)) { |
926 | force_sig(SIGSEGV, current); | 926 | force_sig(SIGSEGV, current); |
927 | retval = -EINVAL; | 927 | retval = -EINVAL; |
928 | goto out_free_dentry; | 928 | goto out_free_dentry; |
929 | } | 929 | } |
930 | } | 930 | } |
931 | 931 | ||
932 | kfree(elf_phdata); | 932 | kfree(elf_phdata); |
933 | 933 | ||
934 | set_binfmt(&elf_format); | 934 | set_binfmt(&elf_format); |
935 | 935 | ||
936 | #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES | 936 | #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES |
937 | retval = arch_setup_additional_pages(bprm, !!elf_interpreter); | 937 | retval = arch_setup_additional_pages(bprm, !!elf_interpreter); |
938 | if (retval < 0) { | 938 | if (retval < 0) { |
939 | send_sig(SIGKILL, current, 0); | 939 | send_sig(SIGKILL, current, 0); |
940 | goto out; | 940 | goto out; |
941 | } | 941 | } |
942 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ | 942 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ |
943 | 943 | ||
944 | install_exec_creds(bprm); | 944 | install_exec_creds(bprm); |
945 | retval = create_elf_tables(bprm, &loc->elf_ex, | 945 | retval = create_elf_tables(bprm, &loc->elf_ex, |
946 | load_addr, interp_load_addr); | 946 | load_addr, interp_load_addr); |
947 | if (retval < 0) { | 947 | if (retval < 0) { |
948 | send_sig(SIGKILL, current, 0); | 948 | send_sig(SIGKILL, current, 0); |
949 | goto out; | 949 | goto out; |
950 | } | 950 | } |
951 | /* N.B. passed_fileno might not be initialized? */ | 951 | /* N.B. passed_fileno might not be initialized? */ |
952 | current->mm->end_code = end_code; | 952 | current->mm->end_code = end_code; |
953 | current->mm->start_code = start_code; | 953 | current->mm->start_code = start_code; |
954 | current->mm->start_data = start_data; | 954 | current->mm->start_data = start_data; |
955 | current->mm->end_data = end_data; | 955 | current->mm->end_data = end_data; |
956 | current->mm->start_stack = bprm->p; | 956 | current->mm->start_stack = bprm->p; |
957 | 957 | ||
958 | #ifdef arch_randomize_brk | 958 | #ifdef arch_randomize_brk |
959 | if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { | 959 | if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { |
960 | current->mm->brk = current->mm->start_brk = | 960 | current->mm->brk = current->mm->start_brk = |
961 | arch_randomize_brk(current->mm); | 961 | arch_randomize_brk(current->mm); |
962 | #ifdef CONFIG_COMPAT_BRK | 962 | #ifdef CONFIG_COMPAT_BRK |
963 | current->brk_randomized = 1; | 963 | current->brk_randomized = 1; |
964 | #endif | 964 | #endif |
965 | } | 965 | } |
966 | #endif | 966 | #endif |
967 | 967 | ||
968 | if (current->personality & MMAP_PAGE_ZERO) { | 968 | if (current->personality & MMAP_PAGE_ZERO) { |
969 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, | 969 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, |
970 | and some applications "depend" upon this behavior. | 970 | and some applications "depend" upon this behavior. |
971 | Since we do not have the power to recompile these, we | 971 | Since we do not have the power to recompile these, we |
972 | emulate the SVr4 behavior. Sigh. */ | 972 | emulate the SVr4 behavior. Sigh. */ |
973 | error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, | 973 | error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, |
974 | MAP_FIXED | MAP_PRIVATE, 0); | 974 | MAP_FIXED | MAP_PRIVATE, 0); |
975 | } | 975 | } |
976 | 976 | ||
977 | #ifdef ELF_PLAT_INIT | 977 | #ifdef ELF_PLAT_INIT |
978 | /* | 978 | /* |
979 | * The ABI may specify that certain registers be set up in special | 979 | * The ABI may specify that certain registers be set up in special |
980 | * ways (on i386 %edx is the address of a DT_FINI function, for | 980 | * ways (on i386 %edx is the address of a DT_FINI function, for |
981 | * example. In addition, it may also specify (eg, PowerPC64 ELF) | 981 | * example. In addition, it may also specify (eg, PowerPC64 ELF) |
982 | * that the e_entry field is the address of the function descriptor | 982 | * that the e_entry field is the address of the function descriptor |
983 | * for the startup routine, rather than the address of the startup | 983 | * for the startup routine, rather than the address of the startup |
984 | * routine itself. This macro performs whatever initialization to | 984 | * routine itself. This macro performs whatever initialization to |
985 | * the regs structure is required as well as any relocations to the | 985 | * the regs structure is required as well as any relocations to the |
986 | * function descriptor entries when executing dynamically links apps. | 986 | * function descriptor entries when executing dynamically links apps. |
987 | */ | 987 | */ |
988 | ELF_PLAT_INIT(regs, reloc_func_desc); | 988 | ELF_PLAT_INIT(regs, reloc_func_desc); |
989 | #endif | 989 | #endif |
990 | 990 | ||
991 | start_thread(regs, elf_entry, bprm->p); | 991 | start_thread(regs, elf_entry, bprm->p); |
992 | retval = 0; | 992 | retval = 0; |
993 | out: | 993 | out: |
994 | kfree(loc); | 994 | kfree(loc); |
995 | out_ret: | 995 | out_ret: |
996 | return retval; | 996 | return retval; |
997 | 997 | ||
998 | /* error cleanup */ | 998 | /* error cleanup */ |
999 | out_free_dentry: | 999 | out_free_dentry: |
1000 | allow_write_access(interpreter); | 1000 | allow_write_access(interpreter); |
1001 | if (interpreter) | 1001 | if (interpreter) |
1002 | fput(interpreter); | 1002 | fput(interpreter); |
1003 | out_free_interp: | 1003 | out_free_interp: |
1004 | kfree(elf_interpreter); | 1004 | kfree(elf_interpreter); |
1005 | out_free_ph: | 1005 | out_free_ph: |
1006 | kfree(elf_phdata); | 1006 | kfree(elf_phdata); |
1007 | goto out; | 1007 | goto out; |
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | /* This is really simpleminded and specialized - we are loading an | 1010 | /* This is really simpleminded and specialized - we are loading an |
1011 | a.out library that is given an ELF header. */ | 1011 | a.out library that is given an ELF header. */ |
1012 | static int load_elf_library(struct file *file) | 1012 | static int load_elf_library(struct file *file) |
1013 | { | 1013 | { |
1014 | struct elf_phdr *elf_phdata; | 1014 | struct elf_phdr *elf_phdata; |
1015 | struct elf_phdr *eppnt; | 1015 | struct elf_phdr *eppnt; |
1016 | unsigned long elf_bss, bss, len; | 1016 | unsigned long elf_bss, bss, len; |
1017 | int retval, error, i, j; | 1017 | int retval, error, i, j; |
1018 | struct elfhdr elf_ex; | 1018 | struct elfhdr elf_ex; |
1019 | 1019 | ||
1020 | error = -ENOEXEC; | 1020 | error = -ENOEXEC; |
1021 | retval = kernel_read(file, 0, (char *)&elf_ex, sizeof(elf_ex)); | 1021 | retval = kernel_read(file, 0, (char *)&elf_ex, sizeof(elf_ex)); |
1022 | if (retval != sizeof(elf_ex)) | 1022 | if (retval != sizeof(elf_ex)) |
1023 | goto out; | 1023 | goto out; |
1024 | 1024 | ||
1025 | if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) | 1025 | if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
1026 | goto out; | 1026 | goto out; |
1027 | 1027 | ||
1028 | /* First of all, some simple consistency checks */ | 1028 | /* First of all, some simple consistency checks */ |
1029 | if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || | 1029 | if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || |
1030 | !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap) | 1030 | !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap) |
1031 | goto out; | 1031 | goto out; |
1032 | 1032 | ||
1033 | /* Now read in all of the header information */ | 1033 | /* Now read in all of the header information */ |
1034 | 1034 | ||
1035 | j = sizeof(struct elf_phdr) * elf_ex.e_phnum; | 1035 | j = sizeof(struct elf_phdr) * elf_ex.e_phnum; |
1036 | /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */ | 1036 | /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */ |
1037 | 1037 | ||
1038 | error = -ENOMEM; | 1038 | error = -ENOMEM; |
1039 | elf_phdata = kmalloc(j, GFP_KERNEL); | 1039 | elf_phdata = kmalloc(j, GFP_KERNEL); |
1040 | if (!elf_phdata) | 1040 | if (!elf_phdata) |
1041 | goto out; | 1041 | goto out; |
1042 | 1042 | ||
1043 | eppnt = elf_phdata; | 1043 | eppnt = elf_phdata; |
1044 | error = -ENOEXEC; | 1044 | error = -ENOEXEC; |
1045 | retval = kernel_read(file, elf_ex.e_phoff, (char *)eppnt, j); | 1045 | retval = kernel_read(file, elf_ex.e_phoff, (char *)eppnt, j); |
1046 | if (retval != j) | 1046 | if (retval != j) |
1047 | goto out_free_ph; | 1047 | goto out_free_ph; |
1048 | 1048 | ||
1049 | for (j = 0, i = 0; i<elf_ex.e_phnum; i++) | 1049 | for (j = 0, i = 0; i<elf_ex.e_phnum; i++) |
1050 | if ((eppnt + i)->p_type == PT_LOAD) | 1050 | if ((eppnt + i)->p_type == PT_LOAD) |
1051 | j++; | 1051 | j++; |
1052 | if (j != 1) | 1052 | if (j != 1) |
1053 | goto out_free_ph; | 1053 | goto out_free_ph; |
1054 | 1054 | ||
1055 | while (eppnt->p_type != PT_LOAD) | 1055 | while (eppnt->p_type != PT_LOAD) |
1056 | eppnt++; | 1056 | eppnt++; |
1057 | 1057 | ||
1058 | /* Now use mmap to map the library into memory. */ | 1058 | /* Now use mmap to map the library into memory. */ |
1059 | error = vm_mmap(file, | 1059 | error = vm_mmap(file, |
1060 | ELF_PAGESTART(eppnt->p_vaddr), | 1060 | ELF_PAGESTART(eppnt->p_vaddr), |
1061 | (eppnt->p_filesz + | 1061 | (eppnt->p_filesz + |
1062 | ELF_PAGEOFFSET(eppnt->p_vaddr)), | 1062 | ELF_PAGEOFFSET(eppnt->p_vaddr)), |
1063 | PROT_READ | PROT_WRITE | PROT_EXEC, | 1063 | PROT_READ | PROT_WRITE | PROT_EXEC, |
1064 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, | 1064 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, |
1065 | (eppnt->p_offset - | 1065 | (eppnt->p_offset - |
1066 | ELF_PAGEOFFSET(eppnt->p_vaddr))); | 1066 | ELF_PAGEOFFSET(eppnt->p_vaddr))); |
1067 | if (error != ELF_PAGESTART(eppnt->p_vaddr)) | 1067 | if (error != ELF_PAGESTART(eppnt->p_vaddr)) |
1068 | goto out_free_ph; | 1068 | goto out_free_ph; |
1069 | 1069 | ||
1070 | elf_bss = eppnt->p_vaddr + eppnt->p_filesz; | 1070 | elf_bss = eppnt->p_vaddr + eppnt->p_filesz; |
1071 | if (padzero(elf_bss)) { | 1071 | if (padzero(elf_bss)) { |
1072 | error = -EFAULT; | 1072 | error = -EFAULT; |
1073 | goto out_free_ph; | 1073 | goto out_free_ph; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr + | 1076 | len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr + |
1077 | ELF_MIN_ALIGN - 1); | 1077 | ELF_MIN_ALIGN - 1); |
1078 | bss = eppnt->p_memsz + eppnt->p_vaddr; | 1078 | bss = eppnt->p_memsz + eppnt->p_vaddr; |
1079 | if (bss > len) | 1079 | if (bss > len) |
1080 | vm_brk(len, bss - len); | 1080 | vm_brk(len, bss - len); |
1081 | error = 0; | 1081 | error = 0; |
1082 | 1082 | ||
1083 | out_free_ph: | 1083 | out_free_ph: |
1084 | kfree(elf_phdata); | 1084 | kfree(elf_phdata); |
1085 | out: | 1085 | out: |
1086 | return error; | 1086 | return error; |
1087 | } | 1087 | } |
1088 | 1088 | ||
1089 | #ifdef CONFIG_ELF_CORE | 1089 | #ifdef CONFIG_ELF_CORE |
1090 | /* | 1090 | /* |
1091 | * ELF core dumper | 1091 | * ELF core dumper |
1092 | * | 1092 | * |
1093 | * Modelled on fs/exec.c:aout_core_dump() | 1093 | * Modelled on fs/exec.c:aout_core_dump() |
1094 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> | 1094 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> |
1095 | */ | 1095 | */ |
1096 | 1096 | ||
1097 | /* | 1097 | /* |
1098 | * The purpose of always_dump_vma() is to make sure that special kernel mappings | 1098 | * The purpose of always_dump_vma() is to make sure that special kernel mappings |
1099 | * that are useful for post-mortem analysis are included in every core dump. | 1099 | * that are useful for post-mortem analysis are included in every core dump. |
1100 | * In that way we ensure that the core dump is fully interpretable later | 1100 | * In that way we ensure that the core dump is fully interpretable later |
1101 | * without matching up the same kernel and hardware config to see what PC values | 1101 | * without matching up the same kernel and hardware config to see what PC values |
1102 | * meant. These special mappings include - vDSO, vsyscall, and other | 1102 | * meant. These special mappings include - vDSO, vsyscall, and other |
1103 | * architecture specific mappings | 1103 | * architecture specific mappings |
1104 | */ | 1104 | */ |
1105 | static bool always_dump_vma(struct vm_area_struct *vma) | 1105 | static bool always_dump_vma(struct vm_area_struct *vma) |
1106 | { | 1106 | { |
1107 | /* Any vsyscall mappings? */ | 1107 | /* Any vsyscall mappings? */ |
1108 | if (vma == get_gate_vma(vma->vm_mm)) | 1108 | if (vma == get_gate_vma(vma->vm_mm)) |
1109 | return true; | 1109 | return true; |
1110 | /* | 1110 | /* |
1111 | * arch_vma_name() returns non-NULL for special architecture mappings, | 1111 | * arch_vma_name() returns non-NULL for special architecture mappings, |
1112 | * such as vDSO sections. | 1112 | * such as vDSO sections. |
1113 | */ | 1113 | */ |
1114 | if (arch_vma_name(vma)) | 1114 | if (arch_vma_name(vma)) |
1115 | return true; | 1115 | return true; |
1116 | 1116 | ||
1117 | return false; | 1117 | return false; |
1118 | } | 1118 | } |
1119 | 1119 | ||
1120 | /* | 1120 | /* |
1121 | * Decide what to dump of a segment, part, all or none. | 1121 | * Decide what to dump of a segment, part, all or none. |
1122 | */ | 1122 | */ |
1123 | static unsigned long vma_dump_size(struct vm_area_struct *vma, | 1123 | static unsigned long vma_dump_size(struct vm_area_struct *vma, |
1124 | unsigned long mm_flags) | 1124 | unsigned long mm_flags) |
1125 | { | 1125 | { |
1126 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) | 1126 | #define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type)) |
1127 | 1127 | ||
1128 | /* always dump the vdso and vsyscall sections */ | 1128 | /* always dump the vdso and vsyscall sections */ |
1129 | if (always_dump_vma(vma)) | 1129 | if (always_dump_vma(vma)) |
1130 | goto whole; | 1130 | goto whole; |
1131 | 1131 | ||
1132 | if (vma->vm_flags & VM_DONTDUMP) | 1132 | if (vma->vm_flags & VM_DONTDUMP) |
1133 | return 0; | 1133 | return 0; |
1134 | 1134 | ||
1135 | /* Hugetlb memory check */ | 1135 | /* Hugetlb memory check */ |
1136 | if (vma->vm_flags & VM_HUGETLB) { | 1136 | if (vma->vm_flags & VM_HUGETLB) { |
1137 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) | 1137 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) |
1138 | goto whole; | 1138 | goto whole; |
1139 | if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE)) | 1139 | if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE)) |
1140 | goto whole; | 1140 | goto whole; |
1141 | return 0; | 1141 | return 0; |
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | /* Do not dump I/O mapped devices or special mappings */ | 1144 | /* Do not dump I/O mapped devices or special mappings */ |
1145 | if (vma->vm_flags & VM_IO) | 1145 | if (vma->vm_flags & VM_IO) |
1146 | return 0; | 1146 | return 0; |
1147 | 1147 | ||
1148 | /* By default, dump shared memory if mapped from an anonymous file. */ | 1148 | /* By default, dump shared memory if mapped from an anonymous file. */ |
1149 | if (vma->vm_flags & VM_SHARED) { | 1149 | if (vma->vm_flags & VM_SHARED) { |
1150 | if (file_inode(vma->vm_file)->i_nlink == 0 ? | 1150 | if (file_inode(vma->vm_file)->i_nlink == 0 ? |
1151 | FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED)) | 1151 | FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED)) |
1152 | goto whole; | 1152 | goto whole; |
1153 | return 0; | 1153 | return 0; |
1154 | } | 1154 | } |
1155 | 1155 | ||
1156 | /* Dump segments that have been written to. */ | 1156 | /* Dump segments that have been written to. */ |
1157 | if (vma->anon_vma && FILTER(ANON_PRIVATE)) | 1157 | if (vma->anon_vma && FILTER(ANON_PRIVATE)) |
1158 | goto whole; | 1158 | goto whole; |
1159 | if (vma->vm_file == NULL) | 1159 | if (vma->vm_file == NULL) |
1160 | return 0; | 1160 | return 0; |
1161 | 1161 | ||
1162 | if (FILTER(MAPPED_PRIVATE)) | 1162 | if (FILTER(MAPPED_PRIVATE)) |
1163 | goto whole; | 1163 | goto whole; |
1164 | 1164 | ||
1165 | /* | 1165 | /* |
1166 | * If this looks like the beginning of a DSO or executable mapping, | 1166 | * If this looks like the beginning of a DSO or executable mapping, |
1167 | * check for an ELF header. If we find one, dump the first page to | 1167 | * check for an ELF header. If we find one, dump the first page to |
1168 | * aid in determining what was mapped here. | 1168 | * aid in determining what was mapped here. |
1169 | */ | 1169 | */ |
1170 | if (FILTER(ELF_HEADERS) && | 1170 | if (FILTER(ELF_HEADERS) && |
1171 | vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { | 1171 | vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { |
1172 | u32 __user *header = (u32 __user *) vma->vm_start; | 1172 | u32 __user *header = (u32 __user *) vma->vm_start; |
1173 | u32 word; | 1173 | u32 word; |
1174 | mm_segment_t fs = get_fs(); | 1174 | mm_segment_t fs = get_fs(); |
1175 | /* | 1175 | /* |
1176 | * Doing it this way gets the constant folded by GCC. | 1176 | * Doing it this way gets the constant folded by GCC. |
1177 | */ | 1177 | */ |
1178 | union { | 1178 | union { |
1179 | u32 cmp; | 1179 | u32 cmp; |
1180 | char elfmag[SELFMAG]; | 1180 | char elfmag[SELFMAG]; |
1181 | } magic; | 1181 | } magic; |
1182 | BUILD_BUG_ON(SELFMAG != sizeof word); | 1182 | BUILD_BUG_ON(SELFMAG != sizeof word); |
1183 | magic.elfmag[EI_MAG0] = ELFMAG0; | 1183 | magic.elfmag[EI_MAG0] = ELFMAG0; |
1184 | magic.elfmag[EI_MAG1] = ELFMAG1; | 1184 | magic.elfmag[EI_MAG1] = ELFMAG1; |
1185 | magic.elfmag[EI_MAG2] = ELFMAG2; | 1185 | magic.elfmag[EI_MAG2] = ELFMAG2; |
1186 | magic.elfmag[EI_MAG3] = ELFMAG3; | 1186 | magic.elfmag[EI_MAG3] = ELFMAG3; |
1187 | /* | 1187 | /* |
1188 | * Switch to the user "segment" for get_user(), | 1188 | * Switch to the user "segment" for get_user(), |
1189 | * then put back what elf_core_dump() had in place. | 1189 | * then put back what elf_core_dump() had in place. |
1190 | */ | 1190 | */ |
1191 | set_fs(USER_DS); | 1191 | set_fs(USER_DS); |
1192 | if (unlikely(get_user(word, header))) | 1192 | if (unlikely(get_user(word, header))) |
1193 | word = 0; | 1193 | word = 0; |
1194 | set_fs(fs); | 1194 | set_fs(fs); |
1195 | if (word == magic.cmp) | 1195 | if (word == magic.cmp) |
1196 | return PAGE_SIZE; | 1196 | return PAGE_SIZE; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | #undef FILTER | 1199 | #undef FILTER |
1200 | 1200 | ||
1201 | return 0; | 1201 | return 0; |
1202 | 1202 | ||
1203 | whole: | 1203 | whole: |
1204 | return vma->vm_end - vma->vm_start; | 1204 | return vma->vm_end - vma->vm_start; |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | /* An ELF note in memory */ | 1207 | /* An ELF note in memory */ |
1208 | struct memelfnote | 1208 | struct memelfnote |
1209 | { | 1209 | { |
1210 | const char *name; | 1210 | const char *name; |
1211 | int type; | 1211 | int type; |
1212 | unsigned int datasz; | 1212 | unsigned int datasz; |
1213 | void *data; | 1213 | void *data; |
1214 | }; | 1214 | }; |
1215 | 1215 | ||
1216 | static int notesize(struct memelfnote *en) | 1216 | static int notesize(struct memelfnote *en) |
1217 | { | 1217 | { |
1218 | int sz; | 1218 | int sz; |
1219 | 1219 | ||
1220 | sz = sizeof(struct elf_note); | 1220 | sz = sizeof(struct elf_note); |
1221 | sz += roundup(strlen(en->name) + 1, 4); | 1221 | sz += roundup(strlen(en->name) + 1, 4); |
1222 | sz += roundup(en->datasz, 4); | 1222 | sz += roundup(en->datasz, 4); |
1223 | 1223 | ||
1224 | return sz; | 1224 | return sz; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | #define DUMP_WRITE(addr, nr, foffset) \ | 1227 | #define DUMP_WRITE(addr, nr, foffset) \ |
1228 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) | 1228 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) |
1229 | 1229 | ||
1230 | static int alignfile(struct file *file, loff_t *foffset) | 1230 | static int alignfile(struct file *file, loff_t *foffset) |
1231 | { | 1231 | { |
1232 | static const char buf[4] = { 0, }; | 1232 | static const char buf[4] = { 0, }; |
1233 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); | 1233 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); |
1234 | return 1; | 1234 | return 1; |
1235 | } | 1235 | } |
1236 | 1236 | ||
1237 | static int writenote(struct memelfnote *men, struct file *file, | 1237 | static int writenote(struct memelfnote *men, struct file *file, |
1238 | loff_t *foffset) | 1238 | loff_t *foffset) |
1239 | { | 1239 | { |
1240 | struct elf_note en; | 1240 | struct elf_note en; |
1241 | en.n_namesz = strlen(men->name) + 1; | 1241 | en.n_namesz = strlen(men->name) + 1; |
1242 | en.n_descsz = men->datasz; | 1242 | en.n_descsz = men->datasz; |
1243 | en.n_type = men->type; | 1243 | en.n_type = men->type; |
1244 | 1244 | ||
1245 | DUMP_WRITE(&en, sizeof(en), foffset); | 1245 | DUMP_WRITE(&en, sizeof(en), foffset); |
1246 | DUMP_WRITE(men->name, en.n_namesz, foffset); | 1246 | DUMP_WRITE(men->name, en.n_namesz, foffset); |
1247 | if (!alignfile(file, foffset)) | 1247 | if (!alignfile(file, foffset)) |
1248 | return 0; | 1248 | return 0; |
1249 | DUMP_WRITE(men->data, men->datasz, foffset); | 1249 | DUMP_WRITE(men->data, men->datasz, foffset); |
1250 | if (!alignfile(file, foffset)) | 1250 | if (!alignfile(file, foffset)) |
1251 | return 0; | 1251 | return 0; |
1252 | 1252 | ||
1253 | return 1; | 1253 | return 1; |
1254 | } | 1254 | } |
1255 | #undef DUMP_WRITE | 1255 | #undef DUMP_WRITE |
1256 | 1256 | ||
1257 | static void fill_elf_header(struct elfhdr *elf, int segs, | 1257 | static void fill_elf_header(struct elfhdr *elf, int segs, |
1258 | u16 machine, u32 flags) | 1258 | u16 machine, u32 flags) |
1259 | { | 1259 | { |
1260 | memset(elf, 0, sizeof(*elf)); | 1260 | memset(elf, 0, sizeof(*elf)); |
1261 | 1261 | ||
1262 | memcpy(elf->e_ident, ELFMAG, SELFMAG); | 1262 | memcpy(elf->e_ident, ELFMAG, SELFMAG); |
1263 | elf->e_ident[EI_CLASS] = ELF_CLASS; | 1263 | elf->e_ident[EI_CLASS] = ELF_CLASS; |
1264 | elf->e_ident[EI_DATA] = ELF_DATA; | 1264 | elf->e_ident[EI_DATA] = ELF_DATA; |
1265 | elf->e_ident[EI_VERSION] = EV_CURRENT; | 1265 | elf->e_ident[EI_VERSION] = EV_CURRENT; |
1266 | elf->e_ident[EI_OSABI] = ELF_OSABI; | 1266 | elf->e_ident[EI_OSABI] = ELF_OSABI; |
1267 | 1267 | ||
1268 | elf->e_type = ET_CORE; | 1268 | elf->e_type = ET_CORE; |
1269 | elf->e_machine = machine; | 1269 | elf->e_machine = machine; |
1270 | elf->e_version = EV_CURRENT; | 1270 | elf->e_version = EV_CURRENT; |
1271 | elf->e_phoff = sizeof(struct elfhdr); | 1271 | elf->e_phoff = sizeof(struct elfhdr); |
1272 | elf->e_flags = flags; | 1272 | elf->e_flags = flags; |
1273 | elf->e_ehsize = sizeof(struct elfhdr); | 1273 | elf->e_ehsize = sizeof(struct elfhdr); |
1274 | elf->e_phentsize = sizeof(struct elf_phdr); | 1274 | elf->e_phentsize = sizeof(struct elf_phdr); |
1275 | elf->e_phnum = segs; | 1275 | elf->e_phnum = segs; |
1276 | 1276 | ||
1277 | return; | 1277 | return; |
1278 | } | 1278 | } |
1279 | 1279 | ||
1280 | static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) | 1280 | static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) |
1281 | { | 1281 | { |
1282 | phdr->p_type = PT_NOTE; | 1282 | phdr->p_type = PT_NOTE; |
1283 | phdr->p_offset = offset; | 1283 | phdr->p_offset = offset; |
1284 | phdr->p_vaddr = 0; | 1284 | phdr->p_vaddr = 0; |
1285 | phdr->p_paddr = 0; | 1285 | phdr->p_paddr = 0; |
1286 | phdr->p_filesz = sz; | 1286 | phdr->p_filesz = sz; |
1287 | phdr->p_memsz = 0; | 1287 | phdr->p_memsz = 0; |
1288 | phdr->p_flags = 0; | 1288 | phdr->p_flags = 0; |
1289 | phdr->p_align = 0; | 1289 | phdr->p_align = 0; |
1290 | return; | 1290 | return; |
1291 | } | 1291 | } |
1292 | 1292 | ||
1293 | static void fill_note(struct memelfnote *note, const char *name, int type, | 1293 | static void fill_note(struct memelfnote *note, const char *name, int type, |
1294 | unsigned int sz, void *data) | 1294 | unsigned int sz, void *data) |
1295 | { | 1295 | { |
1296 | note->name = name; | 1296 | note->name = name; |
1297 | note->type = type; | 1297 | note->type = type; |
1298 | note->datasz = sz; | 1298 | note->datasz = sz; |
1299 | note->data = data; | 1299 | note->data = data; |
1300 | return; | 1300 | return; |
1301 | } | 1301 | } |
1302 | 1302 | ||
1303 | /* | 1303 | /* |
1304 | * fill up all the fields in prstatus from the given task struct, except | 1304 | * fill up all the fields in prstatus from the given task struct, except |
1305 | * registers which need to be filled up separately. | 1305 | * registers which need to be filled up separately. |
1306 | */ | 1306 | */ |
1307 | static void fill_prstatus(struct elf_prstatus *prstatus, | 1307 | static void fill_prstatus(struct elf_prstatus *prstatus, |
1308 | struct task_struct *p, long signr) | 1308 | struct task_struct *p, long signr) |
1309 | { | 1309 | { |
1310 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | 1310 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
1311 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1311 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
1312 | prstatus->pr_sighold = p->blocked.sig[0]; | 1312 | prstatus->pr_sighold = p->blocked.sig[0]; |
1313 | rcu_read_lock(); | 1313 | rcu_read_lock(); |
1314 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | 1314 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); |
1315 | rcu_read_unlock(); | 1315 | rcu_read_unlock(); |
1316 | prstatus->pr_pid = task_pid_vnr(p); | 1316 | prstatus->pr_pid = task_pid_vnr(p); |
1317 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1317 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
1318 | prstatus->pr_sid = task_session_vnr(p); | 1318 | prstatus->pr_sid = task_session_vnr(p); |
1319 | if (thread_group_leader(p)) { | 1319 | if (thread_group_leader(p)) { |
1320 | struct task_cputime cputime; | 1320 | struct task_cputime cputime; |
1321 | 1321 | ||
1322 | /* | 1322 | /* |
1323 | * This is the record for the group leader. It shows the | 1323 | * This is the record for the group leader. It shows the |
1324 | * group-wide total, not its individual thread total. | 1324 | * group-wide total, not its individual thread total. |
1325 | */ | 1325 | */ |
1326 | thread_group_cputime(p, &cputime); | 1326 | thread_group_cputime(p, &cputime); |
1327 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); | 1327 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); |
1328 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); | 1328 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); |
1329 | } else { | 1329 | } else { |
1330 | cputime_t utime, stime; | 1330 | cputime_t utime, stime; |
1331 | 1331 | ||
1332 | task_cputime(p, &utime, &stime); | 1332 | task_cputime(p, &utime, &stime); |
1333 | cputime_to_timeval(utime, &prstatus->pr_utime); | 1333 | cputime_to_timeval(utime, &prstatus->pr_utime); |
1334 | cputime_to_timeval(stime, &prstatus->pr_stime); | 1334 | cputime_to_timeval(stime, &prstatus->pr_stime); |
1335 | } | 1335 | } |
1336 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); | 1336 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); |
1337 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); | 1337 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); |
1338 | } | 1338 | } |
1339 | 1339 | ||
1340 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | 1340 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, |
1341 | struct mm_struct *mm) | 1341 | struct mm_struct *mm) |
1342 | { | 1342 | { |
1343 | const struct cred *cred; | 1343 | const struct cred *cred; |
1344 | unsigned int i, len; | 1344 | unsigned int i, len; |
1345 | 1345 | ||
1346 | /* first copy the parameters from user space */ | 1346 | /* first copy the parameters from user space */ |
1347 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); | 1347 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); |
1348 | 1348 | ||
1349 | len = mm->arg_end - mm->arg_start; | 1349 | len = mm->arg_end - mm->arg_start; |
1350 | if (len >= ELF_PRARGSZ) | 1350 | if (len >= ELF_PRARGSZ) |
1351 | len = ELF_PRARGSZ-1; | 1351 | len = ELF_PRARGSZ-1; |
1352 | if (copy_from_user(&psinfo->pr_psargs, | 1352 | if (copy_from_user(&psinfo->pr_psargs, |
1353 | (const char __user *)mm->arg_start, len)) | 1353 | (const char __user *)mm->arg_start, len)) |
1354 | return -EFAULT; | 1354 | return -EFAULT; |
1355 | for(i = 0; i < len; i++) | 1355 | for(i = 0; i < len; i++) |
1356 | if (psinfo->pr_psargs[i] == 0) | 1356 | if (psinfo->pr_psargs[i] == 0) |
1357 | psinfo->pr_psargs[i] = ' '; | 1357 | psinfo->pr_psargs[i] = ' '; |
1358 | psinfo->pr_psargs[len] = 0; | 1358 | psinfo->pr_psargs[len] = 0; |
1359 | 1359 | ||
1360 | rcu_read_lock(); | 1360 | rcu_read_lock(); |
1361 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | 1361 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); |
1362 | rcu_read_unlock(); | 1362 | rcu_read_unlock(); |
1363 | psinfo->pr_pid = task_pid_vnr(p); | 1363 | psinfo->pr_pid = task_pid_vnr(p); |
1364 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1364 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
1365 | psinfo->pr_sid = task_session_vnr(p); | 1365 | psinfo->pr_sid = task_session_vnr(p); |
1366 | 1366 | ||
1367 | i = p->state ? ffz(~p->state) + 1 : 0; | 1367 | i = p->state ? ffz(~p->state) + 1 : 0; |
1368 | psinfo->pr_state = i; | 1368 | psinfo->pr_state = i; |
1369 | psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; | 1369 | psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; |
1370 | psinfo->pr_zomb = psinfo->pr_sname == 'Z'; | 1370 | psinfo->pr_zomb = psinfo->pr_sname == 'Z'; |
1371 | psinfo->pr_nice = task_nice(p); | 1371 | psinfo->pr_nice = task_nice(p); |
1372 | psinfo->pr_flag = p->flags; | 1372 | psinfo->pr_flag = p->flags; |
1373 | rcu_read_lock(); | 1373 | rcu_read_lock(); |
1374 | cred = __task_cred(p); | 1374 | cred = __task_cred(p); |
1375 | SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); | 1375 | SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); |
1376 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); | 1376 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); |
1377 | rcu_read_unlock(); | 1377 | rcu_read_unlock(); |
1378 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); | 1378 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); |
1379 | 1379 | ||
1380 | return 0; | 1380 | return 0; |
1381 | } | 1381 | } |
1382 | 1382 | ||
1383 | static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) | 1383 | static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) |
1384 | { | 1384 | { |
1385 | elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv; | 1385 | elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv; |
1386 | int i = 0; | 1386 | int i = 0; |
1387 | do | 1387 | do |
1388 | i += 2; | 1388 | i += 2; |
1389 | while (auxv[i - 2] != AT_NULL); | 1389 | while (auxv[i - 2] != AT_NULL); |
1390 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); | 1390 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); |
1391 | } | 1391 | } |
1392 | 1392 | ||
1393 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, | 1393 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, |
1394 | siginfo_t *siginfo) | 1394 | siginfo_t *siginfo) |
1395 | { | 1395 | { |
1396 | mm_segment_t old_fs = get_fs(); | 1396 | mm_segment_t old_fs = get_fs(); |
1397 | set_fs(KERNEL_DS); | 1397 | set_fs(KERNEL_DS); |
1398 | copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo); | 1398 | copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo); |
1399 | set_fs(old_fs); | 1399 | set_fs(old_fs); |
1400 | fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); | 1400 | fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); |
1401 | } | 1401 | } |
1402 | 1402 | ||
1403 | #define MAX_FILE_NOTE_SIZE (4*1024*1024) | 1403 | #define MAX_FILE_NOTE_SIZE (4*1024*1024) |
1404 | /* | 1404 | /* |
1405 | * Format of NT_FILE note: | 1405 | * Format of NT_FILE note: |
1406 | * | 1406 | * |
1407 | * long count -- how many files are mapped | 1407 | * long count -- how many files are mapped |
1408 | * long page_size -- units for file_ofs | 1408 | * long page_size -- units for file_ofs |
1409 | * array of [COUNT] elements of | 1409 | * array of [COUNT] elements of |
1410 | * long start | 1410 | * long start |
1411 | * long end | 1411 | * long end |
1412 | * long file_ofs | 1412 | * long file_ofs |
1413 | * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... | 1413 | * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... |
1414 | */ | 1414 | */ |
1415 | static void fill_files_note(struct memelfnote *note) | 1415 | static void fill_files_note(struct memelfnote *note) |
1416 | { | 1416 | { |
1417 | struct vm_area_struct *vma; | 1417 | struct vm_area_struct *vma; |
1418 | unsigned count, size, names_ofs, remaining, n; | 1418 | unsigned count, size, names_ofs, remaining, n; |
1419 | user_long_t *data; | 1419 | user_long_t *data; |
1420 | user_long_t *start_end_ofs; | 1420 | user_long_t *start_end_ofs; |
1421 | char *name_base, *name_curpos; | 1421 | char *name_base, *name_curpos; |
1422 | 1422 | ||
1423 | /* *Estimated* file count and total data size needed */ | 1423 | /* *Estimated* file count and total data size needed */ |
1424 | count = current->mm->map_count; | 1424 | count = current->mm->map_count; |
1425 | size = count * 64; | 1425 | size = count * 64; |
1426 | 1426 | ||
1427 | names_ofs = (2 + 3 * count) * sizeof(data[0]); | 1427 | names_ofs = (2 + 3 * count) * sizeof(data[0]); |
1428 | alloc: | 1428 | alloc: |
1429 | if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ | 1429 | if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ |
1430 | goto err; | 1430 | goto err; |
1431 | size = round_up(size, PAGE_SIZE); | 1431 | size = round_up(size, PAGE_SIZE); |
1432 | data = vmalloc(size); | 1432 | data = vmalloc(size); |
1433 | if (!data) | 1433 | if (!data) |
1434 | goto err; | 1434 | goto err; |
1435 | 1435 | ||
1436 | start_end_ofs = data + 2; | 1436 | start_end_ofs = data + 2; |
1437 | name_base = name_curpos = ((char *)data) + names_ofs; | 1437 | name_base = name_curpos = ((char *)data) + names_ofs; |
1438 | remaining = size - names_ofs; | 1438 | remaining = size - names_ofs; |
1439 | count = 0; | 1439 | count = 0; |
1440 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1440 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { |
1441 | struct file *file; | 1441 | struct file *file; |
1442 | const char *filename; | 1442 | const char *filename; |
1443 | 1443 | ||
1444 | file = vma->vm_file; | 1444 | file = vma->vm_file; |
1445 | if (!file) | 1445 | if (!file) |
1446 | continue; | 1446 | continue; |
1447 | filename = d_path(&file->f_path, name_curpos, remaining); | 1447 | filename = d_path(&file->f_path, name_curpos, remaining); |
1448 | if (IS_ERR(filename)) { | 1448 | if (IS_ERR(filename)) { |
1449 | if (PTR_ERR(filename) == -ENAMETOOLONG) { | 1449 | if (PTR_ERR(filename) == -ENAMETOOLONG) { |
1450 | vfree(data); | 1450 | vfree(data); |
1451 | size = size * 5 / 4; | 1451 | size = size * 5 / 4; |
1452 | goto alloc; | 1452 | goto alloc; |
1453 | } | 1453 | } |
1454 | continue; | 1454 | continue; |
1455 | } | 1455 | } |
1456 | 1456 | ||
1457 | /* d_path() fills at the end, move name down */ | 1457 | /* d_path() fills at the end, move name down */ |
1458 | /* n = strlen(filename) + 1: */ | 1458 | /* n = strlen(filename) + 1: */ |
1459 | n = (name_curpos + remaining) - filename; | 1459 | n = (name_curpos + remaining) - filename; |
1460 | remaining = filename - name_curpos; | 1460 | remaining = filename - name_curpos; |
1461 | memmove(name_curpos, filename, n); | 1461 | memmove(name_curpos, filename, n); |
1462 | name_curpos += n; | 1462 | name_curpos += n; |
1463 | 1463 | ||
1464 | *start_end_ofs++ = vma->vm_start; | 1464 | *start_end_ofs++ = vma->vm_start; |
1465 | *start_end_ofs++ = vma->vm_end; | 1465 | *start_end_ofs++ = vma->vm_end; |
1466 | *start_end_ofs++ = vma->vm_pgoff; | 1466 | *start_end_ofs++ = vma->vm_pgoff; |
1467 | count++; | 1467 | count++; |
1468 | } | 1468 | } |
1469 | 1469 | ||
1470 | /* Now we know exact count of files, can store it */ | 1470 | /* Now we know exact count of files, can store it */ |
1471 | data[0] = count; | 1471 | data[0] = count; |
1472 | data[1] = PAGE_SIZE; | 1472 | data[1] = PAGE_SIZE; |
1473 | /* | 1473 | /* |
1474 | * Count usually is less than current->mm->map_count, | 1474 | * Count usually is less than current->mm->map_count, |
1475 | * we need to move filenames down. | 1475 | * we need to move filenames down. |
1476 | */ | 1476 | */ |
1477 | n = current->mm->map_count - count; | 1477 | n = current->mm->map_count - count; |
1478 | if (n != 0) { | 1478 | if (n != 0) { |
1479 | unsigned shift_bytes = n * 3 * sizeof(data[0]); | 1479 | unsigned shift_bytes = n * 3 * sizeof(data[0]); |
1480 | memmove(name_base - shift_bytes, name_base, | 1480 | memmove(name_base - shift_bytes, name_base, |
1481 | name_curpos - name_base); | 1481 | name_curpos - name_base); |
1482 | name_curpos -= shift_bytes; | 1482 | name_curpos -= shift_bytes; |
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | size = name_curpos - (char *)data; | 1485 | size = name_curpos - (char *)data; |
1486 | fill_note(note, "CORE", NT_FILE, size, data); | 1486 | fill_note(note, "CORE", NT_FILE, size, data); |
1487 | err: ; | 1487 | err: ; |
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | #ifdef CORE_DUMP_USE_REGSET | 1490 | #ifdef CORE_DUMP_USE_REGSET |
1491 | #include <linux/regset.h> | 1491 | #include <linux/regset.h> |
1492 | 1492 | ||
1493 | struct elf_thread_core_info { | 1493 | struct elf_thread_core_info { |
1494 | struct elf_thread_core_info *next; | 1494 | struct elf_thread_core_info *next; |
1495 | struct task_struct *task; | 1495 | struct task_struct *task; |
1496 | struct elf_prstatus prstatus; | 1496 | struct elf_prstatus prstatus; |
1497 | struct memelfnote notes[0]; | 1497 | struct memelfnote notes[0]; |
1498 | }; | 1498 | }; |
1499 | 1499 | ||
1500 | struct elf_note_info { | 1500 | struct elf_note_info { |
1501 | struct elf_thread_core_info *thread; | 1501 | struct elf_thread_core_info *thread; |
1502 | struct memelfnote psinfo; | 1502 | struct memelfnote psinfo; |
1503 | struct memelfnote signote; | 1503 | struct memelfnote signote; |
1504 | struct memelfnote auxv; | 1504 | struct memelfnote auxv; |
1505 | struct memelfnote files; | 1505 | struct memelfnote files; |
1506 | user_siginfo_t csigdata; | 1506 | user_siginfo_t csigdata; |
1507 | size_t size; | 1507 | size_t size; |
1508 | int thread_notes; | 1508 | int thread_notes; |
1509 | }; | 1509 | }; |
1510 | 1510 | ||
1511 | /* | 1511 | /* |
1512 | * When a regset has a writeback hook, we call it on each thread before | 1512 | * When a regset has a writeback hook, we call it on each thread before |
1513 | * dumping user memory. On register window machines, this makes sure the | 1513 | * dumping user memory. On register window machines, this makes sure the |
1514 | * user memory backing the register data is up to date before we read it. | 1514 | * user memory backing the register data is up to date before we read it. |
1515 | */ | 1515 | */ |
1516 | static void do_thread_regset_writeback(struct task_struct *task, | 1516 | static void do_thread_regset_writeback(struct task_struct *task, |
1517 | const struct user_regset *regset) | 1517 | const struct user_regset *regset) |
1518 | { | 1518 | { |
1519 | if (regset->writeback) | 1519 | if (regset->writeback) |
1520 | regset->writeback(task, regset, 1); | 1520 | regset->writeback(task, regset, 1); |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | #ifndef PR_REG_SIZE | 1523 | #ifndef PR_REG_SIZE |
1524 | #define PR_REG_SIZE(S) sizeof(S) | 1524 | #define PR_REG_SIZE(S) sizeof(S) |
1525 | #endif | 1525 | #endif |
1526 | 1526 | ||
1527 | #ifndef PRSTATUS_SIZE | 1527 | #ifndef PRSTATUS_SIZE |
1528 | #define PRSTATUS_SIZE(S) sizeof(S) | 1528 | #define PRSTATUS_SIZE(S) sizeof(S) |
1529 | #endif | 1529 | #endif |
1530 | 1530 | ||
1531 | #ifndef PR_REG_PTR | 1531 | #ifndef PR_REG_PTR |
1532 | #define PR_REG_PTR(S) (&((S)->pr_reg)) | 1532 | #define PR_REG_PTR(S) (&((S)->pr_reg)) |
1533 | #endif | 1533 | #endif |
1534 | 1534 | ||
1535 | #ifndef SET_PR_FPVALID | 1535 | #ifndef SET_PR_FPVALID |
1536 | #define SET_PR_FPVALID(S, V) ((S)->pr_fpvalid = (V)) | 1536 | #define SET_PR_FPVALID(S, V) ((S)->pr_fpvalid = (V)) |
1537 | #endif | 1537 | #endif |
1538 | 1538 | ||
1539 | static int fill_thread_core_info(struct elf_thread_core_info *t, | 1539 | static int fill_thread_core_info(struct elf_thread_core_info *t, |
1540 | const struct user_regset_view *view, | 1540 | const struct user_regset_view *view, |
1541 | long signr, size_t *total) | 1541 | long signr, size_t *total) |
1542 | { | 1542 | { |
1543 | unsigned int i; | 1543 | unsigned int i; |
1544 | 1544 | ||
1545 | /* | 1545 | /* |
1546 | * NT_PRSTATUS is the one special case, because the regset data | 1546 | * NT_PRSTATUS is the one special case, because the regset data |
1547 | * goes into the pr_reg field inside the note contents, rather | 1547 | * goes into the pr_reg field inside the note contents, rather |
1548 | * than being the whole note contents. We fill the reset in here. | 1548 | * than being the whole note contents. We fill the reset in here. |
1549 | * We assume that regset 0 is NT_PRSTATUS. | 1549 | * We assume that regset 0 is NT_PRSTATUS. |
1550 | */ | 1550 | */ |
1551 | fill_prstatus(&t->prstatus, t->task, signr); | 1551 | fill_prstatus(&t->prstatus, t->task, signr); |
1552 | (void) view->regsets[0].get(t->task, &view->regsets[0], | 1552 | (void) view->regsets[0].get(t->task, &view->regsets[0], |
1553 | 0, PR_REG_SIZE(t->prstatus.pr_reg), | 1553 | 0, PR_REG_SIZE(t->prstatus.pr_reg), |
1554 | PR_REG_PTR(&t->prstatus), NULL); | 1554 | PR_REG_PTR(&t->prstatus), NULL); |
1555 | 1555 | ||
1556 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, | 1556 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, |
1557 | PRSTATUS_SIZE(t->prstatus), &t->prstatus); | 1557 | PRSTATUS_SIZE(t->prstatus), &t->prstatus); |
1558 | *total += notesize(&t->notes[0]); | 1558 | *total += notesize(&t->notes[0]); |
1559 | 1559 | ||
1560 | do_thread_regset_writeback(t->task, &view->regsets[0]); | 1560 | do_thread_regset_writeback(t->task, &view->regsets[0]); |
1561 | 1561 | ||
1562 | /* | 1562 | /* |
1563 | * Each other regset might generate a note too. For each regset | 1563 | * Each other regset might generate a note too. For each regset |
1564 | * that has no core_note_type or is inactive, we leave t->notes[i] | 1564 | * that has no core_note_type or is inactive, we leave t->notes[i] |
1565 | * all zero and we'll know to skip writing it later. | 1565 | * all zero and we'll know to skip writing it later. |
1566 | */ | 1566 | */ |
1567 | for (i = 1; i < view->n; ++i) { | 1567 | for (i = 1; i < view->n; ++i) { |
1568 | const struct user_regset *regset = &view->regsets[i]; | 1568 | const struct user_regset *regset = &view->regsets[i]; |
1569 | do_thread_regset_writeback(t->task, regset); | 1569 | do_thread_regset_writeback(t->task, regset); |
1570 | if (regset->core_note_type && regset->get && | 1570 | if (regset->core_note_type && regset->get && |
1571 | (!regset->active || regset->active(t->task, regset))) { | 1571 | (!regset->active || regset->active(t->task, regset))) { |
1572 | int ret; | 1572 | int ret; |
1573 | size_t size = regset->n * regset->size; | 1573 | size_t size = regset->n * regset->size; |
1574 | void *data = kmalloc(size, GFP_KERNEL); | 1574 | void *data = kmalloc(size, GFP_KERNEL); |
1575 | if (unlikely(!data)) | 1575 | if (unlikely(!data)) |
1576 | return 0; | 1576 | return 0; |
1577 | ret = regset->get(t->task, regset, | 1577 | ret = regset->get(t->task, regset, |
1578 | 0, size, data, NULL); | 1578 | 0, size, data, NULL); |
1579 | if (unlikely(ret)) | 1579 | if (unlikely(ret)) |
1580 | kfree(data); | 1580 | kfree(data); |
1581 | else { | 1581 | else { |
1582 | if (regset->core_note_type != NT_PRFPREG) | 1582 | if (regset->core_note_type != NT_PRFPREG) |
1583 | fill_note(&t->notes[i], "LINUX", | 1583 | fill_note(&t->notes[i], "LINUX", |
1584 | regset->core_note_type, | 1584 | regset->core_note_type, |
1585 | size, data); | 1585 | size, data); |
1586 | else { | 1586 | else { |
1587 | SET_PR_FPVALID(&t->prstatus, 1); | 1587 | SET_PR_FPVALID(&t->prstatus, 1); |
1588 | fill_note(&t->notes[i], "CORE", | 1588 | fill_note(&t->notes[i], "CORE", |
1589 | NT_PRFPREG, size, data); | 1589 | NT_PRFPREG, size, data); |
1590 | } | 1590 | } |
1591 | *total += notesize(&t->notes[i]); | 1591 | *total += notesize(&t->notes[i]); |
1592 | } | 1592 | } |
1593 | } | 1593 | } |
1594 | } | 1594 | } |
1595 | 1595 | ||
1596 | return 1; | 1596 | return 1; |
1597 | } | 1597 | } |
1598 | 1598 | ||
1599 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1599 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1600 | struct elf_note_info *info, | 1600 | struct elf_note_info *info, |
1601 | siginfo_t *siginfo, struct pt_regs *regs) | 1601 | siginfo_t *siginfo, struct pt_regs *regs) |
1602 | { | 1602 | { |
1603 | struct task_struct *dump_task = current; | 1603 | struct task_struct *dump_task = current; |
1604 | const struct user_regset_view *view = task_user_regset_view(dump_task); | 1604 | const struct user_regset_view *view = task_user_regset_view(dump_task); |
1605 | struct elf_thread_core_info *t; | 1605 | struct elf_thread_core_info *t; |
1606 | struct elf_prpsinfo *psinfo; | 1606 | struct elf_prpsinfo *psinfo; |
1607 | struct core_thread *ct; | 1607 | struct core_thread *ct; |
1608 | unsigned int i; | 1608 | unsigned int i; |
1609 | 1609 | ||
1610 | info->size = 0; | 1610 | info->size = 0; |
1611 | info->thread = NULL; | 1611 | info->thread = NULL; |
1612 | 1612 | ||
1613 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); | 1613 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); |
1614 | if (psinfo == NULL) { | 1614 | if (psinfo == NULL) { |
1615 | info->psinfo.data = NULL; /* So we don't free this wrongly */ | 1615 | info->psinfo.data = NULL; /* So we don't free this wrongly */ |
1616 | return 0; | 1616 | return 0; |
1617 | } | 1617 | } |
1618 | 1618 | ||
1619 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | 1619 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); |
1620 | 1620 | ||
1621 | /* | 1621 | /* |
1622 | * Figure out how many notes we're going to need for each thread. | 1622 | * Figure out how many notes we're going to need for each thread. |
1623 | */ | 1623 | */ |
1624 | info->thread_notes = 0; | 1624 | info->thread_notes = 0; |
1625 | for (i = 0; i < view->n; ++i) | 1625 | for (i = 0; i < view->n; ++i) |
1626 | if (view->regsets[i].core_note_type != 0) | 1626 | if (view->regsets[i].core_note_type != 0) |
1627 | ++info->thread_notes; | 1627 | ++info->thread_notes; |
1628 | 1628 | ||
1629 | /* | 1629 | /* |
1630 | * Sanity check. We rely on regset 0 being in NT_PRSTATUS, | 1630 | * Sanity check. We rely on regset 0 being in NT_PRSTATUS, |
1631 | * since it is our one special case. | 1631 | * since it is our one special case. |
1632 | */ | 1632 | */ |
1633 | if (unlikely(info->thread_notes == 0) || | 1633 | if (unlikely(info->thread_notes == 0) || |
1634 | unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) { | 1634 | unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) { |
1635 | WARN_ON(1); | 1635 | WARN_ON(1); |
1636 | return 0; | 1636 | return 0; |
1637 | } | 1637 | } |
1638 | 1638 | ||
1639 | /* | 1639 | /* |
1640 | * Initialize the ELF file header. | 1640 | * Initialize the ELF file header. |
1641 | */ | 1641 | */ |
1642 | fill_elf_header(elf, phdrs, | 1642 | fill_elf_header(elf, phdrs, |
1643 | view->e_machine, view->e_flags); | 1643 | view->e_machine, view->e_flags); |
1644 | 1644 | ||
1645 | /* | 1645 | /* |
1646 | * Allocate a structure for each thread. | 1646 | * Allocate a structure for each thread. |
1647 | */ | 1647 | */ |
1648 | for (ct = &dump_task->mm->core_state->dumper; ct; ct = ct->next) { | 1648 | for (ct = &dump_task->mm->core_state->dumper; ct; ct = ct->next) { |
1649 | t = kzalloc(offsetof(struct elf_thread_core_info, | 1649 | t = kzalloc(offsetof(struct elf_thread_core_info, |
1650 | notes[info->thread_notes]), | 1650 | notes[info->thread_notes]), |
1651 | GFP_KERNEL); | 1651 | GFP_KERNEL); |
1652 | if (unlikely(!t)) | 1652 | if (unlikely(!t)) |
1653 | return 0; | 1653 | return 0; |
1654 | 1654 | ||
1655 | t->task = ct->task; | 1655 | t->task = ct->task; |
1656 | if (ct->task == dump_task || !info->thread) { | 1656 | if (ct->task == dump_task || !info->thread) { |
1657 | t->next = info->thread; | 1657 | t->next = info->thread; |
1658 | info->thread = t; | 1658 | info->thread = t; |
1659 | } else { | 1659 | } else { |
1660 | /* | 1660 | /* |
1661 | * Make sure to keep the original task at | 1661 | * Make sure to keep the original task at |
1662 | * the head of the list. | 1662 | * the head of the list. |
1663 | */ | 1663 | */ |
1664 | t->next = info->thread->next; | 1664 | t->next = info->thread->next; |
1665 | info->thread->next = t; | 1665 | info->thread->next = t; |
1666 | } | 1666 | } |
1667 | } | 1667 | } |
1668 | 1668 | ||
1669 | /* | 1669 | /* |
1670 | * Now fill in each thread's information. | 1670 | * Now fill in each thread's information. |
1671 | */ | 1671 | */ |
1672 | for (t = info->thread; t != NULL; t = t->next) | 1672 | for (t = info->thread; t != NULL; t = t->next) |
1673 | if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) | 1673 | if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) |
1674 | return 0; | 1674 | return 0; |
1675 | 1675 | ||
1676 | /* | 1676 | /* |
1677 | * Fill in the two process-wide notes. | 1677 | * Fill in the two process-wide notes. |
1678 | */ | 1678 | */ |
1679 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); | 1679 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); |
1680 | info->size += notesize(&info->psinfo); | 1680 | info->size += notesize(&info->psinfo); |
1681 | 1681 | ||
1682 | fill_siginfo_note(&info->signote, &info->csigdata, siginfo); | 1682 | fill_siginfo_note(&info->signote, &info->csigdata, siginfo); |
1683 | info->size += notesize(&info->signote); | 1683 | info->size += notesize(&info->signote); |
1684 | 1684 | ||
1685 | fill_auxv_note(&info->auxv, current->mm); | 1685 | fill_auxv_note(&info->auxv, current->mm); |
1686 | info->size += notesize(&info->auxv); | 1686 | info->size += notesize(&info->auxv); |
1687 | 1687 | ||
1688 | fill_files_note(&info->files); | 1688 | fill_files_note(&info->files); |
1689 | info->size += notesize(&info->files); | 1689 | info->size += notesize(&info->files); |
1690 | 1690 | ||
1691 | return 1; | 1691 | return 1; |
1692 | } | 1692 | } |
1693 | 1693 | ||
1694 | static size_t get_note_info_size(struct elf_note_info *info) | 1694 | static size_t get_note_info_size(struct elf_note_info *info) |
1695 | { | 1695 | { |
1696 | return info->size; | 1696 | return info->size; |
1697 | } | 1697 | } |
1698 | 1698 | ||
1699 | /* | 1699 | /* |
1700 | * Write all the notes for each thread. When writing the first thread, the | 1700 | * Write all the notes for each thread. When writing the first thread, the |
1701 | * process-wide notes are interleaved after the first thread-specific note. | 1701 | * process-wide notes are interleaved after the first thread-specific note. |
1702 | */ | 1702 | */ |
1703 | static int write_note_info(struct elf_note_info *info, | 1703 | static int write_note_info(struct elf_note_info *info, |
1704 | struct file *file, loff_t *foffset) | 1704 | struct file *file, loff_t *foffset) |
1705 | { | 1705 | { |
1706 | bool first = 1; | 1706 | bool first = 1; |
1707 | struct elf_thread_core_info *t = info->thread; | 1707 | struct elf_thread_core_info *t = info->thread; |
1708 | 1708 | ||
1709 | do { | 1709 | do { |
1710 | int i; | 1710 | int i; |
1711 | 1711 | ||
1712 | if (!writenote(&t->notes[0], file, foffset)) | 1712 | if (!writenote(&t->notes[0], file, foffset)) |
1713 | return 0; | 1713 | return 0; |
1714 | 1714 | ||
1715 | if (first && !writenote(&info->psinfo, file, foffset)) | 1715 | if (first && !writenote(&info->psinfo, file, foffset)) |
1716 | return 0; | 1716 | return 0; |
1717 | if (first && !writenote(&info->signote, file, foffset)) | 1717 | if (first && !writenote(&info->signote, file, foffset)) |
1718 | return 0; | 1718 | return 0; |
1719 | if (first && !writenote(&info->auxv, file, foffset)) | 1719 | if (first && !writenote(&info->auxv, file, foffset)) |
1720 | return 0; | 1720 | return 0; |
1721 | if (first && !writenote(&info->files, file, foffset)) | 1721 | if (first && !writenote(&info->files, file, foffset)) |
1722 | return 0; | 1722 | return 0; |
1723 | 1723 | ||
1724 | for (i = 1; i < info->thread_notes; ++i) | 1724 | for (i = 1; i < info->thread_notes; ++i) |
1725 | if (t->notes[i].data && | 1725 | if (t->notes[i].data && |
1726 | !writenote(&t->notes[i], file, foffset)) | 1726 | !writenote(&t->notes[i], file, foffset)) |
1727 | return 0; | 1727 | return 0; |
1728 | 1728 | ||
1729 | first = 0; | 1729 | first = 0; |
1730 | t = t->next; | 1730 | t = t->next; |
1731 | } while (t); | 1731 | } while (t); |
1732 | 1732 | ||
1733 | return 1; | 1733 | return 1; |
1734 | } | 1734 | } |
1735 | 1735 | ||
1736 | static void free_note_info(struct elf_note_info *info) | 1736 | static void free_note_info(struct elf_note_info *info) |
1737 | { | 1737 | { |
1738 | struct elf_thread_core_info *threads = info->thread; | 1738 | struct elf_thread_core_info *threads = info->thread; |
1739 | while (threads) { | 1739 | while (threads) { |
1740 | unsigned int i; | 1740 | unsigned int i; |
1741 | struct elf_thread_core_info *t = threads; | 1741 | struct elf_thread_core_info *t = threads; |
1742 | threads = t->next; | 1742 | threads = t->next; |
1743 | WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus); | 1743 | WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus); |
1744 | for (i = 1; i < info->thread_notes; ++i) | 1744 | for (i = 1; i < info->thread_notes; ++i) |
1745 | kfree(t->notes[i].data); | 1745 | kfree(t->notes[i].data); |
1746 | kfree(t); | 1746 | kfree(t); |
1747 | } | 1747 | } |
1748 | kfree(info->psinfo.data); | 1748 | kfree(info->psinfo.data); |
1749 | vfree(info->files.data); | 1749 | vfree(info->files.data); |
1750 | } | 1750 | } |
1751 | 1751 | ||
1752 | #else | 1752 | #else |
1753 | 1753 | ||
1754 | /* Here is the structure in which status of each thread is captured. */ | 1754 | /* Here is the structure in which status of each thread is captured. */ |
1755 | struct elf_thread_status | 1755 | struct elf_thread_status |
1756 | { | 1756 | { |
1757 | struct list_head list; | 1757 | struct list_head list; |
1758 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ | 1758 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ |
1759 | elf_fpregset_t fpu; /* NT_PRFPREG */ | 1759 | elf_fpregset_t fpu; /* NT_PRFPREG */ |
1760 | struct task_struct *thread; | 1760 | struct task_struct *thread; |
1761 | #ifdef ELF_CORE_COPY_XFPREGS | 1761 | #ifdef ELF_CORE_COPY_XFPREGS |
1762 | elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ | 1762 | elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ |
1763 | #endif | 1763 | #endif |
1764 | struct memelfnote notes[3]; | 1764 | struct memelfnote notes[3]; |
1765 | int num_notes; | 1765 | int num_notes; |
1766 | }; | 1766 | }; |
1767 | 1767 | ||
1768 | /* | 1768 | /* |
1769 | * In order to add the specific thread information for the elf file format, | 1769 | * In order to add the specific thread information for the elf file format, |
1770 | * we need to keep a linked list of every threads pr_status and then create | 1770 | * we need to keep a linked list of every threads pr_status and then create |
1771 | * a single section for them in the final core file. | 1771 | * a single section for them in the final core file. |
1772 | */ | 1772 | */ |
1773 | static int elf_dump_thread_status(long signr, struct elf_thread_status *t) | 1773 | static int elf_dump_thread_status(long signr, struct elf_thread_status *t) |
1774 | { | 1774 | { |
1775 | int sz = 0; | 1775 | int sz = 0; |
1776 | struct task_struct *p = t->thread; | 1776 | struct task_struct *p = t->thread; |
1777 | t->num_notes = 0; | 1777 | t->num_notes = 0; |
1778 | 1778 | ||
1779 | fill_prstatus(&t->prstatus, p, signr); | 1779 | fill_prstatus(&t->prstatus, p, signr); |
1780 | elf_core_copy_task_regs(p, &t->prstatus.pr_reg); | 1780 | elf_core_copy_task_regs(p, &t->prstatus.pr_reg); |
1781 | 1781 | ||
1782 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), | 1782 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), |
1783 | &(t->prstatus)); | 1783 | &(t->prstatus)); |
1784 | t->num_notes++; | 1784 | t->num_notes++; |
1785 | sz += notesize(&t->notes[0]); | 1785 | sz += notesize(&t->notes[0]); |
1786 | 1786 | ||
1787 | if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, | 1787 | if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, |
1788 | &t->fpu))) { | 1788 | &t->fpu))) { |
1789 | fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), | 1789 | fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), |
1790 | &(t->fpu)); | 1790 | &(t->fpu)); |
1791 | t->num_notes++; | 1791 | t->num_notes++; |
1792 | sz += notesize(&t->notes[1]); | 1792 | sz += notesize(&t->notes[1]); |
1793 | } | 1793 | } |
1794 | 1794 | ||
1795 | #ifdef ELF_CORE_COPY_XFPREGS | 1795 | #ifdef ELF_CORE_COPY_XFPREGS |
1796 | if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { | 1796 | if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { |
1797 | fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, | 1797 | fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, |
1798 | sizeof(t->xfpu), &t->xfpu); | 1798 | sizeof(t->xfpu), &t->xfpu); |
1799 | t->num_notes++; | 1799 | t->num_notes++; |
1800 | sz += notesize(&t->notes[2]); | 1800 | sz += notesize(&t->notes[2]); |
1801 | } | 1801 | } |
1802 | #endif | 1802 | #endif |
1803 | return sz; | 1803 | return sz; |
1804 | } | 1804 | } |
1805 | 1805 | ||
1806 | struct elf_note_info { | 1806 | struct elf_note_info { |
1807 | struct memelfnote *notes; | 1807 | struct memelfnote *notes; |
1808 | struct elf_prstatus *prstatus; /* NT_PRSTATUS */ | 1808 | struct elf_prstatus *prstatus; /* NT_PRSTATUS */ |
1809 | struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ | 1809 | struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ |
1810 | struct list_head thread_list; | 1810 | struct list_head thread_list; |
1811 | elf_fpregset_t *fpu; | 1811 | elf_fpregset_t *fpu; |
1812 | #ifdef ELF_CORE_COPY_XFPREGS | 1812 | #ifdef ELF_CORE_COPY_XFPREGS |
1813 | elf_fpxregset_t *xfpu; | 1813 | elf_fpxregset_t *xfpu; |
1814 | #endif | 1814 | #endif |
1815 | user_siginfo_t csigdata; | 1815 | user_siginfo_t csigdata; |
1816 | int thread_status_size; | 1816 | int thread_status_size; |
1817 | int numnote; | 1817 | int numnote; |
1818 | }; | 1818 | }; |
1819 | 1819 | ||
1820 | static int elf_note_info_init(struct elf_note_info *info) | 1820 | static int elf_note_info_init(struct elf_note_info *info) |
1821 | { | 1821 | { |
1822 | memset(info, 0, sizeof(*info)); | 1822 | memset(info, 0, sizeof(*info)); |
1823 | INIT_LIST_HEAD(&info->thread_list); | 1823 | INIT_LIST_HEAD(&info->thread_list); |
1824 | 1824 | ||
1825 | /* Allocate space for ELF notes */ | 1825 | /* Allocate space for ELF notes */ |
1826 | info->notes = kmalloc(8 * sizeof(struct memelfnote), GFP_KERNEL); | 1826 | info->notes = kmalloc(8 * sizeof(struct memelfnote), GFP_KERNEL); |
1827 | if (!info->notes) | 1827 | if (!info->notes) |
1828 | return 0; | 1828 | return 0; |
1829 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); | 1829 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); |
1830 | if (!info->psinfo) | 1830 | if (!info->psinfo) |
1831 | return 0; | 1831 | return 0; |
1832 | info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); | 1832 | info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); |
1833 | if (!info->prstatus) | 1833 | if (!info->prstatus) |
1834 | return 0; | 1834 | return 0; |
1835 | info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); | 1835 | info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); |
1836 | if (!info->fpu) | 1836 | if (!info->fpu) |
1837 | return 0; | 1837 | return 0; |
1838 | #ifdef ELF_CORE_COPY_XFPREGS | 1838 | #ifdef ELF_CORE_COPY_XFPREGS |
1839 | info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); | 1839 | info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); |
1840 | if (!info->xfpu) | 1840 | if (!info->xfpu) |
1841 | return 0; | 1841 | return 0; |
1842 | #endif | 1842 | #endif |
1843 | return 1; | 1843 | return 1; |
1844 | } | 1844 | } |
1845 | 1845 | ||
1846 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1846 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1847 | struct elf_note_info *info, | 1847 | struct elf_note_info *info, |
1848 | siginfo_t *siginfo, struct pt_regs *regs) | 1848 | siginfo_t *siginfo, struct pt_regs *regs) |
1849 | { | 1849 | { |
1850 | struct list_head *t; | 1850 | struct list_head *t; |
1851 | 1851 | ||
1852 | if (!elf_note_info_init(info)) | 1852 | if (!elf_note_info_init(info)) |
1853 | return 0; | 1853 | return 0; |
1854 | 1854 | ||
1855 | if (siginfo->si_signo) { | 1855 | if (siginfo->si_signo) { |
1856 | struct core_thread *ct; | 1856 | struct core_thread *ct; |
1857 | struct elf_thread_status *ets; | 1857 | struct elf_thread_status *ets; |
1858 | 1858 | ||
1859 | for (ct = current->mm->core_state->dumper.next; | 1859 | for (ct = current->mm->core_state->dumper.next; |
1860 | ct; ct = ct->next) { | 1860 | ct; ct = ct->next) { |
1861 | ets = kzalloc(sizeof(*ets), GFP_KERNEL); | 1861 | ets = kzalloc(sizeof(*ets), GFP_KERNEL); |
1862 | if (!ets) | 1862 | if (!ets) |
1863 | return 0; | 1863 | return 0; |
1864 | 1864 | ||
1865 | ets->thread = ct->task; | 1865 | ets->thread = ct->task; |
1866 | list_add(&ets->list, &info->thread_list); | 1866 | list_add(&ets->list, &info->thread_list); |
1867 | } | 1867 | } |
1868 | 1868 | ||
1869 | list_for_each(t, &info->thread_list) { | 1869 | list_for_each(t, &info->thread_list) { |
1870 | int sz; | 1870 | int sz; |
1871 | 1871 | ||
1872 | ets = list_entry(t, struct elf_thread_status, list); | 1872 | ets = list_entry(t, struct elf_thread_status, list); |
1873 | sz = elf_dump_thread_status(siginfo->si_signo, ets); | 1873 | sz = elf_dump_thread_status(siginfo->si_signo, ets); |
1874 | info->thread_status_size += sz; | 1874 | info->thread_status_size += sz; |
1875 | } | 1875 | } |
1876 | } | 1876 | } |
1877 | /* now collect the dump for the current */ | 1877 | /* now collect the dump for the current */ |
1878 | memset(info->prstatus, 0, sizeof(*info->prstatus)); | 1878 | memset(info->prstatus, 0, sizeof(*info->prstatus)); |
1879 | fill_prstatus(info->prstatus, current, siginfo->si_signo); | 1879 | fill_prstatus(info->prstatus, current, siginfo->si_signo); |
1880 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); | 1880 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); |
1881 | 1881 | ||
1882 | /* Set up header */ | 1882 | /* Set up header */ |
1883 | fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); | 1883 | fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); |
1884 | 1884 | ||
1885 | /* | 1885 | /* |
1886 | * Set up the notes in similar form to SVR4 core dumps made | 1886 | * Set up the notes in similar form to SVR4 core dumps made |
1887 | * with info from their /proc. | 1887 | * with info from their /proc. |
1888 | */ | 1888 | */ |
1889 | 1889 | ||
1890 | fill_note(info->notes + 0, "CORE", NT_PRSTATUS, | 1890 | fill_note(info->notes + 0, "CORE", NT_PRSTATUS, |
1891 | sizeof(*info->prstatus), info->prstatus); | 1891 | sizeof(*info->prstatus), info->prstatus); |
1892 | fill_psinfo(info->psinfo, current->group_leader, current->mm); | 1892 | fill_psinfo(info->psinfo, current->group_leader, current->mm); |
1893 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, | 1893 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, |
1894 | sizeof(*info->psinfo), info->psinfo); | 1894 | sizeof(*info->psinfo), info->psinfo); |
1895 | 1895 | ||
1896 | fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); | 1896 | fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); |
1897 | fill_auxv_note(info->notes + 3, current->mm); | 1897 | fill_auxv_note(info->notes + 3, current->mm); |
1898 | fill_files_note(info->notes + 4); | 1898 | fill_files_note(info->notes + 4); |
1899 | 1899 | ||
1900 | info->numnote = 5; | 1900 | info->numnote = 5; |
1901 | 1901 | ||
1902 | /* Try to dump the FPU. */ | 1902 | /* Try to dump the FPU. */ |
1903 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, | 1903 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, |
1904 | info->fpu); | 1904 | info->fpu); |
1905 | if (info->prstatus->pr_fpvalid) | 1905 | if (info->prstatus->pr_fpvalid) |
1906 | fill_note(info->notes + info->numnote++, | 1906 | fill_note(info->notes + info->numnote++, |
1907 | "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); | 1907 | "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); |
1908 | #ifdef ELF_CORE_COPY_XFPREGS | 1908 | #ifdef ELF_CORE_COPY_XFPREGS |
1909 | if (elf_core_copy_task_xfpregs(current, info->xfpu)) | 1909 | if (elf_core_copy_task_xfpregs(current, info->xfpu)) |
1910 | fill_note(info->notes + info->numnote++, | 1910 | fill_note(info->notes + info->numnote++, |
1911 | "LINUX", ELF_CORE_XFPREG_TYPE, | 1911 | "LINUX", ELF_CORE_XFPREG_TYPE, |
1912 | sizeof(*info->xfpu), info->xfpu); | 1912 | sizeof(*info->xfpu), info->xfpu); |
1913 | #endif | 1913 | #endif |
1914 | 1914 | ||
1915 | return 1; | 1915 | return 1; |
1916 | } | 1916 | } |
1917 | 1917 | ||
1918 | static size_t get_note_info_size(struct elf_note_info *info) | 1918 | static size_t get_note_info_size(struct elf_note_info *info) |
1919 | { | 1919 | { |
1920 | int sz = 0; | 1920 | int sz = 0; |
1921 | int i; | 1921 | int i; |
1922 | 1922 | ||
1923 | for (i = 0; i < info->numnote; i++) | 1923 | for (i = 0; i < info->numnote; i++) |
1924 | sz += notesize(info->notes + i); | 1924 | sz += notesize(info->notes + i); |
1925 | 1925 | ||
1926 | sz += info->thread_status_size; | 1926 | sz += info->thread_status_size; |
1927 | 1927 | ||
1928 | return sz; | 1928 | return sz; |
1929 | } | 1929 | } |
1930 | 1930 | ||
1931 | static int write_note_info(struct elf_note_info *info, | 1931 | static int write_note_info(struct elf_note_info *info, |
1932 | struct file *file, loff_t *foffset) | 1932 | struct file *file, loff_t *foffset) |
1933 | { | 1933 | { |
1934 | int i; | 1934 | int i; |
1935 | struct list_head *t; | 1935 | struct list_head *t; |
1936 | 1936 | ||
1937 | for (i = 0; i < info->numnote; i++) | 1937 | for (i = 0; i < info->numnote; i++) |
1938 | if (!writenote(info->notes + i, file, foffset)) | 1938 | if (!writenote(info->notes + i, file, foffset)) |
1939 | return 0; | 1939 | return 0; |
1940 | 1940 | ||
1941 | /* write out the thread status notes section */ | 1941 | /* write out the thread status notes section */ |
1942 | list_for_each(t, &info->thread_list) { | 1942 | list_for_each(t, &info->thread_list) { |
1943 | struct elf_thread_status *tmp = | 1943 | struct elf_thread_status *tmp = |
1944 | list_entry(t, struct elf_thread_status, list); | 1944 | list_entry(t, struct elf_thread_status, list); |
1945 | 1945 | ||
1946 | for (i = 0; i < tmp->num_notes; i++) | 1946 | for (i = 0; i < tmp->num_notes; i++) |
1947 | if (!writenote(&tmp->notes[i], file, foffset)) | 1947 | if (!writenote(&tmp->notes[i], file, foffset)) |
1948 | return 0; | 1948 | return 0; |
1949 | } | 1949 | } |
1950 | 1950 | ||
1951 | return 1; | 1951 | return 1; |
1952 | } | 1952 | } |
1953 | 1953 | ||
1954 | static void free_note_info(struct elf_note_info *info) | 1954 | static void free_note_info(struct elf_note_info *info) |
1955 | { | 1955 | { |
1956 | while (!list_empty(&info->thread_list)) { | 1956 | while (!list_empty(&info->thread_list)) { |
1957 | struct list_head *tmp = info->thread_list.next; | 1957 | struct list_head *tmp = info->thread_list.next; |
1958 | list_del(tmp); | 1958 | list_del(tmp); |
1959 | kfree(list_entry(tmp, struct elf_thread_status, list)); | 1959 | kfree(list_entry(tmp, struct elf_thread_status, list)); |
1960 | } | 1960 | } |
1961 | 1961 | ||
1962 | /* Free data allocated by fill_files_note(): */ | 1962 | /* Free data allocated by fill_files_note(): */ |
1963 | vfree(info->notes[4].data); | 1963 | vfree(info->notes[4].data); |
1964 | 1964 | ||
1965 | kfree(info->prstatus); | 1965 | kfree(info->prstatus); |
1966 | kfree(info->psinfo); | 1966 | kfree(info->psinfo); |
1967 | kfree(info->notes); | 1967 | kfree(info->notes); |
1968 | kfree(info->fpu); | 1968 | kfree(info->fpu); |
1969 | #ifdef ELF_CORE_COPY_XFPREGS | 1969 | #ifdef ELF_CORE_COPY_XFPREGS |
1970 | kfree(info->xfpu); | 1970 | kfree(info->xfpu); |
1971 | #endif | 1971 | #endif |
1972 | } | 1972 | } |
1973 | 1973 | ||
1974 | #endif | 1974 | #endif |
1975 | 1975 | ||
1976 | static struct vm_area_struct *first_vma(struct task_struct *tsk, | 1976 | static struct vm_area_struct *first_vma(struct task_struct *tsk, |
1977 | struct vm_area_struct *gate_vma) | 1977 | struct vm_area_struct *gate_vma) |
1978 | { | 1978 | { |
1979 | struct vm_area_struct *ret = tsk->mm->mmap; | 1979 | struct vm_area_struct *ret = tsk->mm->mmap; |
1980 | 1980 | ||
1981 | if (ret) | 1981 | if (ret) |
1982 | return ret; | 1982 | return ret; |
1983 | return gate_vma; | 1983 | return gate_vma; |
1984 | } | 1984 | } |
1985 | /* | 1985 | /* |
1986 | * Helper function for iterating across a vma list. It ensures that the caller | 1986 | * Helper function for iterating across a vma list. It ensures that the caller |
1987 | * will visit `gate_vma' prior to terminating the search. | 1987 | * will visit `gate_vma' prior to terminating the search. |
1988 | */ | 1988 | */ |
1989 | static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, | 1989 | static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, |
1990 | struct vm_area_struct *gate_vma) | 1990 | struct vm_area_struct *gate_vma) |
1991 | { | 1991 | { |
1992 | struct vm_area_struct *ret; | 1992 | struct vm_area_struct *ret; |
1993 | 1993 | ||
1994 | ret = this_vma->vm_next; | 1994 | ret = this_vma->vm_next; |
1995 | if (ret) | 1995 | if (ret) |
1996 | return ret; | 1996 | return ret; |
1997 | if (this_vma == gate_vma) | 1997 | if (this_vma == gate_vma) |
1998 | return NULL; | 1998 | return NULL; |
1999 | return gate_vma; | 1999 | return gate_vma; |
2000 | } | 2000 | } |
2001 | 2001 | ||
2002 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, | 2002 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, |
2003 | elf_addr_t e_shoff, int segs) | 2003 | elf_addr_t e_shoff, int segs) |
2004 | { | 2004 | { |
2005 | elf->e_shoff = e_shoff; | 2005 | elf->e_shoff = e_shoff; |
2006 | elf->e_shentsize = sizeof(*shdr4extnum); | 2006 | elf->e_shentsize = sizeof(*shdr4extnum); |
2007 | elf->e_shnum = 1; | 2007 | elf->e_shnum = 1; |
2008 | elf->e_shstrndx = SHN_UNDEF; | 2008 | elf->e_shstrndx = SHN_UNDEF; |
2009 | 2009 | ||
2010 | memset(shdr4extnum, 0, sizeof(*shdr4extnum)); | 2010 | memset(shdr4extnum, 0, sizeof(*shdr4extnum)); |
2011 | 2011 | ||
2012 | shdr4extnum->sh_type = SHT_NULL; | 2012 | shdr4extnum->sh_type = SHT_NULL; |
2013 | shdr4extnum->sh_size = elf->e_shnum; | 2013 | shdr4extnum->sh_size = elf->e_shnum; |
2014 | shdr4extnum->sh_link = elf->e_shstrndx; | 2014 | shdr4extnum->sh_link = elf->e_shstrndx; |
2015 | shdr4extnum->sh_info = segs; | 2015 | shdr4extnum->sh_info = segs; |
2016 | } | 2016 | } |
2017 | 2017 | ||
2018 | static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma, | 2018 | static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma, |
2019 | unsigned long mm_flags) | 2019 | unsigned long mm_flags) |
2020 | { | 2020 | { |
2021 | struct vm_area_struct *vma; | 2021 | struct vm_area_struct *vma; |
2022 | size_t size = 0; | 2022 | size_t size = 0; |
2023 | 2023 | ||
2024 | for (vma = first_vma(current, gate_vma); vma != NULL; | 2024 | for (vma = first_vma(current, gate_vma); vma != NULL; |
2025 | vma = next_vma(vma, gate_vma)) | 2025 | vma = next_vma(vma, gate_vma)) |
2026 | size += vma_dump_size(vma, mm_flags); | 2026 | size += vma_dump_size(vma, mm_flags); |
2027 | return size; | 2027 | return size; |
2028 | } | 2028 | } |
2029 | 2029 | ||
2030 | /* | 2030 | /* |
2031 | * Actual dumper | 2031 | * Actual dumper |
2032 | * | 2032 | * |
2033 | * This is a two-pass process; first we find the offsets of the bits, | 2033 | * This is a two-pass process; first we find the offsets of the bits, |
2034 | * and then they are actually written out. If we run out of core limit | 2034 | * and then they are actually written out. If we run out of core limit |
2035 | * we just truncate. | 2035 | * we just truncate. |
2036 | */ | 2036 | */ |
2037 | static int elf_core_dump(struct coredump_params *cprm) | 2037 | static int elf_core_dump(struct coredump_params *cprm) |
2038 | { | 2038 | { |
2039 | int has_dumped = 0; | 2039 | int has_dumped = 0; |
2040 | mm_segment_t fs; | 2040 | mm_segment_t fs; |
2041 | int segs; | 2041 | int segs; |
2042 | size_t size = 0; | 2042 | size_t size = 0; |
2043 | struct vm_area_struct *vma, *gate_vma; | 2043 | struct vm_area_struct *vma, *gate_vma; |
2044 | struct elfhdr *elf = NULL; | 2044 | struct elfhdr *elf = NULL; |
2045 | loff_t offset = 0, dataoff, foffset; | 2045 | loff_t offset = 0, dataoff, foffset; |
2046 | struct elf_note_info info; | 2046 | struct elf_note_info info; |
2047 | struct elf_phdr *phdr4note = NULL; | 2047 | struct elf_phdr *phdr4note = NULL; |
2048 | struct elf_shdr *shdr4extnum = NULL; | 2048 | struct elf_shdr *shdr4extnum = NULL; |
2049 | Elf_Half e_phnum; | 2049 | Elf_Half e_phnum; |
2050 | elf_addr_t e_shoff; | 2050 | elf_addr_t e_shoff; |
2051 | 2051 | ||
2052 | /* | 2052 | /* |
2053 | * We no longer stop all VM operations. | 2053 | * We no longer stop all VM operations. |
2054 | * | 2054 | * |
2055 | * This is because those proceses that could possibly change map_count | 2055 | * This is because those proceses that could possibly change map_count |
2056 | * or the mmap / vma pages are now blocked in do_exit on current | 2056 | * or the mmap / vma pages are now blocked in do_exit on current |
2057 | * finishing this core dump. | 2057 | * finishing this core dump. |
2058 | * | 2058 | * |
2059 | * Only ptrace can touch these memory addresses, but it doesn't change | 2059 | * Only ptrace can touch these memory addresses, but it doesn't change |
2060 | * the map_count or the pages allocated. So no possibility of crashing | 2060 | * the map_count or the pages allocated. So no possibility of crashing |
2061 | * exists while dumping the mm->vm_next areas to the core file. | 2061 | * exists while dumping the mm->vm_next areas to the core file. |
2062 | */ | 2062 | */ |
2063 | 2063 | ||
2064 | /* alloc memory for large data structures: too large to be on stack */ | 2064 | /* alloc memory for large data structures: too large to be on stack */ |
2065 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); | 2065 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
2066 | if (!elf) | 2066 | if (!elf) |
2067 | goto out; | 2067 | goto out; |
2068 | /* | 2068 | /* |
2069 | * The number of segs are recored into ELF header as 16bit value. | 2069 | * The number of segs are recored into ELF header as 16bit value. |
2070 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. | 2070 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. |
2071 | */ | 2071 | */ |
2072 | segs = current->mm->map_count; | 2072 | segs = current->mm->map_count; |
2073 | segs += elf_core_extra_phdrs(); | 2073 | segs += elf_core_extra_phdrs(); |
2074 | 2074 | ||
2075 | gate_vma = get_gate_vma(current->mm); | 2075 | gate_vma = get_gate_vma(current->mm); |
2076 | if (gate_vma != NULL) | 2076 | if (gate_vma != NULL) |
2077 | segs++; | 2077 | segs++; |
2078 | 2078 | ||
2079 | /* for notes section */ | 2079 | /* for notes section */ |
2080 | segs++; | 2080 | segs++; |
2081 | 2081 | ||
2082 | /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid | 2082 | /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid |
2083 | * this, kernel supports extended numbering. Have a look at | 2083 | * this, kernel supports extended numbering. Have a look at |
2084 | * include/linux/elf.h for further information. */ | 2084 | * include/linux/elf.h for further information. */ |
2085 | e_phnum = segs > PN_XNUM ? PN_XNUM : segs; | 2085 | e_phnum = segs > PN_XNUM ? PN_XNUM : segs; |
2086 | 2086 | ||
2087 | /* | 2087 | /* |
2088 | * Collect all the non-memory information about the process for the | 2088 | * Collect all the non-memory information about the process for the |
2089 | * notes. This also sets up the file header. | 2089 | * notes. This also sets up the file header. |
2090 | */ | 2090 | */ |
2091 | if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs)) | 2091 | if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs)) |
2092 | goto cleanup; | 2092 | goto cleanup; |
2093 | 2093 | ||
2094 | has_dumped = 1; | 2094 | has_dumped = 1; |
2095 | current->flags |= PF_DUMPCORE; | 2095 | |
2096 | |||
2097 | fs = get_fs(); | 2096 | fs = get_fs(); |
2098 | set_fs(KERNEL_DS); | 2097 | set_fs(KERNEL_DS); |
2099 | 2098 | ||
2100 | offset += sizeof(*elf); /* Elf header */ | 2099 | offset += sizeof(*elf); /* Elf header */ |
2101 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ | 2100 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
2102 | foffset = offset; | 2101 | foffset = offset; |
2103 | 2102 | ||
2104 | /* Write notes phdr entry */ | 2103 | /* Write notes phdr entry */ |
2105 | { | 2104 | { |
2106 | size_t sz = get_note_info_size(&info); | 2105 | size_t sz = get_note_info_size(&info); |
2107 | 2106 | ||
2108 | sz += elf_coredump_extra_notes_size(); | 2107 | sz += elf_coredump_extra_notes_size(); |
2109 | 2108 | ||
2110 | phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); | 2109 | phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); |
2111 | if (!phdr4note) | 2110 | if (!phdr4note) |
2112 | goto end_coredump; | 2111 | goto end_coredump; |
2113 | 2112 | ||
2114 | fill_elf_note_phdr(phdr4note, sz, offset); | 2113 | fill_elf_note_phdr(phdr4note, sz, offset); |
2115 | offset += sz; | 2114 | offset += sz; |
2116 | } | 2115 | } |
2117 | 2116 | ||
2118 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 2117 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
2119 | 2118 | ||
2120 | offset += elf_core_vma_data_size(gate_vma, cprm->mm_flags); | 2119 | offset += elf_core_vma_data_size(gate_vma, cprm->mm_flags); |
2121 | offset += elf_core_extra_data_size(); | 2120 | offset += elf_core_extra_data_size(); |
2122 | e_shoff = offset; | 2121 | e_shoff = offset; |
2123 | 2122 | ||
2124 | if (e_phnum == PN_XNUM) { | 2123 | if (e_phnum == PN_XNUM) { |
2125 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); | 2124 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); |
2126 | if (!shdr4extnum) | 2125 | if (!shdr4extnum) |
2127 | goto end_coredump; | 2126 | goto end_coredump; |
2128 | fill_extnum_info(elf, shdr4extnum, e_shoff, segs); | 2127 | fill_extnum_info(elf, shdr4extnum, e_shoff, segs); |
2129 | } | 2128 | } |
2130 | 2129 | ||
2131 | offset = dataoff; | 2130 | offset = dataoff; |
2132 | 2131 | ||
2133 | size += sizeof(*elf); | 2132 | size += sizeof(*elf); |
2134 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) | 2133 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) |
2135 | goto end_coredump; | 2134 | goto end_coredump; |
2136 | 2135 | ||
2137 | size += sizeof(*phdr4note); | 2136 | size += sizeof(*phdr4note); |
2138 | if (size > cprm->limit | 2137 | if (size > cprm->limit |
2139 | || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note))) | 2138 | || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note))) |
2140 | goto end_coredump; | 2139 | goto end_coredump; |
2141 | 2140 | ||
2142 | /* Write program headers for segments dump */ | 2141 | /* Write program headers for segments dump */ |
2143 | for (vma = first_vma(current, gate_vma); vma != NULL; | 2142 | for (vma = first_vma(current, gate_vma); vma != NULL; |
2144 | vma = next_vma(vma, gate_vma)) { | 2143 | vma = next_vma(vma, gate_vma)) { |
2145 | struct elf_phdr phdr; | 2144 | struct elf_phdr phdr; |
2146 | 2145 | ||
2147 | phdr.p_type = PT_LOAD; | 2146 | phdr.p_type = PT_LOAD; |
2148 | phdr.p_offset = offset; | 2147 | phdr.p_offset = offset; |
2149 | phdr.p_vaddr = vma->vm_start; | 2148 | phdr.p_vaddr = vma->vm_start; |
2150 | phdr.p_paddr = 0; | 2149 | phdr.p_paddr = 0; |
2151 | phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags); | 2150 | phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags); |
2152 | phdr.p_memsz = vma->vm_end - vma->vm_start; | 2151 | phdr.p_memsz = vma->vm_end - vma->vm_start; |
2153 | offset += phdr.p_filesz; | 2152 | offset += phdr.p_filesz; |
2154 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 2153 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
2155 | if (vma->vm_flags & VM_WRITE) | 2154 | if (vma->vm_flags & VM_WRITE) |
2156 | phdr.p_flags |= PF_W; | 2155 | phdr.p_flags |= PF_W; |
2157 | if (vma->vm_flags & VM_EXEC) | 2156 | if (vma->vm_flags & VM_EXEC) |
2158 | phdr.p_flags |= PF_X; | 2157 | phdr.p_flags |= PF_X; |
2159 | phdr.p_align = ELF_EXEC_PAGESIZE; | 2158 | phdr.p_align = ELF_EXEC_PAGESIZE; |
2160 | 2159 | ||
2161 | size += sizeof(phdr); | 2160 | size += sizeof(phdr); |
2162 | if (size > cprm->limit | 2161 | if (size > cprm->limit |
2163 | || !dump_write(cprm->file, &phdr, sizeof(phdr))) | 2162 | || !dump_write(cprm->file, &phdr, sizeof(phdr))) |
2164 | goto end_coredump; | 2163 | goto end_coredump; |
2165 | } | 2164 | } |
2166 | 2165 | ||
2167 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) | 2166 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) |
2168 | goto end_coredump; | 2167 | goto end_coredump; |
2169 | 2168 | ||
2170 | /* write out the notes section */ | 2169 | /* write out the notes section */ |
2171 | if (!write_note_info(&info, cprm->file, &foffset)) | 2170 | if (!write_note_info(&info, cprm->file, &foffset)) |
2172 | goto end_coredump; | 2171 | goto end_coredump; |
2173 | 2172 | ||
2174 | if (elf_coredump_extra_notes_write(cprm->file, &foffset)) | 2173 | if (elf_coredump_extra_notes_write(cprm->file, &foffset)) |
2175 | goto end_coredump; | 2174 | goto end_coredump; |
2176 | 2175 | ||
2177 | /* Align to page */ | 2176 | /* Align to page */ |
2178 | if (!dump_seek(cprm->file, dataoff - foffset)) | 2177 | if (!dump_seek(cprm->file, dataoff - foffset)) |
2179 | goto end_coredump; | 2178 | goto end_coredump; |
2180 | 2179 | ||
2181 | for (vma = first_vma(current, gate_vma); vma != NULL; | 2180 | for (vma = first_vma(current, gate_vma); vma != NULL; |
2182 | vma = next_vma(vma, gate_vma)) { | 2181 | vma = next_vma(vma, gate_vma)) { |
2183 | unsigned long addr; | 2182 | unsigned long addr; |
2184 | unsigned long end; | 2183 | unsigned long end; |
2185 | 2184 | ||
2186 | end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags); | 2185 | end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags); |
2187 | 2186 | ||
2188 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { | 2187 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { |
2189 | struct page *page; | 2188 | struct page *page; |
2190 | int stop; | 2189 | int stop; |
2191 | 2190 | ||
2192 | page = get_dump_page(addr); | 2191 | page = get_dump_page(addr); |
2193 | if (page) { | 2192 | if (page) { |
2194 | void *kaddr = kmap(page); | 2193 | void *kaddr = kmap(page); |
2195 | stop = ((size += PAGE_SIZE) > cprm->limit) || | 2194 | stop = ((size += PAGE_SIZE) > cprm->limit) || |
2196 | !dump_write(cprm->file, kaddr, | 2195 | !dump_write(cprm->file, kaddr, |
2197 | PAGE_SIZE); | 2196 | PAGE_SIZE); |
2198 | kunmap(page); | 2197 | kunmap(page); |
2199 | page_cache_release(page); | 2198 | page_cache_release(page); |
2200 | } else | 2199 | } else |
2201 | stop = !dump_seek(cprm->file, PAGE_SIZE); | 2200 | stop = !dump_seek(cprm->file, PAGE_SIZE); |
2202 | if (stop) | 2201 | if (stop) |
2203 | goto end_coredump; | 2202 | goto end_coredump; |
2204 | } | 2203 | } |
2205 | } | 2204 | } |
2206 | 2205 | ||
2207 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) | 2206 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) |
2208 | goto end_coredump; | 2207 | goto end_coredump; |
2209 | 2208 | ||
2210 | if (e_phnum == PN_XNUM) { | 2209 | if (e_phnum == PN_XNUM) { |
2211 | size += sizeof(*shdr4extnum); | 2210 | size += sizeof(*shdr4extnum); |
2212 | if (size > cprm->limit | 2211 | if (size > cprm->limit |
2213 | || !dump_write(cprm->file, shdr4extnum, | 2212 | || !dump_write(cprm->file, shdr4extnum, |
2214 | sizeof(*shdr4extnum))) | 2213 | sizeof(*shdr4extnum))) |
2215 | goto end_coredump; | 2214 | goto end_coredump; |
2216 | } | 2215 | } |
2217 | 2216 | ||
2218 | end_coredump: | 2217 | end_coredump: |
2219 | set_fs(fs); | 2218 | set_fs(fs); |
2220 | 2219 | ||
2221 | cleanup: | 2220 | cleanup: |
2222 | free_note_info(&info); | 2221 | free_note_info(&info); |
2223 | kfree(shdr4extnum); | 2222 | kfree(shdr4extnum); |
2224 | kfree(phdr4note); | 2223 | kfree(phdr4note); |
2225 | kfree(elf); | 2224 | kfree(elf); |
2226 | out: | 2225 | out: |
2227 | return has_dumped; | 2226 | return has_dumped; |
2228 | } | 2227 | } |
2229 | 2228 | ||
2230 | #endif /* CONFIG_ELF_CORE */ | 2229 | #endif /* CONFIG_ELF_CORE */ |
2231 | 2230 | ||
2232 | static int __init init_elf_binfmt(void) | 2231 | static int __init init_elf_binfmt(void) |
2233 | { | 2232 | { |
2234 | register_binfmt(&elf_format); | 2233 | register_binfmt(&elf_format); |
2235 | return 0; | 2234 | return 0; |
2236 | } | 2235 | } |
2237 | 2236 | ||
2238 | static void __exit exit_elf_binfmt(void) | 2237 | static void __exit exit_elf_binfmt(void) |
2239 | { | 2238 | { |
2240 | /* Remove the COFF and ELF loaders. */ | 2239 | /* Remove the COFF and ELF loaders. */ |
2241 | unregister_binfmt(&elf_format); | 2240 | unregister_binfmt(&elf_format); |
2242 | } | 2241 | } |
2243 | 2242 | ||
2244 | core_initcall(init_elf_binfmt); | 2243 | core_initcall(init_elf_binfmt); |
2245 | module_exit(exit_elf_binfmt); | 2244 | module_exit(exit_elf_binfmt); |
2246 | MODULE_LICENSE("GPL"); | 2245 | MODULE_LICENSE("GPL"); |
2247 | 2246 |
fs/binfmt_elf_fdpic.c
1 | /* binfmt_elf_fdpic.c: FDPIC ELF binary format | 1 | /* binfmt_elf_fdpic.c: FDPIC ELF binary format |
2 | * | 2 | * |
3 | * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * Derived from binfmt_elf.c | 5 | * Derived from binfmt_elf.c |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | 14 | ||
15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/mman.h> | 19 | #include <linux/mman.h> |
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/signal.h> | 21 | #include <linux/signal.h> |
22 | #include <linux/binfmts.h> | 22 | #include <linux/binfmts.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/file.h> | 24 | #include <linux/file.h> |
25 | #include <linux/fcntl.h> | 25 | #include <linux/fcntl.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
28 | #include <linux/security.h> | 28 | #include <linux/security.h> |
29 | #include <linux/highmem.h> | 29 | #include <linux/highmem.h> |
30 | #include <linux/highuid.h> | 30 | #include <linux/highuid.h> |
31 | #include <linux/personality.h> | 31 | #include <linux/personality.h> |
32 | #include <linux/ptrace.h> | 32 | #include <linux/ptrace.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/elf.h> | 34 | #include <linux/elf.h> |
35 | #include <linux/elf-fdpic.h> | 35 | #include <linux/elf-fdpic.h> |
36 | #include <linux/elfcore.h> | 36 | #include <linux/elfcore.h> |
37 | #include <linux/coredump.h> | 37 | #include <linux/coredump.h> |
38 | 38 | ||
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
40 | #include <asm/param.h> | 40 | #include <asm/param.h> |
41 | #include <asm/pgalloc.h> | 41 | #include <asm/pgalloc.h> |
42 | 42 | ||
43 | typedef char *elf_caddr_t; | 43 | typedef char *elf_caddr_t; |
44 | 44 | ||
45 | #if 0 | 45 | #if 0 |
46 | #define kdebug(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) | 46 | #define kdebug(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) |
47 | #else | 47 | #else |
48 | #define kdebug(fmt, ...) do {} while(0) | 48 | #define kdebug(fmt, ...) do {} while(0) |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #if 0 | 51 | #if 0 |
52 | #define kdcore(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) | 52 | #define kdcore(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) |
53 | #else | 53 | #else |
54 | #define kdcore(fmt, ...) do {} while(0) | 54 | #define kdcore(fmt, ...) do {} while(0) |
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | MODULE_LICENSE("GPL"); | 57 | MODULE_LICENSE("GPL"); |
58 | 58 | ||
59 | static int load_elf_fdpic_binary(struct linux_binprm *); | 59 | static int load_elf_fdpic_binary(struct linux_binprm *); |
60 | static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *, struct file *); | 60 | static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *, struct file *); |
61 | static int elf_fdpic_map_file(struct elf_fdpic_params *, struct file *, | 61 | static int elf_fdpic_map_file(struct elf_fdpic_params *, struct file *, |
62 | struct mm_struct *, const char *); | 62 | struct mm_struct *, const char *); |
63 | 63 | ||
64 | static int create_elf_fdpic_tables(struct linux_binprm *, struct mm_struct *, | 64 | static int create_elf_fdpic_tables(struct linux_binprm *, struct mm_struct *, |
65 | struct elf_fdpic_params *, | 65 | struct elf_fdpic_params *, |
66 | struct elf_fdpic_params *); | 66 | struct elf_fdpic_params *); |
67 | 67 | ||
68 | #ifndef CONFIG_MMU | 68 | #ifndef CONFIG_MMU |
69 | static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *, | 69 | static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *, |
70 | unsigned long *); | 70 | unsigned long *); |
71 | static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *, | 71 | static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *, |
72 | struct file *, | 72 | struct file *, |
73 | struct mm_struct *); | 73 | struct mm_struct *); |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, | 76 | static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, |
77 | struct file *, struct mm_struct *); | 77 | struct file *, struct mm_struct *); |
78 | 78 | ||
79 | #ifdef CONFIG_ELF_CORE | 79 | #ifdef CONFIG_ELF_CORE |
80 | static int elf_fdpic_core_dump(struct coredump_params *cprm); | 80 | static int elf_fdpic_core_dump(struct coredump_params *cprm); |
81 | #endif | 81 | #endif |
82 | 82 | ||
83 | static struct linux_binfmt elf_fdpic_format = { | 83 | static struct linux_binfmt elf_fdpic_format = { |
84 | .module = THIS_MODULE, | 84 | .module = THIS_MODULE, |
85 | .load_binary = load_elf_fdpic_binary, | 85 | .load_binary = load_elf_fdpic_binary, |
86 | #ifdef CONFIG_ELF_CORE | 86 | #ifdef CONFIG_ELF_CORE |
87 | .core_dump = elf_fdpic_core_dump, | 87 | .core_dump = elf_fdpic_core_dump, |
88 | #endif | 88 | #endif |
89 | .min_coredump = ELF_EXEC_PAGESIZE, | 89 | .min_coredump = ELF_EXEC_PAGESIZE, |
90 | }; | 90 | }; |
91 | 91 | ||
92 | static int __init init_elf_fdpic_binfmt(void) | 92 | static int __init init_elf_fdpic_binfmt(void) |
93 | { | 93 | { |
94 | register_binfmt(&elf_fdpic_format); | 94 | register_binfmt(&elf_fdpic_format); |
95 | return 0; | 95 | return 0; |
96 | } | 96 | } |
97 | 97 | ||
98 | static void __exit exit_elf_fdpic_binfmt(void) | 98 | static void __exit exit_elf_fdpic_binfmt(void) |
99 | { | 99 | { |
100 | unregister_binfmt(&elf_fdpic_format); | 100 | unregister_binfmt(&elf_fdpic_format); |
101 | } | 101 | } |
102 | 102 | ||
103 | core_initcall(init_elf_fdpic_binfmt); | 103 | core_initcall(init_elf_fdpic_binfmt); |
104 | module_exit(exit_elf_fdpic_binfmt); | 104 | module_exit(exit_elf_fdpic_binfmt); |
105 | 105 | ||
106 | static int is_elf_fdpic(struct elfhdr *hdr, struct file *file) | 106 | static int is_elf_fdpic(struct elfhdr *hdr, struct file *file) |
107 | { | 107 | { |
108 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) | 108 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) |
109 | return 0; | 109 | return 0; |
110 | if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) | 110 | if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) |
111 | return 0; | 111 | return 0; |
112 | if (!elf_check_arch(hdr) || !elf_check_fdpic(hdr)) | 112 | if (!elf_check_arch(hdr) || !elf_check_fdpic(hdr)) |
113 | return 0; | 113 | return 0; |
114 | if (!file->f_op || !file->f_op->mmap) | 114 | if (!file->f_op || !file->f_op->mmap) |
115 | return 0; | 115 | return 0; |
116 | return 1; | 116 | return 1; |
117 | } | 117 | } |
118 | 118 | ||
119 | /*****************************************************************************/ | 119 | /*****************************************************************************/ |
120 | /* | 120 | /* |
121 | * read the program headers table into memory | 121 | * read the program headers table into memory |
122 | */ | 122 | */ |
123 | static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params, | 123 | static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params, |
124 | struct file *file) | 124 | struct file *file) |
125 | { | 125 | { |
126 | struct elf32_phdr *phdr; | 126 | struct elf32_phdr *phdr; |
127 | unsigned long size; | 127 | unsigned long size; |
128 | int retval, loop; | 128 | int retval, loop; |
129 | 129 | ||
130 | if (params->hdr.e_phentsize != sizeof(struct elf_phdr)) | 130 | if (params->hdr.e_phentsize != sizeof(struct elf_phdr)) |
131 | return -ENOMEM; | 131 | return -ENOMEM; |
132 | if (params->hdr.e_phnum > 65536U / sizeof(struct elf_phdr)) | 132 | if (params->hdr.e_phnum > 65536U / sizeof(struct elf_phdr)) |
133 | return -ENOMEM; | 133 | return -ENOMEM; |
134 | 134 | ||
135 | size = params->hdr.e_phnum * sizeof(struct elf_phdr); | 135 | size = params->hdr.e_phnum * sizeof(struct elf_phdr); |
136 | params->phdrs = kmalloc(size, GFP_KERNEL); | 136 | params->phdrs = kmalloc(size, GFP_KERNEL); |
137 | if (!params->phdrs) | 137 | if (!params->phdrs) |
138 | return -ENOMEM; | 138 | return -ENOMEM; |
139 | 139 | ||
140 | retval = kernel_read(file, params->hdr.e_phoff, | 140 | retval = kernel_read(file, params->hdr.e_phoff, |
141 | (char *) params->phdrs, size); | 141 | (char *) params->phdrs, size); |
142 | if (unlikely(retval != size)) | 142 | if (unlikely(retval != size)) |
143 | return retval < 0 ? retval : -ENOEXEC; | 143 | return retval < 0 ? retval : -ENOEXEC; |
144 | 144 | ||
145 | /* determine stack size for this binary */ | 145 | /* determine stack size for this binary */ |
146 | phdr = params->phdrs; | 146 | phdr = params->phdrs; |
147 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { | 147 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { |
148 | if (phdr->p_type != PT_GNU_STACK) | 148 | if (phdr->p_type != PT_GNU_STACK) |
149 | continue; | 149 | continue; |
150 | 150 | ||
151 | if (phdr->p_flags & PF_X) | 151 | if (phdr->p_flags & PF_X) |
152 | params->flags |= ELF_FDPIC_FLAG_EXEC_STACK; | 152 | params->flags |= ELF_FDPIC_FLAG_EXEC_STACK; |
153 | else | 153 | else |
154 | params->flags |= ELF_FDPIC_FLAG_NOEXEC_STACK; | 154 | params->flags |= ELF_FDPIC_FLAG_NOEXEC_STACK; |
155 | 155 | ||
156 | params->stack_size = phdr->p_memsz; | 156 | params->stack_size = phdr->p_memsz; |
157 | break; | 157 | break; |
158 | } | 158 | } |
159 | 159 | ||
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
162 | 162 | ||
163 | /*****************************************************************************/ | 163 | /*****************************************************************************/ |
164 | /* | 164 | /* |
165 | * load an fdpic binary into various bits of memory | 165 | * load an fdpic binary into various bits of memory |
166 | */ | 166 | */ |
167 | static int load_elf_fdpic_binary(struct linux_binprm *bprm) | 167 | static int load_elf_fdpic_binary(struct linux_binprm *bprm) |
168 | { | 168 | { |
169 | struct elf_fdpic_params exec_params, interp_params; | 169 | struct elf_fdpic_params exec_params, interp_params; |
170 | struct pt_regs *regs = current_pt_regs(); | 170 | struct pt_regs *regs = current_pt_regs(); |
171 | struct elf_phdr *phdr; | 171 | struct elf_phdr *phdr; |
172 | unsigned long stack_size, entryaddr; | 172 | unsigned long stack_size, entryaddr; |
173 | #ifdef ELF_FDPIC_PLAT_INIT | 173 | #ifdef ELF_FDPIC_PLAT_INIT |
174 | unsigned long dynaddr; | 174 | unsigned long dynaddr; |
175 | #endif | 175 | #endif |
176 | #ifndef CONFIG_MMU | 176 | #ifndef CONFIG_MMU |
177 | unsigned long stack_prot; | 177 | unsigned long stack_prot; |
178 | #endif | 178 | #endif |
179 | struct file *interpreter = NULL; /* to shut gcc up */ | 179 | struct file *interpreter = NULL; /* to shut gcc up */ |
180 | char *interpreter_name = NULL; | 180 | char *interpreter_name = NULL; |
181 | int executable_stack; | 181 | int executable_stack; |
182 | int retval, i; | 182 | int retval, i; |
183 | 183 | ||
184 | kdebug("____ LOAD %d ____", current->pid); | 184 | kdebug("____ LOAD %d ____", current->pid); |
185 | 185 | ||
186 | memset(&exec_params, 0, sizeof(exec_params)); | 186 | memset(&exec_params, 0, sizeof(exec_params)); |
187 | memset(&interp_params, 0, sizeof(interp_params)); | 187 | memset(&interp_params, 0, sizeof(interp_params)); |
188 | 188 | ||
189 | exec_params.hdr = *(struct elfhdr *) bprm->buf; | 189 | exec_params.hdr = *(struct elfhdr *) bprm->buf; |
190 | exec_params.flags = ELF_FDPIC_FLAG_PRESENT | ELF_FDPIC_FLAG_EXECUTABLE; | 190 | exec_params.flags = ELF_FDPIC_FLAG_PRESENT | ELF_FDPIC_FLAG_EXECUTABLE; |
191 | 191 | ||
192 | /* check that this is a binary we know how to deal with */ | 192 | /* check that this is a binary we know how to deal with */ |
193 | retval = -ENOEXEC; | 193 | retval = -ENOEXEC; |
194 | if (!is_elf_fdpic(&exec_params.hdr, bprm->file)) | 194 | if (!is_elf_fdpic(&exec_params.hdr, bprm->file)) |
195 | goto error; | 195 | goto error; |
196 | 196 | ||
197 | /* read the program header table */ | 197 | /* read the program header table */ |
198 | retval = elf_fdpic_fetch_phdrs(&exec_params, bprm->file); | 198 | retval = elf_fdpic_fetch_phdrs(&exec_params, bprm->file); |
199 | if (retval < 0) | 199 | if (retval < 0) |
200 | goto error; | 200 | goto error; |
201 | 201 | ||
202 | /* scan for a program header that specifies an interpreter */ | 202 | /* scan for a program header that specifies an interpreter */ |
203 | phdr = exec_params.phdrs; | 203 | phdr = exec_params.phdrs; |
204 | 204 | ||
205 | for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) { | 205 | for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) { |
206 | switch (phdr->p_type) { | 206 | switch (phdr->p_type) { |
207 | case PT_INTERP: | 207 | case PT_INTERP: |
208 | retval = -ENOMEM; | 208 | retval = -ENOMEM; |
209 | if (phdr->p_filesz > PATH_MAX) | 209 | if (phdr->p_filesz > PATH_MAX) |
210 | goto error; | 210 | goto error; |
211 | retval = -ENOENT; | 211 | retval = -ENOENT; |
212 | if (phdr->p_filesz < 2) | 212 | if (phdr->p_filesz < 2) |
213 | goto error; | 213 | goto error; |
214 | 214 | ||
215 | /* read the name of the interpreter into memory */ | 215 | /* read the name of the interpreter into memory */ |
216 | interpreter_name = kmalloc(phdr->p_filesz, GFP_KERNEL); | 216 | interpreter_name = kmalloc(phdr->p_filesz, GFP_KERNEL); |
217 | if (!interpreter_name) | 217 | if (!interpreter_name) |
218 | goto error; | 218 | goto error; |
219 | 219 | ||
220 | retval = kernel_read(bprm->file, | 220 | retval = kernel_read(bprm->file, |
221 | phdr->p_offset, | 221 | phdr->p_offset, |
222 | interpreter_name, | 222 | interpreter_name, |
223 | phdr->p_filesz); | 223 | phdr->p_filesz); |
224 | if (unlikely(retval != phdr->p_filesz)) { | 224 | if (unlikely(retval != phdr->p_filesz)) { |
225 | if (retval >= 0) | 225 | if (retval >= 0) |
226 | retval = -ENOEXEC; | 226 | retval = -ENOEXEC; |
227 | goto error; | 227 | goto error; |
228 | } | 228 | } |
229 | 229 | ||
230 | retval = -ENOENT; | 230 | retval = -ENOENT; |
231 | if (interpreter_name[phdr->p_filesz - 1] != '\0') | 231 | if (interpreter_name[phdr->p_filesz - 1] != '\0') |
232 | goto error; | 232 | goto error; |
233 | 233 | ||
234 | kdebug("Using ELF interpreter %s", interpreter_name); | 234 | kdebug("Using ELF interpreter %s", interpreter_name); |
235 | 235 | ||
236 | /* replace the program with the interpreter */ | 236 | /* replace the program with the interpreter */ |
237 | interpreter = open_exec(interpreter_name); | 237 | interpreter = open_exec(interpreter_name); |
238 | retval = PTR_ERR(interpreter); | 238 | retval = PTR_ERR(interpreter); |
239 | if (IS_ERR(interpreter)) { | 239 | if (IS_ERR(interpreter)) { |
240 | interpreter = NULL; | 240 | interpreter = NULL; |
241 | goto error; | 241 | goto error; |
242 | } | 242 | } |
243 | 243 | ||
244 | /* | 244 | /* |
245 | * If the binary is not readable then enforce | 245 | * If the binary is not readable then enforce |
246 | * mm->dumpable = 0 regardless of the interpreter's | 246 | * mm->dumpable = 0 regardless of the interpreter's |
247 | * permissions. | 247 | * permissions. |
248 | */ | 248 | */ |
249 | would_dump(bprm, interpreter); | 249 | would_dump(bprm, interpreter); |
250 | 250 | ||
251 | retval = kernel_read(interpreter, 0, bprm->buf, | 251 | retval = kernel_read(interpreter, 0, bprm->buf, |
252 | BINPRM_BUF_SIZE); | 252 | BINPRM_BUF_SIZE); |
253 | if (unlikely(retval != BINPRM_BUF_SIZE)) { | 253 | if (unlikely(retval != BINPRM_BUF_SIZE)) { |
254 | if (retval >= 0) | 254 | if (retval >= 0) |
255 | retval = -ENOEXEC; | 255 | retval = -ENOEXEC; |
256 | goto error; | 256 | goto error; |
257 | } | 257 | } |
258 | 258 | ||
259 | interp_params.hdr = *((struct elfhdr *) bprm->buf); | 259 | interp_params.hdr = *((struct elfhdr *) bprm->buf); |
260 | break; | 260 | break; |
261 | 261 | ||
262 | case PT_LOAD: | 262 | case PT_LOAD: |
263 | #ifdef CONFIG_MMU | 263 | #ifdef CONFIG_MMU |
264 | if (exec_params.load_addr == 0) | 264 | if (exec_params.load_addr == 0) |
265 | exec_params.load_addr = phdr->p_vaddr; | 265 | exec_params.load_addr = phdr->p_vaddr; |
266 | #endif | 266 | #endif |
267 | break; | 267 | break; |
268 | } | 268 | } |
269 | 269 | ||
270 | } | 270 | } |
271 | 271 | ||
272 | if (elf_check_const_displacement(&exec_params.hdr)) | 272 | if (elf_check_const_displacement(&exec_params.hdr)) |
273 | exec_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; | 273 | exec_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; |
274 | 274 | ||
275 | /* perform insanity checks on the interpreter */ | 275 | /* perform insanity checks on the interpreter */ |
276 | if (interpreter_name) { | 276 | if (interpreter_name) { |
277 | retval = -ELIBBAD; | 277 | retval = -ELIBBAD; |
278 | if (!is_elf_fdpic(&interp_params.hdr, interpreter)) | 278 | if (!is_elf_fdpic(&interp_params.hdr, interpreter)) |
279 | goto error; | 279 | goto error; |
280 | 280 | ||
281 | interp_params.flags = ELF_FDPIC_FLAG_PRESENT; | 281 | interp_params.flags = ELF_FDPIC_FLAG_PRESENT; |
282 | 282 | ||
283 | /* read the interpreter's program header table */ | 283 | /* read the interpreter's program header table */ |
284 | retval = elf_fdpic_fetch_phdrs(&interp_params, interpreter); | 284 | retval = elf_fdpic_fetch_phdrs(&interp_params, interpreter); |
285 | if (retval < 0) | 285 | if (retval < 0) |
286 | goto error; | 286 | goto error; |
287 | } | 287 | } |
288 | 288 | ||
289 | stack_size = exec_params.stack_size; | 289 | stack_size = exec_params.stack_size; |
290 | if (exec_params.flags & ELF_FDPIC_FLAG_EXEC_STACK) | 290 | if (exec_params.flags & ELF_FDPIC_FLAG_EXEC_STACK) |
291 | executable_stack = EXSTACK_ENABLE_X; | 291 | executable_stack = EXSTACK_ENABLE_X; |
292 | else if (exec_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK) | 292 | else if (exec_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK) |
293 | executable_stack = EXSTACK_DISABLE_X; | 293 | executable_stack = EXSTACK_DISABLE_X; |
294 | else | 294 | else |
295 | executable_stack = EXSTACK_DEFAULT; | 295 | executable_stack = EXSTACK_DEFAULT; |
296 | 296 | ||
297 | if (stack_size == 0) { | 297 | if (stack_size == 0) { |
298 | stack_size = interp_params.stack_size; | 298 | stack_size = interp_params.stack_size; |
299 | if (interp_params.flags & ELF_FDPIC_FLAG_EXEC_STACK) | 299 | if (interp_params.flags & ELF_FDPIC_FLAG_EXEC_STACK) |
300 | executable_stack = EXSTACK_ENABLE_X; | 300 | executable_stack = EXSTACK_ENABLE_X; |
301 | else if (interp_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK) | 301 | else if (interp_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK) |
302 | executable_stack = EXSTACK_DISABLE_X; | 302 | executable_stack = EXSTACK_DISABLE_X; |
303 | else | 303 | else |
304 | executable_stack = EXSTACK_DEFAULT; | 304 | executable_stack = EXSTACK_DEFAULT; |
305 | } | 305 | } |
306 | 306 | ||
307 | retval = -ENOEXEC; | 307 | retval = -ENOEXEC; |
308 | if (stack_size == 0) | 308 | if (stack_size == 0) |
309 | goto error; | 309 | goto error; |
310 | 310 | ||
311 | if (elf_check_const_displacement(&interp_params.hdr)) | 311 | if (elf_check_const_displacement(&interp_params.hdr)) |
312 | interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; | 312 | interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; |
313 | 313 | ||
314 | /* flush all traces of the currently running executable */ | 314 | /* flush all traces of the currently running executable */ |
315 | retval = flush_old_exec(bprm); | 315 | retval = flush_old_exec(bprm); |
316 | if (retval) | 316 | if (retval) |
317 | goto error; | 317 | goto error; |
318 | 318 | ||
319 | /* there's now no turning back... the old userspace image is dead, | 319 | /* there's now no turning back... the old userspace image is dead, |
320 | * defunct, deceased, etc. after this point we have to exit via | 320 | * defunct, deceased, etc. after this point we have to exit via |
321 | * error_kill */ | 321 | * error_kill */ |
322 | set_personality(PER_LINUX_FDPIC); | 322 | set_personality(PER_LINUX_FDPIC); |
323 | if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) | 323 | if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) |
324 | current->personality |= READ_IMPLIES_EXEC; | 324 | current->personality |= READ_IMPLIES_EXEC; |
325 | 325 | ||
326 | setup_new_exec(bprm); | 326 | setup_new_exec(bprm); |
327 | 327 | ||
328 | set_binfmt(&elf_fdpic_format); | 328 | set_binfmt(&elf_fdpic_format); |
329 | 329 | ||
330 | current->mm->start_code = 0; | 330 | current->mm->start_code = 0; |
331 | current->mm->end_code = 0; | 331 | current->mm->end_code = 0; |
332 | current->mm->start_stack = 0; | 332 | current->mm->start_stack = 0; |
333 | current->mm->start_data = 0; | 333 | current->mm->start_data = 0; |
334 | current->mm->end_data = 0; | 334 | current->mm->end_data = 0; |
335 | current->mm->context.exec_fdpic_loadmap = 0; | 335 | current->mm->context.exec_fdpic_loadmap = 0; |
336 | current->mm->context.interp_fdpic_loadmap = 0; | 336 | current->mm->context.interp_fdpic_loadmap = 0; |
337 | 337 | ||
338 | #ifdef CONFIG_MMU | 338 | #ifdef CONFIG_MMU |
339 | elf_fdpic_arch_lay_out_mm(&exec_params, | 339 | elf_fdpic_arch_lay_out_mm(&exec_params, |
340 | &interp_params, | 340 | &interp_params, |
341 | ¤t->mm->start_stack, | 341 | ¤t->mm->start_stack, |
342 | ¤t->mm->start_brk); | 342 | ¤t->mm->start_brk); |
343 | 343 | ||
344 | retval = setup_arg_pages(bprm, current->mm->start_stack, | 344 | retval = setup_arg_pages(bprm, current->mm->start_stack, |
345 | executable_stack); | 345 | executable_stack); |
346 | if (retval < 0) { | 346 | if (retval < 0) { |
347 | send_sig(SIGKILL, current, 0); | 347 | send_sig(SIGKILL, current, 0); |
348 | goto error_kill; | 348 | goto error_kill; |
349 | } | 349 | } |
350 | #endif | 350 | #endif |
351 | 351 | ||
352 | /* load the executable and interpreter into memory */ | 352 | /* load the executable and interpreter into memory */ |
353 | retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm, | 353 | retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm, |
354 | "executable"); | 354 | "executable"); |
355 | if (retval < 0) | 355 | if (retval < 0) |
356 | goto error_kill; | 356 | goto error_kill; |
357 | 357 | ||
358 | if (interpreter_name) { | 358 | if (interpreter_name) { |
359 | retval = elf_fdpic_map_file(&interp_params, interpreter, | 359 | retval = elf_fdpic_map_file(&interp_params, interpreter, |
360 | current->mm, "interpreter"); | 360 | current->mm, "interpreter"); |
361 | if (retval < 0) { | 361 | if (retval < 0) { |
362 | printk(KERN_ERR "Unable to load interpreter\n"); | 362 | printk(KERN_ERR "Unable to load interpreter\n"); |
363 | goto error_kill; | 363 | goto error_kill; |
364 | } | 364 | } |
365 | 365 | ||
366 | allow_write_access(interpreter); | 366 | allow_write_access(interpreter); |
367 | fput(interpreter); | 367 | fput(interpreter); |
368 | interpreter = NULL; | 368 | interpreter = NULL; |
369 | } | 369 | } |
370 | 370 | ||
371 | #ifdef CONFIG_MMU | 371 | #ifdef CONFIG_MMU |
372 | if (!current->mm->start_brk) | 372 | if (!current->mm->start_brk) |
373 | current->mm->start_brk = current->mm->end_data; | 373 | current->mm->start_brk = current->mm->end_data; |
374 | 374 | ||
375 | current->mm->brk = current->mm->start_brk = | 375 | current->mm->brk = current->mm->start_brk = |
376 | PAGE_ALIGN(current->mm->start_brk); | 376 | PAGE_ALIGN(current->mm->start_brk); |
377 | 377 | ||
378 | #else | 378 | #else |
379 | /* create a stack and brk area big enough for everyone | 379 | /* create a stack and brk area big enough for everyone |
380 | * - the brk heap starts at the bottom and works up | 380 | * - the brk heap starts at the bottom and works up |
381 | * - the stack starts at the top and works down | 381 | * - the stack starts at the top and works down |
382 | */ | 382 | */ |
383 | stack_size = (stack_size + PAGE_SIZE - 1) & PAGE_MASK; | 383 | stack_size = (stack_size + PAGE_SIZE - 1) & PAGE_MASK; |
384 | if (stack_size < PAGE_SIZE * 2) | 384 | if (stack_size < PAGE_SIZE * 2) |
385 | stack_size = PAGE_SIZE * 2; | 385 | stack_size = PAGE_SIZE * 2; |
386 | 386 | ||
387 | stack_prot = PROT_READ | PROT_WRITE; | 387 | stack_prot = PROT_READ | PROT_WRITE; |
388 | if (executable_stack == EXSTACK_ENABLE_X || | 388 | if (executable_stack == EXSTACK_ENABLE_X || |
389 | (executable_stack == EXSTACK_DEFAULT && VM_STACK_FLAGS & VM_EXEC)) | 389 | (executable_stack == EXSTACK_DEFAULT && VM_STACK_FLAGS & VM_EXEC)) |
390 | stack_prot |= PROT_EXEC; | 390 | stack_prot |= PROT_EXEC; |
391 | 391 | ||
392 | current->mm->start_brk = vm_mmap(NULL, 0, stack_size, stack_prot, | 392 | current->mm->start_brk = vm_mmap(NULL, 0, stack_size, stack_prot, |
393 | MAP_PRIVATE | MAP_ANONYMOUS | | 393 | MAP_PRIVATE | MAP_ANONYMOUS | |
394 | MAP_UNINITIALIZED | MAP_GROWSDOWN, | 394 | MAP_UNINITIALIZED | MAP_GROWSDOWN, |
395 | 0); | 395 | 0); |
396 | 396 | ||
397 | if (IS_ERR_VALUE(current->mm->start_brk)) { | 397 | if (IS_ERR_VALUE(current->mm->start_brk)) { |
398 | retval = current->mm->start_brk; | 398 | retval = current->mm->start_brk; |
399 | current->mm->start_brk = 0; | 399 | current->mm->start_brk = 0; |
400 | goto error_kill; | 400 | goto error_kill; |
401 | } | 401 | } |
402 | 402 | ||
403 | current->mm->brk = current->mm->start_brk; | 403 | current->mm->brk = current->mm->start_brk; |
404 | current->mm->context.end_brk = current->mm->start_brk; | 404 | current->mm->context.end_brk = current->mm->start_brk; |
405 | current->mm->context.end_brk += | 405 | current->mm->context.end_brk += |
406 | (stack_size > PAGE_SIZE) ? (stack_size - PAGE_SIZE) : 0; | 406 | (stack_size > PAGE_SIZE) ? (stack_size - PAGE_SIZE) : 0; |
407 | current->mm->start_stack = current->mm->start_brk + stack_size; | 407 | current->mm->start_stack = current->mm->start_brk + stack_size; |
408 | #endif | 408 | #endif |
409 | 409 | ||
410 | install_exec_creds(bprm); | 410 | install_exec_creds(bprm); |
411 | if (create_elf_fdpic_tables(bprm, current->mm, | 411 | if (create_elf_fdpic_tables(bprm, current->mm, |
412 | &exec_params, &interp_params) < 0) | 412 | &exec_params, &interp_params) < 0) |
413 | goto error_kill; | 413 | goto error_kill; |
414 | 414 | ||
415 | kdebug("- start_code %lx", current->mm->start_code); | 415 | kdebug("- start_code %lx", current->mm->start_code); |
416 | kdebug("- end_code %lx", current->mm->end_code); | 416 | kdebug("- end_code %lx", current->mm->end_code); |
417 | kdebug("- start_data %lx", current->mm->start_data); | 417 | kdebug("- start_data %lx", current->mm->start_data); |
418 | kdebug("- end_data %lx", current->mm->end_data); | 418 | kdebug("- end_data %lx", current->mm->end_data); |
419 | kdebug("- start_brk %lx", current->mm->start_brk); | 419 | kdebug("- start_brk %lx", current->mm->start_brk); |
420 | kdebug("- brk %lx", current->mm->brk); | 420 | kdebug("- brk %lx", current->mm->brk); |
421 | kdebug("- start_stack %lx", current->mm->start_stack); | 421 | kdebug("- start_stack %lx", current->mm->start_stack); |
422 | 422 | ||
423 | #ifdef ELF_FDPIC_PLAT_INIT | 423 | #ifdef ELF_FDPIC_PLAT_INIT |
424 | /* | 424 | /* |
425 | * The ABI may specify that certain registers be set up in special | 425 | * The ABI may specify that certain registers be set up in special |
426 | * ways (on i386 %edx is the address of a DT_FINI function, for | 426 | * ways (on i386 %edx is the address of a DT_FINI function, for |
427 | * example. This macro performs whatever initialization to | 427 | * example. This macro performs whatever initialization to |
428 | * the regs structure is required. | 428 | * the regs structure is required. |
429 | */ | 429 | */ |
430 | dynaddr = interp_params.dynamic_addr ?: exec_params.dynamic_addr; | 430 | dynaddr = interp_params.dynamic_addr ?: exec_params.dynamic_addr; |
431 | ELF_FDPIC_PLAT_INIT(regs, exec_params.map_addr, interp_params.map_addr, | 431 | ELF_FDPIC_PLAT_INIT(regs, exec_params.map_addr, interp_params.map_addr, |
432 | dynaddr); | 432 | dynaddr); |
433 | #endif | 433 | #endif |
434 | 434 | ||
435 | /* everything is now ready... get the userspace context ready to roll */ | 435 | /* everything is now ready... get the userspace context ready to roll */ |
436 | entryaddr = interp_params.entry_addr ?: exec_params.entry_addr; | 436 | entryaddr = interp_params.entry_addr ?: exec_params.entry_addr; |
437 | start_thread(regs, entryaddr, current->mm->start_stack); | 437 | start_thread(regs, entryaddr, current->mm->start_stack); |
438 | 438 | ||
439 | retval = 0; | 439 | retval = 0; |
440 | 440 | ||
441 | error: | 441 | error: |
442 | if (interpreter) { | 442 | if (interpreter) { |
443 | allow_write_access(interpreter); | 443 | allow_write_access(interpreter); |
444 | fput(interpreter); | 444 | fput(interpreter); |
445 | } | 445 | } |
446 | kfree(interpreter_name); | 446 | kfree(interpreter_name); |
447 | kfree(exec_params.phdrs); | 447 | kfree(exec_params.phdrs); |
448 | kfree(exec_params.loadmap); | 448 | kfree(exec_params.loadmap); |
449 | kfree(interp_params.phdrs); | 449 | kfree(interp_params.phdrs); |
450 | kfree(interp_params.loadmap); | 450 | kfree(interp_params.loadmap); |
451 | return retval; | 451 | return retval; |
452 | 452 | ||
453 | /* unrecoverable error - kill the process */ | 453 | /* unrecoverable error - kill the process */ |
454 | error_kill: | 454 | error_kill: |
455 | send_sig(SIGSEGV, current, 0); | 455 | send_sig(SIGSEGV, current, 0); |
456 | goto error; | 456 | goto error; |
457 | 457 | ||
458 | } | 458 | } |
459 | 459 | ||
460 | /*****************************************************************************/ | 460 | /*****************************************************************************/ |
461 | 461 | ||
462 | #ifndef ELF_BASE_PLATFORM | 462 | #ifndef ELF_BASE_PLATFORM |
463 | /* | 463 | /* |
464 | * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. | 464 | * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. |
465 | * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value | 465 | * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value |
466 | * will be copied to the user stack in the same manner as AT_PLATFORM. | 466 | * will be copied to the user stack in the same manner as AT_PLATFORM. |
467 | */ | 467 | */ |
468 | #define ELF_BASE_PLATFORM NULL | 468 | #define ELF_BASE_PLATFORM NULL |
469 | #endif | 469 | #endif |
470 | 470 | ||
471 | /* | 471 | /* |
472 | * present useful information to the program by shovelling it onto the new | 472 | * present useful information to the program by shovelling it onto the new |
473 | * process's stack | 473 | * process's stack |
474 | */ | 474 | */ |
475 | static int create_elf_fdpic_tables(struct linux_binprm *bprm, | 475 | static int create_elf_fdpic_tables(struct linux_binprm *bprm, |
476 | struct mm_struct *mm, | 476 | struct mm_struct *mm, |
477 | struct elf_fdpic_params *exec_params, | 477 | struct elf_fdpic_params *exec_params, |
478 | struct elf_fdpic_params *interp_params) | 478 | struct elf_fdpic_params *interp_params) |
479 | { | 479 | { |
480 | const struct cred *cred = current_cred(); | 480 | const struct cred *cred = current_cred(); |
481 | unsigned long sp, csp, nitems; | 481 | unsigned long sp, csp, nitems; |
482 | elf_caddr_t __user *argv, *envp; | 482 | elf_caddr_t __user *argv, *envp; |
483 | size_t platform_len = 0, len; | 483 | size_t platform_len = 0, len; |
484 | char *k_platform, *k_base_platform; | 484 | char *k_platform, *k_base_platform; |
485 | char __user *u_platform, *u_base_platform, *p; | 485 | char __user *u_platform, *u_base_platform, *p; |
486 | long hwcap; | 486 | long hwcap; |
487 | int loop; | 487 | int loop; |
488 | int nr; /* reset for each csp adjustment */ | 488 | int nr; /* reset for each csp adjustment */ |
489 | 489 | ||
490 | #ifdef CONFIG_MMU | 490 | #ifdef CONFIG_MMU |
491 | /* In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions | 491 | /* In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions |
492 | * by the processes running on the same package. One thing we can do is | 492 | * by the processes running on the same package. One thing we can do is |
493 | * to shuffle the initial stack for them, so we give the architecture | 493 | * to shuffle the initial stack for them, so we give the architecture |
494 | * an opportunity to do so here. | 494 | * an opportunity to do so here. |
495 | */ | 495 | */ |
496 | sp = arch_align_stack(bprm->p); | 496 | sp = arch_align_stack(bprm->p); |
497 | #else | 497 | #else |
498 | sp = mm->start_stack; | 498 | sp = mm->start_stack; |
499 | 499 | ||
500 | /* stack the program arguments and environment */ | 500 | /* stack the program arguments and environment */ |
501 | if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0) | 501 | if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0) |
502 | return -EFAULT; | 502 | return -EFAULT; |
503 | #endif | 503 | #endif |
504 | 504 | ||
505 | hwcap = ELF_HWCAP; | 505 | hwcap = ELF_HWCAP; |
506 | 506 | ||
507 | /* | 507 | /* |
508 | * If this architecture has a platform capability string, copy it | 508 | * If this architecture has a platform capability string, copy it |
509 | * to userspace. In some cases (Sparc), this info is impossible | 509 | * to userspace. In some cases (Sparc), this info is impossible |
510 | * for userspace to get any other way, in others (i386) it is | 510 | * for userspace to get any other way, in others (i386) it is |
511 | * merely difficult. | 511 | * merely difficult. |
512 | */ | 512 | */ |
513 | k_platform = ELF_PLATFORM; | 513 | k_platform = ELF_PLATFORM; |
514 | u_platform = NULL; | 514 | u_platform = NULL; |
515 | 515 | ||
516 | if (k_platform) { | 516 | if (k_platform) { |
517 | platform_len = strlen(k_platform) + 1; | 517 | platform_len = strlen(k_platform) + 1; |
518 | sp -= platform_len; | 518 | sp -= platform_len; |
519 | u_platform = (char __user *) sp; | 519 | u_platform = (char __user *) sp; |
520 | if (__copy_to_user(u_platform, k_platform, platform_len) != 0) | 520 | if (__copy_to_user(u_platform, k_platform, platform_len) != 0) |
521 | return -EFAULT; | 521 | return -EFAULT; |
522 | } | 522 | } |
523 | 523 | ||
524 | /* | 524 | /* |
525 | * If this architecture has a "base" platform capability | 525 | * If this architecture has a "base" platform capability |
526 | * string, copy it to userspace. | 526 | * string, copy it to userspace. |
527 | */ | 527 | */ |
528 | k_base_platform = ELF_BASE_PLATFORM; | 528 | k_base_platform = ELF_BASE_PLATFORM; |
529 | u_base_platform = NULL; | 529 | u_base_platform = NULL; |
530 | 530 | ||
531 | if (k_base_platform) { | 531 | if (k_base_platform) { |
532 | platform_len = strlen(k_base_platform) + 1; | 532 | platform_len = strlen(k_base_platform) + 1; |
533 | sp -= platform_len; | 533 | sp -= platform_len; |
534 | u_base_platform = (char __user *) sp; | 534 | u_base_platform = (char __user *) sp; |
535 | if (__copy_to_user(u_base_platform, k_base_platform, platform_len) != 0) | 535 | if (__copy_to_user(u_base_platform, k_base_platform, platform_len) != 0) |
536 | return -EFAULT; | 536 | return -EFAULT; |
537 | } | 537 | } |
538 | 538 | ||
539 | sp &= ~7UL; | 539 | sp &= ~7UL; |
540 | 540 | ||
541 | /* stack the load map(s) */ | 541 | /* stack the load map(s) */ |
542 | len = sizeof(struct elf32_fdpic_loadmap); | 542 | len = sizeof(struct elf32_fdpic_loadmap); |
543 | len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs; | 543 | len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs; |
544 | sp = (sp - len) & ~7UL; | 544 | sp = (sp - len) & ~7UL; |
545 | exec_params->map_addr = sp; | 545 | exec_params->map_addr = sp; |
546 | 546 | ||
547 | if (copy_to_user((void __user *) sp, exec_params->loadmap, len) != 0) | 547 | if (copy_to_user((void __user *) sp, exec_params->loadmap, len) != 0) |
548 | return -EFAULT; | 548 | return -EFAULT; |
549 | 549 | ||
550 | current->mm->context.exec_fdpic_loadmap = (unsigned long) sp; | 550 | current->mm->context.exec_fdpic_loadmap = (unsigned long) sp; |
551 | 551 | ||
552 | if (interp_params->loadmap) { | 552 | if (interp_params->loadmap) { |
553 | len = sizeof(struct elf32_fdpic_loadmap); | 553 | len = sizeof(struct elf32_fdpic_loadmap); |
554 | len += sizeof(struct elf32_fdpic_loadseg) * | 554 | len += sizeof(struct elf32_fdpic_loadseg) * |
555 | interp_params->loadmap->nsegs; | 555 | interp_params->loadmap->nsegs; |
556 | sp = (sp - len) & ~7UL; | 556 | sp = (sp - len) & ~7UL; |
557 | interp_params->map_addr = sp; | 557 | interp_params->map_addr = sp; |
558 | 558 | ||
559 | if (copy_to_user((void __user *) sp, interp_params->loadmap, | 559 | if (copy_to_user((void __user *) sp, interp_params->loadmap, |
560 | len) != 0) | 560 | len) != 0) |
561 | return -EFAULT; | 561 | return -EFAULT; |
562 | 562 | ||
563 | current->mm->context.interp_fdpic_loadmap = (unsigned long) sp; | 563 | current->mm->context.interp_fdpic_loadmap = (unsigned long) sp; |
564 | } | 564 | } |
565 | 565 | ||
566 | /* force 16 byte _final_ alignment here for generality */ | 566 | /* force 16 byte _final_ alignment here for generality */ |
567 | #define DLINFO_ITEMS 15 | 567 | #define DLINFO_ITEMS 15 |
568 | 568 | ||
569 | nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + | 569 | nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + |
570 | (k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH; | 570 | (k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH; |
571 | 571 | ||
572 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) | 572 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) |
573 | nitems++; | 573 | nitems++; |
574 | 574 | ||
575 | csp = sp; | 575 | csp = sp; |
576 | sp -= nitems * 2 * sizeof(unsigned long); | 576 | sp -= nitems * 2 * sizeof(unsigned long); |
577 | sp -= (bprm->envc + 1) * sizeof(char *); /* envv[] */ | 577 | sp -= (bprm->envc + 1) * sizeof(char *); /* envv[] */ |
578 | sp -= (bprm->argc + 1) * sizeof(char *); /* argv[] */ | 578 | sp -= (bprm->argc + 1) * sizeof(char *); /* argv[] */ |
579 | sp -= 1 * sizeof(unsigned long); /* argc */ | 579 | sp -= 1 * sizeof(unsigned long); /* argc */ |
580 | 580 | ||
581 | csp -= sp & 15UL; | 581 | csp -= sp & 15UL; |
582 | sp -= sp & 15UL; | 582 | sp -= sp & 15UL; |
583 | 583 | ||
584 | /* put the ELF interpreter info on the stack */ | 584 | /* put the ELF interpreter info on the stack */ |
585 | #define NEW_AUX_ENT(id, val) \ | 585 | #define NEW_AUX_ENT(id, val) \ |
586 | do { \ | 586 | do { \ |
587 | struct { unsigned long _id, _val; } __user *ent; \ | 587 | struct { unsigned long _id, _val; } __user *ent; \ |
588 | \ | 588 | \ |
589 | ent = (void __user *) csp; \ | 589 | ent = (void __user *) csp; \ |
590 | __put_user((id), &ent[nr]._id); \ | 590 | __put_user((id), &ent[nr]._id); \ |
591 | __put_user((val), &ent[nr]._val); \ | 591 | __put_user((val), &ent[nr]._val); \ |
592 | nr++; \ | 592 | nr++; \ |
593 | } while (0) | 593 | } while (0) |
594 | 594 | ||
595 | nr = 0; | 595 | nr = 0; |
596 | csp -= 2 * sizeof(unsigned long); | 596 | csp -= 2 * sizeof(unsigned long); |
597 | NEW_AUX_ENT(AT_NULL, 0); | 597 | NEW_AUX_ENT(AT_NULL, 0); |
598 | if (k_platform) { | 598 | if (k_platform) { |
599 | nr = 0; | 599 | nr = 0; |
600 | csp -= 2 * sizeof(unsigned long); | 600 | csp -= 2 * sizeof(unsigned long); |
601 | NEW_AUX_ENT(AT_PLATFORM, | 601 | NEW_AUX_ENT(AT_PLATFORM, |
602 | (elf_addr_t) (unsigned long) u_platform); | 602 | (elf_addr_t) (unsigned long) u_platform); |
603 | } | 603 | } |
604 | 604 | ||
605 | if (k_base_platform) { | 605 | if (k_base_platform) { |
606 | nr = 0; | 606 | nr = 0; |
607 | csp -= 2 * sizeof(unsigned long); | 607 | csp -= 2 * sizeof(unsigned long); |
608 | NEW_AUX_ENT(AT_BASE_PLATFORM, | 608 | NEW_AUX_ENT(AT_BASE_PLATFORM, |
609 | (elf_addr_t) (unsigned long) u_base_platform); | 609 | (elf_addr_t) (unsigned long) u_base_platform); |
610 | } | 610 | } |
611 | 611 | ||
612 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { | 612 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { |
613 | nr = 0; | 613 | nr = 0; |
614 | csp -= 2 * sizeof(unsigned long); | 614 | csp -= 2 * sizeof(unsigned long); |
615 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); | 615 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); |
616 | } | 616 | } |
617 | 617 | ||
618 | nr = 0; | 618 | nr = 0; |
619 | csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long); | 619 | csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long); |
620 | NEW_AUX_ENT(AT_HWCAP, hwcap); | 620 | NEW_AUX_ENT(AT_HWCAP, hwcap); |
621 | NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE); | 621 | NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE); |
622 | NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); | 622 | NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); |
623 | NEW_AUX_ENT(AT_PHDR, exec_params->ph_addr); | 623 | NEW_AUX_ENT(AT_PHDR, exec_params->ph_addr); |
624 | NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); | 624 | NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); |
625 | NEW_AUX_ENT(AT_PHNUM, exec_params->hdr.e_phnum); | 625 | NEW_AUX_ENT(AT_PHNUM, exec_params->hdr.e_phnum); |
626 | NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr); | 626 | NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr); |
627 | NEW_AUX_ENT(AT_FLAGS, 0); | 627 | NEW_AUX_ENT(AT_FLAGS, 0); |
628 | NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr); | 628 | NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr); |
629 | NEW_AUX_ENT(AT_UID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid)); | 629 | NEW_AUX_ENT(AT_UID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid)); |
630 | NEW_AUX_ENT(AT_EUID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid)); | 630 | NEW_AUX_ENT(AT_EUID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid)); |
631 | NEW_AUX_ENT(AT_GID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid)); | 631 | NEW_AUX_ENT(AT_GID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid)); |
632 | NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid)); | 632 | NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid)); |
633 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); | 633 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); |
634 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); | 634 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); |
635 | 635 | ||
636 | #ifdef ARCH_DLINFO | 636 | #ifdef ARCH_DLINFO |
637 | nr = 0; | 637 | nr = 0; |
638 | csp -= AT_VECTOR_SIZE_ARCH * 2 * sizeof(unsigned long); | 638 | csp -= AT_VECTOR_SIZE_ARCH * 2 * sizeof(unsigned long); |
639 | 639 | ||
640 | /* ARCH_DLINFO must come last so platform specific code can enforce | 640 | /* ARCH_DLINFO must come last so platform specific code can enforce |
641 | * special alignment requirements on the AUXV if necessary (eg. PPC). | 641 | * special alignment requirements on the AUXV if necessary (eg. PPC). |
642 | */ | 642 | */ |
643 | ARCH_DLINFO; | 643 | ARCH_DLINFO; |
644 | #endif | 644 | #endif |
645 | #undef NEW_AUX_ENT | 645 | #undef NEW_AUX_ENT |
646 | 646 | ||
647 | /* allocate room for argv[] and envv[] */ | 647 | /* allocate room for argv[] and envv[] */ |
648 | csp -= (bprm->envc + 1) * sizeof(elf_caddr_t); | 648 | csp -= (bprm->envc + 1) * sizeof(elf_caddr_t); |
649 | envp = (elf_caddr_t __user *) csp; | 649 | envp = (elf_caddr_t __user *) csp; |
650 | csp -= (bprm->argc + 1) * sizeof(elf_caddr_t); | 650 | csp -= (bprm->argc + 1) * sizeof(elf_caddr_t); |
651 | argv = (elf_caddr_t __user *) csp; | 651 | argv = (elf_caddr_t __user *) csp; |
652 | 652 | ||
653 | /* stack argc */ | 653 | /* stack argc */ |
654 | csp -= sizeof(unsigned long); | 654 | csp -= sizeof(unsigned long); |
655 | __put_user(bprm->argc, (unsigned long __user *) csp); | 655 | __put_user(bprm->argc, (unsigned long __user *) csp); |
656 | 656 | ||
657 | BUG_ON(csp != sp); | 657 | BUG_ON(csp != sp); |
658 | 658 | ||
659 | /* fill in the argv[] array */ | 659 | /* fill in the argv[] array */ |
660 | #ifdef CONFIG_MMU | 660 | #ifdef CONFIG_MMU |
661 | current->mm->arg_start = bprm->p; | 661 | current->mm->arg_start = bprm->p; |
662 | #else | 662 | #else |
663 | current->mm->arg_start = current->mm->start_stack - | 663 | current->mm->arg_start = current->mm->start_stack - |
664 | (MAX_ARG_PAGES * PAGE_SIZE - bprm->p); | 664 | (MAX_ARG_PAGES * PAGE_SIZE - bprm->p); |
665 | #endif | 665 | #endif |
666 | 666 | ||
667 | p = (char __user *) current->mm->arg_start; | 667 | p = (char __user *) current->mm->arg_start; |
668 | for (loop = bprm->argc; loop > 0; loop--) { | 668 | for (loop = bprm->argc; loop > 0; loop--) { |
669 | __put_user((elf_caddr_t) p, argv++); | 669 | __put_user((elf_caddr_t) p, argv++); |
670 | len = strnlen_user(p, MAX_ARG_STRLEN); | 670 | len = strnlen_user(p, MAX_ARG_STRLEN); |
671 | if (!len || len > MAX_ARG_STRLEN) | 671 | if (!len || len > MAX_ARG_STRLEN) |
672 | return -EINVAL; | 672 | return -EINVAL; |
673 | p += len; | 673 | p += len; |
674 | } | 674 | } |
675 | __put_user(NULL, argv); | 675 | __put_user(NULL, argv); |
676 | current->mm->arg_end = (unsigned long) p; | 676 | current->mm->arg_end = (unsigned long) p; |
677 | 677 | ||
678 | /* fill in the envv[] array */ | 678 | /* fill in the envv[] array */ |
679 | current->mm->env_start = (unsigned long) p; | 679 | current->mm->env_start = (unsigned long) p; |
680 | for (loop = bprm->envc; loop > 0; loop--) { | 680 | for (loop = bprm->envc; loop > 0; loop--) { |
681 | __put_user((elf_caddr_t)(unsigned long) p, envp++); | 681 | __put_user((elf_caddr_t)(unsigned long) p, envp++); |
682 | len = strnlen_user(p, MAX_ARG_STRLEN); | 682 | len = strnlen_user(p, MAX_ARG_STRLEN); |
683 | if (!len || len > MAX_ARG_STRLEN) | 683 | if (!len || len > MAX_ARG_STRLEN) |
684 | return -EINVAL; | 684 | return -EINVAL; |
685 | p += len; | 685 | p += len; |
686 | } | 686 | } |
687 | __put_user(NULL, envp); | 687 | __put_user(NULL, envp); |
688 | current->mm->env_end = (unsigned long) p; | 688 | current->mm->env_end = (unsigned long) p; |
689 | 689 | ||
690 | mm->start_stack = (unsigned long) sp; | 690 | mm->start_stack = (unsigned long) sp; |
691 | return 0; | 691 | return 0; |
692 | } | 692 | } |
693 | 693 | ||
694 | /*****************************************************************************/ | 694 | /*****************************************************************************/ |
695 | /* | 695 | /* |
696 | * transfer the program arguments and environment from the holding pages onto | 696 | * transfer the program arguments and environment from the holding pages onto |
697 | * the stack | 697 | * the stack |
698 | */ | 698 | */ |
699 | #ifndef CONFIG_MMU | 699 | #ifndef CONFIG_MMU |
700 | static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *bprm, | 700 | static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *bprm, |
701 | unsigned long *_sp) | 701 | unsigned long *_sp) |
702 | { | 702 | { |
703 | unsigned long index, stop, sp; | 703 | unsigned long index, stop, sp; |
704 | char *src; | 704 | char *src; |
705 | int ret = 0; | 705 | int ret = 0; |
706 | 706 | ||
707 | stop = bprm->p >> PAGE_SHIFT; | 707 | stop = bprm->p >> PAGE_SHIFT; |
708 | sp = *_sp; | 708 | sp = *_sp; |
709 | 709 | ||
710 | for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { | 710 | for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { |
711 | src = kmap(bprm->page[index]); | 711 | src = kmap(bprm->page[index]); |
712 | sp -= PAGE_SIZE; | 712 | sp -= PAGE_SIZE; |
713 | if (copy_to_user((void *) sp, src, PAGE_SIZE) != 0) | 713 | if (copy_to_user((void *) sp, src, PAGE_SIZE) != 0) |
714 | ret = -EFAULT; | 714 | ret = -EFAULT; |
715 | kunmap(bprm->page[index]); | 715 | kunmap(bprm->page[index]); |
716 | if (ret < 0) | 716 | if (ret < 0) |
717 | goto out; | 717 | goto out; |
718 | } | 718 | } |
719 | 719 | ||
720 | *_sp = (*_sp - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p)) & ~15; | 720 | *_sp = (*_sp - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p)) & ~15; |
721 | 721 | ||
722 | out: | 722 | out: |
723 | return ret; | 723 | return ret; |
724 | } | 724 | } |
725 | #endif | 725 | #endif |
726 | 726 | ||
727 | /*****************************************************************************/ | 727 | /*****************************************************************************/ |
728 | /* | 728 | /* |
729 | * load the appropriate binary image (executable or interpreter) into memory | 729 | * load the appropriate binary image (executable or interpreter) into memory |
730 | * - we assume no MMU is available | 730 | * - we assume no MMU is available |
731 | * - if no other PIC bits are set in params->hdr->e_flags | 731 | * - if no other PIC bits are set in params->hdr->e_flags |
732 | * - we assume that the LOADable segments in the binary are independently relocatable | 732 | * - we assume that the LOADable segments in the binary are independently relocatable |
733 | * - we assume R/O executable segments are shareable | 733 | * - we assume R/O executable segments are shareable |
734 | * - else | 734 | * - else |
735 | * - we assume the loadable parts of the image to require fixed displacement | 735 | * - we assume the loadable parts of the image to require fixed displacement |
736 | * - the image is not shareable | 736 | * - the image is not shareable |
737 | */ | 737 | */ |
738 | static int elf_fdpic_map_file(struct elf_fdpic_params *params, | 738 | static int elf_fdpic_map_file(struct elf_fdpic_params *params, |
739 | struct file *file, | 739 | struct file *file, |
740 | struct mm_struct *mm, | 740 | struct mm_struct *mm, |
741 | const char *what) | 741 | const char *what) |
742 | { | 742 | { |
743 | struct elf32_fdpic_loadmap *loadmap; | 743 | struct elf32_fdpic_loadmap *loadmap; |
744 | #ifdef CONFIG_MMU | 744 | #ifdef CONFIG_MMU |
745 | struct elf32_fdpic_loadseg *mseg; | 745 | struct elf32_fdpic_loadseg *mseg; |
746 | #endif | 746 | #endif |
747 | struct elf32_fdpic_loadseg *seg; | 747 | struct elf32_fdpic_loadseg *seg; |
748 | struct elf32_phdr *phdr; | 748 | struct elf32_phdr *phdr; |
749 | unsigned long load_addr, stop; | 749 | unsigned long load_addr, stop; |
750 | unsigned nloads, tmp; | 750 | unsigned nloads, tmp; |
751 | size_t size; | 751 | size_t size; |
752 | int loop, ret; | 752 | int loop, ret; |
753 | 753 | ||
754 | /* allocate a load map table */ | 754 | /* allocate a load map table */ |
755 | nloads = 0; | 755 | nloads = 0; |
756 | for (loop = 0; loop < params->hdr.e_phnum; loop++) | 756 | for (loop = 0; loop < params->hdr.e_phnum; loop++) |
757 | if (params->phdrs[loop].p_type == PT_LOAD) | 757 | if (params->phdrs[loop].p_type == PT_LOAD) |
758 | nloads++; | 758 | nloads++; |
759 | 759 | ||
760 | if (nloads == 0) | 760 | if (nloads == 0) |
761 | return -ELIBBAD; | 761 | return -ELIBBAD; |
762 | 762 | ||
763 | size = sizeof(*loadmap) + nloads * sizeof(*seg); | 763 | size = sizeof(*loadmap) + nloads * sizeof(*seg); |
764 | loadmap = kzalloc(size, GFP_KERNEL); | 764 | loadmap = kzalloc(size, GFP_KERNEL); |
765 | if (!loadmap) | 765 | if (!loadmap) |
766 | return -ENOMEM; | 766 | return -ENOMEM; |
767 | 767 | ||
768 | params->loadmap = loadmap; | 768 | params->loadmap = loadmap; |
769 | 769 | ||
770 | loadmap->version = ELF32_FDPIC_LOADMAP_VERSION; | 770 | loadmap->version = ELF32_FDPIC_LOADMAP_VERSION; |
771 | loadmap->nsegs = nloads; | 771 | loadmap->nsegs = nloads; |
772 | 772 | ||
773 | load_addr = params->load_addr; | 773 | load_addr = params->load_addr; |
774 | seg = loadmap->segs; | 774 | seg = loadmap->segs; |
775 | 775 | ||
776 | /* map the requested LOADs into the memory space */ | 776 | /* map the requested LOADs into the memory space */ |
777 | switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) { | 777 | switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) { |
778 | case ELF_FDPIC_FLAG_CONSTDISP: | 778 | case ELF_FDPIC_FLAG_CONSTDISP: |
779 | case ELF_FDPIC_FLAG_CONTIGUOUS: | 779 | case ELF_FDPIC_FLAG_CONTIGUOUS: |
780 | #ifndef CONFIG_MMU | 780 | #ifndef CONFIG_MMU |
781 | ret = elf_fdpic_map_file_constdisp_on_uclinux(params, file, mm); | 781 | ret = elf_fdpic_map_file_constdisp_on_uclinux(params, file, mm); |
782 | if (ret < 0) | 782 | if (ret < 0) |
783 | return ret; | 783 | return ret; |
784 | break; | 784 | break; |
785 | #endif | 785 | #endif |
786 | default: | 786 | default: |
787 | ret = elf_fdpic_map_file_by_direct_mmap(params, file, mm); | 787 | ret = elf_fdpic_map_file_by_direct_mmap(params, file, mm); |
788 | if (ret < 0) | 788 | if (ret < 0) |
789 | return ret; | 789 | return ret; |
790 | break; | 790 | break; |
791 | } | 791 | } |
792 | 792 | ||
793 | /* map the entry point */ | 793 | /* map the entry point */ |
794 | if (params->hdr.e_entry) { | 794 | if (params->hdr.e_entry) { |
795 | seg = loadmap->segs; | 795 | seg = loadmap->segs; |
796 | for (loop = loadmap->nsegs; loop > 0; loop--, seg++) { | 796 | for (loop = loadmap->nsegs; loop > 0; loop--, seg++) { |
797 | if (params->hdr.e_entry >= seg->p_vaddr && | 797 | if (params->hdr.e_entry >= seg->p_vaddr && |
798 | params->hdr.e_entry < seg->p_vaddr + seg->p_memsz) { | 798 | params->hdr.e_entry < seg->p_vaddr + seg->p_memsz) { |
799 | params->entry_addr = | 799 | params->entry_addr = |
800 | (params->hdr.e_entry - seg->p_vaddr) + | 800 | (params->hdr.e_entry - seg->p_vaddr) + |
801 | seg->addr; | 801 | seg->addr; |
802 | break; | 802 | break; |
803 | } | 803 | } |
804 | } | 804 | } |
805 | } | 805 | } |
806 | 806 | ||
807 | /* determine where the program header table has wound up if mapped */ | 807 | /* determine where the program header table has wound up if mapped */ |
808 | stop = params->hdr.e_phoff; | 808 | stop = params->hdr.e_phoff; |
809 | stop += params->hdr.e_phnum * sizeof (struct elf_phdr); | 809 | stop += params->hdr.e_phnum * sizeof (struct elf_phdr); |
810 | phdr = params->phdrs; | 810 | phdr = params->phdrs; |
811 | 811 | ||
812 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { | 812 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { |
813 | if (phdr->p_type != PT_LOAD) | 813 | if (phdr->p_type != PT_LOAD) |
814 | continue; | 814 | continue; |
815 | 815 | ||
816 | if (phdr->p_offset > params->hdr.e_phoff || | 816 | if (phdr->p_offset > params->hdr.e_phoff || |
817 | phdr->p_offset + phdr->p_filesz < stop) | 817 | phdr->p_offset + phdr->p_filesz < stop) |
818 | continue; | 818 | continue; |
819 | 819 | ||
820 | seg = loadmap->segs; | 820 | seg = loadmap->segs; |
821 | for (loop = loadmap->nsegs; loop > 0; loop--, seg++) { | 821 | for (loop = loadmap->nsegs; loop > 0; loop--, seg++) { |
822 | if (phdr->p_vaddr >= seg->p_vaddr && | 822 | if (phdr->p_vaddr >= seg->p_vaddr && |
823 | phdr->p_vaddr + phdr->p_filesz <= | 823 | phdr->p_vaddr + phdr->p_filesz <= |
824 | seg->p_vaddr + seg->p_memsz) { | 824 | seg->p_vaddr + seg->p_memsz) { |
825 | params->ph_addr = | 825 | params->ph_addr = |
826 | (phdr->p_vaddr - seg->p_vaddr) + | 826 | (phdr->p_vaddr - seg->p_vaddr) + |
827 | seg->addr + | 827 | seg->addr + |
828 | params->hdr.e_phoff - phdr->p_offset; | 828 | params->hdr.e_phoff - phdr->p_offset; |
829 | break; | 829 | break; |
830 | } | 830 | } |
831 | } | 831 | } |
832 | break; | 832 | break; |
833 | } | 833 | } |
834 | 834 | ||
835 | /* determine where the dynamic section has wound up if there is one */ | 835 | /* determine where the dynamic section has wound up if there is one */ |
836 | phdr = params->phdrs; | 836 | phdr = params->phdrs; |
837 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { | 837 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { |
838 | if (phdr->p_type != PT_DYNAMIC) | 838 | if (phdr->p_type != PT_DYNAMIC) |
839 | continue; | 839 | continue; |
840 | 840 | ||
841 | seg = loadmap->segs; | 841 | seg = loadmap->segs; |
842 | for (loop = loadmap->nsegs; loop > 0; loop--, seg++) { | 842 | for (loop = loadmap->nsegs; loop > 0; loop--, seg++) { |
843 | if (phdr->p_vaddr >= seg->p_vaddr && | 843 | if (phdr->p_vaddr >= seg->p_vaddr && |
844 | phdr->p_vaddr + phdr->p_memsz <= | 844 | phdr->p_vaddr + phdr->p_memsz <= |
845 | seg->p_vaddr + seg->p_memsz) { | 845 | seg->p_vaddr + seg->p_memsz) { |
846 | params->dynamic_addr = | 846 | params->dynamic_addr = |
847 | (phdr->p_vaddr - seg->p_vaddr) + | 847 | (phdr->p_vaddr - seg->p_vaddr) + |
848 | seg->addr; | 848 | seg->addr; |
849 | 849 | ||
850 | /* check the dynamic section contains at least | 850 | /* check the dynamic section contains at least |
851 | * one item, and that the last item is a NULL | 851 | * one item, and that the last item is a NULL |
852 | * entry */ | 852 | * entry */ |
853 | if (phdr->p_memsz == 0 || | 853 | if (phdr->p_memsz == 0 || |
854 | phdr->p_memsz % sizeof(Elf32_Dyn) != 0) | 854 | phdr->p_memsz % sizeof(Elf32_Dyn) != 0) |
855 | goto dynamic_error; | 855 | goto dynamic_error; |
856 | 856 | ||
857 | tmp = phdr->p_memsz / sizeof(Elf32_Dyn); | 857 | tmp = phdr->p_memsz / sizeof(Elf32_Dyn); |
858 | if (((Elf32_Dyn *) | 858 | if (((Elf32_Dyn *) |
859 | params->dynamic_addr)[tmp - 1].d_tag != 0) | 859 | params->dynamic_addr)[tmp - 1].d_tag != 0) |
860 | goto dynamic_error; | 860 | goto dynamic_error; |
861 | break; | 861 | break; |
862 | } | 862 | } |
863 | } | 863 | } |
864 | break; | 864 | break; |
865 | } | 865 | } |
866 | 866 | ||
867 | /* now elide adjacent segments in the load map on MMU linux | 867 | /* now elide adjacent segments in the load map on MMU linux |
868 | * - on uClinux the holes between may actually be filled with system | 868 | * - on uClinux the holes between may actually be filled with system |
869 | * stuff or stuff from other processes | 869 | * stuff or stuff from other processes |
870 | */ | 870 | */ |
871 | #ifdef CONFIG_MMU | 871 | #ifdef CONFIG_MMU |
872 | nloads = loadmap->nsegs; | 872 | nloads = loadmap->nsegs; |
873 | mseg = loadmap->segs; | 873 | mseg = loadmap->segs; |
874 | seg = mseg + 1; | 874 | seg = mseg + 1; |
875 | for (loop = 1; loop < nloads; loop++) { | 875 | for (loop = 1; loop < nloads; loop++) { |
876 | /* see if we have a candidate for merging */ | 876 | /* see if we have a candidate for merging */ |
877 | if (seg->p_vaddr - mseg->p_vaddr == seg->addr - mseg->addr) { | 877 | if (seg->p_vaddr - mseg->p_vaddr == seg->addr - mseg->addr) { |
878 | load_addr = PAGE_ALIGN(mseg->addr + mseg->p_memsz); | 878 | load_addr = PAGE_ALIGN(mseg->addr + mseg->p_memsz); |
879 | if (load_addr == (seg->addr & PAGE_MASK)) { | 879 | if (load_addr == (seg->addr & PAGE_MASK)) { |
880 | mseg->p_memsz += | 880 | mseg->p_memsz += |
881 | load_addr - | 881 | load_addr - |
882 | (mseg->addr + mseg->p_memsz); | 882 | (mseg->addr + mseg->p_memsz); |
883 | mseg->p_memsz += seg->addr & ~PAGE_MASK; | 883 | mseg->p_memsz += seg->addr & ~PAGE_MASK; |
884 | mseg->p_memsz += seg->p_memsz; | 884 | mseg->p_memsz += seg->p_memsz; |
885 | loadmap->nsegs--; | 885 | loadmap->nsegs--; |
886 | continue; | 886 | continue; |
887 | } | 887 | } |
888 | } | 888 | } |
889 | 889 | ||
890 | mseg++; | 890 | mseg++; |
891 | if (mseg != seg) | 891 | if (mseg != seg) |
892 | *mseg = *seg; | 892 | *mseg = *seg; |
893 | } | 893 | } |
894 | #endif | 894 | #endif |
895 | 895 | ||
896 | kdebug("Mapped Object [%s]:", what); | 896 | kdebug("Mapped Object [%s]:", what); |
897 | kdebug("- elfhdr : %lx", params->elfhdr_addr); | 897 | kdebug("- elfhdr : %lx", params->elfhdr_addr); |
898 | kdebug("- entry : %lx", params->entry_addr); | 898 | kdebug("- entry : %lx", params->entry_addr); |
899 | kdebug("- PHDR[] : %lx", params->ph_addr); | 899 | kdebug("- PHDR[] : %lx", params->ph_addr); |
900 | kdebug("- DYNAMIC[]: %lx", params->dynamic_addr); | 900 | kdebug("- DYNAMIC[]: %lx", params->dynamic_addr); |
901 | seg = loadmap->segs; | 901 | seg = loadmap->segs; |
902 | for (loop = 0; loop < loadmap->nsegs; loop++, seg++) | 902 | for (loop = 0; loop < loadmap->nsegs; loop++, seg++) |
903 | kdebug("- LOAD[%d] : %08x-%08x [va=%x ms=%x]", | 903 | kdebug("- LOAD[%d] : %08x-%08x [va=%x ms=%x]", |
904 | loop, | 904 | loop, |
905 | seg->addr, seg->addr + seg->p_memsz - 1, | 905 | seg->addr, seg->addr + seg->p_memsz - 1, |
906 | seg->p_vaddr, seg->p_memsz); | 906 | seg->p_vaddr, seg->p_memsz); |
907 | 907 | ||
908 | return 0; | 908 | return 0; |
909 | 909 | ||
910 | dynamic_error: | 910 | dynamic_error: |
911 | printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)\n", | 911 | printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)\n", |
912 | what, file_inode(file)->i_ino); | 912 | what, file_inode(file)->i_ino); |
913 | return -ELIBBAD; | 913 | return -ELIBBAD; |
914 | } | 914 | } |
915 | 915 | ||
916 | /*****************************************************************************/ | 916 | /*****************************************************************************/ |
917 | /* | 917 | /* |
918 | * map a file with constant displacement under uClinux | 918 | * map a file with constant displacement under uClinux |
919 | */ | 919 | */ |
920 | #ifndef CONFIG_MMU | 920 | #ifndef CONFIG_MMU |
921 | static int elf_fdpic_map_file_constdisp_on_uclinux( | 921 | static int elf_fdpic_map_file_constdisp_on_uclinux( |
922 | struct elf_fdpic_params *params, | 922 | struct elf_fdpic_params *params, |
923 | struct file *file, | 923 | struct file *file, |
924 | struct mm_struct *mm) | 924 | struct mm_struct *mm) |
925 | { | 925 | { |
926 | struct elf32_fdpic_loadseg *seg; | 926 | struct elf32_fdpic_loadseg *seg; |
927 | struct elf32_phdr *phdr; | 927 | struct elf32_phdr *phdr; |
928 | unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0, mflags; | 928 | unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0, mflags; |
929 | loff_t fpos; | 929 | loff_t fpos; |
930 | int loop, ret; | 930 | int loop, ret; |
931 | 931 | ||
932 | load_addr = params->load_addr; | 932 | load_addr = params->load_addr; |
933 | seg = params->loadmap->segs; | 933 | seg = params->loadmap->segs; |
934 | 934 | ||
935 | /* determine the bounds of the contiguous overall allocation we must | 935 | /* determine the bounds of the contiguous overall allocation we must |
936 | * make */ | 936 | * make */ |
937 | phdr = params->phdrs; | 937 | phdr = params->phdrs; |
938 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { | 938 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { |
939 | if (params->phdrs[loop].p_type != PT_LOAD) | 939 | if (params->phdrs[loop].p_type != PT_LOAD) |
940 | continue; | 940 | continue; |
941 | 941 | ||
942 | if (base > phdr->p_vaddr) | 942 | if (base > phdr->p_vaddr) |
943 | base = phdr->p_vaddr; | 943 | base = phdr->p_vaddr; |
944 | if (top < phdr->p_vaddr + phdr->p_memsz) | 944 | if (top < phdr->p_vaddr + phdr->p_memsz) |
945 | top = phdr->p_vaddr + phdr->p_memsz; | 945 | top = phdr->p_vaddr + phdr->p_memsz; |
946 | } | 946 | } |
947 | 947 | ||
948 | /* allocate one big anon block for everything */ | 948 | /* allocate one big anon block for everything */ |
949 | mflags = MAP_PRIVATE; | 949 | mflags = MAP_PRIVATE; |
950 | if (params->flags & ELF_FDPIC_FLAG_EXECUTABLE) | 950 | if (params->flags & ELF_FDPIC_FLAG_EXECUTABLE) |
951 | mflags |= MAP_EXECUTABLE; | 951 | mflags |= MAP_EXECUTABLE; |
952 | 952 | ||
953 | maddr = vm_mmap(NULL, load_addr, top - base, | 953 | maddr = vm_mmap(NULL, load_addr, top - base, |
954 | PROT_READ | PROT_WRITE | PROT_EXEC, mflags, 0); | 954 | PROT_READ | PROT_WRITE | PROT_EXEC, mflags, 0); |
955 | if (IS_ERR_VALUE(maddr)) | 955 | if (IS_ERR_VALUE(maddr)) |
956 | return (int) maddr; | 956 | return (int) maddr; |
957 | 957 | ||
958 | if (load_addr != 0) | 958 | if (load_addr != 0) |
959 | load_addr += PAGE_ALIGN(top - base); | 959 | load_addr += PAGE_ALIGN(top - base); |
960 | 960 | ||
961 | /* and then load the file segments into it */ | 961 | /* and then load the file segments into it */ |
962 | phdr = params->phdrs; | 962 | phdr = params->phdrs; |
963 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { | 963 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { |
964 | if (params->phdrs[loop].p_type != PT_LOAD) | 964 | if (params->phdrs[loop].p_type != PT_LOAD) |
965 | continue; | 965 | continue; |
966 | 966 | ||
967 | fpos = phdr->p_offset; | 967 | fpos = phdr->p_offset; |
968 | 968 | ||
969 | seg->addr = maddr + (phdr->p_vaddr - base); | 969 | seg->addr = maddr + (phdr->p_vaddr - base); |
970 | seg->p_vaddr = phdr->p_vaddr; | 970 | seg->p_vaddr = phdr->p_vaddr; |
971 | seg->p_memsz = phdr->p_memsz; | 971 | seg->p_memsz = phdr->p_memsz; |
972 | 972 | ||
973 | ret = file->f_op->read(file, (void *) seg->addr, | 973 | ret = file->f_op->read(file, (void *) seg->addr, |
974 | phdr->p_filesz, &fpos); | 974 | phdr->p_filesz, &fpos); |
975 | if (ret < 0) | 975 | if (ret < 0) |
976 | return ret; | 976 | return ret; |
977 | 977 | ||
978 | /* map the ELF header address if in this segment */ | 978 | /* map the ELF header address if in this segment */ |
979 | if (phdr->p_offset == 0) | 979 | if (phdr->p_offset == 0) |
980 | params->elfhdr_addr = seg->addr; | 980 | params->elfhdr_addr = seg->addr; |
981 | 981 | ||
982 | /* clear any space allocated but not loaded */ | 982 | /* clear any space allocated but not loaded */ |
983 | if (phdr->p_filesz < phdr->p_memsz) { | 983 | if (phdr->p_filesz < phdr->p_memsz) { |
984 | if (clear_user((void *) (seg->addr + phdr->p_filesz), | 984 | if (clear_user((void *) (seg->addr + phdr->p_filesz), |
985 | phdr->p_memsz - phdr->p_filesz)) | 985 | phdr->p_memsz - phdr->p_filesz)) |
986 | return -EFAULT; | 986 | return -EFAULT; |
987 | } | 987 | } |
988 | 988 | ||
989 | if (mm) { | 989 | if (mm) { |
990 | if (phdr->p_flags & PF_X) { | 990 | if (phdr->p_flags & PF_X) { |
991 | if (!mm->start_code) { | 991 | if (!mm->start_code) { |
992 | mm->start_code = seg->addr; | 992 | mm->start_code = seg->addr; |
993 | mm->end_code = seg->addr + | 993 | mm->end_code = seg->addr + |
994 | phdr->p_memsz; | 994 | phdr->p_memsz; |
995 | } | 995 | } |
996 | } else if (!mm->start_data) { | 996 | } else if (!mm->start_data) { |
997 | mm->start_data = seg->addr; | 997 | mm->start_data = seg->addr; |
998 | mm->end_data = seg->addr + phdr->p_memsz; | 998 | mm->end_data = seg->addr + phdr->p_memsz; |
999 | } | 999 | } |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | seg++; | 1002 | seg++; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | return 0; | 1005 | return 0; |
1006 | } | 1006 | } |
1007 | #endif | 1007 | #endif |
1008 | 1008 | ||
1009 | /*****************************************************************************/ | 1009 | /*****************************************************************************/ |
1010 | /* | 1010 | /* |
1011 | * map a binary by direct mmap() of the individual PT_LOAD segments | 1011 | * map a binary by direct mmap() of the individual PT_LOAD segments |
1012 | */ | 1012 | */ |
1013 | static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, | 1013 | static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, |
1014 | struct file *file, | 1014 | struct file *file, |
1015 | struct mm_struct *mm) | 1015 | struct mm_struct *mm) |
1016 | { | 1016 | { |
1017 | struct elf32_fdpic_loadseg *seg; | 1017 | struct elf32_fdpic_loadseg *seg; |
1018 | struct elf32_phdr *phdr; | 1018 | struct elf32_phdr *phdr; |
1019 | unsigned long load_addr, delta_vaddr; | 1019 | unsigned long load_addr, delta_vaddr; |
1020 | int loop, dvset; | 1020 | int loop, dvset; |
1021 | 1021 | ||
1022 | load_addr = params->load_addr; | 1022 | load_addr = params->load_addr; |
1023 | delta_vaddr = 0; | 1023 | delta_vaddr = 0; |
1024 | dvset = 0; | 1024 | dvset = 0; |
1025 | 1025 | ||
1026 | seg = params->loadmap->segs; | 1026 | seg = params->loadmap->segs; |
1027 | 1027 | ||
1028 | /* deal with each load segment separately */ | 1028 | /* deal with each load segment separately */ |
1029 | phdr = params->phdrs; | 1029 | phdr = params->phdrs; |
1030 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { | 1030 | for (loop = 0; loop < params->hdr.e_phnum; loop++, phdr++) { |
1031 | unsigned long maddr, disp, excess, excess1; | 1031 | unsigned long maddr, disp, excess, excess1; |
1032 | int prot = 0, flags; | 1032 | int prot = 0, flags; |
1033 | 1033 | ||
1034 | if (phdr->p_type != PT_LOAD) | 1034 | if (phdr->p_type != PT_LOAD) |
1035 | continue; | 1035 | continue; |
1036 | 1036 | ||
1037 | kdebug("[LOAD] va=%lx of=%lx fs=%lx ms=%lx", | 1037 | kdebug("[LOAD] va=%lx of=%lx fs=%lx ms=%lx", |
1038 | (unsigned long) phdr->p_vaddr, | 1038 | (unsigned long) phdr->p_vaddr, |
1039 | (unsigned long) phdr->p_offset, | 1039 | (unsigned long) phdr->p_offset, |
1040 | (unsigned long) phdr->p_filesz, | 1040 | (unsigned long) phdr->p_filesz, |
1041 | (unsigned long) phdr->p_memsz); | 1041 | (unsigned long) phdr->p_memsz); |
1042 | 1042 | ||
1043 | /* determine the mapping parameters */ | 1043 | /* determine the mapping parameters */ |
1044 | if (phdr->p_flags & PF_R) prot |= PROT_READ; | 1044 | if (phdr->p_flags & PF_R) prot |= PROT_READ; |
1045 | if (phdr->p_flags & PF_W) prot |= PROT_WRITE; | 1045 | if (phdr->p_flags & PF_W) prot |= PROT_WRITE; |
1046 | if (phdr->p_flags & PF_X) prot |= PROT_EXEC; | 1046 | if (phdr->p_flags & PF_X) prot |= PROT_EXEC; |
1047 | 1047 | ||
1048 | flags = MAP_PRIVATE | MAP_DENYWRITE; | 1048 | flags = MAP_PRIVATE | MAP_DENYWRITE; |
1049 | if (params->flags & ELF_FDPIC_FLAG_EXECUTABLE) | 1049 | if (params->flags & ELF_FDPIC_FLAG_EXECUTABLE) |
1050 | flags |= MAP_EXECUTABLE; | 1050 | flags |= MAP_EXECUTABLE; |
1051 | 1051 | ||
1052 | maddr = 0; | 1052 | maddr = 0; |
1053 | 1053 | ||
1054 | switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) { | 1054 | switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) { |
1055 | case ELF_FDPIC_FLAG_INDEPENDENT: | 1055 | case ELF_FDPIC_FLAG_INDEPENDENT: |
1056 | /* PT_LOADs are independently locatable */ | 1056 | /* PT_LOADs are independently locatable */ |
1057 | break; | 1057 | break; |
1058 | 1058 | ||
1059 | case ELF_FDPIC_FLAG_HONOURVADDR: | 1059 | case ELF_FDPIC_FLAG_HONOURVADDR: |
1060 | /* the specified virtual address must be honoured */ | 1060 | /* the specified virtual address must be honoured */ |
1061 | maddr = phdr->p_vaddr; | 1061 | maddr = phdr->p_vaddr; |
1062 | flags |= MAP_FIXED; | 1062 | flags |= MAP_FIXED; |
1063 | break; | 1063 | break; |
1064 | 1064 | ||
1065 | case ELF_FDPIC_FLAG_CONSTDISP: | 1065 | case ELF_FDPIC_FLAG_CONSTDISP: |
1066 | /* constant displacement | 1066 | /* constant displacement |
1067 | * - can be mapped anywhere, but must be mapped as a | 1067 | * - can be mapped anywhere, but must be mapped as a |
1068 | * unit | 1068 | * unit |
1069 | */ | 1069 | */ |
1070 | if (!dvset) { | 1070 | if (!dvset) { |
1071 | maddr = load_addr; | 1071 | maddr = load_addr; |
1072 | delta_vaddr = phdr->p_vaddr; | 1072 | delta_vaddr = phdr->p_vaddr; |
1073 | dvset = 1; | 1073 | dvset = 1; |
1074 | } else { | 1074 | } else { |
1075 | maddr = load_addr + phdr->p_vaddr - delta_vaddr; | 1075 | maddr = load_addr + phdr->p_vaddr - delta_vaddr; |
1076 | flags |= MAP_FIXED; | 1076 | flags |= MAP_FIXED; |
1077 | } | 1077 | } |
1078 | break; | 1078 | break; |
1079 | 1079 | ||
1080 | case ELF_FDPIC_FLAG_CONTIGUOUS: | 1080 | case ELF_FDPIC_FLAG_CONTIGUOUS: |
1081 | /* contiguity handled later */ | 1081 | /* contiguity handled later */ |
1082 | break; | 1082 | break; |
1083 | 1083 | ||
1084 | default: | 1084 | default: |
1085 | BUG(); | 1085 | BUG(); |
1086 | } | 1086 | } |
1087 | 1087 | ||
1088 | maddr &= PAGE_MASK; | 1088 | maddr &= PAGE_MASK; |
1089 | 1089 | ||
1090 | /* create the mapping */ | 1090 | /* create the mapping */ |
1091 | disp = phdr->p_vaddr & ~PAGE_MASK; | 1091 | disp = phdr->p_vaddr & ~PAGE_MASK; |
1092 | maddr = vm_mmap(file, maddr, phdr->p_memsz + disp, prot, flags, | 1092 | maddr = vm_mmap(file, maddr, phdr->p_memsz + disp, prot, flags, |
1093 | phdr->p_offset - disp); | 1093 | phdr->p_offset - disp); |
1094 | 1094 | ||
1095 | kdebug("mmap[%d] <file> sz=%lx pr=%x fl=%x of=%lx --> %08lx", | 1095 | kdebug("mmap[%d] <file> sz=%lx pr=%x fl=%x of=%lx --> %08lx", |
1096 | loop, phdr->p_memsz + disp, prot, flags, | 1096 | loop, phdr->p_memsz + disp, prot, flags, |
1097 | phdr->p_offset - disp, maddr); | 1097 | phdr->p_offset - disp, maddr); |
1098 | 1098 | ||
1099 | if (IS_ERR_VALUE(maddr)) | 1099 | if (IS_ERR_VALUE(maddr)) |
1100 | return (int) maddr; | 1100 | return (int) maddr; |
1101 | 1101 | ||
1102 | if ((params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) == | 1102 | if ((params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) == |
1103 | ELF_FDPIC_FLAG_CONTIGUOUS) | 1103 | ELF_FDPIC_FLAG_CONTIGUOUS) |
1104 | load_addr += PAGE_ALIGN(phdr->p_memsz + disp); | 1104 | load_addr += PAGE_ALIGN(phdr->p_memsz + disp); |
1105 | 1105 | ||
1106 | seg->addr = maddr + disp; | 1106 | seg->addr = maddr + disp; |
1107 | seg->p_vaddr = phdr->p_vaddr; | 1107 | seg->p_vaddr = phdr->p_vaddr; |
1108 | seg->p_memsz = phdr->p_memsz; | 1108 | seg->p_memsz = phdr->p_memsz; |
1109 | 1109 | ||
1110 | /* map the ELF header address if in this segment */ | 1110 | /* map the ELF header address if in this segment */ |
1111 | if (phdr->p_offset == 0) | 1111 | if (phdr->p_offset == 0) |
1112 | params->elfhdr_addr = seg->addr; | 1112 | params->elfhdr_addr = seg->addr; |
1113 | 1113 | ||
1114 | /* clear the bit between beginning of mapping and beginning of | 1114 | /* clear the bit between beginning of mapping and beginning of |
1115 | * PT_LOAD */ | 1115 | * PT_LOAD */ |
1116 | if (prot & PROT_WRITE && disp > 0) { | 1116 | if (prot & PROT_WRITE && disp > 0) { |
1117 | kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp); | 1117 | kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp); |
1118 | if (clear_user((void __user *) maddr, disp)) | 1118 | if (clear_user((void __user *) maddr, disp)) |
1119 | return -EFAULT; | 1119 | return -EFAULT; |
1120 | maddr += disp; | 1120 | maddr += disp; |
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | /* clear any space allocated but not loaded | 1123 | /* clear any space allocated but not loaded |
1124 | * - on uClinux we can just clear the lot | 1124 | * - on uClinux we can just clear the lot |
1125 | * - on MMU linux we'll get a SIGBUS beyond the last page | 1125 | * - on MMU linux we'll get a SIGBUS beyond the last page |
1126 | * extant in the file | 1126 | * extant in the file |
1127 | */ | 1127 | */ |
1128 | excess = phdr->p_memsz - phdr->p_filesz; | 1128 | excess = phdr->p_memsz - phdr->p_filesz; |
1129 | excess1 = PAGE_SIZE - ((maddr + phdr->p_filesz) & ~PAGE_MASK); | 1129 | excess1 = PAGE_SIZE - ((maddr + phdr->p_filesz) & ~PAGE_MASK); |
1130 | 1130 | ||
1131 | #ifdef CONFIG_MMU | 1131 | #ifdef CONFIG_MMU |
1132 | if (excess > excess1) { | 1132 | if (excess > excess1) { |
1133 | unsigned long xaddr = maddr + phdr->p_filesz + excess1; | 1133 | unsigned long xaddr = maddr + phdr->p_filesz + excess1; |
1134 | unsigned long xmaddr; | 1134 | unsigned long xmaddr; |
1135 | 1135 | ||
1136 | flags |= MAP_FIXED | MAP_ANONYMOUS; | 1136 | flags |= MAP_FIXED | MAP_ANONYMOUS; |
1137 | xmaddr = vm_mmap(NULL, xaddr, excess - excess1, | 1137 | xmaddr = vm_mmap(NULL, xaddr, excess - excess1, |
1138 | prot, flags, 0); | 1138 | prot, flags, 0); |
1139 | 1139 | ||
1140 | kdebug("mmap[%d] <anon>" | 1140 | kdebug("mmap[%d] <anon>" |
1141 | " ad=%lx sz=%lx pr=%x fl=%x of=0 --> %08lx", | 1141 | " ad=%lx sz=%lx pr=%x fl=%x of=0 --> %08lx", |
1142 | loop, xaddr, excess - excess1, prot, flags, | 1142 | loop, xaddr, excess - excess1, prot, flags, |
1143 | xmaddr); | 1143 | xmaddr); |
1144 | 1144 | ||
1145 | if (xmaddr != xaddr) | 1145 | if (xmaddr != xaddr) |
1146 | return -ENOMEM; | 1146 | return -ENOMEM; |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | if (prot & PROT_WRITE && excess1 > 0) { | 1149 | if (prot & PROT_WRITE && excess1 > 0) { |
1150 | kdebug("clear[%d] ad=%lx sz=%lx", | 1150 | kdebug("clear[%d] ad=%lx sz=%lx", |
1151 | loop, maddr + phdr->p_filesz, excess1); | 1151 | loop, maddr + phdr->p_filesz, excess1); |
1152 | if (clear_user((void __user *) maddr + phdr->p_filesz, | 1152 | if (clear_user((void __user *) maddr + phdr->p_filesz, |
1153 | excess1)) | 1153 | excess1)) |
1154 | return -EFAULT; | 1154 | return -EFAULT; |
1155 | } | 1155 | } |
1156 | 1156 | ||
1157 | #else | 1157 | #else |
1158 | if (excess > 0) { | 1158 | if (excess > 0) { |
1159 | kdebug("clear[%d] ad=%lx sz=%lx", | 1159 | kdebug("clear[%d] ad=%lx sz=%lx", |
1160 | loop, maddr + phdr->p_filesz, excess); | 1160 | loop, maddr + phdr->p_filesz, excess); |
1161 | if (clear_user((void *) maddr + phdr->p_filesz, excess)) | 1161 | if (clear_user((void *) maddr + phdr->p_filesz, excess)) |
1162 | return -EFAULT; | 1162 | return -EFAULT; |
1163 | } | 1163 | } |
1164 | #endif | 1164 | #endif |
1165 | 1165 | ||
1166 | if (mm) { | 1166 | if (mm) { |
1167 | if (phdr->p_flags & PF_X) { | 1167 | if (phdr->p_flags & PF_X) { |
1168 | if (!mm->start_code) { | 1168 | if (!mm->start_code) { |
1169 | mm->start_code = maddr; | 1169 | mm->start_code = maddr; |
1170 | mm->end_code = maddr + phdr->p_memsz; | 1170 | mm->end_code = maddr + phdr->p_memsz; |
1171 | } | 1171 | } |
1172 | } else if (!mm->start_data) { | 1172 | } else if (!mm->start_data) { |
1173 | mm->start_data = maddr; | 1173 | mm->start_data = maddr; |
1174 | mm->end_data = maddr + phdr->p_memsz; | 1174 | mm->end_data = maddr + phdr->p_memsz; |
1175 | } | 1175 | } |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | seg++; | 1178 | seg++; |
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | return 0; | 1181 | return 0; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | /*****************************************************************************/ | 1184 | /*****************************************************************************/ |
1185 | /* | 1185 | /* |
1186 | * ELF-FDPIC core dumper | 1186 | * ELF-FDPIC core dumper |
1187 | * | 1187 | * |
1188 | * Modelled on fs/exec.c:aout_core_dump() | 1188 | * Modelled on fs/exec.c:aout_core_dump() |
1189 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> | 1189 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> |
1190 | * | 1190 | * |
1191 | * Modelled on fs/binfmt_elf.c core dumper | 1191 | * Modelled on fs/binfmt_elf.c core dumper |
1192 | */ | 1192 | */ |
1193 | #ifdef CONFIG_ELF_CORE | 1193 | #ifdef CONFIG_ELF_CORE |
1194 | 1194 | ||
1195 | /* | 1195 | /* |
1196 | * Decide whether a segment is worth dumping; default is yes to be | 1196 | * Decide whether a segment is worth dumping; default is yes to be |
1197 | * sure (missing info is worse than too much; etc). | 1197 | * sure (missing info is worse than too much; etc). |
1198 | * Personally I'd include everything, and use the coredump limit... | 1198 | * Personally I'd include everything, and use the coredump limit... |
1199 | * | 1199 | * |
1200 | * I think we should skip something. But I am not sure how. H.J. | 1200 | * I think we should skip something. But I am not sure how. H.J. |
1201 | */ | 1201 | */ |
1202 | static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) | 1202 | static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) |
1203 | { | 1203 | { |
1204 | int dump_ok; | 1204 | int dump_ok; |
1205 | 1205 | ||
1206 | /* Do not dump I/O mapped devices or special mappings */ | 1206 | /* Do not dump I/O mapped devices or special mappings */ |
1207 | if (vma->vm_flags & VM_IO) { | 1207 | if (vma->vm_flags & VM_IO) { |
1208 | kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags); | 1208 | kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags); |
1209 | return 0; | 1209 | return 0; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | /* If we may not read the contents, don't allow us to dump | 1212 | /* If we may not read the contents, don't allow us to dump |
1213 | * them either. "dump_write()" can't handle it anyway. | 1213 | * them either. "dump_write()" can't handle it anyway. |
1214 | */ | 1214 | */ |
1215 | if (!(vma->vm_flags & VM_READ)) { | 1215 | if (!(vma->vm_flags & VM_READ)) { |
1216 | kdcore("%08lx: %08lx: no (!read)", vma->vm_start, vma->vm_flags); | 1216 | kdcore("%08lx: %08lx: no (!read)", vma->vm_start, vma->vm_flags); |
1217 | return 0; | 1217 | return 0; |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | /* By default, dump shared memory if mapped from an anonymous file. */ | 1220 | /* By default, dump shared memory if mapped from an anonymous file. */ |
1221 | if (vma->vm_flags & VM_SHARED) { | 1221 | if (vma->vm_flags & VM_SHARED) { |
1222 | if (file_inode(vma->vm_file)->i_nlink == 0) { | 1222 | if (file_inode(vma->vm_file)->i_nlink == 0) { |
1223 | dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); | 1223 | dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); |
1224 | kdcore("%08lx: %08lx: %s (share)", vma->vm_start, | 1224 | kdcore("%08lx: %08lx: %s (share)", vma->vm_start, |
1225 | vma->vm_flags, dump_ok ? "yes" : "no"); | 1225 | vma->vm_flags, dump_ok ? "yes" : "no"); |
1226 | return dump_ok; | 1226 | return dump_ok; |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); | 1229 | dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); |
1230 | kdcore("%08lx: %08lx: %s (share)", vma->vm_start, | 1230 | kdcore("%08lx: %08lx: %s (share)", vma->vm_start, |
1231 | vma->vm_flags, dump_ok ? "yes" : "no"); | 1231 | vma->vm_flags, dump_ok ? "yes" : "no"); |
1232 | return dump_ok; | 1232 | return dump_ok; |
1233 | } | 1233 | } |
1234 | 1234 | ||
1235 | #ifdef CONFIG_MMU | 1235 | #ifdef CONFIG_MMU |
1236 | /* By default, if it hasn't been written to, don't write it out */ | 1236 | /* By default, if it hasn't been written to, don't write it out */ |
1237 | if (!vma->anon_vma) { | 1237 | if (!vma->anon_vma) { |
1238 | dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); | 1238 | dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); |
1239 | kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start, | 1239 | kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start, |
1240 | vma->vm_flags, dump_ok ? "yes" : "no"); | 1240 | vma->vm_flags, dump_ok ? "yes" : "no"); |
1241 | return dump_ok; | 1241 | return dump_ok; |
1242 | } | 1242 | } |
1243 | #endif | 1243 | #endif |
1244 | 1244 | ||
1245 | dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); | 1245 | dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); |
1246 | kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags, | 1246 | kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags, |
1247 | dump_ok ? "yes" : "no"); | 1247 | dump_ok ? "yes" : "no"); |
1248 | return dump_ok; | 1248 | return dump_ok; |
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | /* An ELF note in memory */ | 1251 | /* An ELF note in memory */ |
1252 | struct memelfnote | 1252 | struct memelfnote |
1253 | { | 1253 | { |
1254 | const char *name; | 1254 | const char *name; |
1255 | int type; | 1255 | int type; |
1256 | unsigned int datasz; | 1256 | unsigned int datasz; |
1257 | void *data; | 1257 | void *data; |
1258 | }; | 1258 | }; |
1259 | 1259 | ||
1260 | static int notesize(struct memelfnote *en) | 1260 | static int notesize(struct memelfnote *en) |
1261 | { | 1261 | { |
1262 | int sz; | 1262 | int sz; |
1263 | 1263 | ||
1264 | sz = sizeof(struct elf_note); | 1264 | sz = sizeof(struct elf_note); |
1265 | sz += roundup(strlen(en->name) + 1, 4); | 1265 | sz += roundup(strlen(en->name) + 1, 4); |
1266 | sz += roundup(en->datasz, 4); | 1266 | sz += roundup(en->datasz, 4); |
1267 | 1267 | ||
1268 | return sz; | 1268 | return sz; |
1269 | } | 1269 | } |
1270 | 1270 | ||
1271 | /* #define DEBUG */ | 1271 | /* #define DEBUG */ |
1272 | 1272 | ||
1273 | #define DUMP_WRITE(addr, nr, foffset) \ | 1273 | #define DUMP_WRITE(addr, nr, foffset) \ |
1274 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) | 1274 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) |
1275 | 1275 | ||
1276 | static int alignfile(struct file *file, loff_t *foffset) | 1276 | static int alignfile(struct file *file, loff_t *foffset) |
1277 | { | 1277 | { |
1278 | static const char buf[4] = { 0, }; | 1278 | static const char buf[4] = { 0, }; |
1279 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); | 1279 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); |
1280 | return 1; | 1280 | return 1; |
1281 | } | 1281 | } |
1282 | 1282 | ||
1283 | static int writenote(struct memelfnote *men, struct file *file, | 1283 | static int writenote(struct memelfnote *men, struct file *file, |
1284 | loff_t *foffset) | 1284 | loff_t *foffset) |
1285 | { | 1285 | { |
1286 | struct elf_note en; | 1286 | struct elf_note en; |
1287 | en.n_namesz = strlen(men->name) + 1; | 1287 | en.n_namesz = strlen(men->name) + 1; |
1288 | en.n_descsz = men->datasz; | 1288 | en.n_descsz = men->datasz; |
1289 | en.n_type = men->type; | 1289 | en.n_type = men->type; |
1290 | 1290 | ||
1291 | DUMP_WRITE(&en, sizeof(en), foffset); | 1291 | DUMP_WRITE(&en, sizeof(en), foffset); |
1292 | DUMP_WRITE(men->name, en.n_namesz, foffset); | 1292 | DUMP_WRITE(men->name, en.n_namesz, foffset); |
1293 | if (!alignfile(file, foffset)) | 1293 | if (!alignfile(file, foffset)) |
1294 | return 0; | 1294 | return 0; |
1295 | DUMP_WRITE(men->data, men->datasz, foffset); | 1295 | DUMP_WRITE(men->data, men->datasz, foffset); |
1296 | if (!alignfile(file, foffset)) | 1296 | if (!alignfile(file, foffset)) |
1297 | return 0; | 1297 | return 0; |
1298 | 1298 | ||
1299 | return 1; | 1299 | return 1; |
1300 | } | 1300 | } |
1301 | #undef DUMP_WRITE | 1301 | #undef DUMP_WRITE |
1302 | 1302 | ||
1303 | static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) | 1303 | static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) |
1304 | { | 1304 | { |
1305 | memcpy(elf->e_ident, ELFMAG, SELFMAG); | 1305 | memcpy(elf->e_ident, ELFMAG, SELFMAG); |
1306 | elf->e_ident[EI_CLASS] = ELF_CLASS; | 1306 | elf->e_ident[EI_CLASS] = ELF_CLASS; |
1307 | elf->e_ident[EI_DATA] = ELF_DATA; | 1307 | elf->e_ident[EI_DATA] = ELF_DATA; |
1308 | elf->e_ident[EI_VERSION] = EV_CURRENT; | 1308 | elf->e_ident[EI_VERSION] = EV_CURRENT; |
1309 | elf->e_ident[EI_OSABI] = ELF_OSABI; | 1309 | elf->e_ident[EI_OSABI] = ELF_OSABI; |
1310 | memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); | 1310 | memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); |
1311 | 1311 | ||
1312 | elf->e_type = ET_CORE; | 1312 | elf->e_type = ET_CORE; |
1313 | elf->e_machine = ELF_ARCH; | 1313 | elf->e_machine = ELF_ARCH; |
1314 | elf->e_version = EV_CURRENT; | 1314 | elf->e_version = EV_CURRENT; |
1315 | elf->e_entry = 0; | 1315 | elf->e_entry = 0; |
1316 | elf->e_phoff = sizeof(struct elfhdr); | 1316 | elf->e_phoff = sizeof(struct elfhdr); |
1317 | elf->e_shoff = 0; | 1317 | elf->e_shoff = 0; |
1318 | elf->e_flags = ELF_FDPIC_CORE_EFLAGS; | 1318 | elf->e_flags = ELF_FDPIC_CORE_EFLAGS; |
1319 | elf->e_ehsize = sizeof(struct elfhdr); | 1319 | elf->e_ehsize = sizeof(struct elfhdr); |
1320 | elf->e_phentsize = sizeof(struct elf_phdr); | 1320 | elf->e_phentsize = sizeof(struct elf_phdr); |
1321 | elf->e_phnum = segs; | 1321 | elf->e_phnum = segs; |
1322 | elf->e_shentsize = 0; | 1322 | elf->e_shentsize = 0; |
1323 | elf->e_shnum = 0; | 1323 | elf->e_shnum = 0; |
1324 | elf->e_shstrndx = 0; | 1324 | elf->e_shstrndx = 0; |
1325 | return; | 1325 | return; |
1326 | } | 1326 | } |
1327 | 1327 | ||
1328 | static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) | 1328 | static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) |
1329 | { | 1329 | { |
1330 | phdr->p_type = PT_NOTE; | 1330 | phdr->p_type = PT_NOTE; |
1331 | phdr->p_offset = offset; | 1331 | phdr->p_offset = offset; |
1332 | phdr->p_vaddr = 0; | 1332 | phdr->p_vaddr = 0; |
1333 | phdr->p_paddr = 0; | 1333 | phdr->p_paddr = 0; |
1334 | phdr->p_filesz = sz; | 1334 | phdr->p_filesz = sz; |
1335 | phdr->p_memsz = 0; | 1335 | phdr->p_memsz = 0; |
1336 | phdr->p_flags = 0; | 1336 | phdr->p_flags = 0; |
1337 | phdr->p_align = 0; | 1337 | phdr->p_align = 0; |
1338 | return; | 1338 | return; |
1339 | } | 1339 | } |
1340 | 1340 | ||
1341 | static inline void fill_note(struct memelfnote *note, const char *name, int type, | 1341 | static inline void fill_note(struct memelfnote *note, const char *name, int type, |
1342 | unsigned int sz, void *data) | 1342 | unsigned int sz, void *data) |
1343 | { | 1343 | { |
1344 | note->name = name; | 1344 | note->name = name; |
1345 | note->type = type; | 1345 | note->type = type; |
1346 | note->datasz = sz; | 1346 | note->datasz = sz; |
1347 | note->data = data; | 1347 | note->data = data; |
1348 | return; | 1348 | return; |
1349 | } | 1349 | } |
1350 | 1350 | ||
1351 | /* | 1351 | /* |
1352 | * fill up all the fields in prstatus from the given task struct, except | 1352 | * fill up all the fields in prstatus from the given task struct, except |
1353 | * registers which need to be filled up separately. | 1353 | * registers which need to be filled up separately. |
1354 | */ | 1354 | */ |
1355 | static void fill_prstatus(struct elf_prstatus *prstatus, | 1355 | static void fill_prstatus(struct elf_prstatus *prstatus, |
1356 | struct task_struct *p, long signr) | 1356 | struct task_struct *p, long signr) |
1357 | { | 1357 | { |
1358 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | 1358 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
1359 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1359 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
1360 | prstatus->pr_sighold = p->blocked.sig[0]; | 1360 | prstatus->pr_sighold = p->blocked.sig[0]; |
1361 | rcu_read_lock(); | 1361 | rcu_read_lock(); |
1362 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | 1362 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); |
1363 | rcu_read_unlock(); | 1363 | rcu_read_unlock(); |
1364 | prstatus->pr_pid = task_pid_vnr(p); | 1364 | prstatus->pr_pid = task_pid_vnr(p); |
1365 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1365 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
1366 | prstatus->pr_sid = task_session_vnr(p); | 1366 | prstatus->pr_sid = task_session_vnr(p); |
1367 | if (thread_group_leader(p)) { | 1367 | if (thread_group_leader(p)) { |
1368 | struct task_cputime cputime; | 1368 | struct task_cputime cputime; |
1369 | 1369 | ||
1370 | /* | 1370 | /* |
1371 | * This is the record for the group leader. It shows the | 1371 | * This is the record for the group leader. It shows the |
1372 | * group-wide total, not its individual thread total. | 1372 | * group-wide total, not its individual thread total. |
1373 | */ | 1373 | */ |
1374 | thread_group_cputime(p, &cputime); | 1374 | thread_group_cputime(p, &cputime); |
1375 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); | 1375 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); |
1376 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); | 1376 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); |
1377 | } else { | 1377 | } else { |
1378 | cputime_t utime, stime; | 1378 | cputime_t utime, stime; |
1379 | 1379 | ||
1380 | task_cputime(p, &utime, &stime); | 1380 | task_cputime(p, &utime, &stime); |
1381 | cputime_to_timeval(utime, &prstatus->pr_utime); | 1381 | cputime_to_timeval(utime, &prstatus->pr_utime); |
1382 | cputime_to_timeval(stime, &prstatus->pr_stime); | 1382 | cputime_to_timeval(stime, &prstatus->pr_stime); |
1383 | } | 1383 | } |
1384 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); | 1384 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); |
1385 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); | 1385 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); |
1386 | 1386 | ||
1387 | prstatus->pr_exec_fdpic_loadmap = p->mm->context.exec_fdpic_loadmap; | 1387 | prstatus->pr_exec_fdpic_loadmap = p->mm->context.exec_fdpic_loadmap; |
1388 | prstatus->pr_interp_fdpic_loadmap = p->mm->context.interp_fdpic_loadmap; | 1388 | prstatus->pr_interp_fdpic_loadmap = p->mm->context.interp_fdpic_loadmap; |
1389 | } | 1389 | } |
1390 | 1390 | ||
1391 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | 1391 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, |
1392 | struct mm_struct *mm) | 1392 | struct mm_struct *mm) |
1393 | { | 1393 | { |
1394 | const struct cred *cred; | 1394 | const struct cred *cred; |
1395 | unsigned int i, len; | 1395 | unsigned int i, len; |
1396 | 1396 | ||
1397 | /* first copy the parameters from user space */ | 1397 | /* first copy the parameters from user space */ |
1398 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); | 1398 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); |
1399 | 1399 | ||
1400 | len = mm->arg_end - mm->arg_start; | 1400 | len = mm->arg_end - mm->arg_start; |
1401 | if (len >= ELF_PRARGSZ) | 1401 | if (len >= ELF_PRARGSZ) |
1402 | len = ELF_PRARGSZ - 1; | 1402 | len = ELF_PRARGSZ - 1; |
1403 | if (copy_from_user(&psinfo->pr_psargs, | 1403 | if (copy_from_user(&psinfo->pr_psargs, |
1404 | (const char __user *) mm->arg_start, len)) | 1404 | (const char __user *) mm->arg_start, len)) |
1405 | return -EFAULT; | 1405 | return -EFAULT; |
1406 | for (i = 0; i < len; i++) | 1406 | for (i = 0; i < len; i++) |
1407 | if (psinfo->pr_psargs[i] == 0) | 1407 | if (psinfo->pr_psargs[i] == 0) |
1408 | psinfo->pr_psargs[i] = ' '; | 1408 | psinfo->pr_psargs[i] = ' '; |
1409 | psinfo->pr_psargs[len] = 0; | 1409 | psinfo->pr_psargs[len] = 0; |
1410 | 1410 | ||
1411 | rcu_read_lock(); | 1411 | rcu_read_lock(); |
1412 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | 1412 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); |
1413 | rcu_read_unlock(); | 1413 | rcu_read_unlock(); |
1414 | psinfo->pr_pid = task_pid_vnr(p); | 1414 | psinfo->pr_pid = task_pid_vnr(p); |
1415 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1415 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
1416 | psinfo->pr_sid = task_session_vnr(p); | 1416 | psinfo->pr_sid = task_session_vnr(p); |
1417 | 1417 | ||
1418 | i = p->state ? ffz(~p->state) + 1 : 0; | 1418 | i = p->state ? ffz(~p->state) + 1 : 0; |
1419 | psinfo->pr_state = i; | 1419 | psinfo->pr_state = i; |
1420 | psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; | 1420 | psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; |
1421 | psinfo->pr_zomb = psinfo->pr_sname == 'Z'; | 1421 | psinfo->pr_zomb = psinfo->pr_sname == 'Z'; |
1422 | psinfo->pr_nice = task_nice(p); | 1422 | psinfo->pr_nice = task_nice(p); |
1423 | psinfo->pr_flag = p->flags; | 1423 | psinfo->pr_flag = p->flags; |
1424 | rcu_read_lock(); | 1424 | rcu_read_lock(); |
1425 | cred = __task_cred(p); | 1425 | cred = __task_cred(p); |
1426 | SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); | 1426 | SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); |
1427 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); | 1427 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); |
1428 | rcu_read_unlock(); | 1428 | rcu_read_unlock(); |
1429 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); | 1429 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); |
1430 | 1430 | ||
1431 | return 0; | 1431 | return 0; |
1432 | } | 1432 | } |
1433 | 1433 | ||
1434 | /* Here is the structure in which status of each thread is captured. */ | 1434 | /* Here is the structure in which status of each thread is captured. */ |
1435 | struct elf_thread_status | 1435 | struct elf_thread_status |
1436 | { | 1436 | { |
1437 | struct list_head list; | 1437 | struct list_head list; |
1438 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ | 1438 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ |
1439 | elf_fpregset_t fpu; /* NT_PRFPREG */ | 1439 | elf_fpregset_t fpu; /* NT_PRFPREG */ |
1440 | struct task_struct *thread; | 1440 | struct task_struct *thread; |
1441 | #ifdef ELF_CORE_COPY_XFPREGS | 1441 | #ifdef ELF_CORE_COPY_XFPREGS |
1442 | elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ | 1442 | elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ |
1443 | #endif | 1443 | #endif |
1444 | struct memelfnote notes[3]; | 1444 | struct memelfnote notes[3]; |
1445 | int num_notes; | 1445 | int num_notes; |
1446 | }; | 1446 | }; |
1447 | 1447 | ||
1448 | /* | 1448 | /* |
1449 | * In order to add the specific thread information for the elf file format, | 1449 | * In order to add the specific thread information for the elf file format, |
1450 | * we need to keep a linked list of every thread's pr_status and then create | 1450 | * we need to keep a linked list of every thread's pr_status and then create |
1451 | * a single section for them in the final core file. | 1451 | * a single section for them in the final core file. |
1452 | */ | 1452 | */ |
1453 | static int elf_dump_thread_status(long signr, struct elf_thread_status *t) | 1453 | static int elf_dump_thread_status(long signr, struct elf_thread_status *t) |
1454 | { | 1454 | { |
1455 | struct task_struct *p = t->thread; | 1455 | struct task_struct *p = t->thread; |
1456 | int sz = 0; | 1456 | int sz = 0; |
1457 | 1457 | ||
1458 | t->num_notes = 0; | 1458 | t->num_notes = 0; |
1459 | 1459 | ||
1460 | fill_prstatus(&t->prstatus, p, signr); | 1460 | fill_prstatus(&t->prstatus, p, signr); |
1461 | elf_core_copy_task_regs(p, &t->prstatus.pr_reg); | 1461 | elf_core_copy_task_regs(p, &t->prstatus.pr_reg); |
1462 | 1462 | ||
1463 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), | 1463 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), |
1464 | &t->prstatus); | 1464 | &t->prstatus); |
1465 | t->num_notes++; | 1465 | t->num_notes++; |
1466 | sz += notesize(&t->notes[0]); | 1466 | sz += notesize(&t->notes[0]); |
1467 | 1467 | ||
1468 | t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu); | 1468 | t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu); |
1469 | if (t->prstatus.pr_fpvalid) { | 1469 | if (t->prstatus.pr_fpvalid) { |
1470 | fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), | 1470 | fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), |
1471 | &t->fpu); | 1471 | &t->fpu); |
1472 | t->num_notes++; | 1472 | t->num_notes++; |
1473 | sz += notesize(&t->notes[1]); | 1473 | sz += notesize(&t->notes[1]); |
1474 | } | 1474 | } |
1475 | 1475 | ||
1476 | #ifdef ELF_CORE_COPY_XFPREGS | 1476 | #ifdef ELF_CORE_COPY_XFPREGS |
1477 | if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { | 1477 | if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { |
1478 | fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, | 1478 | fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, |
1479 | sizeof(t->xfpu), &t->xfpu); | 1479 | sizeof(t->xfpu), &t->xfpu); |
1480 | t->num_notes++; | 1480 | t->num_notes++; |
1481 | sz += notesize(&t->notes[2]); | 1481 | sz += notesize(&t->notes[2]); |
1482 | } | 1482 | } |
1483 | #endif | 1483 | #endif |
1484 | return sz; | 1484 | return sz; |
1485 | } | 1485 | } |
1486 | 1486 | ||
1487 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, | 1487 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, |
1488 | elf_addr_t e_shoff, int segs) | 1488 | elf_addr_t e_shoff, int segs) |
1489 | { | 1489 | { |
1490 | elf->e_shoff = e_shoff; | 1490 | elf->e_shoff = e_shoff; |
1491 | elf->e_shentsize = sizeof(*shdr4extnum); | 1491 | elf->e_shentsize = sizeof(*shdr4extnum); |
1492 | elf->e_shnum = 1; | 1492 | elf->e_shnum = 1; |
1493 | elf->e_shstrndx = SHN_UNDEF; | 1493 | elf->e_shstrndx = SHN_UNDEF; |
1494 | 1494 | ||
1495 | memset(shdr4extnum, 0, sizeof(*shdr4extnum)); | 1495 | memset(shdr4extnum, 0, sizeof(*shdr4extnum)); |
1496 | 1496 | ||
1497 | shdr4extnum->sh_type = SHT_NULL; | 1497 | shdr4extnum->sh_type = SHT_NULL; |
1498 | shdr4extnum->sh_size = elf->e_shnum; | 1498 | shdr4extnum->sh_size = elf->e_shnum; |
1499 | shdr4extnum->sh_link = elf->e_shstrndx; | 1499 | shdr4extnum->sh_link = elf->e_shstrndx; |
1500 | shdr4extnum->sh_info = segs; | 1500 | shdr4extnum->sh_info = segs; |
1501 | } | 1501 | } |
1502 | 1502 | ||
1503 | /* | 1503 | /* |
1504 | * dump the segments for an MMU process | 1504 | * dump the segments for an MMU process |
1505 | */ | 1505 | */ |
1506 | #ifdef CONFIG_MMU | 1506 | #ifdef CONFIG_MMU |
1507 | static int elf_fdpic_dump_segments(struct file *file, size_t *size, | 1507 | static int elf_fdpic_dump_segments(struct file *file, size_t *size, |
1508 | unsigned long *limit, unsigned long mm_flags) | 1508 | unsigned long *limit, unsigned long mm_flags) |
1509 | { | 1509 | { |
1510 | struct vm_area_struct *vma; | 1510 | struct vm_area_struct *vma; |
1511 | int err = 0; | 1511 | int err = 0; |
1512 | 1512 | ||
1513 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { | 1513 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
1514 | unsigned long addr; | 1514 | unsigned long addr; |
1515 | 1515 | ||
1516 | if (!maydump(vma, mm_flags)) | 1516 | if (!maydump(vma, mm_flags)) |
1517 | continue; | 1517 | continue; |
1518 | 1518 | ||
1519 | for (addr = vma->vm_start; addr < vma->vm_end; | 1519 | for (addr = vma->vm_start; addr < vma->vm_end; |
1520 | addr += PAGE_SIZE) { | 1520 | addr += PAGE_SIZE) { |
1521 | struct page *page = get_dump_page(addr); | 1521 | struct page *page = get_dump_page(addr); |
1522 | if (page) { | 1522 | if (page) { |
1523 | void *kaddr = kmap(page); | 1523 | void *kaddr = kmap(page); |
1524 | *size += PAGE_SIZE; | 1524 | *size += PAGE_SIZE; |
1525 | if (*size > *limit) | 1525 | if (*size > *limit) |
1526 | err = -EFBIG; | 1526 | err = -EFBIG; |
1527 | else if (!dump_write(file, kaddr, PAGE_SIZE)) | 1527 | else if (!dump_write(file, kaddr, PAGE_SIZE)) |
1528 | err = -EIO; | 1528 | err = -EIO; |
1529 | kunmap(page); | 1529 | kunmap(page); |
1530 | page_cache_release(page); | 1530 | page_cache_release(page); |
1531 | } else if (!dump_seek(file, PAGE_SIZE)) | 1531 | } else if (!dump_seek(file, PAGE_SIZE)) |
1532 | err = -EFBIG; | 1532 | err = -EFBIG; |
1533 | if (err) | 1533 | if (err) |
1534 | goto out; | 1534 | goto out; |
1535 | } | 1535 | } |
1536 | } | 1536 | } |
1537 | out: | 1537 | out: |
1538 | return err; | 1538 | return err; |
1539 | } | 1539 | } |
1540 | #endif | 1540 | #endif |
1541 | 1541 | ||
1542 | /* | 1542 | /* |
1543 | * dump the segments for a NOMMU process | 1543 | * dump the segments for a NOMMU process |
1544 | */ | 1544 | */ |
1545 | #ifndef CONFIG_MMU | 1545 | #ifndef CONFIG_MMU |
1546 | static int elf_fdpic_dump_segments(struct file *file, size_t *size, | 1546 | static int elf_fdpic_dump_segments(struct file *file, size_t *size, |
1547 | unsigned long *limit, unsigned long mm_flags) | 1547 | unsigned long *limit, unsigned long mm_flags) |
1548 | { | 1548 | { |
1549 | struct vm_area_struct *vma; | 1549 | struct vm_area_struct *vma; |
1550 | 1550 | ||
1551 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { | 1551 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
1552 | if (!maydump(vma, mm_flags)) | 1552 | if (!maydump(vma, mm_flags)) |
1553 | continue; | 1553 | continue; |
1554 | 1554 | ||
1555 | if ((*size += PAGE_SIZE) > *limit) | 1555 | if ((*size += PAGE_SIZE) > *limit) |
1556 | return -EFBIG; | 1556 | return -EFBIG; |
1557 | 1557 | ||
1558 | if (!dump_write(file, (void *) vma->vm_start, | 1558 | if (!dump_write(file, (void *) vma->vm_start, |
1559 | vma->vm_end - vma->vm_start)) | 1559 | vma->vm_end - vma->vm_start)) |
1560 | return -EIO; | 1560 | return -EIO; |
1561 | } | 1561 | } |
1562 | 1562 | ||
1563 | return 0; | 1563 | return 0; |
1564 | } | 1564 | } |
1565 | #endif | 1565 | #endif |
1566 | 1566 | ||
1567 | static size_t elf_core_vma_data_size(unsigned long mm_flags) | 1567 | static size_t elf_core_vma_data_size(unsigned long mm_flags) |
1568 | { | 1568 | { |
1569 | struct vm_area_struct *vma; | 1569 | struct vm_area_struct *vma; |
1570 | size_t size = 0; | 1570 | size_t size = 0; |
1571 | 1571 | ||
1572 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) | 1572 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) |
1573 | if (maydump(vma, mm_flags)) | 1573 | if (maydump(vma, mm_flags)) |
1574 | size += vma->vm_end - vma->vm_start; | 1574 | size += vma->vm_end - vma->vm_start; |
1575 | return size; | 1575 | return size; |
1576 | } | 1576 | } |
1577 | 1577 | ||
1578 | /* | 1578 | /* |
1579 | * Actual dumper | 1579 | * Actual dumper |
1580 | * | 1580 | * |
1581 | * This is a two-pass process; first we find the offsets of the bits, | 1581 | * This is a two-pass process; first we find the offsets of the bits, |
1582 | * and then they are actually written out. If we run out of core limit | 1582 | * and then they are actually written out. If we run out of core limit |
1583 | * we just truncate. | 1583 | * we just truncate. |
1584 | */ | 1584 | */ |
1585 | static int elf_fdpic_core_dump(struct coredump_params *cprm) | 1585 | static int elf_fdpic_core_dump(struct coredump_params *cprm) |
1586 | { | 1586 | { |
1587 | #define NUM_NOTES 6 | 1587 | #define NUM_NOTES 6 |
1588 | int has_dumped = 0; | 1588 | int has_dumped = 0; |
1589 | mm_segment_t fs; | 1589 | mm_segment_t fs; |
1590 | int segs; | 1590 | int segs; |
1591 | size_t size = 0; | 1591 | size_t size = 0; |
1592 | int i; | 1592 | int i; |
1593 | struct vm_area_struct *vma; | 1593 | struct vm_area_struct *vma; |
1594 | struct elfhdr *elf = NULL; | 1594 | struct elfhdr *elf = NULL; |
1595 | loff_t offset = 0, dataoff, foffset; | 1595 | loff_t offset = 0, dataoff, foffset; |
1596 | int numnote; | 1596 | int numnote; |
1597 | struct memelfnote *notes = NULL; | 1597 | struct memelfnote *notes = NULL; |
1598 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ | 1598 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ |
1599 | struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ | 1599 | struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ |
1600 | LIST_HEAD(thread_list); | 1600 | LIST_HEAD(thread_list); |
1601 | struct list_head *t; | 1601 | struct list_head *t; |
1602 | elf_fpregset_t *fpu = NULL; | 1602 | elf_fpregset_t *fpu = NULL; |
1603 | #ifdef ELF_CORE_COPY_XFPREGS | 1603 | #ifdef ELF_CORE_COPY_XFPREGS |
1604 | elf_fpxregset_t *xfpu = NULL; | 1604 | elf_fpxregset_t *xfpu = NULL; |
1605 | #endif | 1605 | #endif |
1606 | int thread_status_size = 0; | 1606 | int thread_status_size = 0; |
1607 | elf_addr_t *auxv; | 1607 | elf_addr_t *auxv; |
1608 | struct elf_phdr *phdr4note = NULL; | 1608 | struct elf_phdr *phdr4note = NULL; |
1609 | struct elf_shdr *shdr4extnum = NULL; | 1609 | struct elf_shdr *shdr4extnum = NULL; |
1610 | Elf_Half e_phnum; | 1610 | Elf_Half e_phnum; |
1611 | elf_addr_t e_shoff; | 1611 | elf_addr_t e_shoff; |
1612 | 1612 | ||
1613 | /* | 1613 | /* |
1614 | * We no longer stop all VM operations. | 1614 | * We no longer stop all VM operations. |
1615 | * | 1615 | * |
1616 | * This is because those proceses that could possibly change map_count | 1616 | * This is because those proceses that could possibly change map_count |
1617 | * or the mmap / vma pages are now blocked in do_exit on current | 1617 | * or the mmap / vma pages are now blocked in do_exit on current |
1618 | * finishing this core dump. | 1618 | * finishing this core dump. |
1619 | * | 1619 | * |
1620 | * Only ptrace can touch these memory addresses, but it doesn't change | 1620 | * Only ptrace can touch these memory addresses, but it doesn't change |
1621 | * the map_count or the pages allocated. So no possibility of crashing | 1621 | * the map_count or the pages allocated. So no possibility of crashing |
1622 | * exists while dumping the mm->vm_next areas to the core file. | 1622 | * exists while dumping the mm->vm_next areas to the core file. |
1623 | */ | 1623 | */ |
1624 | 1624 | ||
1625 | /* alloc memory for large data structures: too large to be on stack */ | 1625 | /* alloc memory for large data structures: too large to be on stack */ |
1626 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); | 1626 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
1627 | if (!elf) | 1627 | if (!elf) |
1628 | goto cleanup; | 1628 | goto cleanup; |
1629 | prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL); | 1629 | prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL); |
1630 | if (!prstatus) | 1630 | if (!prstatus) |
1631 | goto cleanup; | 1631 | goto cleanup; |
1632 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); | 1632 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); |
1633 | if (!psinfo) | 1633 | if (!psinfo) |
1634 | goto cleanup; | 1634 | goto cleanup; |
1635 | notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL); | 1635 | notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL); |
1636 | if (!notes) | 1636 | if (!notes) |
1637 | goto cleanup; | 1637 | goto cleanup; |
1638 | fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); | 1638 | fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); |
1639 | if (!fpu) | 1639 | if (!fpu) |
1640 | goto cleanup; | 1640 | goto cleanup; |
1641 | #ifdef ELF_CORE_COPY_XFPREGS | 1641 | #ifdef ELF_CORE_COPY_XFPREGS |
1642 | xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); | 1642 | xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); |
1643 | if (!xfpu) | 1643 | if (!xfpu) |
1644 | goto cleanup; | 1644 | goto cleanup; |
1645 | #endif | 1645 | #endif |
1646 | 1646 | ||
1647 | if (cprm->siginfo->si_signo) { | 1647 | if (cprm->siginfo->si_signo) { |
1648 | struct core_thread *ct; | 1648 | struct core_thread *ct; |
1649 | struct elf_thread_status *tmp; | 1649 | struct elf_thread_status *tmp; |
1650 | 1650 | ||
1651 | for (ct = current->mm->core_state->dumper.next; | 1651 | for (ct = current->mm->core_state->dumper.next; |
1652 | ct; ct = ct->next) { | 1652 | ct; ct = ct->next) { |
1653 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); | 1653 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
1654 | if (!tmp) | 1654 | if (!tmp) |
1655 | goto cleanup; | 1655 | goto cleanup; |
1656 | 1656 | ||
1657 | tmp->thread = ct->task; | 1657 | tmp->thread = ct->task; |
1658 | list_add(&tmp->list, &thread_list); | 1658 | list_add(&tmp->list, &thread_list); |
1659 | } | 1659 | } |
1660 | 1660 | ||
1661 | list_for_each(t, &thread_list) { | 1661 | list_for_each(t, &thread_list) { |
1662 | struct elf_thread_status *tmp; | 1662 | struct elf_thread_status *tmp; |
1663 | int sz; | 1663 | int sz; |
1664 | 1664 | ||
1665 | tmp = list_entry(t, struct elf_thread_status, list); | 1665 | tmp = list_entry(t, struct elf_thread_status, list); |
1666 | sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); | 1666 | sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); |
1667 | thread_status_size += sz; | 1667 | thread_status_size += sz; |
1668 | } | 1668 | } |
1669 | } | 1669 | } |
1670 | 1670 | ||
1671 | /* now collect the dump for the current */ | 1671 | /* now collect the dump for the current */ |
1672 | fill_prstatus(prstatus, current, cprm->siginfo->si_signo); | 1672 | fill_prstatus(prstatus, current, cprm->siginfo->si_signo); |
1673 | elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); | 1673 | elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); |
1674 | 1674 | ||
1675 | segs = current->mm->map_count; | 1675 | segs = current->mm->map_count; |
1676 | segs += elf_core_extra_phdrs(); | 1676 | segs += elf_core_extra_phdrs(); |
1677 | 1677 | ||
1678 | /* for notes section */ | 1678 | /* for notes section */ |
1679 | segs++; | 1679 | segs++; |
1680 | 1680 | ||
1681 | /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid | 1681 | /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid |
1682 | * this, kernel supports extended numbering. Have a look at | 1682 | * this, kernel supports extended numbering. Have a look at |
1683 | * include/linux/elf.h for further information. */ | 1683 | * include/linux/elf.h for further information. */ |
1684 | e_phnum = segs > PN_XNUM ? PN_XNUM : segs; | 1684 | e_phnum = segs > PN_XNUM ? PN_XNUM : segs; |
1685 | 1685 | ||
1686 | /* Set up header */ | 1686 | /* Set up header */ |
1687 | fill_elf_fdpic_header(elf, e_phnum); | 1687 | fill_elf_fdpic_header(elf, e_phnum); |
1688 | 1688 | ||
1689 | has_dumped = 1; | 1689 | has_dumped = 1; |
1690 | current->flags |= PF_DUMPCORE; | ||
1691 | |||
1692 | /* | 1690 | /* |
1693 | * Set up the notes in similar form to SVR4 core dumps made | 1691 | * Set up the notes in similar form to SVR4 core dumps made |
1694 | * with info from their /proc. | 1692 | * with info from their /proc. |
1695 | */ | 1693 | */ |
1696 | 1694 | ||
1697 | fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); | 1695 | fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); |
1698 | fill_psinfo(psinfo, current->group_leader, current->mm); | 1696 | fill_psinfo(psinfo, current->group_leader, current->mm); |
1699 | fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | 1697 | fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); |
1700 | 1698 | ||
1701 | numnote = 2; | 1699 | numnote = 2; |
1702 | 1700 | ||
1703 | auxv = (elf_addr_t *) current->mm->saved_auxv; | 1701 | auxv = (elf_addr_t *) current->mm->saved_auxv; |
1704 | 1702 | ||
1705 | i = 0; | 1703 | i = 0; |
1706 | do | 1704 | do |
1707 | i += 2; | 1705 | i += 2; |
1708 | while (auxv[i - 2] != AT_NULL); | 1706 | while (auxv[i - 2] != AT_NULL); |
1709 | fill_note(¬es[numnote++], "CORE", NT_AUXV, | 1707 | fill_note(¬es[numnote++], "CORE", NT_AUXV, |
1710 | i * sizeof(elf_addr_t), auxv); | 1708 | i * sizeof(elf_addr_t), auxv); |
1711 | 1709 | ||
1712 | /* Try to dump the FPU. */ | 1710 | /* Try to dump the FPU. */ |
1713 | if ((prstatus->pr_fpvalid = | 1711 | if ((prstatus->pr_fpvalid = |
1714 | elf_core_copy_task_fpregs(current, cprm->regs, fpu))) | 1712 | elf_core_copy_task_fpregs(current, cprm->regs, fpu))) |
1715 | fill_note(notes + numnote++, | 1713 | fill_note(notes + numnote++, |
1716 | "CORE", NT_PRFPREG, sizeof(*fpu), fpu); | 1714 | "CORE", NT_PRFPREG, sizeof(*fpu), fpu); |
1717 | #ifdef ELF_CORE_COPY_XFPREGS | 1715 | #ifdef ELF_CORE_COPY_XFPREGS |
1718 | if (elf_core_copy_task_xfpregs(current, xfpu)) | 1716 | if (elf_core_copy_task_xfpregs(current, xfpu)) |
1719 | fill_note(notes + numnote++, | 1717 | fill_note(notes + numnote++, |
1720 | "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); | 1718 | "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); |
1721 | #endif | 1719 | #endif |
1722 | 1720 | ||
1723 | fs = get_fs(); | 1721 | fs = get_fs(); |
1724 | set_fs(KERNEL_DS); | 1722 | set_fs(KERNEL_DS); |
1725 | 1723 | ||
1726 | offset += sizeof(*elf); /* Elf header */ | 1724 | offset += sizeof(*elf); /* Elf header */ |
1727 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ | 1725 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
1728 | foffset = offset; | 1726 | foffset = offset; |
1729 | 1727 | ||
1730 | /* Write notes phdr entry */ | 1728 | /* Write notes phdr entry */ |
1731 | { | 1729 | { |
1732 | int sz = 0; | 1730 | int sz = 0; |
1733 | 1731 | ||
1734 | for (i = 0; i < numnote; i++) | 1732 | for (i = 0; i < numnote; i++) |
1735 | sz += notesize(notes + i); | 1733 | sz += notesize(notes + i); |
1736 | 1734 | ||
1737 | sz += thread_status_size; | 1735 | sz += thread_status_size; |
1738 | 1736 | ||
1739 | phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); | 1737 | phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); |
1740 | if (!phdr4note) | 1738 | if (!phdr4note) |
1741 | goto end_coredump; | 1739 | goto end_coredump; |
1742 | 1740 | ||
1743 | fill_elf_note_phdr(phdr4note, sz, offset); | 1741 | fill_elf_note_phdr(phdr4note, sz, offset); |
1744 | offset += sz; | 1742 | offset += sz; |
1745 | } | 1743 | } |
1746 | 1744 | ||
1747 | /* Page-align dumped data */ | 1745 | /* Page-align dumped data */ |
1748 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1746 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1749 | 1747 | ||
1750 | offset += elf_core_vma_data_size(cprm->mm_flags); | 1748 | offset += elf_core_vma_data_size(cprm->mm_flags); |
1751 | offset += elf_core_extra_data_size(); | 1749 | offset += elf_core_extra_data_size(); |
1752 | e_shoff = offset; | 1750 | e_shoff = offset; |
1753 | 1751 | ||
1754 | if (e_phnum == PN_XNUM) { | 1752 | if (e_phnum == PN_XNUM) { |
1755 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); | 1753 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); |
1756 | if (!shdr4extnum) | 1754 | if (!shdr4extnum) |
1757 | goto end_coredump; | 1755 | goto end_coredump; |
1758 | fill_extnum_info(elf, shdr4extnum, e_shoff, segs); | 1756 | fill_extnum_info(elf, shdr4extnum, e_shoff, segs); |
1759 | } | 1757 | } |
1760 | 1758 | ||
1761 | offset = dataoff; | 1759 | offset = dataoff; |
1762 | 1760 | ||
1763 | size += sizeof(*elf); | 1761 | size += sizeof(*elf); |
1764 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) | 1762 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) |
1765 | goto end_coredump; | 1763 | goto end_coredump; |
1766 | 1764 | ||
1767 | size += sizeof(*phdr4note); | 1765 | size += sizeof(*phdr4note); |
1768 | if (size > cprm->limit | 1766 | if (size > cprm->limit |
1769 | || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note))) | 1767 | || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note))) |
1770 | goto end_coredump; | 1768 | goto end_coredump; |
1771 | 1769 | ||
1772 | /* write program headers for segments dump */ | 1770 | /* write program headers for segments dump */ |
1773 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { | 1771 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
1774 | struct elf_phdr phdr; | 1772 | struct elf_phdr phdr; |
1775 | size_t sz; | 1773 | size_t sz; |
1776 | 1774 | ||
1777 | sz = vma->vm_end - vma->vm_start; | 1775 | sz = vma->vm_end - vma->vm_start; |
1778 | 1776 | ||
1779 | phdr.p_type = PT_LOAD; | 1777 | phdr.p_type = PT_LOAD; |
1780 | phdr.p_offset = offset; | 1778 | phdr.p_offset = offset; |
1781 | phdr.p_vaddr = vma->vm_start; | 1779 | phdr.p_vaddr = vma->vm_start; |
1782 | phdr.p_paddr = 0; | 1780 | phdr.p_paddr = 0; |
1783 | phdr.p_filesz = maydump(vma, cprm->mm_flags) ? sz : 0; | 1781 | phdr.p_filesz = maydump(vma, cprm->mm_flags) ? sz : 0; |
1784 | phdr.p_memsz = sz; | 1782 | phdr.p_memsz = sz; |
1785 | offset += phdr.p_filesz; | 1783 | offset += phdr.p_filesz; |
1786 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1784 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
1787 | if (vma->vm_flags & VM_WRITE) | 1785 | if (vma->vm_flags & VM_WRITE) |
1788 | phdr.p_flags |= PF_W; | 1786 | phdr.p_flags |= PF_W; |
1789 | if (vma->vm_flags & VM_EXEC) | 1787 | if (vma->vm_flags & VM_EXEC) |
1790 | phdr.p_flags |= PF_X; | 1788 | phdr.p_flags |= PF_X; |
1791 | phdr.p_align = ELF_EXEC_PAGESIZE; | 1789 | phdr.p_align = ELF_EXEC_PAGESIZE; |
1792 | 1790 | ||
1793 | size += sizeof(phdr); | 1791 | size += sizeof(phdr); |
1794 | if (size > cprm->limit | 1792 | if (size > cprm->limit |
1795 | || !dump_write(cprm->file, &phdr, sizeof(phdr))) | 1793 | || !dump_write(cprm->file, &phdr, sizeof(phdr))) |
1796 | goto end_coredump; | 1794 | goto end_coredump; |
1797 | } | 1795 | } |
1798 | 1796 | ||
1799 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) | 1797 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) |
1800 | goto end_coredump; | 1798 | goto end_coredump; |
1801 | 1799 | ||
1802 | /* write out the notes section */ | 1800 | /* write out the notes section */ |
1803 | for (i = 0; i < numnote; i++) | 1801 | for (i = 0; i < numnote; i++) |
1804 | if (!writenote(notes + i, cprm->file, &foffset)) | 1802 | if (!writenote(notes + i, cprm->file, &foffset)) |
1805 | goto end_coredump; | 1803 | goto end_coredump; |
1806 | 1804 | ||
1807 | /* write out the thread status notes section */ | 1805 | /* write out the thread status notes section */ |
1808 | list_for_each(t, &thread_list) { | 1806 | list_for_each(t, &thread_list) { |
1809 | struct elf_thread_status *tmp = | 1807 | struct elf_thread_status *tmp = |
1810 | list_entry(t, struct elf_thread_status, list); | 1808 | list_entry(t, struct elf_thread_status, list); |
1811 | 1809 | ||
1812 | for (i = 0; i < tmp->num_notes; i++) | 1810 | for (i = 0; i < tmp->num_notes; i++) |
1813 | if (!writenote(&tmp->notes[i], cprm->file, &foffset)) | 1811 | if (!writenote(&tmp->notes[i], cprm->file, &foffset)) |
1814 | goto end_coredump; | 1812 | goto end_coredump; |
1815 | } | 1813 | } |
1816 | 1814 | ||
1817 | if (!dump_seek(cprm->file, dataoff - foffset)) | 1815 | if (!dump_seek(cprm->file, dataoff - foffset)) |
1818 | goto end_coredump; | 1816 | goto end_coredump; |
1819 | 1817 | ||
1820 | if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit, | 1818 | if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit, |
1821 | cprm->mm_flags) < 0) | 1819 | cprm->mm_flags) < 0) |
1822 | goto end_coredump; | 1820 | goto end_coredump; |
1823 | 1821 | ||
1824 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) | 1822 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) |
1825 | goto end_coredump; | 1823 | goto end_coredump; |
1826 | 1824 | ||
1827 | if (e_phnum == PN_XNUM) { | 1825 | if (e_phnum == PN_XNUM) { |
1828 | size += sizeof(*shdr4extnum); | 1826 | size += sizeof(*shdr4extnum); |
1829 | if (size > cprm->limit | 1827 | if (size > cprm->limit |
1830 | || !dump_write(cprm->file, shdr4extnum, | 1828 | || !dump_write(cprm->file, shdr4extnum, |
1831 | sizeof(*shdr4extnum))) | 1829 | sizeof(*shdr4extnum))) |
1832 | goto end_coredump; | 1830 | goto end_coredump; |
1833 | } | 1831 | } |
1834 | 1832 | ||
1835 | if (cprm->file->f_pos != offset) { | 1833 | if (cprm->file->f_pos != offset) { |
1836 | /* Sanity check */ | 1834 | /* Sanity check */ |
1837 | printk(KERN_WARNING | 1835 | printk(KERN_WARNING |
1838 | "elf_core_dump: file->f_pos (%lld) != offset (%lld)\n", | 1836 | "elf_core_dump: file->f_pos (%lld) != offset (%lld)\n", |
1839 | cprm->file->f_pos, offset); | 1837 | cprm->file->f_pos, offset); |
1840 | } | 1838 | } |
1841 | 1839 | ||
1842 | end_coredump: | 1840 | end_coredump: |
1843 | set_fs(fs); | 1841 | set_fs(fs); |
1844 | 1842 | ||
1845 | cleanup: | 1843 | cleanup: |
1846 | while (!list_empty(&thread_list)) { | 1844 | while (!list_empty(&thread_list)) { |
1847 | struct list_head *tmp = thread_list.next; | 1845 | struct list_head *tmp = thread_list.next; |
1848 | list_del(tmp); | 1846 | list_del(tmp); |
1849 | kfree(list_entry(tmp, struct elf_thread_status, list)); | 1847 | kfree(list_entry(tmp, struct elf_thread_status, list)); |
1850 | } | 1848 | } |
1851 | kfree(phdr4note); | 1849 | kfree(phdr4note); |
1852 | kfree(elf); | 1850 | kfree(elf); |
1853 | kfree(prstatus); | 1851 | kfree(prstatus); |
1854 | kfree(psinfo); | 1852 | kfree(psinfo); |
1855 | kfree(notes); | 1853 | kfree(notes); |
1856 | kfree(fpu); | 1854 | kfree(fpu); |
1857 | kfree(shdr4extnum); | 1855 | kfree(shdr4extnum); |
1858 | #ifdef ELF_CORE_COPY_XFPREGS | 1856 | #ifdef ELF_CORE_COPY_XFPREGS |
1859 | kfree(xfpu); | 1857 | kfree(xfpu); |
1860 | #endif | 1858 | #endif |
1861 | return has_dumped; | 1859 | return has_dumped; |
1862 | #undef NUM_NOTES | 1860 | #undef NUM_NOTES |
1863 | } | 1861 | } |
1864 | 1862 | ||
1865 | #endif /* CONFIG_ELF_CORE */ | 1863 | #endif /* CONFIG_ELF_CORE */ |
1866 | 1864 |
fs/coredump.c
1 | #include <linux/slab.h> | 1 | #include <linux/slab.h> |
2 | #include <linux/file.h> | 2 | #include <linux/file.h> |
3 | #include <linux/fdtable.h> | 3 | #include <linux/fdtable.h> |
4 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
5 | #include <linux/stat.h> | 5 | #include <linux/stat.h> |
6 | #include <linux/fcntl.h> | 6 | #include <linux/fcntl.h> |
7 | #include <linux/swap.h> | 7 | #include <linux/swap.h> |
8 | #include <linux/string.h> | 8 | #include <linux/string.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/pagemap.h> | 10 | #include <linux/pagemap.h> |
11 | #include <linux/perf_event.h> | 11 | #include <linux/perf_event.h> |
12 | #include <linux/highmem.h> | 12 | #include <linux/highmem.h> |
13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
14 | #include <linux/key.h> | 14 | #include <linux/key.h> |
15 | #include <linux/personality.h> | 15 | #include <linux/personality.h> |
16 | #include <linux/binfmts.h> | 16 | #include <linux/binfmts.h> |
17 | #include <linux/coredump.h> | 17 | #include <linux/coredump.h> |
18 | #include <linux/utsname.h> | 18 | #include <linux/utsname.h> |
19 | #include <linux/pid_namespace.h> | 19 | #include <linux/pid_namespace.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/namei.h> | 21 | #include <linux/namei.h> |
22 | #include <linux/mount.h> | 22 | #include <linux/mount.h> |
23 | #include <linux/security.h> | 23 | #include <linux/security.h> |
24 | #include <linux/syscalls.h> | 24 | #include <linux/syscalls.h> |
25 | #include <linux/tsacct_kern.h> | 25 | #include <linux/tsacct_kern.h> |
26 | #include <linux/cn_proc.h> | 26 | #include <linux/cn_proc.h> |
27 | #include <linux/audit.h> | 27 | #include <linux/audit.h> |
28 | #include <linux/tracehook.h> | 28 | #include <linux/tracehook.h> |
29 | #include <linux/kmod.h> | 29 | #include <linux/kmod.h> |
30 | #include <linux/fsnotify.h> | 30 | #include <linux/fsnotify.h> |
31 | #include <linux/fs_struct.h> | 31 | #include <linux/fs_struct.h> |
32 | #include <linux/pipe_fs_i.h> | 32 | #include <linux/pipe_fs_i.h> |
33 | #include <linux/oom.h> | 33 | #include <linux/oom.h> |
34 | #include <linux/compat.h> | 34 | #include <linux/compat.h> |
35 | 35 | ||
36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
37 | #include <asm/mmu_context.h> | 37 | #include <asm/mmu_context.h> |
38 | #include <asm/tlb.h> | 38 | #include <asm/tlb.h> |
39 | #include <asm/exec.h> | 39 | #include <asm/exec.h> |
40 | 40 | ||
41 | #include <trace/events/task.h> | 41 | #include <trace/events/task.h> |
42 | #include "internal.h" | 42 | #include "internal.h" |
43 | #include "coredump.h" | 43 | #include "coredump.h" |
44 | 44 | ||
45 | #include <trace/events/sched.h> | 45 | #include <trace/events/sched.h> |
46 | 46 | ||
47 | int core_uses_pid; | 47 | int core_uses_pid; |
48 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | 48 | char core_pattern[CORENAME_MAX_SIZE] = "core"; |
49 | unsigned int core_pipe_limit; | 49 | unsigned int core_pipe_limit; |
50 | 50 | ||
51 | struct core_name { | 51 | struct core_name { |
52 | char *corename; | 52 | char *corename; |
53 | int used, size; | 53 | int used, size; |
54 | }; | 54 | }; |
55 | static atomic_t call_count = ATOMIC_INIT(1); | 55 | static atomic_t call_count = ATOMIC_INIT(1); |
56 | 56 | ||
57 | /* The maximal length of core_pattern is also specified in sysctl.c */ | 57 | /* The maximal length of core_pattern is also specified in sysctl.c */ |
58 | 58 | ||
59 | static int expand_corename(struct core_name *cn) | 59 | static int expand_corename(struct core_name *cn) |
60 | { | 60 | { |
61 | char *old_corename = cn->corename; | 61 | char *old_corename = cn->corename; |
62 | 62 | ||
63 | cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count); | 63 | cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count); |
64 | cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); | 64 | cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); |
65 | 65 | ||
66 | if (!cn->corename) { | 66 | if (!cn->corename) { |
67 | kfree(old_corename); | 67 | kfree(old_corename); |
68 | return -ENOMEM; | 68 | return -ENOMEM; |
69 | } | 69 | } |
70 | 70 | ||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | static int cn_printf(struct core_name *cn, const char *fmt, ...) | 74 | static int cn_printf(struct core_name *cn, const char *fmt, ...) |
75 | { | 75 | { |
76 | char *cur; | 76 | char *cur; |
77 | int need; | 77 | int need; |
78 | int ret; | 78 | int ret; |
79 | va_list arg; | 79 | va_list arg; |
80 | 80 | ||
81 | va_start(arg, fmt); | 81 | va_start(arg, fmt); |
82 | need = vsnprintf(NULL, 0, fmt, arg); | 82 | need = vsnprintf(NULL, 0, fmt, arg); |
83 | va_end(arg); | 83 | va_end(arg); |
84 | 84 | ||
85 | if (likely(need < cn->size - cn->used - 1)) | 85 | if (likely(need < cn->size - cn->used - 1)) |
86 | goto out_printf; | 86 | goto out_printf; |
87 | 87 | ||
88 | ret = expand_corename(cn); | 88 | ret = expand_corename(cn); |
89 | if (ret) | 89 | if (ret) |
90 | goto expand_fail; | 90 | goto expand_fail; |
91 | 91 | ||
92 | out_printf: | 92 | out_printf: |
93 | cur = cn->corename + cn->used; | 93 | cur = cn->corename + cn->used; |
94 | va_start(arg, fmt); | 94 | va_start(arg, fmt); |
95 | vsnprintf(cur, need + 1, fmt, arg); | 95 | vsnprintf(cur, need + 1, fmt, arg); |
96 | va_end(arg); | 96 | va_end(arg); |
97 | cn->used += need; | 97 | cn->used += need; |
98 | return 0; | 98 | return 0; |
99 | 99 | ||
100 | expand_fail: | 100 | expand_fail: |
101 | return ret; | 101 | return ret; |
102 | } | 102 | } |
103 | 103 | ||
104 | static void cn_escape(char *str) | 104 | static void cn_escape(char *str) |
105 | { | 105 | { |
106 | for (; *str; str++) | 106 | for (; *str; str++) |
107 | if (*str == '/') | 107 | if (*str == '/') |
108 | *str = '!'; | 108 | *str = '!'; |
109 | } | 109 | } |
110 | 110 | ||
111 | static int cn_print_exe_file(struct core_name *cn) | 111 | static int cn_print_exe_file(struct core_name *cn) |
112 | { | 112 | { |
113 | struct file *exe_file; | 113 | struct file *exe_file; |
114 | char *pathbuf, *path; | 114 | char *pathbuf, *path; |
115 | int ret; | 115 | int ret; |
116 | 116 | ||
117 | exe_file = get_mm_exe_file(current->mm); | 117 | exe_file = get_mm_exe_file(current->mm); |
118 | if (!exe_file) { | 118 | if (!exe_file) { |
119 | char *commstart = cn->corename + cn->used; | 119 | char *commstart = cn->corename + cn->used; |
120 | ret = cn_printf(cn, "%s (path unknown)", current->comm); | 120 | ret = cn_printf(cn, "%s (path unknown)", current->comm); |
121 | cn_escape(commstart); | 121 | cn_escape(commstart); |
122 | return ret; | 122 | return ret; |
123 | } | 123 | } |
124 | 124 | ||
125 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); | 125 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); |
126 | if (!pathbuf) { | 126 | if (!pathbuf) { |
127 | ret = -ENOMEM; | 127 | ret = -ENOMEM; |
128 | goto put_exe_file; | 128 | goto put_exe_file; |
129 | } | 129 | } |
130 | 130 | ||
131 | path = d_path(&exe_file->f_path, pathbuf, PATH_MAX); | 131 | path = d_path(&exe_file->f_path, pathbuf, PATH_MAX); |
132 | if (IS_ERR(path)) { | 132 | if (IS_ERR(path)) { |
133 | ret = PTR_ERR(path); | 133 | ret = PTR_ERR(path); |
134 | goto free_buf; | 134 | goto free_buf; |
135 | } | 135 | } |
136 | 136 | ||
137 | cn_escape(path); | 137 | cn_escape(path); |
138 | 138 | ||
139 | ret = cn_printf(cn, "%s", path); | 139 | ret = cn_printf(cn, "%s", path); |
140 | 140 | ||
141 | free_buf: | 141 | free_buf: |
142 | kfree(pathbuf); | 142 | kfree(pathbuf); |
143 | put_exe_file: | 143 | put_exe_file: |
144 | fput(exe_file); | 144 | fput(exe_file); |
145 | return ret; | 145 | return ret; |
146 | } | 146 | } |
147 | 147 | ||
148 | /* format_corename will inspect the pattern parameter, and output a | 148 | /* format_corename will inspect the pattern parameter, and output a |
149 | * name into corename, which must have space for at least | 149 | * name into corename, which must have space for at least |
150 | * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. | 150 | * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. |
151 | */ | 151 | */ |
152 | static int format_corename(struct core_name *cn, struct coredump_params *cprm) | 152 | static int format_corename(struct core_name *cn, struct coredump_params *cprm) |
153 | { | 153 | { |
154 | const struct cred *cred = current_cred(); | 154 | const struct cred *cred = current_cred(); |
155 | const char *pat_ptr = core_pattern; | 155 | const char *pat_ptr = core_pattern; |
156 | int ispipe = (*pat_ptr == '|'); | 156 | int ispipe = (*pat_ptr == '|'); |
157 | int pid_in_pattern = 0; | 157 | int pid_in_pattern = 0; |
158 | int err = 0; | 158 | int err = 0; |
159 | 159 | ||
160 | cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count); | 160 | cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count); |
161 | cn->corename = kmalloc(cn->size, GFP_KERNEL); | 161 | cn->corename = kmalloc(cn->size, GFP_KERNEL); |
162 | cn->used = 0; | 162 | cn->used = 0; |
163 | 163 | ||
164 | if (!cn->corename) | 164 | if (!cn->corename) |
165 | return -ENOMEM; | 165 | return -ENOMEM; |
166 | 166 | ||
167 | /* Repeat as long as we have more pattern to process and more output | 167 | /* Repeat as long as we have more pattern to process and more output |
168 | space */ | 168 | space */ |
169 | while (*pat_ptr) { | 169 | while (*pat_ptr) { |
170 | if (*pat_ptr != '%') { | 170 | if (*pat_ptr != '%') { |
171 | if (*pat_ptr == 0) | 171 | if (*pat_ptr == 0) |
172 | goto out; | 172 | goto out; |
173 | err = cn_printf(cn, "%c", *pat_ptr++); | 173 | err = cn_printf(cn, "%c", *pat_ptr++); |
174 | } else { | 174 | } else { |
175 | switch (*++pat_ptr) { | 175 | switch (*++pat_ptr) { |
176 | /* single % at the end, drop that */ | 176 | /* single % at the end, drop that */ |
177 | case 0: | 177 | case 0: |
178 | goto out; | 178 | goto out; |
179 | /* Double percent, output one percent */ | 179 | /* Double percent, output one percent */ |
180 | case '%': | 180 | case '%': |
181 | err = cn_printf(cn, "%c", '%'); | 181 | err = cn_printf(cn, "%c", '%'); |
182 | break; | 182 | break; |
183 | /* pid */ | 183 | /* pid */ |
184 | case 'p': | 184 | case 'p': |
185 | pid_in_pattern = 1; | 185 | pid_in_pattern = 1; |
186 | err = cn_printf(cn, "%d", | 186 | err = cn_printf(cn, "%d", |
187 | task_tgid_vnr(current)); | 187 | task_tgid_vnr(current)); |
188 | break; | 188 | break; |
189 | /* uid */ | 189 | /* uid */ |
190 | case 'u': | 190 | case 'u': |
191 | err = cn_printf(cn, "%d", cred->uid); | 191 | err = cn_printf(cn, "%d", cred->uid); |
192 | break; | 192 | break; |
193 | /* gid */ | 193 | /* gid */ |
194 | case 'g': | 194 | case 'g': |
195 | err = cn_printf(cn, "%d", cred->gid); | 195 | err = cn_printf(cn, "%d", cred->gid); |
196 | break; | 196 | break; |
197 | case 'd': | 197 | case 'd': |
198 | err = cn_printf(cn, "%d", | 198 | err = cn_printf(cn, "%d", |
199 | __get_dumpable(cprm->mm_flags)); | 199 | __get_dumpable(cprm->mm_flags)); |
200 | break; | 200 | break; |
201 | /* signal that caused the coredump */ | 201 | /* signal that caused the coredump */ |
202 | case 's': | 202 | case 's': |
203 | err = cn_printf(cn, "%ld", cprm->siginfo->si_signo); | 203 | err = cn_printf(cn, "%ld", cprm->siginfo->si_signo); |
204 | break; | 204 | break; |
205 | /* UNIX time of coredump */ | 205 | /* UNIX time of coredump */ |
206 | case 't': { | 206 | case 't': { |
207 | struct timeval tv; | 207 | struct timeval tv; |
208 | do_gettimeofday(&tv); | 208 | do_gettimeofday(&tv); |
209 | err = cn_printf(cn, "%lu", tv.tv_sec); | 209 | err = cn_printf(cn, "%lu", tv.tv_sec); |
210 | break; | 210 | break; |
211 | } | 211 | } |
212 | /* hostname */ | 212 | /* hostname */ |
213 | case 'h': { | 213 | case 'h': { |
214 | char *namestart = cn->corename + cn->used; | 214 | char *namestart = cn->corename + cn->used; |
215 | down_read(&uts_sem); | 215 | down_read(&uts_sem); |
216 | err = cn_printf(cn, "%s", | 216 | err = cn_printf(cn, "%s", |
217 | utsname()->nodename); | 217 | utsname()->nodename); |
218 | up_read(&uts_sem); | 218 | up_read(&uts_sem); |
219 | cn_escape(namestart); | 219 | cn_escape(namestart); |
220 | break; | 220 | break; |
221 | } | 221 | } |
222 | /* executable */ | 222 | /* executable */ |
223 | case 'e': { | 223 | case 'e': { |
224 | char *commstart = cn->corename + cn->used; | 224 | char *commstart = cn->corename + cn->used; |
225 | err = cn_printf(cn, "%s", current->comm); | 225 | err = cn_printf(cn, "%s", current->comm); |
226 | cn_escape(commstart); | 226 | cn_escape(commstart); |
227 | break; | 227 | break; |
228 | } | 228 | } |
229 | case 'E': | 229 | case 'E': |
230 | err = cn_print_exe_file(cn); | 230 | err = cn_print_exe_file(cn); |
231 | break; | 231 | break; |
232 | /* core limit size */ | 232 | /* core limit size */ |
233 | case 'c': | 233 | case 'c': |
234 | err = cn_printf(cn, "%lu", | 234 | err = cn_printf(cn, "%lu", |
235 | rlimit(RLIMIT_CORE)); | 235 | rlimit(RLIMIT_CORE)); |
236 | break; | 236 | break; |
237 | default: | 237 | default: |
238 | break; | 238 | break; |
239 | } | 239 | } |
240 | ++pat_ptr; | 240 | ++pat_ptr; |
241 | } | 241 | } |
242 | 242 | ||
243 | if (err) | 243 | if (err) |
244 | return err; | 244 | return err; |
245 | } | 245 | } |
246 | 246 | ||
247 | /* Backward compatibility with core_uses_pid: | 247 | /* Backward compatibility with core_uses_pid: |
248 | * | 248 | * |
249 | * If core_pattern does not include a %p (as is the default) | 249 | * If core_pattern does not include a %p (as is the default) |
250 | * and core_uses_pid is set, then .%pid will be appended to | 250 | * and core_uses_pid is set, then .%pid will be appended to |
251 | * the filename. Do not do this for piped commands. */ | 251 | * the filename. Do not do this for piped commands. */ |
252 | if (!ispipe && !pid_in_pattern && core_uses_pid) { | 252 | if (!ispipe && !pid_in_pattern && core_uses_pid) { |
253 | err = cn_printf(cn, ".%d", task_tgid_vnr(current)); | 253 | err = cn_printf(cn, ".%d", task_tgid_vnr(current)); |
254 | if (err) | 254 | if (err) |
255 | return err; | 255 | return err; |
256 | } | 256 | } |
257 | out: | 257 | out: |
258 | return ispipe; | 258 | return ispipe; |
259 | } | 259 | } |
260 | 260 | ||
261 | static int zap_process(struct task_struct *start, int exit_code) | 261 | static int zap_process(struct task_struct *start, int exit_code) |
262 | { | 262 | { |
263 | struct task_struct *t; | 263 | struct task_struct *t; |
264 | int nr = 0; | 264 | int nr = 0; |
265 | 265 | ||
266 | start->signal->group_exit_code = exit_code; | 266 | start->signal->group_exit_code = exit_code; |
267 | start->signal->group_stop_count = 0; | 267 | start->signal->group_stop_count = 0; |
268 | 268 | ||
269 | t = start; | 269 | t = start; |
270 | do { | 270 | do { |
271 | task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK); | 271 | task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK); |
272 | if (t != current && t->mm) { | 272 | if (t != current && t->mm) { |
273 | sigaddset(&t->pending.signal, SIGKILL); | 273 | sigaddset(&t->pending.signal, SIGKILL); |
274 | signal_wake_up(t, 1); | 274 | signal_wake_up(t, 1); |
275 | nr++; | 275 | nr++; |
276 | } | 276 | } |
277 | } while_each_thread(start, t); | 277 | } while_each_thread(start, t); |
278 | 278 | ||
279 | return nr; | 279 | return nr; |
280 | } | 280 | } |
281 | 281 | ||
282 | static int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | 282 | static int zap_threads(struct task_struct *tsk, struct mm_struct *mm, |
283 | struct core_state *core_state, int exit_code) | 283 | struct core_state *core_state, int exit_code) |
284 | { | 284 | { |
285 | struct task_struct *g, *p; | 285 | struct task_struct *g, *p; |
286 | unsigned long flags; | 286 | unsigned long flags; |
287 | int nr = -EAGAIN; | 287 | int nr = -EAGAIN; |
288 | 288 | ||
289 | spin_lock_irq(&tsk->sighand->siglock); | 289 | spin_lock_irq(&tsk->sighand->siglock); |
290 | if (!signal_group_exit(tsk->signal)) { | 290 | if (!signal_group_exit(tsk->signal)) { |
291 | mm->core_state = core_state; | 291 | mm->core_state = core_state; |
292 | nr = zap_process(tsk, exit_code); | 292 | nr = zap_process(tsk, exit_code); |
293 | tsk->signal->group_exit_task = tsk; | 293 | tsk->signal->group_exit_task = tsk; |
294 | /* ignore all signals except SIGKILL, see prepare_signal() */ | 294 | /* ignore all signals except SIGKILL, see prepare_signal() */ |
295 | tsk->signal->flags = SIGNAL_GROUP_COREDUMP; | 295 | tsk->signal->flags = SIGNAL_GROUP_COREDUMP; |
296 | clear_tsk_thread_flag(tsk, TIF_SIGPENDING); | 296 | clear_tsk_thread_flag(tsk, TIF_SIGPENDING); |
297 | } | 297 | } |
298 | spin_unlock_irq(&tsk->sighand->siglock); | 298 | spin_unlock_irq(&tsk->sighand->siglock); |
299 | if (unlikely(nr < 0)) | 299 | if (unlikely(nr < 0)) |
300 | return nr; | 300 | return nr; |
301 | 301 | ||
302 | tsk->flags = PF_DUMPCORE; | ||
302 | if (atomic_read(&mm->mm_users) == nr + 1) | 303 | if (atomic_read(&mm->mm_users) == nr + 1) |
303 | goto done; | 304 | goto done; |
304 | /* | 305 | /* |
305 | * We should find and kill all tasks which use this mm, and we should | 306 | * We should find and kill all tasks which use this mm, and we should |
306 | * count them correctly into ->nr_threads. We don't take tasklist | 307 | * count them correctly into ->nr_threads. We don't take tasklist |
307 | * lock, but this is safe wrt: | 308 | * lock, but this is safe wrt: |
308 | * | 309 | * |
309 | * fork: | 310 | * fork: |
310 | * None of sub-threads can fork after zap_process(leader). All | 311 | * None of sub-threads can fork after zap_process(leader). All |
311 | * processes which were created before this point should be | 312 | * processes which were created before this point should be |
312 | * visible to zap_threads() because copy_process() adds the new | 313 | * visible to zap_threads() because copy_process() adds the new |
313 | * process to the tail of init_task.tasks list, and lock/unlock | 314 | * process to the tail of init_task.tasks list, and lock/unlock |
314 | * of ->siglock provides a memory barrier. | 315 | * of ->siglock provides a memory barrier. |
315 | * | 316 | * |
316 | * do_exit: | 317 | * do_exit: |
317 | * The caller holds mm->mmap_sem. This means that the task which | 318 | * The caller holds mm->mmap_sem. This means that the task which |
318 | * uses this mm can't pass exit_mm(), so it can't exit or clear | 319 | * uses this mm can't pass exit_mm(), so it can't exit or clear |
319 | * its ->mm. | 320 | * its ->mm. |
320 | * | 321 | * |
321 | * de_thread: | 322 | * de_thread: |
322 | * It does list_replace_rcu(&leader->tasks, ¤t->tasks), | 323 | * It does list_replace_rcu(&leader->tasks, ¤t->tasks), |
323 | * we must see either old or new leader, this does not matter. | 324 | * we must see either old or new leader, this does not matter. |
324 | * However, it can change p->sighand, so lock_task_sighand(p) | 325 | * However, it can change p->sighand, so lock_task_sighand(p) |
325 | * must be used. Since p->mm != NULL and we hold ->mmap_sem | 326 | * must be used. Since p->mm != NULL and we hold ->mmap_sem |
326 | * it can't fail. | 327 | * it can't fail. |
327 | * | 328 | * |
328 | * Note also that "g" can be the old leader with ->mm == NULL | 329 | * Note also that "g" can be the old leader with ->mm == NULL |
329 | * and already unhashed and thus removed from ->thread_group. | 330 | * and already unhashed and thus removed from ->thread_group. |
330 | * This is OK, __unhash_process()->list_del_rcu() does not | 331 | * This is OK, __unhash_process()->list_del_rcu() does not |
331 | * clear the ->next pointer, we will find the new leader via | 332 | * clear the ->next pointer, we will find the new leader via |
332 | * next_thread(). | 333 | * next_thread(). |
333 | */ | 334 | */ |
334 | rcu_read_lock(); | 335 | rcu_read_lock(); |
335 | for_each_process(g) { | 336 | for_each_process(g) { |
336 | if (g == tsk->group_leader) | 337 | if (g == tsk->group_leader) |
337 | continue; | 338 | continue; |
338 | if (g->flags & PF_KTHREAD) | 339 | if (g->flags & PF_KTHREAD) |
339 | continue; | 340 | continue; |
340 | p = g; | 341 | p = g; |
341 | do { | 342 | do { |
342 | if (p->mm) { | 343 | if (p->mm) { |
343 | if (unlikely(p->mm == mm)) { | 344 | if (unlikely(p->mm == mm)) { |
344 | lock_task_sighand(p, &flags); | 345 | lock_task_sighand(p, &flags); |
345 | nr += zap_process(p, exit_code); | 346 | nr += zap_process(p, exit_code); |
346 | p->signal->flags = SIGNAL_GROUP_EXIT; | 347 | p->signal->flags = SIGNAL_GROUP_EXIT; |
347 | unlock_task_sighand(p, &flags); | 348 | unlock_task_sighand(p, &flags); |
348 | } | 349 | } |
349 | break; | 350 | break; |
350 | } | 351 | } |
351 | } while_each_thread(g, p); | 352 | } while_each_thread(g, p); |
352 | } | 353 | } |
353 | rcu_read_unlock(); | 354 | rcu_read_unlock(); |
354 | done: | 355 | done: |
355 | atomic_set(&core_state->nr_threads, nr); | 356 | atomic_set(&core_state->nr_threads, nr); |
356 | return nr; | 357 | return nr; |
357 | } | 358 | } |
358 | 359 | ||
359 | static int coredump_wait(int exit_code, struct core_state *core_state) | 360 | static int coredump_wait(int exit_code, struct core_state *core_state) |
360 | { | 361 | { |
361 | struct task_struct *tsk = current; | 362 | struct task_struct *tsk = current; |
362 | struct mm_struct *mm = tsk->mm; | 363 | struct mm_struct *mm = tsk->mm; |
363 | int core_waiters = -EBUSY; | 364 | int core_waiters = -EBUSY; |
364 | 365 | ||
365 | init_completion(&core_state->startup); | 366 | init_completion(&core_state->startup); |
366 | core_state->dumper.task = tsk; | 367 | core_state->dumper.task = tsk; |
367 | core_state->dumper.next = NULL; | 368 | core_state->dumper.next = NULL; |
368 | 369 | ||
369 | down_write(&mm->mmap_sem); | 370 | down_write(&mm->mmap_sem); |
370 | if (!mm->core_state) | 371 | if (!mm->core_state) |
371 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); | 372 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); |
372 | up_write(&mm->mmap_sem); | 373 | up_write(&mm->mmap_sem); |
373 | 374 | ||
374 | if (core_waiters > 0) { | 375 | if (core_waiters > 0) { |
375 | struct core_thread *ptr; | 376 | struct core_thread *ptr; |
376 | 377 | ||
377 | wait_for_completion(&core_state->startup); | 378 | wait_for_completion(&core_state->startup); |
378 | /* | 379 | /* |
379 | * Wait for all the threads to become inactive, so that | 380 | * Wait for all the threads to become inactive, so that |
380 | * all the thread context (extended register state, like | 381 | * all the thread context (extended register state, like |
381 | * fpu etc) gets copied to the memory. | 382 | * fpu etc) gets copied to the memory. |
382 | */ | 383 | */ |
383 | ptr = core_state->dumper.next; | 384 | ptr = core_state->dumper.next; |
384 | while (ptr != NULL) { | 385 | while (ptr != NULL) { |
385 | wait_task_inactive(ptr->task, 0); | 386 | wait_task_inactive(ptr->task, 0); |
386 | ptr = ptr->next; | 387 | ptr = ptr->next; |
387 | } | 388 | } |
388 | } | 389 | } |
389 | 390 | ||
390 | return core_waiters; | 391 | return core_waiters; |
391 | } | 392 | } |
392 | 393 | ||
393 | static void coredump_finish(struct mm_struct *mm, bool core_dumped) | 394 | static void coredump_finish(struct mm_struct *mm, bool core_dumped) |
394 | { | 395 | { |
395 | struct core_thread *curr, *next; | 396 | struct core_thread *curr, *next; |
396 | struct task_struct *task; | 397 | struct task_struct *task; |
397 | 398 | ||
398 | spin_lock_irq(¤t->sighand->siglock); | 399 | spin_lock_irq(¤t->sighand->siglock); |
399 | if (core_dumped && !__fatal_signal_pending(current)) | 400 | if (core_dumped && !__fatal_signal_pending(current)) |
400 | current->signal->group_exit_code |= 0x80; | 401 | current->signal->group_exit_code |= 0x80; |
401 | current->signal->group_exit_task = NULL; | 402 | current->signal->group_exit_task = NULL; |
402 | current->signal->flags = SIGNAL_GROUP_EXIT; | 403 | current->signal->flags = SIGNAL_GROUP_EXIT; |
403 | spin_unlock_irq(¤t->sighand->siglock); | 404 | spin_unlock_irq(¤t->sighand->siglock); |
404 | 405 | ||
405 | next = mm->core_state->dumper.next; | 406 | next = mm->core_state->dumper.next; |
406 | while ((curr = next) != NULL) { | 407 | while ((curr = next) != NULL) { |
407 | next = curr->next; | 408 | next = curr->next; |
408 | task = curr->task; | 409 | task = curr->task; |
409 | /* | 410 | /* |
410 | * see exit_mm(), curr->task must not see | 411 | * see exit_mm(), curr->task must not see |
411 | * ->task == NULL before we read ->next. | 412 | * ->task == NULL before we read ->next. |
412 | */ | 413 | */ |
413 | smp_mb(); | 414 | smp_mb(); |
414 | curr->task = NULL; | 415 | curr->task = NULL; |
415 | wake_up_process(task); | 416 | wake_up_process(task); |
416 | } | 417 | } |
417 | 418 | ||
418 | mm->core_state = NULL; | 419 | mm->core_state = NULL; |
419 | } | 420 | } |
420 | 421 | ||
421 | static bool dump_interrupted(void) | 422 | static bool dump_interrupted(void) |
422 | { | 423 | { |
423 | /* | 424 | /* |
424 | * SIGKILL or freezing() interrupt the coredumping. Perhaps we | 425 | * SIGKILL or freezing() interrupt the coredumping. Perhaps we |
425 | * can do try_to_freeze() and check __fatal_signal_pending(), | 426 | * can do try_to_freeze() and check __fatal_signal_pending(), |
426 | * but then we need to teach dump_write() to restart and clear | 427 | * but then we need to teach dump_write() to restart and clear |
427 | * TIF_SIGPENDING. | 428 | * TIF_SIGPENDING. |
428 | */ | 429 | */ |
429 | return signal_pending(current); | 430 | return signal_pending(current); |
430 | } | 431 | } |
431 | 432 | ||
432 | static void wait_for_dump_helpers(struct file *file) | 433 | static void wait_for_dump_helpers(struct file *file) |
433 | { | 434 | { |
434 | struct pipe_inode_info *pipe; | 435 | struct pipe_inode_info *pipe; |
435 | 436 | ||
436 | pipe = file_inode(file)->i_pipe; | 437 | pipe = file_inode(file)->i_pipe; |
437 | 438 | ||
438 | pipe_lock(pipe); | 439 | pipe_lock(pipe); |
439 | pipe->readers++; | 440 | pipe->readers++; |
440 | pipe->writers--; | 441 | pipe->writers--; |
441 | 442 | ||
442 | while ((pipe->readers > 1) && (!signal_pending(current))) { | 443 | while ((pipe->readers > 1) && (!signal_pending(current))) { |
443 | wake_up_interruptible_sync(&pipe->wait); | 444 | wake_up_interruptible_sync(&pipe->wait); |
444 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); | 445 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
445 | pipe_wait(pipe); | 446 | pipe_wait(pipe); |
446 | } | 447 | } |
447 | 448 | ||
448 | pipe->readers--; | 449 | pipe->readers--; |
449 | pipe->writers++; | 450 | pipe->writers++; |
450 | pipe_unlock(pipe); | 451 | pipe_unlock(pipe); |
451 | 452 | ||
452 | } | 453 | } |
453 | 454 | ||
454 | /* | 455 | /* |
455 | * umh_pipe_setup | 456 | * umh_pipe_setup |
456 | * helper function to customize the process used | 457 | * helper function to customize the process used |
457 | * to collect the core in userspace. Specifically | 458 | * to collect the core in userspace. Specifically |
458 | * it sets up a pipe and installs it as fd 0 (stdin) | 459 | * it sets up a pipe and installs it as fd 0 (stdin) |
459 | * for the process. Returns 0 on success, or | 460 | * for the process. Returns 0 on success, or |
460 | * PTR_ERR on failure. | 461 | * PTR_ERR on failure. |
461 | * Note that it also sets the core limit to 1. This | 462 | * Note that it also sets the core limit to 1. This |
462 | * is a special value that we use to trap recursive | 463 | * is a special value that we use to trap recursive |
463 | * core dumps | 464 | * core dumps |
464 | */ | 465 | */ |
465 | static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) | 466 | static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) |
466 | { | 467 | { |
467 | struct file *files[2]; | 468 | struct file *files[2]; |
468 | struct coredump_params *cp = (struct coredump_params *)info->data; | 469 | struct coredump_params *cp = (struct coredump_params *)info->data; |
469 | int err = create_pipe_files(files, 0); | 470 | int err = create_pipe_files(files, 0); |
470 | if (err) | 471 | if (err) |
471 | return err; | 472 | return err; |
472 | 473 | ||
473 | cp->file = files[1]; | 474 | cp->file = files[1]; |
474 | 475 | ||
475 | err = replace_fd(0, files[0], 0); | 476 | err = replace_fd(0, files[0], 0); |
476 | fput(files[0]); | 477 | fput(files[0]); |
477 | /* and disallow core files too */ | 478 | /* and disallow core files too */ |
478 | current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; | 479 | current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; |
479 | 480 | ||
480 | return err; | 481 | return err; |
481 | } | 482 | } |
482 | 483 | ||
483 | void do_coredump(siginfo_t *siginfo) | 484 | void do_coredump(siginfo_t *siginfo) |
484 | { | 485 | { |
485 | struct core_state core_state; | 486 | struct core_state core_state; |
486 | struct core_name cn; | 487 | struct core_name cn; |
487 | struct mm_struct *mm = current->mm; | 488 | struct mm_struct *mm = current->mm; |
488 | struct linux_binfmt * binfmt; | 489 | struct linux_binfmt * binfmt; |
489 | const struct cred *old_cred; | 490 | const struct cred *old_cred; |
490 | struct cred *cred; | 491 | struct cred *cred; |
491 | int retval = 0; | 492 | int retval = 0; |
492 | int flag = 0; | 493 | int flag = 0; |
493 | int ispipe; | 494 | int ispipe; |
494 | struct files_struct *displaced; | 495 | struct files_struct *displaced; |
495 | bool need_nonrelative = false; | 496 | bool need_nonrelative = false; |
496 | bool core_dumped = false; | 497 | bool core_dumped = false; |
497 | static atomic_t core_dump_count = ATOMIC_INIT(0); | 498 | static atomic_t core_dump_count = ATOMIC_INIT(0); |
498 | struct coredump_params cprm = { | 499 | struct coredump_params cprm = { |
499 | .siginfo = siginfo, | 500 | .siginfo = siginfo, |
500 | .regs = signal_pt_regs(), | 501 | .regs = signal_pt_regs(), |
501 | .limit = rlimit(RLIMIT_CORE), | 502 | .limit = rlimit(RLIMIT_CORE), |
502 | /* | 503 | /* |
503 | * We must use the same mm->flags while dumping core to avoid | 504 | * We must use the same mm->flags while dumping core to avoid |
504 | * inconsistency of bit flags, since this flag is not protected | 505 | * inconsistency of bit flags, since this flag is not protected |
505 | * by any locks. | 506 | * by any locks. |
506 | */ | 507 | */ |
507 | .mm_flags = mm->flags, | 508 | .mm_flags = mm->flags, |
508 | }; | 509 | }; |
509 | 510 | ||
510 | audit_core_dumps(siginfo->si_signo); | 511 | audit_core_dumps(siginfo->si_signo); |
511 | 512 | ||
512 | binfmt = mm->binfmt; | 513 | binfmt = mm->binfmt; |
513 | if (!binfmt || !binfmt->core_dump) | 514 | if (!binfmt || !binfmt->core_dump) |
514 | goto fail; | 515 | goto fail; |
515 | if (!__get_dumpable(cprm.mm_flags)) | 516 | if (!__get_dumpable(cprm.mm_flags)) |
516 | goto fail; | 517 | goto fail; |
517 | 518 | ||
518 | cred = prepare_creds(); | 519 | cred = prepare_creds(); |
519 | if (!cred) | 520 | if (!cred) |
520 | goto fail; | 521 | goto fail; |
521 | /* | 522 | /* |
522 | * We cannot trust fsuid as being the "true" uid of the process | 523 | * We cannot trust fsuid as being the "true" uid of the process |
523 | * nor do we know its entire history. We only know it was tainted | 524 | * nor do we know its entire history. We only know it was tainted |
524 | * so we dump it as root in mode 2, and only into a controlled | 525 | * so we dump it as root in mode 2, and only into a controlled |
525 | * environment (pipe handler or fully qualified path). | 526 | * environment (pipe handler or fully qualified path). |
526 | */ | 527 | */ |
527 | if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { | 528 | if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { |
528 | /* Setuid core dump mode */ | 529 | /* Setuid core dump mode */ |
529 | flag = O_EXCL; /* Stop rewrite attacks */ | 530 | flag = O_EXCL; /* Stop rewrite attacks */ |
530 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ | 531 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ |
531 | need_nonrelative = true; | 532 | need_nonrelative = true; |
532 | } | 533 | } |
533 | 534 | ||
534 | retval = coredump_wait(siginfo->si_signo, &core_state); | 535 | retval = coredump_wait(siginfo->si_signo, &core_state); |
535 | if (retval < 0) | 536 | if (retval < 0) |
536 | goto fail_creds; | 537 | goto fail_creds; |
537 | 538 | ||
538 | old_cred = override_creds(cred); | 539 | old_cred = override_creds(cred); |
539 | 540 | ||
540 | ispipe = format_corename(&cn, &cprm); | 541 | ispipe = format_corename(&cn, &cprm); |
541 | 542 | ||
542 | if (ispipe) { | 543 | if (ispipe) { |
543 | int dump_count; | 544 | int dump_count; |
544 | char **helper_argv; | 545 | char **helper_argv; |
545 | struct subprocess_info *sub_info; | 546 | struct subprocess_info *sub_info; |
546 | 547 | ||
547 | if (ispipe < 0) { | 548 | if (ispipe < 0) { |
548 | printk(KERN_WARNING "format_corename failed\n"); | 549 | printk(KERN_WARNING "format_corename failed\n"); |
549 | printk(KERN_WARNING "Aborting core\n"); | 550 | printk(KERN_WARNING "Aborting core\n"); |
550 | goto fail_corename; | 551 | goto fail_corename; |
551 | } | 552 | } |
552 | 553 | ||
553 | if (cprm.limit == 1) { | 554 | if (cprm.limit == 1) { |
554 | /* See umh_pipe_setup() which sets RLIMIT_CORE = 1. | 555 | /* See umh_pipe_setup() which sets RLIMIT_CORE = 1. |
555 | * | 556 | * |
556 | * Normally core limits are irrelevant to pipes, since | 557 | * Normally core limits are irrelevant to pipes, since |
557 | * we're not writing to the file system, but we use | 558 | * we're not writing to the file system, but we use |
558 | * cprm.limit of 1 here as a speacial value, this is a | 559 | * cprm.limit of 1 here as a speacial value, this is a |
559 | * consistent way to catch recursive crashes. | 560 | * consistent way to catch recursive crashes. |
560 | * We can still crash if the core_pattern binary sets | 561 | * We can still crash if the core_pattern binary sets |
561 | * RLIM_CORE = !1, but it runs as root, and can do | 562 | * RLIM_CORE = !1, but it runs as root, and can do |
562 | * lots of stupid things. | 563 | * lots of stupid things. |
563 | * | 564 | * |
564 | * Note that we use task_tgid_vnr here to grab the pid | 565 | * Note that we use task_tgid_vnr here to grab the pid |
565 | * of the process group leader. That way we get the | 566 | * of the process group leader. That way we get the |
566 | * right pid if a thread in a multi-threaded | 567 | * right pid if a thread in a multi-threaded |
567 | * core_pattern process dies. | 568 | * core_pattern process dies. |
568 | */ | 569 | */ |
569 | printk(KERN_WARNING | 570 | printk(KERN_WARNING |
570 | "Process %d(%s) has RLIMIT_CORE set to 1\n", | 571 | "Process %d(%s) has RLIMIT_CORE set to 1\n", |
571 | task_tgid_vnr(current), current->comm); | 572 | task_tgid_vnr(current), current->comm); |
572 | printk(KERN_WARNING "Aborting core\n"); | 573 | printk(KERN_WARNING "Aborting core\n"); |
573 | goto fail_unlock; | 574 | goto fail_unlock; |
574 | } | 575 | } |
575 | cprm.limit = RLIM_INFINITY; | 576 | cprm.limit = RLIM_INFINITY; |
576 | 577 | ||
577 | dump_count = atomic_inc_return(&core_dump_count); | 578 | dump_count = atomic_inc_return(&core_dump_count); |
578 | if (core_pipe_limit && (core_pipe_limit < dump_count)) { | 579 | if (core_pipe_limit && (core_pipe_limit < dump_count)) { |
579 | printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", | 580 | printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", |
580 | task_tgid_vnr(current), current->comm); | 581 | task_tgid_vnr(current), current->comm); |
581 | printk(KERN_WARNING "Skipping core dump\n"); | 582 | printk(KERN_WARNING "Skipping core dump\n"); |
582 | goto fail_dropcount; | 583 | goto fail_dropcount; |
583 | } | 584 | } |
584 | 585 | ||
585 | helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL); | 586 | helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL); |
586 | if (!helper_argv) { | 587 | if (!helper_argv) { |
587 | printk(KERN_WARNING "%s failed to allocate memory\n", | 588 | printk(KERN_WARNING "%s failed to allocate memory\n", |
588 | __func__); | 589 | __func__); |
589 | goto fail_dropcount; | 590 | goto fail_dropcount; |
590 | } | 591 | } |
591 | 592 | ||
592 | retval = -ENOMEM; | 593 | retval = -ENOMEM; |
593 | sub_info = call_usermodehelper_setup(helper_argv[0], | 594 | sub_info = call_usermodehelper_setup(helper_argv[0], |
594 | helper_argv, NULL, GFP_KERNEL, | 595 | helper_argv, NULL, GFP_KERNEL, |
595 | umh_pipe_setup, NULL, &cprm); | 596 | umh_pipe_setup, NULL, &cprm); |
596 | if (sub_info) | 597 | if (sub_info) |
597 | retval = call_usermodehelper_exec(sub_info, | 598 | retval = call_usermodehelper_exec(sub_info, |
598 | UMH_WAIT_EXEC); | 599 | UMH_WAIT_EXEC); |
599 | 600 | ||
600 | argv_free(helper_argv); | 601 | argv_free(helper_argv); |
601 | if (retval) { | 602 | if (retval) { |
602 | printk(KERN_INFO "Core dump to %s pipe failed\n", | 603 | printk(KERN_INFO "Core dump to %s pipe failed\n", |
603 | cn.corename); | 604 | cn.corename); |
604 | goto close_fail; | 605 | goto close_fail; |
605 | } | 606 | } |
606 | } else { | 607 | } else { |
607 | struct inode *inode; | 608 | struct inode *inode; |
608 | 609 | ||
609 | if (cprm.limit < binfmt->min_coredump) | 610 | if (cprm.limit < binfmt->min_coredump) |
610 | goto fail_unlock; | 611 | goto fail_unlock; |
611 | 612 | ||
612 | if (need_nonrelative && cn.corename[0] != '/') { | 613 | if (need_nonrelative && cn.corename[0] != '/') { |
613 | printk(KERN_WARNING "Pid %d(%s) can only dump core "\ | 614 | printk(KERN_WARNING "Pid %d(%s) can only dump core "\ |
614 | "to fully qualified path!\n", | 615 | "to fully qualified path!\n", |
615 | task_tgid_vnr(current), current->comm); | 616 | task_tgid_vnr(current), current->comm); |
616 | printk(KERN_WARNING "Skipping core dump\n"); | 617 | printk(KERN_WARNING "Skipping core dump\n"); |
617 | goto fail_unlock; | 618 | goto fail_unlock; |
618 | } | 619 | } |
619 | 620 | ||
620 | cprm.file = filp_open(cn.corename, | 621 | cprm.file = filp_open(cn.corename, |
621 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, | 622 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, |
622 | 0600); | 623 | 0600); |
623 | if (IS_ERR(cprm.file)) | 624 | if (IS_ERR(cprm.file)) |
624 | goto fail_unlock; | 625 | goto fail_unlock; |
625 | 626 | ||
626 | inode = file_inode(cprm.file); | 627 | inode = file_inode(cprm.file); |
627 | if (inode->i_nlink > 1) | 628 | if (inode->i_nlink > 1) |
628 | goto close_fail; | 629 | goto close_fail; |
629 | if (d_unhashed(cprm.file->f_path.dentry)) | 630 | if (d_unhashed(cprm.file->f_path.dentry)) |
630 | goto close_fail; | 631 | goto close_fail; |
631 | /* | 632 | /* |
632 | * AK: actually i see no reason to not allow this for named | 633 | * AK: actually i see no reason to not allow this for named |
633 | * pipes etc, but keep the previous behaviour for now. | 634 | * pipes etc, but keep the previous behaviour for now. |
634 | */ | 635 | */ |
635 | if (!S_ISREG(inode->i_mode)) | 636 | if (!S_ISREG(inode->i_mode)) |
636 | goto close_fail; | 637 | goto close_fail; |
637 | /* | 638 | /* |
638 | * Dont allow local users get cute and trick others to coredump | 639 | * Dont allow local users get cute and trick others to coredump |
639 | * into their pre-created files. | 640 | * into their pre-created files. |
640 | */ | 641 | */ |
641 | if (!uid_eq(inode->i_uid, current_fsuid())) | 642 | if (!uid_eq(inode->i_uid, current_fsuid())) |
642 | goto close_fail; | 643 | goto close_fail; |
643 | if (!cprm.file->f_op || !cprm.file->f_op->write) | 644 | if (!cprm.file->f_op || !cprm.file->f_op->write) |
644 | goto close_fail; | 645 | goto close_fail; |
645 | if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file)) | 646 | if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file)) |
646 | goto close_fail; | 647 | goto close_fail; |
647 | } | 648 | } |
648 | 649 | ||
649 | /* get us an unshared descriptor table; almost always a no-op */ | 650 | /* get us an unshared descriptor table; almost always a no-op */ |
650 | retval = unshare_files(&displaced); | 651 | retval = unshare_files(&displaced); |
651 | if (retval) | 652 | if (retval) |
652 | goto close_fail; | 653 | goto close_fail; |
653 | if (displaced) | 654 | if (displaced) |
654 | put_files_struct(displaced); | 655 | put_files_struct(displaced); |
655 | core_dumped = !dump_interrupted() && binfmt->core_dump(&cprm); | 656 | core_dumped = !dump_interrupted() && binfmt->core_dump(&cprm); |
656 | 657 | ||
657 | if (ispipe && core_pipe_limit) | 658 | if (ispipe && core_pipe_limit) |
658 | wait_for_dump_helpers(cprm.file); | 659 | wait_for_dump_helpers(cprm.file); |
659 | close_fail: | 660 | close_fail: |
660 | if (cprm.file) | 661 | if (cprm.file) |
661 | filp_close(cprm.file, NULL); | 662 | filp_close(cprm.file, NULL); |
662 | fail_dropcount: | 663 | fail_dropcount: |
663 | if (ispipe) | 664 | if (ispipe) |
664 | atomic_dec(&core_dump_count); | 665 | atomic_dec(&core_dump_count); |
665 | fail_unlock: | 666 | fail_unlock: |
666 | kfree(cn.corename); | 667 | kfree(cn.corename); |
667 | fail_corename: | 668 | fail_corename: |
668 | coredump_finish(mm, core_dumped); | 669 | coredump_finish(mm, core_dumped); |
669 | revert_creds(old_cred); | 670 | revert_creds(old_cred); |
670 | fail_creds: | 671 | fail_creds: |
671 | put_cred(cred); | 672 | put_cred(cred); |
672 | fail: | 673 | fail: |
673 | return; | 674 | return; |
674 | } | 675 | } |
675 | 676 | ||
676 | /* | 677 | /* |
677 | * Core dumping helper functions. These are the only things you should | 678 | * Core dumping helper functions. These are the only things you should |
678 | * do on a core-file: use only these functions to write out all the | 679 | * do on a core-file: use only these functions to write out all the |
679 | * necessary info. | 680 | * necessary info. |
680 | */ | 681 | */ |
681 | int dump_write(struct file *file, const void *addr, int nr) | 682 | int dump_write(struct file *file, const void *addr, int nr) |
682 | { | 683 | { |
683 | return !dump_interrupted() && | 684 | return !dump_interrupted() && |
684 | access_ok(VERIFY_READ, addr, nr) && | 685 | access_ok(VERIFY_READ, addr, nr) && |
685 | file->f_op->write(file, addr, nr, &file->f_pos) == nr; | 686 | file->f_op->write(file, addr, nr, &file->f_pos) == nr; |
686 | } | 687 | } |
687 | EXPORT_SYMBOL(dump_write); | 688 | EXPORT_SYMBOL(dump_write); |
688 | 689 | ||
689 | int dump_seek(struct file *file, loff_t off) | 690 | int dump_seek(struct file *file, loff_t off) |
690 | { | 691 | { |
691 | int ret = 1; | 692 | int ret = 1; |
692 | 693 | ||
693 | if (file->f_op->llseek && file->f_op->llseek != no_llseek) { | 694 | if (file->f_op->llseek && file->f_op->llseek != no_llseek) { |
694 | if (dump_interrupted() || | 695 | if (dump_interrupted() || |
695 | file->f_op->llseek(file, off, SEEK_CUR) < 0) | 696 | file->f_op->llseek(file, off, SEEK_CUR) < 0) |
696 | return 0; | 697 | return 0; |
697 | } else { | 698 | } else { |
698 | char *buf = (char *)get_zeroed_page(GFP_KERNEL); | 699 | char *buf = (char *)get_zeroed_page(GFP_KERNEL); |
699 | 700 | ||
700 | if (!buf) | 701 | if (!buf) |
701 | return 0; | 702 | return 0; |
702 | while (off > 0) { | 703 | while (off > 0) { |
703 | unsigned long n = off; | 704 | unsigned long n = off; |
704 | 705 | ||
705 | if (n > PAGE_SIZE) | 706 | if (n > PAGE_SIZE) |
706 | n = PAGE_SIZE; | 707 | n = PAGE_SIZE; |
707 | if (!dump_write(file, buf, n)) { | 708 | if (!dump_write(file, buf, n)) { |
708 | ret = 0; | 709 | ret = 0; |
709 | break; | 710 | break; |
710 | } | 711 | } |
711 | off -= n; | 712 | off -= n; |
712 | } | 713 | } |
713 | free_page((unsigned long)buf); | 714 | free_page((unsigned long)buf); |
714 | } | 715 | } |
715 | return ret; | 716 | return ret; |
716 | } | 717 | } |
717 | EXPORT_SYMBOL(dump_seek); | 718 | EXPORT_SYMBOL(dump_seek); |
718 | 719 |
-
mentioned in commit 1e6be3
-
mentioned in commit f5eef0
-
mentioned in commit f5eef0
-
mentioned in commit f5eef0
-
mentioned in commit f5eef0
-
mentioned in commit f5eef0
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad
-
mentioned in commit aed8ad