summaryrefslogtreecommitdiff
path: root/exec/exec.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-11-13 20:11:23 +0000
committerRoland McGrath <roland@gnu.org>1995-11-13 20:11:23 +0000
commit27f42e12d27bb6be11df847eaeb0a7c79b32c6be (patch)
tree97dcb98814d4e249364940306a8667f94977e972 /exec/exec.c
parent622f5af54831ad1c04ad7d086422d6453cca6e3b (diff)
(load_section): Catch faults while zeroing partial bss page.
Diffstat (limited to 'exec/exec.c')
-rw-r--r--exec/exec.c69
1 files changed, 47 insertions, 22 deletions
diff --git a/exec/exec.c b/exec/exec.c
index 4fd3135e..cd960011 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -18,7 +18,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -237,7 +237,7 @@ load_section (void *section, struct execdata *u)
u->error = vm_map (u->task,
&mapstart, filesz - (mapstart - addr),
mask, anywhere,
- u->filemap, filepos + (mapstart - addr), 1,
+ u->filemap, filepos + (mapstart - addr), 1,
vm_prot,
VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
VM_INHERIT_COPY);
@@ -392,9 +392,34 @@ load_section (void *section, struct execdata *u)
vm_deallocate (u->task, mapstart, memsz);
return;
}
- bzero ((void *) (ourpage + (addr - overlap_page)),
- size - (addr - overlap_page));
- if (!(vm_prot & VM_PROT_WRITE))
+ {
+ /* Zero the appropriate portion of our copy of the page. All
+ this rigamorole is in case the memory backing this page is
+ bogus and we fault in bzero; we want to return the fault's
+ error code to the user, rather than crash the server. */
+ jmp_buf env;
+ void fault (int signo) { longjmp (env, 1); }
+ thread_t thisthread = hurd_thread_self ();
+ sighandler_t preempt (thread_t thread, int signo,
+ long int sigcode, int sigerror)
+ {
+ if (thread == thisthread)
+ {
+ u->error = sigerror ?: EIO;
+ return &fault;
+ }
+ return SIG_DFL;
+ }
+ struct hurd_signal_preempt preempter;
+ hurd_preempt_signals (&preempter, SIGSEGV,
+ ourpage, ourpage + vm_page_size,
+ &preempt);
+ if (! setjmp (env))
+ bzero ((void *) (ourpage + (addr - overlap_page)),
+ size - (addr - overlap_page));
+ hurd_unpreempt_signals (&preempter, SIGSEGV);
+ }
+ if (! u->error && !(vm_prot & VM_PROT_WRITE))
u->error = vm_protect (u->task, overlap_page, size,
0, VM_PROT_WRITE);
if (! u->error)
@@ -565,7 +590,7 @@ prepare (file_t file, struct execdata *e)
else
e->error = vm_map (mach_task_self (), (vm_address_t *) &e->cntl,
vm_page_size, 0, 1, e->cntlmap, 0, 0,
- VM_PROT_READ|VM_PROT_WRITE,
+ VM_PROT_READ|VM_PROT_WRITE,
VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
if (e->cntl)
@@ -738,7 +763,7 @@ check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr,
phdr->p_filesz))
e->error = EINVAL;
break;
- }
+ }
}
@@ -787,7 +812,7 @@ finish_mapping (struct execdata *e)
e->cntlmap = MACH_PORT_NULL;
}
}
-
+
/* Clean up after reading the file (need not be completed). */
void
finish (struct execdata *e, int dealloc_file)
@@ -869,12 +894,12 @@ load (task_t usertask, struct execdata *e)
vm_address_t myaddr, a;
vm_size_t mysize;
myaddr = 0;
-
+
/* We have already mapped the file into the task in
load_section. Now read from the task's memory into our
own address space so we can peek each page and cause it to
be paged in. */
- u->error = vm_read (u->task, trunc_page (addr),
+ u->error = vm_read (u->task, trunc_page (addr),
round_page (secsize), &myaddr, &mysize);
if (u->error)
return;
@@ -1041,7 +1066,7 @@ do_exec (file_t file,
vm_address_t phdr_addr = 0;
vm_size_t phdr_size = 0;
mach_msg_type_number_t i;
-
+
/* Prime E for executing FILE and check its validity. This must be an
inline function because it stores pointers into alloca'd storage in E
for later use in `load'. */
@@ -1136,7 +1161,7 @@ do_exec (file_t file,
if (flags & (EXEC_NEWTASK|EXEC_SECURE))
{
/* Create the new task. If we are not being secure, then use OLDTASK
- for the task_create RPC, in case it is something magical. */
+ for the task_create RPC, in case it is something magical. */
e.error = task_create (((flags & EXEC_SECURE) ||
oldtask == MACH_PORT_NULL) ?
mach_task_self () : oldtask,
@@ -1169,7 +1194,7 @@ do_exec (file_t file,
e.error = io_reauthenticate (new, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! e.error)
e.error = auth_user_authenticate
- (boot->portarray[INIT_PORT_AUTH],
+ (boot->portarray[INIT_PORT_AUTH],
new, ref, MACH_MSG_TYPE_MAKE_SEND, &authed);
mach_port_destroy (mach_task_self (), ref);
if (e.error)
@@ -1182,7 +1207,7 @@ do_exec (file_t file,
mach_port_mod_refs (mach_task_self (),
new, MACH_PORT_RIGHT_SEND, 1);
}
-
+
boot->portarray[idx] = new;
ports_replaced[idx] = 1;
}
@@ -1288,11 +1313,11 @@ do_exec (file_t file,
if ((secure || defaults)
&& boot->portarray[INIT_PORT_AUTH] == MACH_PORT_NULL)
/* Q: Doesn't this let anyone run a program and make it
- get a root auth port?
+ get a root auth port?
A: No; the standard port for INIT_PORT_AUTH has no UID's at all.
See init.trim/init.c (init_stdarrays). */
use (INIT_PORT_AUTH, std_ports[INIT_PORT_AUTH], 0, 0);
- if (secure || (defaults
+ if (secure || (defaults
&& boot->portarray[INIT_PORT_PROC] == MACH_PORT_NULL))
{
/* Ask the proc server for the proc port for this task. */
@@ -1305,13 +1330,13 @@ do_exec (file_t file,
/* XXX We should also call proc_setowner at this point. */
}
- else if (oldtask != newtask && oldtask != MACH_PORT_NULL
+ else if (oldtask != newtask && oldtask != MACH_PORT_NULL
&& boot->portarray[INIT_PORT_PROC] != MACH_PORT_NULL)
{
mach_port_t new;
/* This task port refers to the old task; use it to fetch a new
one for the new task. */
- e.error = proc_task2proc (boot->portarray[INIT_PORT_PROC],
+ e.error = proc_task2proc (boot->portarray[INIT_PORT_PROC],
newtask, &new);
if (e.error)
goto stdout;
@@ -1323,7 +1348,7 @@ do_exec (file_t file,
if ((secure || defaults)
&& boot->portarray[INIT_PORT_CWDIR] == MACH_PORT_NULL)
use (INIT_PORT_CWDIR, std_ports[INIT_PORT_CWDIR], 1, 0);
- }
+ }
rwlock_reader_unlock (&std_lock);
@@ -1457,7 +1482,7 @@ do_exec (file_t file,
for (i = 0; i < ndestroynames; ++i)
mach_port_destroy (oldtask, destroynames[i]);
}
-
+
/* XXX this should be below
it is here to work around a vm_map kernel bug. */
if (interp.file != MACH_PORT_NULL)
@@ -1490,7 +1515,7 @@ do_exec (file_t file,
/* Start up the initial thread at the entry point. */
boot->stack_base = 0, boot->stack_size = 0; /* Don't care about values. */
- e.error = mach_setup_thread (newtask, thread,
+ e.error = mach_setup_thread (newtask, thread,
(void *) (e.interp.section ? interp.entry :
e.entry),
&boot->stack_base, &boot->stack_size);
@@ -1740,7 +1765,7 @@ S_exec_setexecdata (struct trivfs_protid *protid,
mach_msg_type_number_t i;
for (i = 0; i < std_nports; ++i)
mach_port_deallocate (mach_task_self (), std_ports[i]);
- vm_deallocate (mach_task_self (), (vm_address_t)std_ports,
+ vm_deallocate (mach_task_self (), (vm_address_t)std_ports,
std_nports * sizeof (mach_port_t));
}