1 /* Copyright (C) 1991-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <hurd.h>
25 #include <hurd/fd.h>
26 #include <hurd/signal.h>
27 #include <hurd/id.h>
28 #include <assert.h>
29 #include <argz.h>
30 
31 /* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
32    If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
33    ARGV and ENVP are terminated by NULL pointers.
34    Deprecated: use _hurd_exec_paths instead.  */
35 error_t
_hurd_exec(task_t task,file_t file,char * const argv[],char * const envp[])36 _hurd_exec (task_t task, file_t file,
37 	    char *const argv[], char *const envp[])
38 {
39   return _hurd_exec_paths (task, file, NULL, NULL, argv, envp);
40 }
41 
42 link_warning (_hurd_exec,
43 	      "_hurd_exec is deprecated, use _hurd_exec_paths instead");
44 
45 /* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
46    If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
47    ARGV and ENVP are terminated by NULL pointers.  PATH is the relative path to
48    FILE and ABSPATH is the absolute path to FILE. Passing NULL, though possible,
49    should be avoided, since then the exec server may not know the path to
50    FILE if FILE is a script, and will then pass /dev/fd/N to the
51    interpreter.  */
52 error_t
_hurd_exec_paths(task_t task,file_t file,const char * path,const char * abspath,char * const argv[],char * const envp[])53 _hurd_exec_paths (task_t task, file_t file,
54 		   const char *path, const char *abspath,
55 		   char *const argv[], char *const envp[])
56 {
57   error_t err;
58   char *args, *env;
59   size_t argslen, envlen;
60   int ints[INIT_INT_MAX];
61   mach_port_t ports[_hurd_nports];
62   struct hurd_userlink ulink_ports[_hurd_nports];
63   inline void free_port (unsigned int i)
64     {
65       _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
66     }
67   file_t *dtable;
68   unsigned int dtablesize, i, j;
69   struct hurd_port **dtable_cells;
70   struct hurd_userlink *ulink_dtable;
71   struct hurd_sigstate *ss;
72   mach_port_t *please_dealloc, *pdp;
73   int reauth = 0;
74   mach_port_t *portnames = NULL;
75   mach_msg_type_number_t nportnames = 0;
76   mach_port_type_t *porttypes = NULL;
77   mach_msg_type_number_t nporttypes = 0;
78 
79   /* XXX needs to be hurdmalloc XXX */
80   if (argv == NULL)
81     args = NULL, argslen = 0;
82   else if (err = __argz_create (argv, &args, &argslen))
83     return err;
84   if (envp == NULL)
85     env = NULL, envlen = 0;
86   else if (err = __argz_create (envp, &env, &envlen))
87     goto outargs;
88 
89   /* Load up the ports to give to the new program.  */
90   for (i = 0; i < _hurd_nports; ++i)
91     if (i == INIT_PORT_PROC && task != __mach_task_self ())
92       {
93 	/* This is another task, so we need to ask the proc server
94 	   for the right proc server port for it.  */
95 	if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
96 	  {
97 	    while (--i > 0)
98 	      free_port (i);
99 	    goto outenv;
100 	  }
101       }
102     else
103       ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
104 
105 
106   /* Load up the ints to give the new program.  */
107   for (i = 0; i < INIT_INT_MAX; ++i)
108     switch (i)
109       {
110       case INIT_UMASK:
111 	ints[i] = _hurd_umask;
112 	break;
113 
114       case INIT_SIGMASK:
115       case INIT_SIGIGN:
116       case INIT_SIGPENDING:
117 	/* We will set these all below.  */
118 	break;
119 
120       case INIT_TRACEMASK:
121 	ints[i] = _hurdsig_traced;
122 	break;
123 
124       default:
125 	ints[i] = 0;
126       }
127 
128   ss = _hurd_self_sigstate ();
129 
130 retry:
131   assert (! __spin_lock_locked (&ss->critical_section_lock));
132   __spin_lock (&ss->critical_section_lock);
133 
134   _hurd_sigstate_lock (ss);
135   struct sigaction *actions = _hurd_sigstate_actions (ss);
136   ints[INIT_SIGMASK] = ss->blocked;
137   ints[INIT_SIGPENDING] = _hurd_sigstate_pending (ss);
138   ints[INIT_SIGIGN] = 0;
139   for (i = 1; i < NSIG; ++i)
140     if (actions[i].sa_handler == SIG_IGN)
141       ints[INIT_SIGIGN] |= __sigmask (i);
142 
143   /* We hold the sigstate lock until the exec has failed so that no signal
144      can arrive between when we pack the blocked and ignored signals, and
145      when the exec actually happens.  A signal handler could change what
146      signals are blocked and ignored.  Either the change will be reflected
147      in the exec, or the signal will never be delivered.  Setting the
148      critical section flag avoids anything we call trying to acquire the
149      sigstate lock.  */
150 
151   _hurd_sigstate_unlock (ss);
152 
153   /* Pack up the descriptor table to give the new program.  */
154   __mutex_lock (&_hurd_dtable_lock);
155 
156   dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
157 
158   if (task == __mach_task_self ())
159     /* Request the exec server to deallocate some ports from us if the exec
160        succeeds.  The init ports and descriptor ports will arrive in the
161        new program's exec_startup message.  If we failed to deallocate
162        them, the new program would have duplicate user references for them.
163        But we cannot deallocate them ourselves, because we must still have
164        them after a failed exec call.  */
165     please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
166 				* sizeof (mach_port_t));
167   else
168     please_dealloc = NULL;
169   pdp = please_dealloc;
170 
171   if (_hurd_dtable != NULL)
172     {
173       dtable = __alloca (dtablesize * sizeof (dtable[0]));
174       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
175       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
176       for (i = 0; i < dtablesize; ++i)
177 	{
178 	  struct hurd_fd *const d = _hurd_dtable[i];
179 	  if (d == NULL)
180 	    {
181 	      dtable[i] = MACH_PORT_NULL;
182 	      continue;
183 	    }
184 	  __spin_lock (&d->port.lock);
185 	  if (d->flags & FD_CLOEXEC)
186 	    {
187 	      /* This descriptor is marked to be closed on exec.
188 		 So don't pass it to the new program.  */
189 	      dtable[i] = MACH_PORT_NULL;
190 	      if (pdp && d->port.port != MACH_PORT_NULL)
191 		{
192 		  /* We still need to deallocate the ports.  */
193 		  *pdp++ = d->port.port;
194 		  if (d->ctty.port != MACH_PORT_NULL)
195 		    *pdp++ = d->ctty.port;
196 		}
197 	      __spin_unlock (&d->port.lock);
198 	    }
199 	  else
200 	    {
201 	      if (pdp && d->ctty.port != MACH_PORT_NULL)
202 		/* All the elements of DTABLE are added to PLEASE_DEALLOC
203 		   below, so we needn't add the port itself.
204 		   But we must deallocate the ctty port as well as
205 		   the normal port that got installed in DTABLE[I].  */
206 		*pdp++ = d->ctty.port;
207 	      dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
208 	      dtable_cells[i] = &d->port;
209 	    }
210 	}
211     }
212   else
213     {
214       dtable = _hurd_init_dtable;
215       ulink_dtable = NULL;
216       dtable_cells = NULL;
217     }
218 
219   /* Prune trailing null ports from the descriptor table.  */
220   while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
221     --dtablesize;
222 
223   /* See if we need to diddle the auth port of the new program.
224      The purpose of this is to get the effect setting the saved-set UID and
225      GID to the respective effective IDs after the exec, as POSIX.1 requires.
226      Note that we don't reauthenticate with the proc server; that would be a
227      no-op since it only keeps track of the effective UIDs, and if it did
228      keep track of the available IDs we would have the problem that we'd be
229      changing the IDs before the exec and have to change them back after a
230      failure.  Arguably we could skip all the reauthentications because the
231      available IDs have no bearing on any filesystem.  But the conservative
232      approach is to reauthenticate all the io ports so that no state anywhere
233      reflects that our whole ID set differs from what we've set it to.  */
234   __mutex_lock (&_hurd_id.lock);
235   err = _hurd_check_ids ();
236 
237   /* Avoid leaking the rid_auth port reference to the new progam */
238   if (_hurd_id.rid_auth != MACH_PORT_NULL)
239     {
240       __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
241       _hurd_id.rid_auth = MACH_PORT_NULL;
242     }
243 
244   if (err == 0 && ((_hurd_id.aux.nuids >= 2 && _hurd_id.gen.nuids >= 1
245 		    && _hurd_id.aux.uids[1] != _hurd_id.gen.uids[0])
246 		   || (_hurd_id.aux.ngids >= 2 && _hurd_id.gen.ngids >= 1
247 		       && _hurd_id.aux.gids[1] != _hurd_id.gen.gids[0])))
248     {
249       /* We have euid != svuid or egid != svgid.  POSIX.1 says that exec
250 	 sets svuid = euid and svgid = egid.  So we must get a new auth
251 	 port and reauthenticate everything with it.  We'll pass the new
252 	 ports in file_exec_paths instead of our own ports.  */
253 
254       auth_t newauth;
255 
256       _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
257       _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
258       _hurd_id.valid = 0;
259 
260       err = __auth_makeauth (ports[INIT_PORT_AUTH],
261 			     NULL, MACH_MSG_TYPE_COPY_SEND, 0,
262 			     _hurd_id.gen.uids, _hurd_id.gen.nuids,
263 			     _hurd_id.aux.uids, _hurd_id.aux.nuids,
264 			     _hurd_id.gen.gids, _hurd_id.gen.ngids,
265 			     _hurd_id.aux.gids, _hurd_id.aux.ngids,
266 			     &newauth);
267       if (err == 0)
268 	{
269 	  /* Now we have to reauthenticate the ports with this new ID.
270 	   */
271 
272 	  inline error_t reauth_io (io_t port, io_t *newport)
273 	    {
274 	      mach_port_t ref = __mach_reply_port ();
275 	      *newport = MACH_PORT_NULL;
276 	      error_t err = __io_reauthenticate (port,
277 						 ref, MACH_MSG_TYPE_MAKE_SEND);
278 	      if (!err)
279 		err = __auth_user_authenticate (newauth,
280 						ref, MACH_MSG_TYPE_MAKE_SEND,
281 						newport);
282 	      __mach_port_destroy (__mach_task_self (), ref);
283 	      return err;
284 	    }
285 	  inline void reauth_port (unsigned int idx)
286 	    {
287 	      io_t newport;
288 	      err = reauth_io (ports[idx], &newport) ?: err;
289 	      if (pdp)
290 		*pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
291 	      free_port (idx);
292 	      ports[idx] = newport;
293 	    }
294 
295 	  if (pdp)
296 	    *pdp++ = ports[INIT_PORT_AUTH];
297 	  free_port (INIT_PORT_AUTH);
298 	  ports[INIT_PORT_AUTH] = newauth;
299 
300 	  reauth_port (INIT_PORT_CRDIR);
301 	  reauth_port (INIT_PORT_CWDIR);
302 
303 	  if (!err)
304 	    {
305 	      /* Now we'll reauthenticate each file descriptor.  */
306 	      if (ulink_dtable == NULL)
307 		{
308 		  assert (dtable == _hurd_init_dtable);
309 		  dtable = __alloca (dtablesize * sizeof (dtable[0]));
310 		  for (i = 0; i < dtablesize; ++i)
311 		    if (_hurd_init_dtable[i] != MACH_PORT_NULL)
312 		      {
313 			if (pdp)
314 			  *pdp++ = _hurd_init_dtable[i];
315 			err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
316 			if (err)
317 			  {
318 			    while (++i < dtablesize)
319 			      dtable[i] = MACH_PORT_NULL;
320 			    break;
321 			  }
322 		      }
323 		    else
324 		      dtable[i] = MACH_PORT_NULL;
325 		}
326 	      else
327 		{
328 		  if (pdp)
329 		    {
330 		      /* Ask to deallocate all the old fd ports,
331 			 since we will have new ones in DTABLE.  */
332 		      memcpy (pdp, dtable, dtablesize * sizeof pdp[0]);
333 		      pdp += dtablesize;
334 		    }
335 		  for (i = 0; i < dtablesize; ++i)
336 		    if (dtable[i] != MACH_PORT_NULL)
337 		      {
338 			io_t newport;
339 			err = reauth_io (dtable[i], &newport);
340 			_hurd_port_free (dtable_cells[i], &ulink_dtable[i],
341 					 dtable[i]);
342 			dtable[i] = newport;
343 			if (err)
344 			  {
345 			    while (++i < dtablesize)
346 			      _hurd_port_free (dtable_cells[i],
347 					       &ulink_dtable[i], dtable[i]);
348 			    break;
349 			  }
350 		      }
351 		  ulink_dtable = NULL;
352 		  dtable_cells = NULL;
353 		}
354 	    }
355 	}
356 
357       reauth = 1;
358     }
359   __mutex_unlock (&_hurd_id.lock);
360 
361   /* The information is all set up now.  Try to exec the file.  */
362   if (!err)
363     {
364       int flags;
365 
366       if (pdp)
367 	{
368 	  /* Get all ports that we may not know about and we should thus destroy.  */
369 	  /* XXX need to disable other threads to be safe.  */
370 	  if (err = __mach_port_names (__mach_task_self (),
371 				     &portnames, &nportnames,
372 				     &porttypes, &nporttypes))
373 	    return err;
374 	  if (nportnames != nporttypes)
375 	    return EGRATUITOUS;
376 
377 	  /* Request the exec server to deallocate some ports from us if
378 	     the exec succeeds.  The init ports and descriptor ports will
379 	     arrive in the new program's exec_startup message.  If we
380 	     failed to deallocate them, the new program would have
381 	     duplicate user references for them.  But we cannot deallocate
382 	     them ourselves, because we must still have them after a failed
383 	     exec call.  */
384 
385 	  for (i = 0; i < _hurd_nports; ++i)
386 	    if (ports[i] != MACH_PORT_NULL)
387 	      {
388 		*pdp++ = ports[i];
389 		for (j = 0; j < nportnames; j++)
390 		  if (portnames[j] == ports[i])
391 		    portnames[j] = MACH_PORT_NULL;
392 	      }
393 	  for (i = 0; i < dtablesize; ++i)
394 	    if (dtable[i] != MACH_PORT_NULL)
395 	      {
396 		*pdp++ = dtable[i];
397 		for (j = 0; j < nportnames; j++)
398 		  if (portnames[j] == dtable[i])
399 		    portnames[j] = MACH_PORT_NULL;
400 	      }
401 
402 	  /* Pack ports to be destroyed together.  */
403 	  for (i = 0, j = 0; i < nportnames; i++)
404 	    {
405 	      if (portnames[i] == MACH_PORT_NULL)
406 		continue;
407 	      if (j != i)
408 		portnames[j] = portnames[i];
409 	      j++;
410 	    }
411 	  nportnames = j;
412 	}
413 
414       flags = 0;
415 #ifdef EXEC_SIGTRAP
416       /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is
417 	 propagated through exec by INIT_TRACEMASK, so this checks if
418 	 PTRACE_TRACEME has been called in this process in any of its
419 	 current or prior lives.  */
420       if (__sigismember (&_hurdsig_traced, SIGKILL))
421 	flags |= EXEC_SIGTRAP;
422 #endif
423       err = __file_exec_paths (file, task, flags,
424 			       path ? path : "",
425 			       abspath ? abspath : "",
426 			       args, argslen, env, envlen,
427 			       dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
428 			       ports, MACH_MSG_TYPE_COPY_SEND,
429 			       _hurd_nports,
430 			       ints, INIT_INT_MAX,
431 			       please_dealloc, pdp - please_dealloc,
432 			       portnames, nportnames);
433       /* Fall back for backwards compatibility.  This can just be removed
434          when __file_exec goes away.  */
435       if (err == MIG_BAD_ID)
436 	err = __file_exec (file, task, flags,
437 			   args, argslen, env, envlen,
438 			   dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
439 			   ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
440 			   ints, INIT_INT_MAX,
441 			   please_dealloc, pdp - please_dealloc,
442 			   portnames, nportnames);
443     }
444 
445   /* Release references to the standard ports.  */
446   for (i = 0; i < _hurd_nports; ++i)
447     if ((i == INIT_PORT_PROC && task != __mach_task_self ())
448 	|| (reauth && (i == INIT_PORT_AUTH
449 		       || i == INIT_PORT_CRDIR || i == INIT_PORT_CWDIR)))
450       __mach_port_deallocate (__mach_task_self (), ports[i]);
451     else
452       free_port (i);
453 
454   /* Release references to the file descriptor ports.  */
455   if (ulink_dtable != NULL)
456     {
457       for (i = 0; i < dtablesize; ++i)
458 	if (dtable[i] != MACH_PORT_NULL)
459 	  _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
460     }
461   else if (dtable && dtable != _hurd_init_dtable)
462     for (i = 0; i < dtablesize; ++i)
463       __mach_port_deallocate (__mach_task_self (), dtable[i]);
464 
465   /* Release lock on the file descriptor table. */
466   __mutex_unlock (&_hurd_dtable_lock);
467 
468   /* Safe to let signals happen now.  */
469   _hurd_critical_section_unlock (ss);
470   if (err == EINTR)
471     /* Got a signal while inside an RPC of the critical section, retry again */
472     goto retry;
473 
474  outenv:
475   free (env);
476  outargs:
477   free (args);
478   return err;
479 }
480 libc_hidden_def (_hurd_exec_paths)
481