summaryrefslogtreecommitdiff
path: root/exec/hashexec.c
diff options
context:
space:
mode:
Diffstat (limited to 'exec/hashexec.c')
-rw-r--r--exec/hashexec.c135
1 files changed, 53 insertions, 82 deletions
diff --git a/exec/hashexec.c b/exec/hashexec.c
index bd617124..6eff8015 100644
--- a/exec/hashexec.c
+++ b/exec/hashexec.c
@@ -1,5 +1,5 @@
/* GNU Hurd standard exec server, #! script execution support.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -20,7 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include <hurd/signal.h>
+#include <hurd/sigpreempt.h>
#include <unistd.h>
/* This is called to check E for a #! interpreter specification. E has
@@ -164,21 +164,17 @@ check_hashbang (struct execdata *e,
if (! e->error)
{
- /* This code is in a local function here for convenience. Some things in
- this function need to be protected against faults while accessing ARGV
- and ENVP; below, we register to preempt signals on these fault areas
- before calling prepare_args, and unregister afterwards. When such a
- fault is detected, the handler does `longjmp (args_faulted, 1)'. */
-
jmp_buf args_faulted;
-
- inline void prepare_args (void)
+ void fault_handler (int signo)
+ { longjmp (args_faulted, 1); }
+ error_t setup_args (struct hurd_signal_preempter *preempter)
{
-
char *file_name = NULL;
size_t namelen;
- if (! (flags & EXEC_SECURE))
+ if (setjmp (args_faulted))
+ file_name = NULL;
+ else if (! (flags & EXEC_SECURE))
{
/* Try to figure out the file's name. We guess that if ARGV[0]
contains a slash, it might be the name of the file; and that
@@ -193,29 +189,12 @@ check_hashbang (struct execdata *e,
fsid_t file_fsid;
ino_t file_fileno;
- error = io_stat (file, &st); /* XXX insecure */
- if (error)
- goto out;
- file_fstype = st.st_fstype;
- file_fsid = st.st_fsid;
- file_fileno = st.st_ino;
-
- if (memchr (argv, '\0', argvlen) == NULL)
+ /* Search $PATH for NAME, opening a port NAME_FILE on it.
+ This is encapsulated in a function so we can catch faults
+ reading the user's environment. */
+ error_t search_path (struct hurd_signal_preempter *preempter)
{
- name = alloca (argvlen + 1);
- bcopy (argv, name, argvlen);
- name[argvlen] = '\0';
- }
- else
- name = argv;
-
- if (strchr (name, '/') != NULL)
- error = lookup (name, 0, &name_file);
- else if (! setjmp (args_faulted))
- {
- /* Search PATH for it. If we fault accessing ENVP, setjmp
- will return again, nonzero this time, and we give up. */
-
+ error_t error;
const char envar[] = "\0PATH=";
char *path, *p;
if (envplen >= sizeof (envar) &&
@@ -270,8 +249,32 @@ check_hashbang (struct execdata *e,
break;
}
} while ((p = path) != NULL);
+
+ return p ? error : ENOENT;
+ }
+
+ error = io_stat (file, &st); /* XXX insecure */
+ if (error)
+ goto out;
+ file_fstype = st.st_fstype;
+ file_fsid = st.st_fsid;
+ file_fileno = st.st_ino;
+
+ if (memchr (argv, '\0', argvlen) == NULL)
+ {
+ name = alloca (argvlen + 1);
+ bcopy (argv, name, argvlen);
+ name[argvlen] = '\0';
}
else
+ name = argv;
+
+ if (strchr (name, '/') != NULL)
+ error = lookup (name, 0, &name_file);
+ else if ((error = hurd_catch_signal
+ (sigmask (SIGBUS) | sigmask (SIGSEGV),
+ (vm_address_t) envp, (vm_address_t) envp + envplen,
+ &search_path, SIG_ERR)))
name_file = MACH_PORT_NULL;
if (!error && name_file != MACH_PORT_NULL)
@@ -319,16 +322,16 @@ check_hashbang (struct execdata *e,
namelen = strlen (file_name) + 1;
+ new_argvlen = argvlen + len + namelen;
+ e->error = vm_allocate (mach_task_self (),
+ (vm_address_t *) &new_argv,
+ new_argvlen, 1);
+ if (e->error)
+ return e->error;
+
if (! setjmp (args_faulted))
{
- /* XXX leaks below if fault */
char *other_args;
- new_argvlen = argvlen + len + namelen;
- e->error = vm_allocate (mach_task_self (),
- (vm_address_t *) &new_argv,
- new_argvlen, 1);
- if (e->error)
- return;
other_args = memccpy (new_argv, argv, '\0', argvlen);
p = &new_argv[other_args ? other_args - new_argv : argvlen];
if (arg)
@@ -345,51 +348,19 @@ check_hashbang (struct execdata *e,
else
{
/* We got a fault reading ARGV. So don't use it. */
- static const char loser[]
- = "**fault in exec server reading argv[0]**";
- new_argvlen = sizeof (loser) + len + namelen;
- new_argv = alloca (argvlen);
- memcpy (new_argv, loser, sizeof (loser));
- memcpy (new_argv + sizeof (loser), arg, len);
- memcpy (new_argv + sizeof (loser) + len, file_name, namelen);
+ char *n = stpncpy (new_argv,
+ "**fault in exec server reading argv[0]**",
+ argvlen);
+ memcpy (memcpy (n, arg, len) + len, file_name, namelen);
}
- }
-
- /* Preempt SIGSEGV signals for the address ranges of ARGV and ENVP.
- When such a signal arrives, `preempter' is called to decide what
- handler to run; it always returns `handler', which is then invoked
- as a normal signal handler. Our handler always simply longjmps to
- ARGS_FAULTED. */
- void handler (int sig)
- {
- longjmp (args_faulted, 1);
- }
- const thread_t mythread = hurd_thread_self ();
- sighandler_t preempter (thread_t thread,
- int signo, long int sigcode, int sigerror)
- {
- return thread == mythread ? handler : SIG_DFL;
+ return 0;
}
- struct hurd_signal_preempt argv_preempter, envp_preempter;
-
- /* Register the preemptions. */
- hurd_preempt_signals (&argv_preempter, SIGSEGV,
- (long int) argv, (long int) argv + argvlen - 1,
- preempter);
- hurd_preempt_signals (&envp_preempter, SIGSEGV,
- (long int) envp, (long int) envp + envplen - 1,
- preempter);
-
- /* Do the work. Everywhere we might get a page fault inside ARGV or
- ENVP, is inside the zero-return case of an `if' on setjmp
- (ARGS_FAULTED). */
- prepare_args ();
-
- /* Unregister the preemptions. */
- hurd_unpreempt_signals (&argv_preempter, SIGSEGV);
- hurd_unpreempt_signals (&envp_preempter, SIGSEGV);
+ /* Set up the arguments. */
+ hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
+ (vm_address_t) argv, (vm_address_t) argv + argvlen,
+ &setup_args, &fault_handler);
}
/* We are now done reading the script file. */