Commit | Line | Data |
---|---|---|
8c0dbd1c KB |
1 | /*- |
2 | * Copyright (c) 1982, 1986, 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
8c0dbd1c KB |
5 | * %sccs.include.proprietary.c% |
6 | * | |
2881f082 | 7 | * @(#)kern_exec.c 7.74 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
28db9b87 | 9 | |
38a01dbe KB |
10 | #include <sys/param.h> |
11 | #include <sys/systm.h> | |
12 | #include <sys/filedesc.h> | |
13 | #include <sys/kernel.h> | |
14 | #include <sys/proc.h> | |
15 | #include <sys/mount.h> | |
16 | #include <sys/malloc.h> | |
17 | #include <sys/namei.h> | |
18 | #include <sys/vnode.h> | |
19 | #include <sys/file.h> | |
20 | #include <sys/acct.h> | |
21 | #include <sys/exec.h> | |
22 | #include <sys/ktrace.h> | |
23 | #include <sys/resourcevar.h> | |
28db9b87 | 24 | |
38a01dbe KB |
25 | #include <machine/cpu.h> |
26 | #include <machine/reg.h> | |
d301d150 | 27 | |
38a01dbe KB |
28 | #include <sys/mman.h> |
29 | #include <vm/vm.h> | |
30 | #include <vm/vm_param.h> | |
31 | #include <vm/vm_map.h> | |
32 | #include <vm/vm_kern.h> | |
33 | #include <vm/vm_pager.h> | |
9d4095a1 | 34 | |
38a01dbe | 35 | #include <sys/signalvar.h> |
605f1ab4 | 36 | |
93422d4b | 37 | #ifdef HPUXCOMPAT |
38a01dbe KB |
38 | #include <sys/user.h> /* for pcb */ |
39 | #include <hp/hpux/hpux_exec.h> | |
93422d4b KM |
40 | #endif |
41 | ||
75a969a7 MK |
42 | #ifdef COPY_SIGCODE |
43 | extern char sigcode[], esigcode[]; | |
44 | #define szsigcode (esigcode - sigcode) | |
45 | #else | |
46 | #define szsigcode 0 | |
47 | #endif | |
48 | ||
8429d022 MK |
49 | /* |
50 | * exec system call | |
51 | */ | |
9e97623a CT |
52 | struct execve_args { |
53 | char *fname; | |
54 | char **argp; | |
55 | char **envp; | |
56 | }; | |
c9714ae3 KM |
57 | /* ARGSUSED */ |
58 | execve(p, uap, retval) | |
59 | register struct proc *p; | |
9e97623a | 60 | register struct execve_args *uap; |
c9714ae3 | 61 | int *retval; |
28db9b87 | 62 | { |
8429d022 | 63 | register struct ucred *cred = p->p_ucred; |
5e00df3b | 64 | register struct filedesc *fdp = p->p_fd; |
0a5745b2 | 65 | int na, ne, ucp, ap, cc, ssize; |
5e00df3b KM |
66 | register char *cp; |
67 | register int nc; | |
8011f5df | 68 | unsigned len; |
28db9b87 SL |
69 | int indir, uid, gid; |
70 | char *sharg; | |
c4ec2128 | 71 | struct vnode *vp; |
34dc7acb | 72 | int resid, error, paged = 0; |
f0729cac | 73 | vm_offset_t execargs = 0; |
c4ec2128 | 74 | struct vattr vattr; |
cb9392ae | 75 | char cfarg[MAXINTERP]; |
9fd50f35 | 76 | union { |
cb9392ae | 77 | char ex_shell[MAXINTERP]; /* #! and interpreter name */ |
9fd50f35 | 78 | struct exec ex_exec; |
93422d4b KM |
79 | #ifdef HPUXCOMPAT |
80 | struct hpux_exec ex_hexec; | |
81 | #endif | |
9fd50f35 | 82 | } exdata; |
93422d4b KM |
83 | #ifdef HPUXCOMPAT |
84 | struct hpux_exec hhead; | |
85 | #endif | |
8429d022 | 86 | struct nameidata nd; |
29075cfd | 87 | struct ps_strings ps; |
ec67a3ce MK |
88 | #ifdef SECSIZE |
89 | extern long argdbsize; /* XXX */ | |
90 | #endif SECSIZE | |
28db9b87 | 91 | |
2881f082 | 92 | NDINIT(&nd, LOOKUP, FOLLOW | SAVENAME, UIO_USERSPACE, |
62ce54a4 KM |
93 | uap->fname, p); |
94 | if (error = namei(&nd)) | |
d9c2f47f | 95 | return (error); |
62ce54a4 | 96 | vp = nd.ni_vp; |
2881f082 KM |
97 | LEASE_CHECK(vp, p, cred, LEASE_READ); |
98 | VOP_LOCK(vp); | |
28db9b87 | 99 | indir = 0; |
c9714ae3 KM |
100 | uid = cred->cr_uid; |
101 | gid = cred->cr_gid; | |
f254ddb7 | 102 | if (error = VOP_GETATTR(vp, &vattr, cred, p)) |
c4ec2128 | 103 | goto bad; |
54fb9dc2 | 104 | if (vp->v_mount->mnt_flag & MNT_NOEXEC) { |
c9714ae3 | 105 | error = EACCES; |
c4ec2128 KM |
106 | goto bad; |
107 | } | |
54fb9dc2 | 108 | if ((vp->v_mount->mnt_flag & MNT_NOSUID) == 0) { |
c4ec2128 KM |
109 | if (vattr.va_mode & VSUID) |
110 | uid = vattr.va_uid; | |
111 | if (vattr.va_mode & VSGID) | |
112 | gid = vattr.va_gid; | |
113 | } | |
28db9b87 SL |
114 | |
115 | again: | |
f254ddb7 | 116 | if (error = VOP_ACCESS(vp, VEXEC, cred, p)) |
28db9b87 | 117 | goto bad; |
f254ddb7 | 118 | if ((p->p_flag & STRC) && (error = VOP_ACCESS(vp, VREAD, cred, p))) |
28db9b87 | 119 | goto bad; |
c4ec2128 KM |
120 | if (vp->v_type != VREG || |
121 | (vattr.va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) { | |
c9714ae3 | 122 | error = EACCES; |
28db9b87 SL |
123 | goto bad; |
124 | } | |
125 | ||
126 | /* | |
f3aaea26 | 127 | * Read in first few bytes of file for segment sizes, magic number: |
c4ec2128 KM |
128 | * OMAGIC = plain executable |
129 | * NMAGIC = RO text | |
130 | * ZMAGIC = demand paged RO text | |
28db9b87 SL |
131 | * Also an ASCII line beginning with #! is |
132 | * the file name of a ``shell'' and arguments may be prepended | |
133 | * to the argument list if given here. | |
134 | * | |
135 | * SHELL NAMES ARE LIMITED IN LENGTH. | |
136 | * | |
137 | * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM | |
138 | * THE ASCII LINE. | |
139 | */ | |
9fd50f35 | 140 | exdata.ex_shell[0] = '\0'; /* for zero length files */ |
c9714ae3 | 141 | error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata), |
f254ddb7 KM |
142 | (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &resid, |
143 | (struct proc *)0); | |
c9714ae3 | 144 | if (error) |
28db9b87 | 145 | goto bad; |
28db9b87 | 146 | #ifndef lint |
ce66cb03 | 147 | if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) && |
9fd50f35 | 148 | exdata.ex_shell[0] != '#') { |
c9714ae3 | 149 | error = ENOEXEC; |
28db9b87 SL |
150 | goto bad; |
151 | } | |
93422d4b | 152 | #endif |
96e7b0e1 | 153 | #if defined(hp300) || defined(luna68k) |
93422d4b KM |
154 | switch ((int)exdata.ex_exec.a_mid) { |
155 | ||
156 | /* | |
157 | * An ancient hp200 or hp300 binary, shouldn't happen anymore. | |
158 | * Mark as invalid. | |
159 | */ | |
160 | case MID_ZERO: | |
161 | exdata.ex_exec.a_magic = 0; | |
162 | break; | |
163 | ||
164 | /* | |
165 | * HP200 series has a smaller page size so we cannot | |
166 | * demand-load or even write protect text, so we just | |
167 | * treat as OMAGIC. | |
168 | */ | |
169 | case MID_HP200: | |
170 | exdata.ex_exec.a_magic = OMAGIC; | |
171 | break; | |
172 | ||
173 | case MID_HP300: | |
174 | break; | |
175 | ||
176 | #ifdef HPUXCOMPAT | |
177 | case MID_HPUX: | |
178 | /* | |
179 | * Save a.out header. This is eventually saved in the pcb, | |
180 | * but we cannot do that yet in case the exec fails before | |
181 | * the image is overlayed. | |
182 | */ | |
183 | bcopy((caddr_t)&exdata.ex_hexec, | |
184 | (caddr_t)&hhead, sizeof hhead); | |
93422d4b KM |
185 | /* |
186 | * Shuffle important fields to their BSD locations. | |
187 | * Note that the order in which this is done is important. | |
188 | */ | |
189 | exdata.ex_exec.a_text = exdata.ex_hexec.ha_text; | |
190 | exdata.ex_exec.a_data = exdata.ex_hexec.ha_data; | |
191 | exdata.ex_exec.a_bss = exdata.ex_hexec.ha_bss; | |
192 | exdata.ex_exec.a_entry = exdata.ex_hexec.ha_entry; | |
193 | /* | |
194 | * For ZMAGIC files, make sizes consistant with those | |
195 | * generated by BSD ld. | |
196 | */ | |
197 | if (exdata.ex_exec.a_magic == ZMAGIC) { | |
198 | exdata.ex_exec.a_text = | |
199 | ctob(btoc(exdata.ex_exec.a_text)); | |
200 | nc = exdata.ex_exec.a_data + exdata.ex_exec.a_bss; | |
201 | exdata.ex_exec.a_data = | |
202 | ctob(btoc(exdata.ex_exec.a_data)); | |
203 | nc -= (int)exdata.ex_exec.a_data; | |
204 | exdata.ex_exec.a_bss = (nc < 0) ? 0 : nc; | |
205 | } | |
206 | break; | |
207 | #endif | |
208 | } | |
28db9b87 | 209 | #endif |
aec7dd3b | 210 | switch ((int)exdata.ex_exec.a_magic) { |
28db9b87 | 211 | |
c4ec2128 | 212 | case OMAGIC: |
f0729cac RC |
213 | #ifdef COFF |
214 | if (exdata.ex_exec.ex_fhdr.magic != COFF_MAGIC) { | |
215 | error = ENOEXEC; | |
216 | goto bad; | |
217 | } | |
0a5745b2 CT |
218 | #endif |
219 | #ifdef sparc | |
220 | if (exdata.ex_exec.a_mid != MID_SUN_SPARC) { | |
221 | error = ENOEXEC; | |
222 | goto bad; | |
223 | } | |
f0729cac | 224 | #endif |
9fd50f35 SL |
225 | exdata.ex_exec.a_data += exdata.ex_exec.a_text; |
226 | exdata.ex_exec.a_text = 0; | |
28db9b87 SL |
227 | break; |
228 | ||
c4ec2128 | 229 | case ZMAGIC: |
0a5745b2 | 230 | paged = 1; |
34dc7acb | 231 | /* FALLTHROUGH */ |
0a5745b2 | 232 | |
c4ec2128 | 233 | case NMAGIC: |
f0729cac RC |
234 | #ifdef COFF |
235 | if (exdata.ex_exec.ex_fhdr.magic != COFF_MAGIC) { | |
236 | error = ENOEXEC; | |
237 | goto bad; | |
238 | } | |
0a5745b2 CT |
239 | #endif |
240 | #ifdef sparc | |
241 | if (exdata.ex_exec.a_mid != MID_SUN_SPARC) { | |
242 | error = ENOEXEC; | |
243 | goto bad; | |
244 | } | |
f0729cac | 245 | #endif |
9fd50f35 | 246 | if (exdata.ex_exec.a_text == 0) { |
c9714ae3 | 247 | error = ENOEXEC; |
28db9b87 SL |
248 | goto bad; |
249 | } | |
250 | break; | |
251 | ||
252 | default: | |
446115cb MK |
253 | if (exdata.ex_shell[0] != '#' || |
254 | exdata.ex_shell[1] != '!' || | |
255 | indir) { | |
c9714ae3 | 256 | error = ENOEXEC; |
28db9b87 SL |
257 | goto bad; |
258 | } | |
d26813a4 | 259 | for (cp = &exdata.ex_shell[2];; ++cp) { |
446115cb | 260 | if (cp >= &exdata.ex_shell[MAXINTERP]) { |
c9714ae3 | 261 | error = ENOEXEC; |
d26813a4 KB |
262 | goto bad; |
263 | } | |
264 | if (*cp == '\n') { | |
28db9b87 SL |
265 | *cp = '\0'; |
266 | break; | |
267 | } | |
d26813a4 KB |
268 | if (*cp == '\t') |
269 | *cp = ' '; | |
28db9b87 | 270 | } |
446115cb MK |
271 | cp = &exdata.ex_shell[2]; |
272 | while (*cp == ' ') | |
273 | cp++; | |
62ce54a4 | 274 | nd.ni_dirp = cp; |
446115cb MK |
275 | while (*cp && *cp != ' ') |
276 | cp++; | |
e7db1101 | 277 | cfarg[0] = '\0'; |
28db9b87 | 278 | if (*cp) { |
446115cb MK |
279 | *cp++ = '\0'; |
280 | while (*cp == ' ') | |
281 | cp++; | |
ce66cb03 | 282 | if (*cp) |
cb9392ae | 283 | bcopy((caddr_t)cp, (caddr_t)cfarg, MAXINTERP); |
e7db1101 | 284 | } |
446115cb | 285 | indir = 1; |
c4ec2128 | 286 | vput(vp); |
62ce54a4 KM |
287 | nd.ni_segflg = UIO_SYSSPACE; |
288 | if (error = namei(&nd)) | |
d9c2f47f | 289 | return (error); |
62ce54a4 | 290 | vp = nd.ni_vp; |
f254ddb7 | 291 | if (error = VOP_GETATTR(vp, &vattr, cred, p)) |
c4ec2128 | 292 | goto bad; |
c9714ae3 KM |
293 | uid = cred->cr_uid; /* shell scripts can't be setuid */ |
294 | gid = cred->cr_gid; | |
28db9b87 SL |
295 | goto again; |
296 | } | |
297 | ||
298 | /* | |
299 | * Collect arguments on "file" in swap space. | |
300 | */ | |
301 | na = 0; | |
302 | ne = 0; | |
303 | nc = 0; | |
9d4095a1 KM |
304 | cc = NCARGS; |
305 | execargs = kmem_alloc_wait(exec_map, NCARGS); | |
f0729cac RC |
306 | #ifdef DIAGNOSTIC |
307 | if (execargs == (vm_offset_t)0) | |
308 | panic("execve: kmem_alloc_wait"); | |
309 | #endif | |
9d4095a1 | 310 | cp = (char *) execargs; |
f3aaea26 SL |
311 | /* |
312 | * Copy arguments into file in argdev area. | |
313 | */ | |
28db9b87 SL |
314 | if (uap->argp) for (;;) { |
315 | ap = NULL; | |
ce66cb03 MK |
316 | sharg = NULL; |
317 | if (indir && na == 0) { | |
62ce54a4 | 318 | sharg = nd.ni_cnd.cn_nameptr; |
ce66cb03 MK |
319 | ap = (int)sharg; |
320 | uap->argp++; /* ignore argv[0] */ | |
321 | } else if (indir && (na == 1 && cfarg[0])) { | |
322 | sharg = cfarg; | |
323 | ap = (int)sharg; | |
324 | } else if (indir && (na == 1 || na == 2 && cfarg[0])) | |
28db9b87 SL |
325 | ap = (int)uap->fname; |
326 | else if (uap->argp) { | |
327 | ap = fuword((caddr_t)uap->argp); | |
328 | uap->argp++; | |
329 | } | |
f3aaea26 | 330 | if (ap == NULL && uap->envp) { |
28db9b87 | 331 | uap->argp = NULL; |
f3aaea26 SL |
332 | if ((ap = fuword((caddr_t)uap->envp)) != NULL) |
333 | uap->envp++, ne++; | |
28db9b87 SL |
334 | } |
335 | if (ap == NULL) | |
336 | break; | |
337 | na++; | |
f3aaea26 | 338 | if (ap == -1) { |
c9714ae3 | 339 | error = EFAULT; |
9d4095a1 | 340 | goto bad; |
f3aaea26 | 341 | } |
28db9b87 | 342 | do { |
9d4095a1 KM |
343 | if (nc >= NCARGS-1) { |
344 | error = E2BIG; | |
345 | break; | |
28db9b87 | 346 | } |
ce66cb03 | 347 | if (sharg) { |
8011f5df | 348 | error = copystr(sharg, cp, (unsigned)cc, &len); |
ce66cb03 MK |
349 | sharg += len; |
350 | } else { | |
8011f5df MK |
351 | error = copyinstr((caddr_t)ap, cp, (unsigned)cc, |
352 | &len); | |
ce66cb03 MK |
353 | ap += len; |
354 | } | |
f3aaea26 SL |
355 | cp += len; |
356 | nc += len; | |
357 | cc -= len; | |
9e73a4eb | 358 | } while (error == ENAMETOOLONG); |
9d4095a1 KM |
359 | if (error) |
360 | goto bad; | |
28db9b87 | 361 | } |
0a5745b2 CT |
362 | |
363 | /* | |
364 | * XXX the following is excessively bogus | |
365 | * | |
366 | * Compute initial process stack size and location of argc | |
367 | * and character strings. `nc' is currently just the number | |
368 | * of characters of arg and env strings. | |
369 | * | |
29075cfd KM |
370 | * nc = size of ps_strings structure + |
371 | * size of signal code + | |
372 | * 4 bytes of NULL pointer + | |
373 | * nc, | |
374 | * rounded to nearest integer; | |
0a5745b2 CT |
375 | * ucp = USRSTACK - nc; [user characters pointer] |
376 | * apsize = padding (if any) + | |
377 | * 4 bytes of NULL pointer + | |
378 | * ne 4-byte pointers to env strings + | |
379 | * 4 bytes of NULL pointer + | |
380 | * (na-ne) 4-byte pointers to arg strings + | |
381 | * 4 bytes of argc; | |
382 | * (this is the same as nc + (na+3)*4) | |
383 | * ap = ucp - apsize; [user address of argc] | |
384 | * ssize = ssize + nc + machine-dependent space; | |
385 | */ | |
29075cfd | 386 | nc = (sizeof(ps) + szsigcode + 4 + nc + NBPW-1) & ~(NBPW - 1); |
e74c0572 | 387 | #if defined(sparc) || defined(mips) |
0a5745b2 | 388 | ucp = USRSTACK; |
e74c0572 | 389 | ssize = ALIGN(nc + (na + 3) * NBPW); |
0a5745b2 CT |
390 | ap = ucp - ssize; |
391 | ucp -= nc; | |
e74c0572 | 392 | #ifdef sparc |
0a5745b2 | 393 | ssize += sizeof(struct rwindow); |
e74c0572 | 394 | #endif |
0a5745b2 CT |
395 | #else |
396 | ssize = (na + 3) * NBPW; | |
397 | ucp = USRSTACK - nc; | |
398 | ap = ucp - ssize; | |
399 | ssize += nc; | |
400 | #endif | |
401 | error = getxfile(p, vp, &exdata.ex_exec, paged, ssize, uid, gid); | |
9d4095a1 | 402 | if (error) |
28db9b87 | 403 | goto bad; |
c4ec2128 KM |
404 | vput(vp); |
405 | vp = NULL; | |
28db9b87 | 406 | |
93422d4b KM |
407 | #ifdef HPUXCOMPAT |
408 | /* | |
409 | * We are now committed to the exec so we can save the exec | |
410 | * header in the pcb where we can dump it if necessary in core() | |
411 | */ | |
9921f05f | 412 | if (p->p_md.md_flags & MDP_HPUX) |
93422d4b | 413 | bcopy((caddr_t)&hhead, |
9921f05f | 414 | (caddr_t)p->p_addr->u_md.md_exec, sizeof hhead); |
93422d4b KM |
415 | #endif |
416 | ||
28db9b87 | 417 | /* |
f3aaea26 | 418 | * Copy back arglist. |
28db9b87 | 419 | */ |
09936ccc | 420 | cpu_setstack(p, ap); |
28db9b87 SL |
421 | (void) suword((caddr_t)ap, na-ne); |
422 | nc = 0; | |
9d4095a1 KM |
423 | cp = (char *) execargs; |
424 | cc = NCARGS; | |
29075cfd KM |
425 | ps.ps_argvstr = (char *)ucp; /* first argv string */ |
426 | ps.ps_nargvstr = na - ne; /* argc */ | |
28db9b87 SL |
427 | for (;;) { |
428 | ap += NBPW; | |
f3aaea26 | 429 | if (na == ne) { |
28db9b87 SL |
430 | (void) suword((caddr_t)ap, 0); |
431 | ap += NBPW; | |
29075cfd KM |
432 | ps.ps_envstr = (char *)ucp; |
433 | ps.ps_nenvstr = ne; | |
28db9b87 SL |
434 | } |
435 | if (--na < 0) | |
436 | break; | |
437 | (void) suword((caddr_t)ap, ucp); | |
438 | do { | |
8011f5df MK |
439 | error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc, |
440 | &len); | |
72d4f41a SL |
441 | ucp += len; |
442 | cp += len; | |
443 | nc += len; | |
444 | cc -= len; | |
9e73a4eb | 445 | } while (error == ENAMETOOLONG); |
72d4f41a SL |
446 | if (error == EFAULT) |
447 | panic("exec: EFAULT"); | |
28db9b87 SL |
448 | } |
449 | (void) suword((caddr_t)ap, 0); | |
29075cfd | 450 | (void) copyout((caddr_t)&ps, (caddr_t)PS_STRINGS, sizeof(ps)); |
ce66cb03 | 451 | |
c9714ae3 | 452 | execsigs(p); |
ce66cb03 | 453 | |
5e00df3b | 454 | for (nc = fdp->fd_lastfile; nc >= 0; --nc) { |
605f1ab4 MK |
455 | if (fdp->fd_ofileflags[nc] & UF_EXCLOSE) { |
456 | (void) closef(fdp->fd_ofiles[nc], p); | |
457 | fdp->fd_ofiles[nc] = NULL; | |
458 | fdp->fd_ofileflags[nc] = 0; | |
8429d022 MK |
459 | if (nc < fdp->fd_freefile) |
460 | fdp->fd_freefile = nc; | |
ce66cb03 | 461 | } |
605f1ab4 | 462 | fdp->fd_ofileflags[nc] &= ~UF_MAPPED; |
ce66cb03 | 463 | } |
605f1ab4 MK |
464 | /* |
465 | * Adjust fd_lastfile to account for descriptors closed above. | |
466 | * Don't decrement fd_lastfile past 0, as it's unsigned. | |
467 | */ | |
468 | while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) | |
5e00df3b | 469 | fdp->fd_lastfile--; |
54955369 | 470 | setregs(p, exdata.ex_exec.a_entry, retval); |
75a969a7 | 471 | #ifdef COPY_SIGCODE |
9d4095a1 KM |
472 | /* |
473 | * Install sigcode at top of user stack. | |
474 | */ | |
29075cfd | 475 | copyout((caddr_t)sigcode, (caddr_t)PS_STRINGS - szsigcode, szsigcode); |
75a969a7 | 476 | #endif |
715baff1 KM |
477 | /* |
478 | * Remember file name for accounting. | |
479 | */ | |
8429d022 | 480 | p->p_acflag &= ~AFORK; |
62ce54a4 KM |
481 | if (nd.ni_cnd.cn_namelen > MAXCOMLEN) |
482 | nd.ni_cnd.cn_namelen = MAXCOMLEN; | |
483 | bcopy((caddr_t)nd.ni_cnd.cn_nameptr, (caddr_t)p->p_comm, | |
0a5745b2 | 484 | (unsigned)nd.ni_cnd.cn_namelen); |
62ce54a4 | 485 | p->p_comm[nd.ni_cnd.cn_namelen] = '\0'; |
75a969a7 | 486 | cpu_exec(p); |
28db9b87 | 487 | bad: |
62ce54a4 | 488 | FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); |
9d4095a1 KM |
489 | if (execargs) |
490 | kmem_free_wakeup(exec_map, execargs, NCARGS); | |
ec67a3ce | 491 | #endif SECSIZE |
c4ec2128 KM |
492 | if (vp) |
493 | vput(vp); | |
d9c2f47f | 494 | return (error); |
28db9b87 SL |
495 | } |
496 | ||
497 | /* | |
498 | * Read in and set up memory for executed file. | |
499 | */ | |
0a5745b2 | 500 | getxfile(p, vp, ep, paged, ssize, uid, gid) |
c9714ae3 | 501 | register struct proc *p; |
c4ec2128 | 502 | register struct vnode *vp; |
9fd50f35 | 503 | register struct exec *ep; |
0a5745b2 | 504 | int paged, ssize, uid, gid; |
28db9b87 | 505 | { |
8429d022 | 506 | register struct ucred *cred = p->p_ucred; |
0a5745b2 CT |
507 | register struct vmspace *vm = p->p_vmspace; |
508 | vm_offset_t addr; | |
509 | vm_size_t xts, size; | |
510 | segsz_t ds; | |
93422d4b | 511 | off_t toff; |
9d4095a1 | 512 | int error = 0; |
28db9b87 | 513 | |
93422d4b | 514 | #ifdef HPUXCOMPAT |
d59f854f KM |
515 | if (ep->a_mid == MID_HPUX) |
516 | toff = paged ? CLBYTES : sizeof(struct hpux_exec); | |
517 | else | |
93422d4b | 518 | #endif |
f0729cac RC |
519 | #ifdef COFF |
520 | toff = N_TXTOFF(*ep); | |
521 | #else | |
0a5745b2 CT |
522 | #ifdef sparc |
523 | if (ep->a_mid == MID_SUN_SPARC) | |
524 | toff = paged ? 0 : sizeof(struct exec); | |
525 | else | |
526 | #endif | |
34dc7acb | 527 | if (paged) |
1a7b5528 RC |
528 | #ifdef mips |
529 | toff = 0; | |
530 | #else | |
9d4095a1 | 531 | toff = CLBYTES; |
1a7b5528 | 532 | #endif |
9d4095a1 KM |
533 | else |
534 | toff = sizeof (struct exec); | |
f0729cac | 535 | #endif |
c4ec2128 | 536 | if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 && |
82177e7b KM |
537 | vp->v_writecount != 0) |
538 | return (ETXTBSY); | |
28db9b87 SL |
539 | |
540 | /* | |
541 | * Compute text and data sizes and make sure not too large. | |
0a5745b2 CT |
542 | * Text size is rounded to an ``ld page''; data+bss is left |
543 | * in machine pages. Check data and bss separately as they | |
544 | * may overflow when summed together. (XXX not done yet) | |
28db9b87 | 545 | */ |
0a5745b2 | 546 | xts = roundup(ep->a_text, __LDPGSZ); |
f3aaea26 | 547 | ds = clrnd(btoc(ep->a_data + ep->a_bss)); |
605f1ab4 MK |
548 | |
549 | /* | |
550 | * If we're sharing the address space, allocate a new space | |
551 | * and release our reference to the old one. Otherwise, | |
552 | * empty out the existing vmspace. | |
553 | */ | |
0a5745b2 CT |
554 | #ifdef sparc |
555 | kill_user_windows(p); /* before addrs go away */ | |
556 | #endif | |
605f1ab4 | 557 | if (vm->vm_refcnt > 1) { |
54955369 WN |
558 | p->p_vmspace = vmspace_alloc(VM_MIN_ADDRESS, |
559 | VM_MAXUSER_ADDRESS, 1); | |
605f1ab4 MK |
560 | vmspace_free(vm); |
561 | vm = p->p_vmspace; | |
562 | } else { | |
9d4095a1 | 563 | #ifdef SYSVSHM |
605f1ab4 MK |
564 | if (vm->vm_shm) |
565 | shmexit(p); | |
9d4095a1 | 566 | #endif |
54955369 WN |
567 | (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS, |
568 | VM_MAXUSER_ADDRESS); | |
605f1ab4 | 569 | } |
28db9b87 | 570 | /* |
8429d022 MK |
571 | * If parent is waiting for us to exec or exit, |
572 | * SPPWAIT will be set; clear it and wakeup parent. | |
28db9b87 | 573 | */ |
8429d022 MK |
574 | if (p->p_flag & SPPWAIT) { |
575 | p->p_flag &= ~SPPWAIT; | |
576 | wakeup((caddr_t) p->p_pptr); | |
28db9b87 | 577 | } |
9921f05f MH |
578 | #if defined(HP380) |
579 | /* default to copyback caching on 68040 */ | |
580 | if (mmutype == MMU_68040) | |
581 | p->p_md.md_flags |= (MDP_CCBDATA|MDP_CCBSTACK); | |
582 | #endif | |
93422d4b | 583 | #ifdef HPUXCOMPAT |
9921f05f MH |
584 | p->p_md.md_flags &= ~(MDP_HPUX|MDP_HPUXMMAP); |
585 | /* note that we are an HP-UX binary */ | |
93422d4b | 586 | if (ep->a_mid == MID_HPUX) |
9921f05f MH |
587 | p->p_md.md_flags |= MDP_HPUX; |
588 | /* deal with miscellaneous attributes */ | |
589 | if (ep->a_trsize & HPUXM_VALID) { | |
590 | if (ep->a_trsize & HPUXM_DATAWT) | |
591 | p->p_md.md_flags &= ~MDP_CCBDATA; | |
592 | if (ep->a_trsize & HPUXM_STKWT) | |
593 | p->p_md.md_flags &= ~MDP_CCBSTACK; | |
594 | } | |
f0729cac RC |
595 | #endif |
596 | #ifdef ULTRIXCOMPAT | |
597 | /* | |
598 | * Always start out as an ULTRIX process. | |
599 | * A system call in crt0.o will change us to BSD system calls later. | |
600 | */ | |
601 | p->p_md.md_flags |= MDP_ULTRIX; | |
93422d4b | 602 | #endif |
34dc7acb | 603 | p->p_flag |= SEXEC; |
f0729cac | 604 | #ifndef COFF |
9d4095a1 | 605 | addr = VM_MIN_ADDRESS; |
0a5745b2 | 606 | if (vm_allocate(&vm->vm_map, &addr, xts + ctob(ds), FALSE)) { |
9d4095a1 KM |
607 | uprintf("Cannot allocate text+data space\n"); |
608 | error = ENOMEM; /* XXX */ | |
609 | goto badmap; | |
610 | } | |
f0729cac | 611 | vm->vm_taddr = (caddr_t)VM_MIN_ADDRESS; |
0a5745b2 | 612 | vm->vm_daddr = (caddr_t)(VM_MIN_ADDRESS + xts); |
f0729cac RC |
613 | #else /* COFF */ |
614 | addr = (vm_offset_t)ep->ex_aout.codeStart; | |
615 | vm->vm_taddr = (caddr_t)addr; | |
0a5745b2 | 616 | if (vm_allocate(&vm->vm_map, &addr, xts, FALSE)) { |
f0729cac RC |
617 | uprintf("Cannot allocate text space\n"); |
618 | error = ENOMEM; /* XXX */ | |
619 | goto badmap; | |
620 | } | |
621 | addr = (vm_offset_t)ep->ex_aout.heapStart; | |
622 | vm->vm_daddr = (caddr_t)addr; | |
623 | if (vm_allocate(&vm->vm_map, &addr, round_page(ctob(ds)), FALSE)) { | |
624 | uprintf("Cannot allocate data space\n"); | |
625 | error = ENOMEM; /* XXX */ | |
626 | goto badmap; | |
627 | } | |
628 | #endif /* COFF */ | |
9d4095a1 | 629 | size = round_page(MAXSSIZ); /* XXX */ |
4021f565 WN |
630 | #ifdef i386 |
631 | addr = trunc_page(USRSTACK - size) - NBPG; /* XXX */ | |
632 | #else | |
54955369 | 633 | addr = trunc_page(USRSTACK - size); |
4021f565 | 634 | #endif |
8429d022 | 635 | if (vm_allocate(&vm->vm_map, &addr, size, FALSE)) { |
9d4095a1 KM |
636 | uprintf("Cannot allocate stack space\n"); |
637 | error = ENOMEM; /* XXX */ | |
638 | goto badmap; | |
639 | } | |
54955369 WN |
640 | size -= round_page(p->p_rlimit[RLIMIT_STACK].rlim_cur); |
641 | if (vm_map_protect(&vm->vm_map, addr, addr+size, VM_PROT_NONE, FALSE)) { | |
642 | uprintf("Cannot protect stack space\n"); | |
643 | error = ENOMEM; | |
644 | goto badmap; | |
645 | } | |
8429d022 | 646 | vm->vm_maxsaddr = (caddr_t)addr; |
28db9b87 | 647 | |
34dc7acb | 648 | if (paged == 0) { |
605f1ab4 MK |
649 | /* |
650 | * Read in data segment. | |
651 | */ | |
8429d022 MK |
652 | (void) vn_rdwr(UIO_READ, vp, vm->vm_daddr, (int) ep->a_data, |
653 | (off_t)(toff + ep->a_text), UIO_USERSPACE, | |
f254ddb7 | 654 | (IO_UNIT|IO_NODELOCKED), cred, (int *)0, p); |
605f1ab4 MK |
655 | /* |
656 | * Read in text segment if necessary (0410), | |
657 | * and read-protect it. | |
658 | */ | |
9d4095a1 | 659 | if (ep->a_text > 0) { |
8429d022 | 660 | error = vn_rdwr(UIO_READ, vp, vm->vm_taddr, |
451df175 KM |
661 | (int)ep->a_text, toff, UIO_USERSPACE, |
662 | (IO_UNIT|IO_NODELOCKED), cred, (int *)0, p); | |
663 | (void) vm_map_protect(&vm->vm_map, | |
664 | (vm_offset_t)vm->vm_taddr, | |
665 | (vm_offset_t)vm->vm_taddr + trunc_page(ep->a_text), | |
666 | VM_PROT_READ|VM_PROT_EXECUTE, FALSE); | |
9d4095a1 KM |
667 | } |
668 | } else { | |
669 | /* | |
670 | * Allocate a region backed by the exec'ed vnode. | |
671 | */ | |
f0729cac | 672 | #ifndef COFF |
9d4095a1 | 673 | addr = VM_MIN_ADDRESS; |
0a5745b2 | 674 | size = round_page(xts + ep->a_data); |
79f39708 MH |
675 | error = vm_mmap(&vm->vm_map, &addr, size, |
676 | VM_PROT_ALL, VM_PROT_ALL, | |
a24ecba5 | 677 | MAP_COPY|MAP_FIXED, |
8429d022 | 678 | (caddr_t)vp, (vm_offset_t)toff); |
0a5745b2 | 679 | (void) vm_map_protect(&vm->vm_map, addr, addr + xts, |
8429d022 | 680 | VM_PROT_READ|VM_PROT_EXECUTE, FALSE); |
f0729cac RC |
681 | #else /* COFF */ |
682 | addr = (vm_offset_t)vm->vm_taddr; | |
0a5745b2 | 683 | size = xts; |
f0729cac | 684 | error = vm_mmap(&vm->vm_map, &addr, size, |
79f39708 | 685 | VM_PROT_READ|VM_PROT_EXECUTE, VM_PROT_ALL, |
a24ecba5 | 686 | MAP_COPY|MAP_FIXED, |
f0729cac RC |
687 | (caddr_t)vp, (vm_offset_t)toff); |
688 | toff += size; | |
689 | addr = (vm_offset_t)vm->vm_daddr; | |
690 | size = round_page(ep->a_data); | |
79f39708 MH |
691 | error = vm_mmap(&vm->vm_map, &addr, size, |
692 | VM_PROT_ALL, VM_PROT_ALL, | |
a24ecba5 | 693 | MAP_COPY|MAP_FIXED, |
f0729cac RC |
694 | (caddr_t)vp, (vm_offset_t)toff); |
695 | #endif /* COFF */ | |
605f1ab4 | 696 | vp->v_flag |= VTEXT; |
9d4095a1 | 697 | } |
9d4095a1 | 698 | if (error) { |
0a5745b2 | 699 | badmap: |
055fc5f3 | 700 | killproc(p, "VM allocation in exec"); |
34dc7acb | 701 | p->p_flag |= SKEEP; |
9d4095a1 | 702 | return(error); |
fb1db32c | 703 | } |
28db9b87 | 704 | |
28db9b87 SL |
705 | /* |
706 | * set SUID/SGID protections, if no tracing | |
707 | */ | |
517b1f15 KM |
708 | p->p_flag &= ~SUGID; |
709 | if ((p->p_flag & STRC) == 0) { | |
7c9a1d1f | 710 | if (uid != cred->cr_uid || gid != cred->cr_gid) { |
8429d022 | 711 | p->p_ucred = cred = crcopy(cred); |
7c9a1d1f MT |
712 | /* |
713 | * If process is being ktraced, turn off - unless | |
714 | * root set it. | |
715 | */ | |
716 | if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT)) { | |
717 | vrele(p->p_tracep); | |
718 | p->p_tracep = NULL; | |
719 | p->p_traceflag = 0; | |
720 | } | |
0a5745b2 CT |
721 | cred->cr_uid = uid; |
722 | cred->cr_gid = gid; | |
517b1f15 | 723 | p->p_flag |= SUGID; |
7c9a1d1f | 724 | } |
28db9b87 | 725 | } else |
ba7abd07 | 726 | psignal(p, SIGTRAP); |
8429d022 MK |
727 | p->p_cred->p_svuid = cred->cr_uid; |
728 | p->p_cred->p_svgid = cred->cr_gid; | |
0a5745b2 | 729 | vm->vm_tsize = btoc(xts); |
8429d022 | 730 | vm->vm_dsize = ds; |
916f93da | 731 | vm->vm_ssize = btoc(ssize); |
e0ef57b1 KM |
732 | if (p->p_flag & SPROFIL) |
733 | stopprofclock(p); | |
fb1db32c | 734 | #if defined(tahoe) |
75a969a7 MK |
735 | /* move this when tahoe cpu_exec is created */ |
736 | p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; | |
fb1db32c | 737 | #endif |
c9714ae3 | 738 | return (0); |
28db9b87 | 739 | } |