summaryrefslogtreecommitdiff
path: root/exec/exec.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-04-10 03:04:45 +0000
committerRoland McGrath <roland@gnu.org>1995-04-10 03:04:45 +0000
commit0924d80bcb4deb56cb07b85fdc52f1c7cbd8270c (patch)
tree5c36722c1cb80d4abcd6b9b32d36399d8815d7dc /exec/exec.c
parent17825154d7630b9b8786375ccd944da1c16dafb9 (diff)
(struct execdata) [BFD]: New member `interp_section'.
(check_section): Notice section named ".interp" and set that pointer. (load_section): Do nothing if the section is zero size. When reading into our copy of the overlap page, don't read past the end of the section. (do_exec): Consolidate new subfunction `check_maybe_gzip'. If there is an interpreter section, load the interpreter file too, and use its entry point instead of the user program's. Cleaned up and made more robust deallocation of BOOT info on error. (deadboot): New function, split out of do_mach_port_notify_no_senders.
Diffstat (limited to 'exec/exec.c')
-rw-r--r--exec/exec.c255
1 files changed, 186 insertions, 69 deletions
diff --git a/exec/exec.c b/exec/exec.c
index 7ff99826..42fbea3d 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -77,6 +77,7 @@ struct execdata
file_t file;
#ifdef BFD
bfd *bfd;
+ asection *interp_section; /* Interpreter section giving name of file. */
#else
struct exec *header, headbuf;
#endif
@@ -150,10 +151,19 @@ check_section (bfd *bfd, asection *sec, void *userdata)
{
struct execdata *u = userdata;
vm_address_t addr;
+ static const union
+ {
+ char string[8];
+ unsigned int quadword __attribute__ ((mode (DI)));
+ } interp = { string: ".interp" };
if (u->error)
return;
+ /* Fast strcmp for this 8-byte constant string. */
+ if (*(const __typeof (interp.quadword) *) sec->name == interp.quadword)
+ u->interp_section = sec;
+
if (!(sec->flags & (SEC_ALLOC|SEC_LOAD)) ||
(sec->flags & SEC_NEVER_LOAD))
/* Nothing to do for this section. */
@@ -226,6 +236,10 @@ load_section (enum section section, struct execdata *u)
}
#endif
+ if (secsize == 0)
+ /* This section is empty; ignore it. */
+ return;
+
if (
#ifdef BFD
sec->flags & SEC_LOAD
@@ -360,6 +374,8 @@ load_section (enum section section, struct execdata *u)
readaddr = (void *) (ourpage + (addr - overlap_page));
readsize = size - (addr - overlap_page);
+ if (readsize > secsize)
+ readsize = secsize;
if (SECTION_IN_MEMORY_P)
bcopy (SECTION_CONTENTS, readaddr, readsize);
@@ -692,6 +708,7 @@ prepare (file_t file, struct execdata *e)
e->error = b2he (ENOEXEC);
return;
}
+ e->interp_section = NULL;
#endif
}
@@ -1064,32 +1081,40 @@ do_exec (mach_port_t execserver,
mach_port_t *deallocnames, u_int ndeallocnames,
mach_port_t *destroynames, u_int ndestroynames)
{
- struct execdata e;
+ struct execdata e, interp;
int finished = 0;
task_t newtask = MACH_PORT_NULL;
thread_t thread = MACH_PORT_NULL;
struct bootinfo *boot = 0;
int secure, defaults;
+ void check_maybe_gzip (struct execdata *e)
+ {
+ check (e);
+ if (e->error == ENOEXEC)
+ {
+ /* See if it is a compressed image. */
+ check_gzip (e);
+ if (e->error == 0)
+ /* The file was uncompressed into memory, and now E describes the
+ uncompressed image rather than the actual file. Check it again
+ for a valid magic number. */
+ check (e);
+ }
+ }
+
/* Catch this error now, rather than later. */
if ((!std_ports || !std_ints) && (flags & (EXEC_SECURE|EXEC_DEFAULTS)))
return EIEIO;
+ interp.file = MACH_PORT_NULL;
+
/* Prepare E to read the file. */
prepare (file, &e);
/* Check the file for validity first. */
- check (&e);
- if (e.error == ENOEXEC)
- {
- /* See if it is a compressed image. */
- check_gzip (&e);
- if (e.error == 0)
- /* The file was uncompressed into memory, and now E describes the
- uncompressed image rather than the actual file. Check it again
- for a valid magic number. */
- check (&e);
- }
+
+ check_maybe_gzip (&e);
#if 0
if (e.error == ENOEXEC)
/* Check for a #! executable file. */
@@ -1109,9 +1134,48 @@ do_exec (mach_port_t execserver,
e.locations = alloca (e.bfd->section_count * sizeof (vm_offset_t));
bfd_map_over_sections (e.bfd, check_section, &e);
}
+ if (! e.error && e.interp_section)
+ {
+ /* There is an interpreter section specifying another file to load
+ along with this executable. */
+ char name[e.interp_section->_raw_size];
+ if (! bfd_get_section_contents (e.bfd, e.interp_section,
+ name, 0, e.interp_section->_raw_size))
+ {
+ e.error = b2he (errno);
+ e.interp_section = NULL;
+ }
+ else
+ {
+ inline mach_port_t user_port (unsigned int idx)
+ {
+ return (((flags & (EXEC_SECURE|EXEC_DEFAULTS)) || idx >= nports)
+ ? std_ports : portarray)
+ [idx];
+ }
+
+ e.error = hurd_file_name_lookup (user_port (INIT_PORT_CRDIR),
+ user_port (INIT_PORT_CWDIR),
+ name, O_READ, 0, &interp.file);
+ }
+ }
+ if (interp.file != MACH_PORT_NULL)
+ {
+ prepare (interp.file, &interp);
+ check_maybe_gzip (&interp);
+ if (! interp.error)
+ {
+ interp.locations = alloca (interp.bfd->section_count *
+ sizeof (vm_offset_t));
+ bfd_map_over_sections (interp.bfd, check_section, &interp);
+ }
+ e.error = interp.error;
+ }
#endif
if (e.error)
{
+ if (interp.file != MACH_PORT_NULL)
+ finish (&interp);
finish (&e);
return e.error;
}
@@ -1180,6 +1244,23 @@ do_exec (mach_port_t execserver,
if (e.error)
goto out;
+ if (interp.file != MACH_PORT_NULL)
+ {
+ /* Load the interpreter file. */
+ load (newtask, &interp);
+ if (! interp.error)
+ {
+ finish_mapping (&interp);
+ postload (&interp);
+ }
+ if (interp.error)
+ {
+ e.error = interp.error;
+ goto out;
+ }
+ finish (&interp);
+ }
+
/* Clean up. */
finish (&e);
finished = 1;
@@ -1220,46 +1301,56 @@ do_exec (mach_port_t execserver,
goto out;
mach_port_deallocate (mach_task_self (), (mach_port_t) boot);
+#ifdef XXX
+ boot->user_entry = e.entry;
+#endif
+
if (e.error = servercopy ((void **) &argv, argvlen, argv_copy))
- goto bootout;
+ goto bootallocout;
boot->argv = argv;
boot->argvlen = argvlen;
if (e.error = servercopy ((void **) &envp, envplen, envp_copy))
- goto bootout;
+ goto argvout;
boot->envp = envp;
boot->envplen = envplen;
if (e.error = servercopy ((void **) &dtable,
dtablesize * sizeof (mach_port_t),
dtable_copy))
- goto bootout;
+ goto envpout;
boot->dtable = dtable;
boot->dtablesize = dtablesize;
if (e.error = servercopy ((void **) &portarray,
nports * sizeof (mach_port_t),
portarray_copy))
- goto bootout;
+ goto portsout;
boot->portarray = portarray;
boot->nports = nports;
if (e.error = servercopy ((void **) &intarray,
- nints * sizeof (mach_port_t),
+ nints * sizeof (int),
intarray_copy))
- goto bootout;
+ {
+ bootout:
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) intarray, nints * sizeof (int));
+ portsout:
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) portarray, nports * sizeof (mach_port_t));
+ envpout:
+ vm_deallocate (mach_task_self (), (vm_address_t) envp, envplen);
+ argvout:
+ vm_deallocate (mach_task_self (), (vm_address_t) argv, argvlen);
+ bootallocout:
+ free (boot);
+ mach_port_destroy (mach_task_self (), (mach_port_t) boot);
+ }
+
boot->intarray = intarray;
boot->nints = nints;
boot->flags = flags;
- {
- mach_port_t unused;
- mach_port_request_notification (mach_task_self (),
- (mach_port_t) boot,
- MACH_NOTIFY_NO_SENDERS, 0,
- (mach_port_t) boot,
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &unused);
- }
+ /* Adjust the information in BOOT for the secure and/or defaults flags. */
secure = (flags & EXEC_SECURE);
-
defaults = (flags & EXEC_DEFAULTS);
if ((secure || defaults) && nports < INIT_PORT_MAX)
@@ -1276,8 +1367,8 @@ do_exec (mach_port_t execserver,
nports = INIT_PORT_MAX;
}
- /* Note that the paretheses on this first test are different from the others
- below it. */
+ /* Note that the parentheses on this first test are different from the
+ others below it. */
if ((secure || defaults)
&& boot->portarray[INIT_PORT_AUTH] == MACH_PORT_NULL)
/* Q: Doesn't this let anyone run a program and make it
@@ -1341,7 +1432,11 @@ do_exec (mach_port_t execserver,
/* Start up the initial thread at the entry point. */
boot->stack_base = 0, boot->stack_size = 0; /* Don't care about values. */
- if (e.error = mach_setup_thread (newtask, thread, (void *) e.entry,
+ if (e.error = mach_setup_thread (newtask, thread,
+#ifdef BFD
+ e.interp_section ? (void *) interp.entry :
+#endif
+ (void *) e.entry,
&boot->stack_base, &boot->stack_size))
goto bootout;
@@ -1373,16 +1468,22 @@ do_exec (mach_port_t execserver,
newtask = MACH_PORT_NULL;
- bootout:
- if (e.error)
- {
- mach_port_deallocate (mach_task_self (), (vm_address_t) boot);
- if (boot->portarray != portarray)
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->portarray,
- boot->nports * sizeof (mach_port_t));
- free (boot);
- }
+ /* Request no-senders notification on BOOT, so we can release
+ its resources if the task dies before calling exec_startup. */
+ {
+ mach_port_t unused;
+ mach_port_request_notification (mach_task_self (),
+ (mach_port_t) boot,
+ MACH_NOTIFY_NO_SENDERS, 0,
+ (mach_port_t) boot,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &unused);
+ }
+
+ /* Add BOOT to the server port-set so we will respond to RPCs there. */
+ mach_port_move_member (mach_task_self (),
+ (mach_port_t) boot, request_portset);
+
out:
if (newtask != MACH_PORT_NULL)
@@ -1391,18 +1492,25 @@ do_exec (mach_port_t execserver,
mach_port_deallocate (mach_task_self (), newtask);
}
if (!finished)
- finish (&e);
-
- task_resume (oldtask);
- thread_resume (thread);
+ {
+ if (interp.file != MACH_PORT_NULL)
+ finish (&interp);
+ if (e.error)
+ /* Don't deallocate this port; mig will do it for us. */
+ e.file = MACH_PORT_NULL;
+ finish (&e);
+ }
+ if (oldtask != newtask)
+ task_resume (oldtask);
if (thread != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), thread);
+ {
+ thread_resume (thread);
+ mach_port_deallocate (mach_task_self (), thread);
+ }
- mach_port_deallocate (mach_task_self (), oldtask);
-
- mach_port_move_member (mach_task_self (),
- (mach_port_t) boot, request_portset);
+ if (! e.error)
+ mach_port_deallocate (mach_task_self (), oldtask);
return e.error;
}
@@ -1685,6 +1793,32 @@ S_exec_startup (mach_port_t port,
return 0;
}
+/* Clean up the storage in BOOT, which was never used. */
+void
+deadboot (struct bootinfo *boot)
+{
+ size_t i;
+
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) boot->argv, boot->argvlen);
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) boot->envp, boot->envplen);
+
+ for (i = 0; i < boot->dtablesize; ++i)
+ mach_port_deallocate (mach_task_self (), boot->dtable[i]);
+ for (i = 0; i < boot->nports; ++i)
+ mach_port_deallocate (mach_task_self (), boot->portarray[i]);
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) boot->portarray,
+ boot->nports * sizeof (mach_port_t));
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) boot->intarray,
+ boot->nints * sizeof (int));
+
+ free (boot);
+}
+
+
/* Notice when a receive right has no senders. Either this is the
bootstrap port of a stillborn task, or it is the execserver port itself. */
@@ -1697,30 +1831,13 @@ do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t mscount)
which can no longer ask for them. */
struct bootinfo *boot = (struct bootinfo *) port;
- size_t i;
-
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->argv, boot->argvlen);
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->envp, boot->envplen);
-
- for (i = 0; i < boot->dtablesize; ++i)
- mach_port_deallocate (mach_task_self (), boot->dtable[i]);
- for (i = 0; i < boot->nports; ++i)
- mach_port_deallocate (mach_task_self (), boot->portarray[i]);
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->portarray,
- boot->nports * sizeof (mach_port_t));
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->intarray,
- boot->nints * sizeof (int));
-
- free (boot);
+ deadboot (boot);
}
/* Deallocate the request port. */
mach_port_mod_refs (mach_task_self (), port, MACH_PORT_TYPE_RECEIVE, -1);
+ /* XXX what is this for??? */
mach_port_mod_refs (mach_task_self (), request_portset,
MACH_PORT_TYPE_RECEIVE, -1);