1 /* Copyright (C) 1991-2021 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;
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 
75   /* XXX needs to be hurdmalloc XXX */
76   if (argv == NULL)
77     args = NULL, argslen = 0;
78   else if (err = __argz_create (argv, &args, &argslen))
79     return err;
80   if (envp == NULL)
81     env = NULL, envlen = 0;
82   else if (err = __argz_create (envp, &env, &envlen))
83     goto outargs;
84 
85   /* Load up the ports to give to the new program.  */
86   for (i = 0; i < _hurd_nports; ++i)
87     if (i == INIT_PORT_PROC && task != __mach_task_self ())
88       {
89 	/* This is another task, so we need to ask the proc server
90 	   for the right proc server port for it.  */
91 	if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
92 	  {
93 	    while (--i > 0)
94 	      free_port (i);
95 	    goto outenv;
96 	  }
97       }
98     else
99       ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
100 
101 
102   /* Load up the ints to give the new program.  */
103   for (i = 0; i < INIT_INT_MAX; ++i)
104     switch (i)
105       {
106       case INIT_UMASK:
107 	ints[i] = _hurd_umask;
108 	break;
109 
110       case INIT_SIGMASK:
111       case INIT_SIGIGN:
112       case INIT_SIGPENDING:
113 	/* We will set these all below.  */
114 	break;
115 
116       case INIT_TRACEMASK:
117 	ints[i] = _hurdsig_traced;
118 	break;
119 
120       default:
121 	ints[i] = 0;
122       }
123 
124   ss = _hurd_self_sigstate ();
125 
126 retry:
127   assert (! __spin_lock_locked (&ss->critical_section_lock));
128   __spin_lock (&ss->critical_section_lock);
129 
130   _hurd_sigstate_lock (ss);
131   struct sigaction *actions = _hurd_sigstate_actions (ss);
132   ints[INIT_SIGMASK] = ss->blocked;
133   ints[INIT_SIGPENDING] = _hurd_sigstate_pending (ss);
134   ints[INIT_SIGIGN] = 0;
135   for (i = 1; i < NSIG; ++i)
136     if (actions[i].sa_handler == SIG_IGN)
137       ints[INIT_SIGIGN] |= __sigmask (i);
138 
139   /* We hold the sigstate lock until the exec has failed so that no signal
140      can arrive between when we pack the blocked and ignored signals, and
141      when the exec actually happens.  A signal handler could change what
142      signals are blocked and ignored.  Either the change will be reflected
143      in the exec, or the signal will never be delivered.  Setting the
144      critical section flag avoids anything we call trying to acquire the
145      sigstate lock.  */
146 
147   _hurd_sigstate_unlock (ss);
148 
149   /* Pack up the descriptor table to give the new program.  */
150   __mutex_lock (&_hurd_dtable_lock);
151 
152   dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
153 
154   if (task == __mach_task_self ())
155     /* Request the exec server to deallocate some ports from us if the exec
156        succeeds.  The init ports and descriptor ports will arrive in the
157        new program's exec_startup message.  If we failed to deallocate
158        them, the new program would have duplicate user references for them.
159        But we cannot deallocate them ourselves, because we must still have
160        them after a failed exec call.  */
161     please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
162 				* sizeof (mach_port_t));
163   else
164     please_dealloc = NULL;
165   pdp = please_dealloc;
166 
167   if (_hurd_dtable != NULL)
168     {
169       dtable = __alloca (dtablesize * sizeof (dtable[0]));
170       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
171       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
172       for (i = 0; i < dtablesize; ++i)
173 	{
174 	  struct hurd_fd *const d = _hurd_dtable[i];
175 	  if (d == NULL)
176 	    {
177 	      dtable[i] = MACH_PORT_NULL;
178 	      continue;
179 	    }
180 	  __spin_lock (&d->port.lock);
181 	  if (d->flags & FD_CLOEXEC)
182 	    {
183 	      /* This descriptor is marked to be closed on exec.
184 		 So don't pass it to the new program.  */
185 	      dtable[i] = MACH_PORT_NULL;
186 	      if (pdp && d->port.port != MACH_PORT_NULL)
187 		{
188 		  /* We still need to deallocate the ports.  */
189 		  *pdp++ = d->port.port;
190 		  if (d->ctty.port != MACH_PORT_NULL)
191 		    *pdp++ = d->ctty.port;
192 		}
193 	      __spin_unlock (&d->port.lock);
194 	    }
195 	  else
196 	    {
197 	      if (pdp && d->ctty.port != MACH_PORT_NULL)
198 		/* All the elements of DTABLE are added to PLEASE_DEALLOC
199 		   below, so we needn't add the port itself.
200 		   But we must deallocate the ctty port as well as
201 		   the normal port that got installed in DTABLE[I].  */
202 		*pdp++ = d->ctty.port;
203 	      dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
204 	      dtable_cells[i] = &d->port;
205 	    }
206 	}
207     }
208   else
209     {
210       dtable = _hurd_init_dtable;
211       ulink_dtable = NULL;
212       dtable_cells = NULL;
213     }
214 
215   /* Prune trailing null ports from the descriptor table.  */
216   while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
217     --dtablesize;
218 
219   /* See if we need to diddle the auth port of the new program.
220      The purpose of this is to get the effect setting the saved-set UID and
221      GID to the respective effective IDs after the exec, as POSIX.1 requires.
222      Note that we don't reauthenticate with the proc server; that would be a
223      no-op since it only keeps track of the effective UIDs, and if it did
224      keep track of the available IDs we would have the problem that we'd be
225      changing the IDs before the exec and have to change them back after a
226      failure.  Arguably we could skip all the reauthentications because the
227      available IDs have no bearing on any filesystem.  But the conservative
228      approach is to reauthenticate all the io ports so that no state anywhere
229      reflects that our whole ID set differs from what we've set it to.  */
230   __mutex_lock (&_hurd_id.lock);
231   err = _hurd_check_ids ();
232   if (err == 0 && ((_hurd_id.aux.nuids >= 2 && _hurd_id.gen.nuids >= 1
233 		    && _hurd_id.aux.uids[1] != _hurd_id.gen.uids[0])
234 		   || (_hurd_id.aux.ngids >= 2 && _hurd_id.gen.ngids >= 1
235 		       && _hurd_id.aux.gids[1] != _hurd_id.gen.gids[0])))
236     {
237       /* We have euid != svuid or egid != svgid.  POSIX.1 says that exec
238 	 sets svuid = euid and svgid = egid.  So we must get a new auth
239 	 port and reauthenticate everything with it.  We'll pass the new
240 	 ports in file_exec_paths instead of our own ports.  */
241 
242       auth_t newauth;
243 
244       _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
245       _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
246       _hurd_id.valid = 0;
247       if (_hurd_id.rid_auth != MACH_PORT_NULL)
248 	{
249 	  __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
250 	  _hurd_id.rid_auth = MACH_PORT_NULL;
251 	}
252 
253       err = __auth_makeauth (ports[INIT_PORT_AUTH],
254 			     NULL, MACH_MSG_TYPE_COPY_SEND, 0,
255 			     _hurd_id.gen.uids, _hurd_id.gen.nuids,
256 			     _hurd_id.aux.uids, _hurd_id.aux.nuids,
257 			     _hurd_id.gen.gids, _hurd_id.gen.ngids,
258 			     _hurd_id.aux.gids, _hurd_id.aux.ngids,
259 			     &newauth);
260       if (err == 0)
261 	{
262 	  /* Now we have to reauthenticate the ports with this new ID.
263 	   */
264 
265 	  inline error_t reauth_io (io_t port, io_t *newport)
266 	    {
267 	      mach_port_t ref = __mach_reply_port ();
268 	      *newport = MACH_PORT_NULL;
269 	      error_t err = __io_reauthenticate (port,
270 						 ref, MACH_MSG_TYPE_MAKE_SEND);
271 	      if (!err)
272 		err = __auth_user_authenticate (newauth,
273 						ref, MACH_MSG_TYPE_MAKE_SEND,
274 						newport);
275 	      __mach_port_destroy (__mach_task_self (), ref);
276 	      return err;
277 	    }
278 	  inline void reauth_port (unsigned int idx)
279 	    {
280 	      io_t newport;
281 	      err = reauth_io (ports[idx], &newport) ?: err;
282 	      if (pdp)
283 		*pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
284 	      free_port (idx);
285 	      ports[idx] = newport;
286 	    }
287 
288 	  if (pdp)
289 	    *pdp++ = ports[INIT_PORT_AUTH];
290 	  free_port (INIT_PORT_AUTH);
291 	  ports[INIT_PORT_AUTH] = newauth;
292 
293 	  reauth_port (INIT_PORT_CRDIR);
294 	  reauth_port (INIT_PORT_CWDIR);
295 
296 	  if (!err)
297 	    {
298 	      /* Now we'll reauthenticate each file descriptor.  */
299 	      if (ulink_dtable == NULL)
300 		{
301 		  assert (dtable == _hurd_init_dtable);
302 		  dtable = __alloca (dtablesize * sizeof (dtable[0]));
303 		  for (i = 0; i < dtablesize; ++i)
304 		    if (_hurd_init_dtable[i] != MACH_PORT_NULL)
305 		      {
306 			if (pdp)
307 			  *pdp++ = _hurd_init_dtable[i];
308 			err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
309 			if (err)
310 			  {
311 			    while (++i < dtablesize)
312 			      dtable[i] = MACH_PORT_NULL;
313 			    break;
314 			  }
315 		      }
316 		    else
317 		      dtable[i] = MACH_PORT_NULL;
318 		}
319 	      else
320 		{
321 		  if (pdp)
322 		    {
323 		      /* Ask to deallocate all the old fd ports,
324 			 since we will have new ones in DTABLE.  */
325 		      memcpy (pdp, dtable, dtablesize * sizeof pdp[0]);
326 		      pdp += dtablesize;
327 		    }
328 		  for (i = 0; i < dtablesize; ++i)
329 		    if (dtable[i] != MACH_PORT_NULL)
330 		      {
331 			io_t newport;
332 			err = reauth_io (dtable[i], &newport);
333 			_hurd_port_free (dtable_cells[i], &ulink_dtable[i],
334 					 dtable[i]);
335 			dtable[i] = newport;
336 			if (err)
337 			  {
338 			    while (++i < dtablesize)
339 			      _hurd_port_free (dtable_cells[i],
340 					       &ulink_dtable[i], dtable[i]);
341 			    break;
342 			  }
343 		      }
344 		  ulink_dtable = NULL;
345 		  dtable_cells = NULL;
346 		}
347 	    }
348 	}
349 
350       reauth = 1;
351     }
352   __mutex_unlock (&_hurd_id.lock);
353 
354   /* The information is all set up now.  Try to exec the file.  */
355   if (!err)
356     {
357       int flags;
358 
359       if (pdp)
360 	{
361 	  /* Request the exec server to deallocate some ports from us if
362 	     the exec succeeds.  The init ports and descriptor ports will
363 	     arrive in the new program's exec_startup message.  If we
364 	     failed to deallocate them, the new program would have
365 	     duplicate user references for them.  But we cannot deallocate
366 	     them ourselves, because we must still have them after a failed
367 	     exec call.  */
368 
369 	  for (i = 0; i < _hurd_nports; ++i)
370 	    *pdp++ = ports[i];
371 	  for (i = 0; i < dtablesize; ++i)
372 	    *pdp++ = dtable[i];
373 	}
374 
375       flags = 0;
376 #ifdef EXEC_SIGTRAP
377       /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is
378 	 propagated through exec by INIT_TRACEMASK, so this checks if
379 	 PTRACE_TRACEME has been called in this process in any of its
380 	 current or prior lives.  */
381       if (__sigismember (&_hurdsig_traced, SIGKILL))
382 	flags |= EXEC_SIGTRAP;
383 #endif
384       err = __file_exec_paths (file, task, flags,
385 			       path ? path : "",
386 			       abspath ? abspath : "",
387 			       args, argslen, env, envlen,
388 			       dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
389 			       ports, MACH_MSG_TYPE_COPY_SEND,
390 			       _hurd_nports,
391 			       ints, INIT_INT_MAX,
392 			       please_dealloc, pdp - please_dealloc,
393 			       &_hurd_msgport,
394 			       task == __mach_task_self () ? 1 : 0);
395       /* Fall back for backwards compatibility.  This can just be removed
396          when __file_exec goes away.  */
397       if (err == MIG_BAD_ID)
398 	err = __file_exec (file, task, flags,
399 			   args, argslen, env, envlen,
400 			   dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
401 			   ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
402 			   ints, INIT_INT_MAX,
403 			   please_dealloc, pdp - please_dealloc,
404 			   &_hurd_msgport,
405 			   task == __mach_task_self () ? 1 : 0);
406     }
407 
408   /* Release references to the standard ports.  */
409   for (i = 0; i < _hurd_nports; ++i)
410     if ((i == INIT_PORT_PROC && task != __mach_task_self ())
411 	|| (reauth && (i == INIT_PORT_AUTH
412 		       || i == INIT_PORT_CRDIR || i == INIT_PORT_CWDIR)))
413       __mach_port_deallocate (__mach_task_self (), ports[i]);
414     else
415       free_port (i);
416 
417   /* Release references to the file descriptor ports.  */
418   if (ulink_dtable != NULL)
419     {
420       for (i = 0; i < dtablesize; ++i)
421 	if (dtable[i] != MACH_PORT_NULL)
422 	  _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
423     }
424   else if (dtable && dtable != _hurd_init_dtable)
425     for (i = 0; i < dtablesize; ++i)
426       __mach_port_deallocate (__mach_task_self (), dtable[i]);
427 
428   /* Release lock on the file descriptor table. */
429   __mutex_unlock (&_hurd_dtable_lock);
430 
431   /* Safe to let signals happen now.  */
432   _hurd_critical_section_unlock (ss);
433   if (err == EINTR)
434     /* Got a signal while inside an RPC of the critical section, retry again */
435     goto retry;
436 
437  outargs:
438   free (args);
439  outenv:
440   free (env);
441   return err;
442 }
443 libc_hidden_def (_hurd_exec_paths)
444