(root)/
glibc-2.38/
hurd/
hurdmsg.c
       1  /* Copyright (C) 1992-2023 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 <hurd.h>
      19  #include <hurd/msg_server.h>
      20  #include <hurd/fd.h>
      21  #include <unistd.h>
      22  #include <limits.h>
      23  #include <string.h>
      24  #include <argz.h>
      25  
      26  
      27  #define AUTHCHECK \
      28    if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth)) \
      29      return EPERM
      30  
      31  
      32  /* Snarfing and frobbing the init ports.  */
      33  
      34  kern_return_t
      35    _S_msg_get_init_port (mach_port_t msgport, mach_port_t auth, int which,
      36  			mach_port_t *result, mach_msg_type_name_t *result_type)
      37  {
      38    error_t err;
      39  
      40    AUTHCHECK;
      41  
      42    *result_type = MACH_MSG_TYPE_MOVE_SEND;
      43    /* This function adds a new user reference for the *RESULT it gives back.
      44       Our reply message uses a move-send right that consumes this reference.  */
      45    err = _hurd_ports_get (which, result);
      46    if (!err && MACH_PORT_VALID (auth))
      47      __mach_port_deallocate (__mach_task_self (), auth);
      48    return err;
      49  }
      50  
      51  kern_return_t
      52  _S_msg_set_init_port (mach_port_t msgport, mach_port_t auth,
      53  		      int which, mach_port_t port)
      54  {
      55    error_t err;
      56  
      57    AUTHCHECK;
      58  
      59    err = _hurd_ports_set (which, port);
      60  
      61    if (!err && MACH_PORT_VALID (port))
      62      __mach_port_deallocate (__mach_task_self (), port);
      63    if (!err && MACH_PORT_VALID (auth))
      64      __mach_port_deallocate (__mach_task_self (), auth);
      65  
      66    return err;
      67  }
      68  
      69  kern_return_t
      70  _S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth,
      71  		       mach_port_t **ports,
      72  		       mach_msg_type_name_t *ports_type,
      73  		       mach_msg_type_number_t *nports)
      74  {
      75    mach_msg_type_number_t i;
      76    error_t err;
      77  
      78    AUTHCHECK;
      79  
      80    if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports,
      81  			   _hurd_nports * sizeof (mach_port_t), 1))
      82      return err;
      83    *nports = _hurd_nports;
      84  
      85    for (i = 0; i < _hurd_nports; ++i)
      86      /* This function adds a new user ref for the *RESULT it gives back.
      87         Our reply message uses move-send rights that consumes this ref.  */
      88      if (err = _hurd_ports_get (i, &(*ports)[i]))
      89        {
      90  	/* Died part way through.  Deallocate the ports already fetched.  */
      91  	while (i-- > 0)
      92  	  __mach_port_deallocate (__mach_task_self (), (*ports)[i]);
      93  	__vm_deallocate (__mach_task_self (),
      94  			 (vm_address_t) *ports,
      95  			 *nports * sizeof (mach_port_t));
      96  	return err;
      97        }
      98  
      99    *ports_type = MACH_MSG_TYPE_MOVE_SEND;
     100    if (MACH_PORT_VALID (auth))
     101      __mach_port_deallocate (__mach_task_self (), auth);
     102    return 0;
     103  }
     104  
     105  kern_return_t
     106  _S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth,
     107  		       const mach_port_t *ports, mach_msg_type_number_t nports)
     108  {
     109    mach_msg_type_number_t i;
     110    error_t err;
     111  
     112    AUTHCHECK;
     113  
     114    for (i = 0; i < _hurd_nports; ++i)
     115      {
     116        if (err = _hurd_ports_set (i, ports[i]))
     117  	return err;
     118        else
     119  	__mach_port_deallocate (__mach_task_self (), ports[i]);
     120      }
     121  
     122    if (MACH_PORT_VALID (auth))
     123      __mach_port_deallocate (__mach_task_self (), auth);
     124    return 0;
     125  }
     126  
     127  /* Snarfing and frobbing the init ints.  */
     128  
     129  static kern_return_t
     130  get_int (int which, int *value)
     131  {
     132    switch (which)
     133      {
     134      case INIT_UMASK:
     135        *value = _hurd_umask;
     136        return 0;
     137      case INIT_SIGPENDING:
     138        {
     139  	struct hurd_sigstate *ss = _hurd_global_sigstate;
     140  	__spin_lock (&ss->lock);
     141  	*value = ss->pending;
     142  	__spin_unlock (&ss->lock);
     143  	return 0;
     144        }
     145      case INIT_SIGIGN:
     146        {
     147  	struct hurd_sigstate *ss = _hurd_global_sigstate;
     148  	sigset_t ign;
     149  	int sig;
     150  	__spin_lock (&ss->lock);
     151  	__sigemptyset (&ign);
     152  	for (sig = 1; sig < NSIG; ++sig)
     153  	  if (ss->actions[sig].sa_handler == SIG_IGN)
     154  	    __sigaddset (&ign, sig);
     155  	__spin_unlock (&ss->lock);
     156  	*value = ign;
     157  	return 0;
     158        }
     159      default:
     160        return EINVAL;
     161      }
     162  }
     163  
     164  kern_return_t
     165  _S_msg_get_init_int (mach_port_t msgport, mach_port_t auth,
     166  		     int which, int *value)
     167  {
     168    error_t err;
     169  
     170    AUTHCHECK;
     171  
     172    err = get_int (which, value);
     173    if (err)
     174      return err;
     175    if (MACH_PORT_VALID (auth))
     176      __mach_port_deallocate (__mach_task_self (), auth);
     177    return 0;
     178  }
     179  
     180  kern_return_t
     181  _S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth,
     182  		      int **values, mach_msg_type_number_t *nvalues)
     183  {
     184    error_t err;
     185    mach_msg_type_number_t i;
     186  
     187    AUTHCHECK;
     188  
     189    if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values,
     190  			   INIT_INT_MAX * sizeof (int), 1))
     191      return err;
     192    *nvalues = INIT_INT_MAX;
     193  
     194    for (i = 0; i < INIT_INT_MAX; ++i)
     195      switch (err = get_int (i, &(*values)[i]))
     196        {
     197        case 0:			/* Success.  */
     198  	break;
     199        case EINVAL:		/* Unknown index.  */
     200  	(*values)[i] = 0;
     201  	break;
     202        default:			/* Lossage.  */
     203  	__vm_deallocate (__mach_task_self (),
     204  			 (vm_address_t) *values, INIT_INT_MAX * sizeof (int));
     205  	return err;
     206        }
     207  
     208    if (MACH_PORT_VALID (auth))
     209      __mach_port_deallocate (__mach_task_self (), auth);
     210    return 0;
     211  }
     212  
     213  
     214  static kern_return_t
     215  set_int (int which, int value)
     216  {
     217    switch (which)
     218      {
     219      case INIT_UMASK:
     220        _hurd_umask = value;
     221        return 0;
     222  
     223        /* These are pretty odd things to do.  But you asked for it.  */
     224      case INIT_SIGPENDING:
     225        {
     226  	struct hurd_sigstate *ss = _hurd_global_sigstate;
     227  	__spin_lock (&ss->lock);
     228  	ss->pending = value;
     229  	__spin_unlock (&ss->lock);
     230  	return 0;
     231        }
     232      case INIT_SIGIGN:
     233        {
     234  	struct hurd_sigstate *ss = _hurd_global_sigstate;
     235  	int sig;
     236  	const sigset_t ign = value;
     237  	__spin_lock (&ss->lock);
     238  	for (sig = 1; sig < NSIG; ++sig)
     239  	  {
     240  	    if (__sigismember (&ign, sig))
     241  	      ss->actions[sig].sa_handler = SIG_IGN;
     242  	    else if (ss->actions[sig].sa_handler == SIG_IGN)
     243  	      ss->actions[sig].sa_handler = SIG_DFL;
     244  	  }
     245  	__spin_unlock (&ss->lock);
     246  	return 0;
     247  
     248        case INIT_TRACEMASK:
     249  	_hurdsig_traced = value;
     250  	return 0;
     251        }
     252      default:
     253        return EINVAL;
     254      }
     255  }
     256  
     257  kern_return_t
     258  _S_msg_set_init_int (mach_port_t msgport, mach_port_t auth,
     259  		     int which, int value)
     260  {
     261    error_t err;
     262  
     263    AUTHCHECK;
     264  
     265    err = set_int (which, value);
     266    if (err)
     267      return err;
     268    if (MACH_PORT_VALID (auth))
     269      __mach_port_deallocate (__mach_task_self (), auth);
     270    return 0;
     271  }
     272  
     273  kern_return_t
     274  _S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth,
     275  		      const int *values, mach_msg_type_number_t nvalues)
     276  {
     277    error_t err;
     278    mach_msg_type_number_t i;
     279  
     280    AUTHCHECK;
     281  
     282    for (i = 0; i < INIT_INT_MAX; ++i)
     283      switch (err = set_int (i, values[i]))
     284        {
     285        case 0:			/* Success.  */
     286  	break;
     287        case EINVAL:		/* Unknown index.  */
     288  	break;
     289        default:			/* Lossage.  */
     290  	return err;
     291        }
     292  
     293    if (MACH_PORT_VALID (auth))
     294      __mach_port_deallocate (__mach_task_self (), auth);
     295    return 0;
     296  }
     297  
     298  
     299  kern_return_t
     300  _S_msg_get_fd (mach_port_t msgport, mach_port_t auth, int which,
     301  	       mach_port_t *result, mach_msg_type_name_t *result_type)
     302  {
     303    AUTHCHECK;
     304  
     305    /* This creates a new user reference for the send right.
     306       Our reply message will move that reference to the caller.  */
     307    *result = __getdport (which);
     308    if (*result == MACH_PORT_NULL)
     309      return errno;
     310    *result_type = MACH_MSG_TYPE_MOVE_SEND;
     311  
     312    if (MACH_PORT_VALID (auth))
     313      __mach_port_deallocate (__mach_task_self (), auth);
     314    return 0;
     315  }
     316  
     317  kern_return_t
     318  _S_msg_set_fd (mach_port_t msgport, mach_port_t auth,
     319  	       int which, mach_port_t port)
     320  {
     321    error_t err;
     322  
     323    AUTHCHECK;
     324  
     325    /* We consume the reference if successful.  */
     326    err = HURD_FD_USE (which,
     327  		     ({
     328  		       int flags = (descriptor->flags & FD_CLOEXEC)
     329  				   ? O_CLOEXEC : 0;
     330  		       _hurd_port2fd (descriptor, port, flags);
     331  		       0;
     332  		     }));
     333    if (err)
     334      return err;
     335  
     336    if (MACH_PORT_VALID (auth))
     337      __mach_port_deallocate (__mach_task_self (), auth);
     338    return 0;
     339  }
     340  
     341  /* Snarfing and frobbing environment variables.  */
     342  
     343  kern_return_t
     344  _S_msg_get_env_variable (mach_port_t msgport,
     345  			 const_string_t variable,
     346  			 char **data, mach_msg_type_number_t *datalen)
     347  {
     348    error_t err;
     349    mach_msg_type_number_t valuelen;
     350    const char *value = getenv (variable);
     351  
     352    if (value == NULL)
     353      return ENOENT;
     354  
     355    valuelen = strlen (value);
     356    if (valuelen > *datalen)
     357      {
     358        if (err = __vm_allocate (__mach_task_self (),
     359  			       (vm_address_t *) data, valuelen, 1))
     360  	return err;
     361      }
     362  
     363    memcpy (*data, value, valuelen);
     364    *datalen = valuelen;
     365  
     366    return 0;
     367  }
     368  
     369  
     370  kern_return_t
     371  _S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth,
     372  			 const_string_t variable,
     373  			 const_string_t value,
     374  			 int replace)
     375  {
     376    AUTHCHECK;
     377  
     378    if (__setenv (variable, value, replace)) /* XXX name space */
     379      return errno;
     380  
     381    if (MACH_PORT_VALID (auth))
     382      __mach_port_deallocate (__mach_task_self (), auth);
     383    return 0;
     384  }
     385  
     386  kern_return_t
     387  _S_msg_get_environment (mach_port_t msgport,
     388  			char **data, mach_msg_type_number_t *datalen)
     389  {
     390    /* Pack the environment into an array with nulls separating elements.  */
     391    if (__environ != NULL)
     392      {
     393        char *ap, **p;
     394        size_t envlen = 0;
     395  
     396        for (p = __environ; *p != NULL; ++p)
     397  	envlen += strlen (*p) + 1;
     398  
     399        if (envlen > *datalen)
     400  	{
     401  	  if (__vm_allocate (__mach_task_self (),
     402  			     (vm_address_t *) data, envlen, 1))
     403  	    return ENOMEM;
     404  	}
     405  
     406        ap = *data;
     407        for (p = __environ; *p != NULL; ++p)
     408  	ap = __memccpy (ap, *p, '\0', ULONG_MAX);
     409  
     410        *datalen = envlen;
     411      }
     412    else
     413      *datalen = 0;
     414  
     415    return 0;
     416  }
     417  
     418  kern_return_t
     419  _S_msg_set_environment (mach_port_t msgport, mach_port_t auth,
     420  			const char *data, mach_msg_type_number_t datalen)
     421  {
     422    int _hurd_split_args (char *, mach_msg_type_number_t, char **);
     423    int envc;
     424    char **envp;
     425  
     426    AUTHCHECK;
     427  
     428    envc = __argz_count (data, datalen);
     429    envp = malloc ((envc + 1) * sizeof (char *));
     430    if (envp == NULL)
     431      return errno;
     432    __argz_extract (data, datalen, envp);
     433    __environ = envp;		/* XXX cooperate with loadenv et al */
     434  
     435    if (MACH_PORT_VALID (auth))
     436      __mach_port_deallocate (__mach_task_self (), auth);
     437    return 0;
     438  }
     439  
     440  
     441  kern_return_t
     442  _S_msg_get_dtable (mach_port_t process,
     443  		   mach_port_t auth,
     444  		   portarray_t *dtable,
     445  		   mach_msg_type_name_t *dtablePoly,
     446  		   mach_msg_type_number_t *dtableCnt)
     447  {
     448    mach_port_t *ports;
     449    mach_msg_type_number_t i;
     450    error_t err;
     451  
     452    AUTHCHECK;
     453  
     454    HURD_CRITICAL_BEGIN;
     455    __mutex_lock (&_hurd_dtable_lock);
     456  
     457    if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) &ports,
     458  			   _hurd_dtablesize * sizeof(mach_port_t), 1))
     459      goto out;
     460  
     461    for (i = 0; i < _hurd_dtablesize; i++)
     462      {
     463        struct hurd_fd *cell = _hurd_dtable[i];
     464        if (cell == NULL)
     465  	ports[i] = MACH_PORT_NULL;
     466        else
     467  	{
     468  	  __spin_lock (&cell->port.lock);
     469  	  if (cell->port.port == MACH_PORT_NULL)
     470  	    ports[i] = MACH_PORT_NULL;
     471  	  else
     472  	    {
     473  	      ports[i] = cell->port.port;
     474  	      /* We will move this send right.  */
     475  	      __mach_port_mod_refs (__mach_task_self (), ports[i],
     476  				    MACH_PORT_RIGHT_SEND, +1);
     477  	    }
     478  	  __spin_unlock (&cell->port.lock);
     479  	}
     480      }
     481  
     482    *dtable = ports;
     483    *dtablePoly = MACH_MSG_TYPE_MOVE_SEND;
     484    *dtableCnt = _hurd_dtablesize;
     485  
     486  out:
     487    __mutex_unlock (&_hurd_dtable_lock);
     488    HURD_CRITICAL_END;
     489    if (!err && MACH_PORT_VALID (auth))
     490      __mach_port_deallocate (__mach_task_self (), auth);
     491    return err;
     492  }
     493  
     494  /* XXX */
     495  
     496  kern_return_t
     497  _S_msg_set_dtable (mach_port_t process,
     498  		   mach_port_t refport,
     499  		   const_portarray_t dtable,
     500  		   mach_msg_type_number_t dtableCnt)
     501  { return EOPNOTSUPP; }