1 /* This file handles the EXEC system call. It performs the work as follows:
2 * - see if the permissions allow the file to be executed
3 * - read the header and extract the sizes
4 * - fetch the initial args and environment from the user space
5 * - allocate the memory for the new process
6 * - copy the initial stack from PM to the process
7 * - read in the text and data segments and copy to the process
8 * - take care of setuid and setgid bits
9 * - fix up 'mproc' table
10 * - tell kernel about EXEC
11 * - save offset to initial argc (for ps)
13 * The entry points into this file are:
14 * pm_exec: perform the EXEC system call
20 #include <minix/callnr.h>
21 #include <minix/endpoint.h>
22 #include <minix/com.h>
23 #include <minix/u64.h>
28 #include <sys/dirent.h>
30 #include <sys/param.h>
34 #include <minix/vfsif.h>
35 #include <machine/vmparam.h>
39 #define _KERNEL /* for ELF_AUX_ENTRIES */
42 /* fields only used by elf and in VFS */
43 struct vfs_exec_info
{
44 struct exec_info args
; /* libexec exec args */
45 struct vnode
*vp
; /* Exec file's vnode */
46 struct vmnt
*vmp
; /* Exec file's vmnt */
47 struct stat sb
; /* Exec file's stat structure */
48 int userflags
; /* exec() flags from userland */
49 int is_dyn
; /* Dynamically linked executable */
50 int elf_main_fd
; /* Dyn: FD of main program execuatble */
51 char execname
[PATH_MAX
]; /* Full executable invocation */
56 static int patch_stack(struct vnode
*vp
, char stack
[ARG_MAX
],
57 size_t *stk_bytes
, char path
[PATH_MAX
], vir_bytes
*vsp
);
58 static int is_script(struct vfs_exec_info
*execi
);
59 static int insert_arg(char stack
[ARG_MAX
], size_t *stk_bytes
, char *arg
,
60 vir_bytes
*vsp
, char replace
);
61 static void clo_exec(struct fproc
*rfp
);
62 static int stack_prepare_elf(struct vfs_exec_info
*execi
,
63 char *curstack
, size_t *frame_len
, vir_bytes
*vsp
);
64 static int map_header(struct vfs_exec_info
*execi
);
65 static int read_seg(struct exec_info
*execi
, off_t off
, vir_bytes seg_addr
, size_t seg_bytes
);
67 #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
69 /* Array of loaders for different object file formats */
70 typedef int (*exechook_t
)(struct vfs_exec_info
*execpackage
);
71 typedef int (*stackhook_t
)(struct vfs_exec_info
*execi
, char *curstack
,
72 size_t *frame_len
, vir_bytes
*vsp
);
74 libexec_exec_loadfunc_t load_object
; /* load executable into memory */
75 stackhook_t setup_stack
; /* prepare stack before argc and argv push */
78 static const struct exec_loaders exec_loaders
[] = {
79 { libexec_load_elf
, stack_prepare_elf
},
83 #define lock_exec() lock_proc(fproc_addr(VM_PROC_NR))
84 #define unlock_exec() unlock_proc(fproc_addr(VM_PROC_NR))
86 /*===========================================================================*
88 *===========================================================================*/
89 static int get_read_vp(struct vfs_exec_info
*execi
,
90 char *fullpath
, int copyprogname
, int sugid
, struct lookup
*resolve
, struct fproc
*fp
)
92 /* Make the executable that we want to exec() into the binary pointed
93 * to by 'fullpath.' This function fills in necessary details in the execi
94 * structure, such as opened vnode. It unlocks and releases the vnode if
95 * it was already there. This makes it easy to change the executable
96 * during the exec(), which is often necessary, by calling this function
97 * more than once. This is specifically necessary when we discover the
98 * executable is actually a script or a dynamically linked executable.
102 /* Caller wants to switch vp to the file in 'fullpath.'
103 * unlock and put it first if there is any there.
106 unlock_vnode(execi
->vp
);
107 put_vnode(execi
->vp
);
111 /* Remember/overwrite the executable name if requested. */
113 char *cp
= strrchr(fullpath
, '/');
116 strlcpy(execi
->args
.progname
, cp
, sizeof(execi
->args
.progname
));
117 execi
->args
.progname
[sizeof(execi
->args
.progname
)-1] = '\0';
120 /* Open executable */
121 if ((execi
->vp
= eat_path(resolve
, fp
)) == NULL
)
124 unlock_vmnt(execi
->vmp
);
126 if (!S_ISREG(execi
->vp
->v_mode
))
128 else if ((r
= forbidden(fp
, execi
->vp
, X_BIT
)) != OK
)
131 r
= req_stat(execi
->vp
->v_fs_e
, execi
->vp
->v_inode_nr
,
132 VFS_PROC_NR
, (vir_bytes
) &(execi
->sb
));
134 if (r
!= OK
) return r
;
136 /* If caller wants us to, honour suid/guid mode bits. */
138 /* Deal with setuid/setgid executables */
139 if (execi
->vp
->v_mode
& I_SET_UID_BIT
) {
140 execi
->args
.new_uid
= execi
->vp
->v_uid
;
141 execi
->args
.allow_setuid
= 1;
143 if (execi
->vp
->v_mode
& I_SET_GID_BIT
) {
144 execi
->args
.new_gid
= execi
->vp
->v_gid
;
145 execi
->args
.allow_setuid
= 1;
149 /* Read in first chunk of file. */
150 if((r
=map_header(execi
)) != OK
)
156 #define FAILCHECK(expr) if((r=(expr)) != OK) { goto pm_execfinal; } while(0)
157 #define Get_read_vp(e,f,p,s,rs,fp) do { \
158 r=get_read_vp(&e,f,p,s,rs,fp); if(r != OK) { FAILCHECK(r); } \
161 static int vfs_memmap(struct exec_info
*execi
,
162 vir_bytes vaddr
, vir_bytes len
, vir_bytes foffset
, u16_t clearend
,
165 struct vfs_exec_info
*vi
= (struct vfs_exec_info
*) execi
->opaque
;
166 struct vnode
*vp
= ((struct vfs_exec_info
*) execi
->opaque
)->vp
;
170 if(protflags
& PROT_WRITE
)
171 flags
|= MVM_WRITABLE
;
173 r
= minix_vfs_mmap(execi
->proc_e
, foffset
, len
,
174 vp
->v_dev
, vp
->v_inode_nr
, vi
->vmfd
, vaddr
, clearend
, flags
);
182 /*===========================================================================*
184 *===========================================================================*/
185 int pm_exec(vir_bytes path
, size_t path_len
, vir_bytes frame
, size_t frame_len
,
186 vir_bytes
*pc
, vir_bytes
*newsp
, vir_bytes
*UNUSED(ps_str
))
188 /* Perform the execve(name, argv, envp) call. The user library builds a
189 * complete stack image, including pointers, args, environ, etc. The stack
190 * is copied to a buffer inside VFS, and then to the new core image.
192 * ps_str is not currently used, but may be if the ps_strings structure has to
193 * be moved to another location.
197 static char mbuf
[ARG_MAX
]; /* buffer for stack and zeroes */
198 struct vfs_exec_info execi
;
200 static char fullpath
[PATH_MAX
],
201 elf_interpreter
[PATH_MAX
],
204 struct lookup resolve
;
205 struct fproc
*vmfp
= fproc_addr(VM_PROC_NR
);
206 stackhook_t makestack
= NULL
;
207 struct filp
*newfilp
= NULL
;
211 /* unset execi values are 0. */
212 memset(&execi
, 0, sizeof(execi
));
215 /* passed from exec() libc code */
217 execi
.args
.stack_high
= minix_get_user_sp();
218 execi
.args
.stack_size
= DEFAULT_STACK_LIMIT
;
220 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &execi
.vmp
, &execi
.vp
);
222 resolve
.l_vmnt_lock
= VMNT_READ
;
223 resolve
.l_vnode_lock
= VNODE_READ
;
225 /* Fetch the stack from the user before destroying the old core image. */
226 if (frame_len
> ARG_MAX
)
227 FAILCHECK(ENOMEM
); /* stack too big */
229 r
= sys_datacopy_wrapper(fp
->fp_endpoint
, (vir_bytes
) frame
, SELF
, (vir_bytes
) mbuf
,
231 if (r
!= OK
) { /* can't fetch stack (e.g. bad virtual addr) */
232 printf("VFS: pm_exec: sys_datacopy failed\n");
236 /* Compute the current virtual stack pointer, has to be done before calling
237 * patch_stack, which needs it, and will adapt as required. */
238 vsp
= execi
.args
.stack_high
- frame_len
;
240 /* The default is to keep the original user and group IDs */
241 execi
.args
.new_uid
= fp
->fp_effuid
;
242 execi
.args
.new_gid
= fp
->fp_effgid
;
244 /* Get the exec file name. */
245 FAILCHECK(fetch_name(path
, path_len
, fullpath
));
246 strlcpy(finalexec
, fullpath
, PATH_MAX
);
247 strlcpy(firstexec
, fullpath
, PATH_MAX
);
249 /* Get_read_vp will return an opened vn in execi.
250 * if necessary it releases the existing vp so we can
251 * switch after we find out what's inside the file.
252 * It reads the start of the file.
254 Get_read_vp(execi
, fullpath
, 1, 1, &resolve
, fp
);
256 /* If this is a script (i.e. has a #!/interpreter line),
257 * retrieve the name of the interpreter and open that
258 * executable instead.
260 if(is_script(&execi
)) {
261 /* patch_stack will add interpreter name and
262 * args to stack and retrieve the new binary
263 * name into fullpath.
265 FAILCHECK(fetch_name(path
, path_len
, fullpath
));
266 FAILCHECK(patch_stack(execi
.vp
, mbuf
, &frame_len
, fullpath
, &vsp
));
268 strlcpy(finalexec
, fullpath
, PATH_MAX
);
269 strlcpy(firstexec
, fullpath
, PATH_MAX
);
270 Get_read_vp(execi
, fullpath
, 1, 0, &resolve
, fp
);
273 /* If this is a dynamically linked executable, retrieve
274 * the name of that interpreter in elf_interpreter and open that
275 * executable instead. But open the current executable in an
276 * fd for the current process.
278 r
= elf_has_interpreter(execi
.args
.hdr
, execi
.args
.hdr_len
,
279 elf_interpreter
, sizeof(elf_interpreter
));
284 /* Switch the executable vnode to the interpreter */
287 /* The interpreter (loader) needs an fd to the main program,
288 * which is currently in finalexec
290 if ((r
= execi
.elf_main_fd
=
291 common_open(finalexec
, O_RDONLY
, 0, TRUE
/*for_exec*/)) < 0) {
292 printf("VFS: exec: dynamic: open main exec failed %s (%d)\n",
297 /* ld.so is linked at 0, but it can relocate itself; we
298 * want it higher to trap NULL pointer dereferences.
299 * Let's put it below the stack, and reserve 10MB for ld.so.
301 execi
.args
.load_offset
=
302 execi
.args
.stack_high
- execi
.args
.stack_size
- 0xa00000;
305 strlcpy(execi
.execname
, finalexec
, PATH_MAX
);
307 /* The executable we need to execute first (loader)
308 * is in elf_interpreter, and has to be in fullpath to
311 strlcpy(fullpath
, elf_interpreter
, PATH_MAX
);
312 strlcpy(firstexec
, elf_interpreter
, PATH_MAX
);
313 Get_read_vp(execi
, fullpath
, 0, 0, &resolve
, fp
);
316 /* We also want an FD for VM to mmap() the process in if possible. */
318 struct vnode
*vp
= execi
.vp
;
320 if ((vp
->v_vmnt
->m_fs_flags
& RES_HASPEEK
) &&
321 major(vp
->v_dev
) != MEMORY_MAJOR
) {
323 if(get_fd(vmfp
, 0, R_BIT
, &newfd
, &newfilp
) == OK
) {
324 assert(newfd
>= 0 && newfd
< OPEN_MAX
);
325 assert(!vmfp
->fp_filp
[newfd
]);
326 newfilp
->filp_count
= 1;
327 newfilp
->filp_vno
= vp
;
328 newfilp
->filp_flags
= O_RDONLY
;
329 vmfp
->fp_filp
[newfd
] = newfilp
;
332 execi
.args
.memmap
= vfs_memmap
;
337 /* callback functions and data */
338 execi
.args
.copymem
= read_seg
;
339 execi
.args
.clearproc
= libexec_clearproc_vm_procctl
;
340 execi
.args
.clearmem
= libexec_clear_sys_memset
;
341 execi
.args
.allocmem_prealloc_cleared
= libexec_alloc_mmap_prealloc_cleared
;
342 execi
.args
.allocmem_prealloc_junk
= libexec_alloc_mmap_prealloc_junk
;
343 execi
.args
.allocmem_ondemand
= libexec_alloc_mmap_ondemand
;
344 execi
.args
.opaque
= &execi
;
346 execi
.args
.proc_e
= fp
->fp_endpoint
;
347 execi
.args
.frame_len
= frame_len
;
348 execi
.args
.filesize
= execi
.vp
->v_size
;
350 for (i
= 0; exec_loaders
[i
].load_object
!= NULL
; i
++) {
351 r
= (*exec_loaders
[i
].load_object
)(&execi
.args
);
352 /* Loaded successfully, so no need to try other loaders */
353 if (r
== OK
) { makestack
= exec_loaders
[i
].setup_stack
; break; }
359 FAILCHECK(libexec_pm_newexec(fp
->fp_endpoint
, &execi
.args
));
364 /* call a stack-setup function if this executable type wants it */
365 if(makestack
) FAILCHECK(makestack(&execi
, mbuf
, &frame_len
, &vsp
));
367 /* Copy the stack from VFS to new core image. */
368 FAILCHECK(sys_datacopy_wrapper(SELF
, (vir_bytes
) mbuf
, fp
->fp_endpoint
,
369 (vir_bytes
) vsp
, (phys_bytes
)frame_len
));
371 /* Return new stack pointer to caller */
376 if (execi
.args
.allow_setuid
) {
377 /* If after loading the image we're still allowed to run with
378 * setuid or setgid, change credentials now */
379 fp
->fp_effuid
= execi
.args
.new_uid
;
380 fp
->fp_effgid
= execi
.args
.new_gid
;
383 /* Remember the new name of the process */
384 strlcpy(fp
->fp_name
, execi
.args
.progname
, PROC_NAME_LEN
);
387 if(newfilp
) unlock_filp(newfilp
);
388 else if (execi
.vp
!= NULL
) {
389 unlock_vnode(execi
.vp
);
393 if(execi
.vmfd
>= 0 && !execi
.vmfd_used
) {
394 if(OK
!= close_fd(vmfp
, execi
.vmfd
, FALSE
/*may_suspend*/)) {
395 printf("VFS: unexpected close fail of vm fd\n");
404 /* This is a copy-paste of the same macro in minix/lib/libc/sys/stack_utils.c.
405 * Keep it synchronized. */
406 #define STACK_MIN_SZ \
408 sizeof(int) + sizeof(void *) * 2 + \
409 sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
410 sizeof(struct ps_strings) \
413 static int stack_prepare_elf(struct vfs_exec_info
*execi
, char *frame
, size_t *frame_size
,
416 AuxInfo
*aux_vec
, *aux_vec_end
;
417 vir_bytes vap
; /* Address in proc space of the first AuxVec. */
418 Elf_Ehdr
const * const elf_header
= (Elf_Ehdr
*) execi
->args
.hdr
;
419 struct ps_strings
const * const psp
= (struct ps_strings
*)
420 (frame
+ (*frame_size
- sizeof(struct ps_strings
)));
422 size_t const execname_len
= strlen(execi
->execname
);
427 if (execi
->args
.hdr_len
< sizeof(*elf_header
)) {
428 printf("VFS: malformed ELF headers for exec\n");
432 if (*frame_size
< STACK_MIN_SZ
) {
433 printf("VFS: malformed stack for exec(), smaller than minimum"
434 " possible size.\n");
438 /* Find first Aux vector in the stack frame. */
439 vap
= (vir_bytes
)(psp
->ps_envstr
+ (psp
->ps_nenvstr
+ 1));
440 aux_vec
= (AuxInfo
*) (frame
+ (vap
- *vsp
));
441 aux_vec_end
= aux_vec
+ PMEF_AUXVECTORS
;
443 if (((char *)aux_vec
< frame
) ||
444 ((char *)aux_vec
> (frame
+ *frame_size
))) {
445 printf("VFS: malformed stack for exec(), first AuxVector is"
446 " not on the stack.\n");
450 if (((char *)aux_vec_end
< frame
) ||
451 ((char *)aux_vec_end
> (frame
+ *frame_size
))) {
452 printf("VFS: malformed stack for exec(), last AuxVector is"
453 " not on the stack.\n");
457 /* Userland provides a fully filled stack frame, with argc, argv, envp
458 * and then all the argv and envp strings; consistent with ELF ABI,
459 * except for a list of Aux vectors that should be between envp points
460 * and the start of the strings.
462 * It would take some very unpleasant hackery to insert the aux vectors
463 * before the strings, and correct all the pointers, so the exec code
464 * in libc makes space for us.
467 #define AUXINFO(a, type, value) \
469 if (a < aux_vec_end) { \
474 printf("VFS: No more room for ELF AuxVec type %d, skipping it for %s\n", type, execi->execname); \
475 (aux_vec_end - 1)->a_type = AT_NULL; \
476 (aux_vec_end - 1)->a_v = 0; \
480 AUXINFO(aux_vec
, AT_BASE
, execi
->args
.load_base
);
481 AUXINFO(aux_vec
, AT_ENTRY
, execi
->args
.pc
);
482 AUXINFO(aux_vec
, AT_EXECFD
, execi
->elf_main_fd
);
484 AUXINFO(aux_vec
, AT_PHDR
, XXX
); /* should be &phdr[0] */
485 AUXINFO(aux_vec
, AT_PHENT
, elf_header
->e_phentsize
);
486 AUXINFO(aux_vec
, AT_PHNUM
, elf_header
->e_phnum
);
488 AUXINFO(aux_vec
, AT_RUID
, XXX
);
489 AUXINFO(aux_vec
, AT_RGID
, XXX
);
491 AUXINFO(aux_vec
, AT_EUID
, execi
->args
.new_uid
);
492 AUXINFO(aux_vec
, AT_EGID
, execi
->args
.new_gid
);
493 AUXINFO(aux_vec
, AT_PAGESZ
, PAGE_SIZE
);
495 if(execname_len
< PMEF_EXECNAMELEN1
) {
499 /* Empty space starts after aux_vec table; we can put the name
501 spacestart
= (char *) aux_vec
+ 2 * sizeof(AuxInfo
);
502 strlcpy(spacestart
, execi
->execname
, PMEF_EXECNAMELEN1
);
503 memset(spacestart
+ execname_len
, '\0',
504 PMEF_EXECNAMELEN1
- execname_len
);
506 /* What will the address of the string for the user be */
507 userp
= *vsp
+ (spacestart
- frame
);
509 /* Move back to where the AT_NULL is */
510 AUXINFO(aux_vec
, AT_SUN_EXECNAME
, userp
);
513 /* Always terminate with AT_NULL */
514 AUXINFO(aux_vec
, AT_NULL
, 0);
519 /*===========================================================================*
521 *===========================================================================*/
522 static int is_script(struct vfs_exec_info
*execi
)
524 /* Is Interpreted script? */
525 assert(execi
->args
.hdr
!= NULL
);
527 return(execi
->args
.hdr
[0] == '#' && execi
->args
.hdr
[1] == '!'
528 && execi
->args
.hdr_len
>= 2);
531 /*===========================================================================*
533 *===========================================================================*/
534 static int patch_stack(vp
, stack
, stk_bytes
, path
, vsp
)
535 struct vnode
*vp
; /* pointer for open script file */
536 char stack
[ARG_MAX
]; /* pointer to stack image within VFS */
537 size_t *stk_bytes
; /* size of initial stack */
538 char path
[PATH_MAX
]; /* path to script file */
541 /* Patch the argument vector to include the path name of the script to be
542 * interpreted, and all strings on the #! line. Returns the path name of
545 enum { INSERT
=FALSE
, REPLACE
=TRUE
};
548 char *sp
, *interp
= NULL
;
552 /* Make 'path' the new argv[0]. */
553 if (!insert_arg(stack
, stk_bytes
, path
, vsp
, REPLACE
)) return(ENOMEM
);
555 pos
= 0; /* Read from the start of the file */
558 r
= req_readwrite(vp
->v_fs_e
, vp
->v_inode_nr
, pos
, READING
, VFS_PROC_NR
,
559 (vir_bytes
) buf
, sizeof(buf
), &new_pos
, &cum_io
);
561 if (r
!= OK
) return(r
);
566 if (n
< 2) return ENOEXEC
;
568 sp
= &(buf
[2]); /* just behind the #! */
570 if (n
> PATH_MAX
) n
= PATH_MAX
;
572 /* Use the 'path' variable for temporary storage */
575 if ((sp
= memchr(path
, '\n', n
)) == NULL
) /* must be a proper line */
578 /* Move sp backwards through script[], prepending each string to stack. */
580 /* skip spaces behind argument. */
581 while (sp
> path
&& (*--sp
== ' ' || *sp
== '\t')) {}
582 if (sp
== path
) break;
585 /* Move to the start of the argument. */
586 while (sp
> path
&& sp
[-1] != ' ' && sp
[-1] != '\t') --sp
;
589 if (!insert_arg(stack
, stk_bytes
, sp
, vsp
, INSERT
)) {
590 printf("VFS: patch_stack: insert_arg failed\n");
599 memmove(path
, interp
, strlen(interp
)+1);
604 /*===========================================================================*
606 *===========================================================================*/
607 static int insert_arg(char stack
[ARG_MAX
], size_t *stk_bytes
, char *arg
,
608 vir_bytes
*vsp
, char replace
)
610 /* Patch the stack so that arg will become argv[0]. Be careful, the
611 * stack may be filled with garbage, although it normally looks like
613 * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
614 * followed by the strings "pointed" to by the argv[i] and the envp[i].
615 * The * pointers are in the new process address space.
617 * Return true iff the operation succeeded.
619 struct ps_strings
*psp
;
621 size_t old_bytes
= *stk_bytes
;
623 int const arg_len
= strlen(arg
) + 1;
625 /* Offset to argv[0][0] in the stack frame. */
626 int const a0
= (int)(((char **)stack
)[1] - *vsp
);
628 /* Check that argv[0] points within the stack frame. */
629 if ((a0
< 0) || (a0
>= old_bytes
)) {
630 printf("vfs:: argv[0][] not within stack range!! %i\n", a0
);
635 /* Prepending arg adds one pointer, one string and a zero byte. */
636 offset
= arg_len
+ PTRSIZE
;
638 /* replacing argv[0] with arg adds the difference in length of
639 * the two strings. Make sure we don't go beyond the stack size
640 * when computing the length of the current argv[0]. */
641 offset
= arg_len
- strnlen(stack
+ a0
, ARG_MAX
- a0
- 1);
644 /* As ps_strings follows the strings, ensure the offset is word aligned. */
645 offset
= offset
+ (PTRSIZE
- ((PTRSIZE
+ offset
) % PTRSIZE
));
647 /* The stack will grow (or shrink) by offset bytes. */
648 if ((*stk_bytes
+= offset
) > ARG_MAX
) {
649 printf("vfs:: offset too big!! %zu (max %d)\n", *stk_bytes
,
654 /* Reposition the strings by offset bytes */
655 memmove(stack
+ a0
+ offset
, stack
+ a0
, old_bytes
- a0
);
657 /* Put arg in the new space, leaving padding in front of it. */
658 strlcpy(stack
+ a0
+ offset
- arg_len
, arg
, arg_len
);
661 /* Make space for a new argv[0]. */
662 memmove(stack
+ 2 * PTRSIZE
,
663 stack
+ 1 * PTRSIZE
, a0
- 2 * PTRSIZE
);
665 ((char **) stack
)[0]++; /* nargs++; */
668 /* set argv[0] correctly */
669 ((char **) stack
)[1] = (char *) a0
- arg_len
+ *vsp
;
671 /* Update stack pointer in the process address space. */
674 /* Update argv and envp in ps_strings */
675 psp
= (struct ps_strings
*) (stack
+ *stk_bytes
- sizeof(struct ps_strings
));
676 psp
->ps_argvstr
-= (offset
/ PTRSIZE
);
680 psp
->ps_envstr
= psp
->ps_argvstr
+ psp
->ps_nargvstr
+ 1;
685 /*===========================================================================*
687 *===========================================================================*/
688 static int read_seg(struct exec_info
*execi
, off_t off
, vir_bytes seg_addr
, size_t seg_bytes
)
691 * The byte count on read is usually smaller than the segment count, because
692 * a segment is padded out to a click multiple, and the data segment is only
693 * partially initialized.
698 struct vnode
*vp
= ((struct vfs_exec_info
*) execi
->opaque
)->vp
;
700 /* Make sure that the file is big enough */
701 if (off
+ seg_bytes
> LONG_MAX
) return(EIO
);
702 if ((unsigned long) vp
->v_size
< off
+seg_bytes
) return(EIO
);
704 if ((r
= req_readwrite(vp
->v_fs_e
, vp
->v_inode_nr
, off
, READING
,
705 execi
->proc_e
, (vir_bytes
) seg_addr
, seg_bytes
,
706 &new_pos
, &cum_io
)) != OK
) {
707 printf("VFS: read_seg: req_readwrite failed (data)\n");
711 if (r
== OK
&& cum_io
!= seg_bytes
)
712 printf("VFS: read_seg segment has not been read properly\n");
718 /*===========================================================================*
720 *===========================================================================*/
721 static void clo_exec(struct fproc
*rfp
)
723 /* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec).
727 /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
728 for (i
= 0; i
< OPEN_MAX
; i
++)
729 if ( FD_ISSET(i
, &rfp
->fp_cloexec_set
))
730 (void) close_fd(rfp
, i
, FALSE
/*may_suspend*/);
733 /*===========================================================================*
735 *===========================================================================*/
736 static int map_header(struct vfs_exec_info
*execi
)
741 /* Assume that header is not larger than a page. Align the buffer reasonably
742 * well, because libexec casts it to a structure directly and therefore
743 * expects it to be aligned appropriately. From here we can only guess the
744 * proper alignment, but 64 bits should work for all versions of ELF..
746 static char hdr
[10*PAGE_SIZE
] __aligned(8);
748 pos
= 0; /* Read from the start of the file */
750 /* How much is sensible to read */
751 execi
->args
.hdr_len
= MIN(execi
->vp
->v_size
, sizeof(hdr
));
752 execi
->args
.hdr
= hdr
;
754 r
= req_readwrite(execi
->vp
->v_fs_e
, execi
->vp
->v_inode_nr
,
755 pos
, READING
, VFS_PROC_NR
, (vir_bytes
) hdr
,
756 execi
->args
.hdr_len
, &new_pos
, &cum_io
);
758 printf("VFS: exec: map_header: req_readwrite failed\n");