hurd: Add __rtld_execve
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Sat, 15 Jan 2022 22:41:14 +0000 (23:41 +0100)
committerSamuel Thibault <samuel.thibault@ens-lyon.org>
Sat, 15 Jan 2022 22:42:35 +0000 (23:42 +0100)
It trivially execs with the same dtable, portarray and intarray, and only
has to take care of deallocating / destroying ports (file, notably).

sysdeps/mach/hurd/dl-execve.h [new file with mode: 0644]
sysdeps/mach/hurd/dl-sysdep.c

diff --git a/sysdeps/mach/hurd/dl-execve.h b/sysdeps/mach/hurd/dl-execve.h
new file mode 100644 (file)
index 0000000..e5c14ef
--- /dev/null
@@ -0,0 +1,19 @@
+/* execve for the dynamic linker.  Hurd version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+extern int __rtld_execve (const char *path, char *const *argv, char *const *envp);
index b6256a2..6d52558 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/wait.h>
 #include <assert.h>
 #include <sysdep.h>
+#include <argz.h>
 #include <mach/mig_support.h>
 #include <mach/machine/vm_param.h>
 #include "hurdstartup.h"
@@ -291,7 +292,8 @@ open_file (const char *file_name, int flags,
       return MACH_PORT_NULL;
     }
 
-  assert (!(flags & ~(O_READ | O_CLOEXEC)));
+  assert (!(flags & ~(O_READ | O_EXEC | O_CLOEXEC)));
+  flags &= ~O_CLOEXEC;
 
   startdir = _dl_hurd_data->portarray[file_name[0] == '/'
                                      ? INIT_PORT_CRDIR : INIT_PORT_CWDIR];
@@ -299,7 +301,7 @@ open_file (const char *file_name, int flags,
   while (file_name[0] == '/')
     file_name++;
 
-  err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
+  err = __dir_lookup (startdir, (char *)file_name, flags, 0,
                      &doretry, retryname, port);
 
   if (!err)
@@ -558,6 +560,109 @@ __access_noerrno (const char *file, int type)
   return -1;
 }
 
+int
+__rtld_execve (const char *file_name, char *const argv[],
+               char *const envp[])
+{
+  file_t file;
+  error_t err;
+  char *args, *env;
+  size_t argslen, envlen;
+  mach_port_t *ports = _dl_hurd_data->portarray;
+  unsigned int portarraysize = _dl_hurd_data->portarraysize;
+  file_t *dtable = _dl_hurd_data->dtable;
+  unsigned int dtablesize = _dl_hurd_data->dtablesize;
+  int *intarray = _dl_hurd_data->intarray;
+  unsigned int i, j;
+  mach_port_t *please_dealloc, *pdp;
+  mach_port_t *portnames = NULL;
+  mach_msg_type_number_t nportnames = 0;
+  mach_port_type_t *porttypes = NULL;
+  mach_msg_type_number_t nporttypes = 0;
+  int flags;
+
+  err = open_file (file_name, O_EXEC, &file, NULL);
+  if (err)
+    goto out;
+
+  if (argv == NULL)
+    args = NULL, argslen = 0;
+  else if (err = __argz_create (argv, &args, &argslen))
+    goto outfile;
+  if (envp == NULL)
+    env = NULL, envlen = 0;
+  else if (err = __argz_create (envp, &env, &envlen))
+    goto outargs;
+
+  please_dealloc = __alloca ((portarraysize + dtablesize)
+                            * sizeof (mach_port_t));
+  pdp = please_dealloc;
+
+  /* Get all ports that we may not know about and we should thus destroy.  */
+  err = __mach_port_names (__mach_task_self (),
+                          &portnames, &nportnames,
+                          &porttypes, &nporttypes);
+  if (err)
+    goto outenv;
+  if (nportnames != nporttypes)
+    {
+      err = EGRATUITOUS;
+      goto outenv;
+    }
+
+  for (i = 0; i < portarraysize; ++i)
+    {
+      *pdp++ = ports[i];
+      for (j = 0; j < nportnames; j++)
+       if (portnames[j] == ports[i])
+         portnames[j] = MACH_PORT_NULL;
+    }
+  for (i = 0; i < dtablesize; ++i)
+    {
+      *pdp++ = dtable[i];
+      for (j = 0; j < nportnames; j++)
+       if (portnames[j] == dtable[i])
+         portnames[j] = MACH_PORT_NULL;
+    }
+
+  /* Pack ports to be destroyed together.  */
+  for (i = 0, j = 0; i < nportnames; i++)
+    {
+      if (portnames[i] == MACH_PORT_NULL)
+       continue;
+      if (j != i)
+       portnames[j] = portnames[i];
+      j++;
+    }
+  nportnames = j;
+
+  flags = 0;
+#ifdef EXEC_SIGTRAP
+  if (__sigismember (&intarray[INIT_TRACEMASK], SIGKILL))
+    flags |= EXEC_SIGTRAP;
+#endif
+
+  err = __file_exec_paths (file, __mach_task_self (), flags,
+                          file_name, file_name[0] == '/' ? file_name : "",
+                          args, argslen,
+                          env, envlen,
+                          dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
+                          ports, MACH_MSG_TYPE_COPY_SEND, portarraysize,
+                          intarray, INIT_INT_MAX,
+                          please_dealloc, pdp - please_dealloc,
+                          portnames, nportnames);
+
+  /* Oh well.  Might as well be tidy.  */
+outenv:
+  free (env);
+outargs:
+  free (args);
+outfile:
+  __mach_port_deallocate (__mach_task_self (), file);
+out:
+  return err;
+}
+
 check_no_hidden(__getpid);
 pid_t weak_function
 __getpid (void)