From 54dda2cdba0766be599e747ee4660aae80aa8647 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 15 Jan 2022 23:41:14 +0100 Subject: hurd: Add __rtld_execve 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 | 19 ++++++++ sysdeps/mach/hurd/dl-sysdep.c | 109 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 sysdeps/mach/hurd/dl-execve.h (limited to 'sysdeps/mach/hurd') diff --git a/sysdeps/mach/hurd/dl-execve.h b/sysdeps/mach/hurd/dl-execve.h new file mode 100644 index 0000000000..e5c14efc69 --- /dev/null +++ b/sysdeps/mach/hurd/dl-execve.h @@ -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 + . */ + +extern int __rtld_execve (const char *path, char *const *argv, char *const *envp); diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c index b6256a2c0e..6d52558c24 100644 --- a/sysdeps/mach/hurd/dl-sysdep.c +++ b/sysdeps/mach/hurd/dl-sysdep.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #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) -- cgit 1.4.1