Пример #1
0
kern_return_t
S_exec_init (struct trivfs_protid *protid,
	     auth_t auth, process_t proc)
{
  mach_port_t host_priv, startup;
  error_t err;

  if (! protid || ! protid->isroot)
    return EPERM;

  _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc); /* Consume.  */
  _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], auth); /* Consume.  */

  /* Do initial setup with the proc server.  */
  _hurd_proc_init (save_argv, NULL, 0);

  procserver = getproc ();

  /* Have the proc server notify us when the canonical ints and ports
     change.  This will generate an immediate callback giving us the
     initial boot-time canonical sets.  */
  {
    struct iouser *user;
    struct trivfs_protid *cred;
    mach_port_t right;

    err = iohelp_create_empty_iouser (&user);
    assert_perror (err);
    err = trivfs_open (fsys, user, 0, MACH_PORT_NULL, &cred);
    assert_perror (err);

    right = ports_get_send_right (cred);
    proc_execdata_notify (procserver, right, MACH_MSG_TYPE_COPY_SEND);
    mach_port_deallocate (mach_task_self (), right);
  }

  err = get_privileged_ports (&host_priv, NULL);
  assert_perror (err);

  proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION);

  err = proc_getmsgport (procserver, 1, &startup);
  assert_perror (err);
  mach_port_deallocate (mach_task_self (), procserver);

  /* Call startup_essential task last; init assumes we are ready to
     run once we call it. */
  err = startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL,
				"exec", host_priv);
  assert_perror (err);
  mach_port_deallocate (mach_task_self (), startup);

  mach_port_deallocate (mach_task_self (), host_priv);

  return 0;
}
Пример #2
0
int
_hurd_change_directory_port_from_name (struct hurd_port *portcell,
				       const char *name)
{
  size_t len;
  const char *lookup;
  file_t dir;

  /* Append trailing "/." to directory name to force ENOTDIR if it's not a
     directory and EACCES if we don't have search permission.  */
  len = strlen (name);
  if (len >= 2 && name[len - 2] == '/' && name[len - 1] == '.')
    lookup = name;
  else if (len == 0)
    /* Special-case empty file name according to POSIX.  */
    return __hurd_fail (ENOENT);
  else
    {
      char *n = alloca (len + 3);
      memcpy (n, name, len);
      n[len] = '/';
      n[len + 1] = '.';
      n[len + 2] = '\0';
      lookup = n;
    }

  dir = __file_name_lookup (lookup, 0, 0);
  if (dir == MACH_PORT_NULL)
    return -1;

  _hurd_port_set (portcell, dir);
  return 0;
}
error_t
_hurd_fd_close (struct hurd_fd *fd)
{
  error_t err;

  HURD_CRITICAL_BEGIN;

  __spin_lock (&fd->port.lock);
  if (fd->port.port == MACH_PORT_NULL)
    {
      __spin_unlock (&fd->port.lock);
      err = EBADF;
    }
  else
    {
      /* Clear the descriptor's port cells.
	 This deallocates the ports if noone else is still using them.  */
      _hurd_port_set (&fd->ctty, MACH_PORT_NULL);
      _hurd_port_locked_set (&fd->port, MACH_PORT_NULL);
      err = 0;
    }

  HURD_CRITICAL_END;

  return err;
}
error_t
_hurd_ports_set (unsigned int which, mach_port_t newport)
{
  error_t err;
  if (which >= _hurd_nports)
    return EINVAL;
  if (err = __mach_port_mod_refs (__mach_task_self (), newport,
				  MACH_PORT_RIGHT_SEND, 1))
    return err;
  if (which >= INIT_PORT_MAX || _hurd_ports_setters[which] == NULL)
    {
      _hurd_port_set (&_hurd_ports[which], newport);
      return 0;
    }
  return (*_hurd_ports_setters[which]) (newport);
}
Пример #5
0
void
_hurd_port2fd (struct hurd_fd *d, io_t port, int flags)
{
  io_t ctty;
  mach_port_t cttyid;
  int is_ctty = !(flags & O_IGNORE_CTTY) && ! __term_getctty (port, &cttyid);

  if (is_ctty)
    {
      /* This port is capable of being a controlling tty.
	 Is it ours?  */
      struct hurd_port *const id = &_hurd_ports[INIT_PORT_CTTYID];
      __spin_lock (&id->lock);
      if (id->port == MACH_PORT_NULL)
	/* We have no controlling tty, so make this one it.  */
	_hurd_port_locked_set (id, cttyid);
      else
	{
	  if (cttyid != id->port)
	    /* We have a controlling tty and this is not it.  */
	    is_ctty = 0;
	  /* Either we don't want CTTYID, or ID->port already is it.
	     So we don't need to change ID->port, and we can release
	     the reference to CTTYID.  */
	  __spin_unlock (&id->lock);
	  __mach_port_deallocate (__mach_task_self (), cttyid);
	}
    }

  if (!is_ctty || __term_open_ctty (port, _hurd_pid, _hurd_pgrp, &ctty) != 0)
    /* XXX if IS_CTTY, then this port is our ctty, but we are
       not doing ctty style i/o because term_become_ctty barfed.
       What to do?  */
    /* No ctty magic happening here.  */
    ctty = MACH_PORT_NULL;

  /* Install PORT in the descriptor cell, leaving it locked.  */
  {
    mach_port_t old
      = _hurd_userlink_clear (&d->port.users) ? d->port.port : MACH_PORT_NULL;
    d->port.port = port;
    if (old != MACH_PORT_NULL)
      __mach_port_deallocate (__mach_task_self (), old);
  }

  _hurd_port_set (&d->ctty, ctty);
}
Пример #6
0
/* Make PATH be the root directory (the starting point for absolute
   paths).  Note that while on traditional UNIX systems this call is
   restricted to the super-user, it isn't on the Hurd.  */
int
chroot (const char *path)
{
  const char *lookup;
  size_t len;
  file_t dir, root;
  error_t err;

  /* Append trailing "/." to directory name to force ENOTDIR if it's not a
     directory and EACCES if we don't have search permission.  */
  len = strlen (path);
  if (len >= 2 && path[len - 2] == '/' && path[len - 1] == '.')
    lookup = path;
  else if (len == 0)
    /* Special-case empty file name according to POSIX.  */
    return __hurd_fail (ENOENT);
  else
    {
      char *n = alloca (len + 3);
      memcpy (n, path, len);
      n[len] = '/';
      n[len + 1] = '.';
      n[len + 2] = '\0';
      lookup = n;
    }

  dir = __file_name_lookup (lookup, 0, 0);
  if (dir == MACH_PORT_NULL)
    return -1;

  /* Prevent going through DIR's ..  */
  err = __file_reparent (dir, MACH_PORT_NULL, &root);
  __mach_port_deallocate (__mach_task_self (), dir);
  if (err)
    return __hurd_fail (err);

  _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], root);
  return 0;
}
Пример #7
0
int
main (int argc, char **argv, char **envp)
{
  mach_port_t boot;
  error_t err;
  void *genport;
  process_t startup_port;
  mach_port_t startup;
  struct argp argp = { 0, 0, 0, "Hurd process server" };

  argp_parse (&argp, argc, argv, 0, 0, 0);

  initialize_version_info ();

  err = task_get_bootstrap_port (mach_task_self (), &boot);
  assert_perror (err);
  if (boot == MACH_PORT_NULL)
    error (2, 0, "proc server can only be run by init during boot");

  proc_bucket = ports_create_bucket ();
  proc_class = ports_create_class (0, 0);
  generic_port_class = ports_create_class (0, 0);
  exc_class = ports_create_class (exc_clean, 0);
  ports_create_port (generic_port_class, proc_bucket,
		     sizeof (struct port_info), &genport);
  generic_port = ports_get_right (genport);

  /* Create the initial proc object for init (PID 1).  */
  init_proc = create_init_proc ();

  /* Create the startup proc object for /hurd/init (PID 2).  */
  startup_proc = allocate_proc (MACH_PORT_NULL);
  startup_proc->p_deadmsg = 1;
  complete_proc (startup_proc, HURD_PID_STARTUP);

  /* Create our own proc object.  */
  self_proc = allocate_proc (mach_task_self ());
  assert (self_proc);

  complete_proc (self_proc, HURD_PID_PROC);

  startup_port = ports_get_send_right (startup_proc);
  err = startup_procinit (boot, startup_port, &startup_proc->p_task,
			  &authserver, &_hurd_host_priv, &_hurd_device_master);
  assert_perror (err);
  mach_port_deallocate (mach_task_self (), startup_port);

  mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1);
  _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
  mach_port_deallocate (mach_task_self (), boot);

  proc_death_notify (startup_proc);
  add_proc_to_hash (startup_proc); /* Now that we have the task port.  */

  /* Set our own argv and envp locations.  */
  self_proc->p_argv = (vm_address_t) argv;
  self_proc->p_envp = (vm_address_t) envp;

  /* Give ourselves good scheduling performance, because we are so
     important. */
  err = increase_priority ();
  if (err)
    error (0, err, "Increasing priority failed");

#if 0
  err = register_new_task_notification (_hurd_host_priv,
					generic_port,
					MACH_MSG_TYPE_MAKE_SEND);
  if (err)
    error (0, err, "Registering task notifications failed");
#endif

  {
    /* Get our stderr set up to print on the console, in case we have
       to panic or something.  */
    mach_port_t cons;
    error_t err;
    err = device_open (_hurd_device_master, D_READ|D_WRITE, "console", &cons);
    assert_perror (err);
    stdin = mach_open_devstream (cons, "r");
    stdout = stderr = mach_open_devstream (cons, "w");
    mach_port_deallocate (mach_task_self (), cons);
  }

  startup = file_name_lookup (_SERVERS_STARTUP, 0, 0);
  if (MACH_PORT_VALID (startup))
    {
      err = startup_essential_task (startup, mach_task_self (),
				    MACH_PORT_NULL, "proc", _hurd_host_priv);
      if (err)
	/* Due to the single-threaded nature of /hurd/startup, it can
	   only handle requests once the core server bootstrap has
	   completed.  Therefore, it does not bind itself to
	   /servers/startup until it is ready.	*/
	/* Fall back to abusing the message port lookup.  */
	startup_fallback = 1;

      err = mach_port_deallocate (mach_task_self (), startup);
      assert_perror (err);
    }
  else
    /* Fall back to abusing the message port lookup.	*/
    startup_fallback = 1;

  while (1)
    ports_manage_port_operations_multithread (proc_bucket,
					      message_demuxer,
					      0, 0, 0);
}
Пример #8
0
/* Duplicate FD to FD2, closing the old FD2 and making FD2 be
   open on the same file as FD is, and setting FD2's flags according to FLAGS.
   Return FD2 or -1.  */
int
__dup3 (int fd, int fd2, int flags)
{
  struct hurd_fd *d;

  /* Both passing flags different from O_CLOEXEC and FD2 being the same as FD
     are invalid.  */
  if ((flags & ~O_CLOEXEC
       || fd2 == fd)
      /* ... with the exception in case that dup2 behavior is requested: if FD
	 is valid and FD2 is already the same then just return it.  */
      && ! (flags == -1
	    && fd2 == fd))
    return __hurd_fail (EINVAL);

  /* Extract the ports and flags from FD.  */
  d = _hurd_fd_get (fd);
  if (d == NULL)
    return __hurd_fail (EBADF);

  HURD_CRITICAL_BEGIN;

  __spin_lock (&d->port.lock);
  if (d->port.port == MACH_PORT_NULL)
    {
      __spin_unlock (&d->port.lock);
      fd2 = __hurd_fail (EBADF);
    }
  else if (fd2 == fd)
    __spin_unlock (&d->port.lock);
  else
    {
      struct hurd_userlink ulink, ctty_ulink;
      int d_flags = d->flags;
      io_t ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
      io_t port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D.  */

      if (fd2 < 0)
	fd2 = __hurd_fail (EBADF);
      else
	{
	  /* Get a hold of the destination descriptor.  */
	  struct hurd_fd *d2;

	  __mutex_lock (&_hurd_dtable_lock);

	  if (fd2 >= _hurd_dtablesize)
	    {
	      /* The table is not large enough to hold the destination
		 descriptor.  Enlarge it as necessary to allocate this
		 descriptor.  */
	      __mutex_unlock (&_hurd_dtable_lock);
	      d2 = _hurd_alloc_fd (NULL, fd2);
	      if (d2)
		__spin_unlock (&d2->port.lock);
	      __mutex_lock (&_hurd_dtable_lock);
	    }
	  else
	    {
	      d2 = _hurd_dtable[fd2];
	      if (d2 == NULL)
		{
		  /* Must allocate a new one.  We don't initialize the port
		     cells with this call so that if it fails (out of
		     memory), we will not have already added user
		     references for the ports, which we would then have to
		     deallocate.  */
		  d2 = _hurd_dtable[fd2] = _hurd_new_fd (MACH_PORT_NULL,
							 MACH_PORT_NULL);
		}
	    }
	  __mutex_unlock (&_hurd_dtable_lock);

	  if (d2 == NULL)
	    {
	      fd2 = -1;
	      if (errno == EINVAL)
		errno = EBADF;	/* POSIX.1-1990 6.2.1.2 ll 54-55.  */
	    }
	  else
	    {
	      /* Give the ports each a user ref for the new descriptor.  */
	      __mach_port_mod_refs (__mach_task_self (), port,
				    MACH_PORT_RIGHT_SEND, 1);
	      if (ctty != MACH_PORT_NULL)
		__mach_port_mod_refs (__mach_task_self (), ctty,
				      MACH_PORT_RIGHT_SEND, 1);

	      /* Install the ports and flags in the new descriptor slot.  */
	      __spin_lock (&d2->port.lock);
	      if (flags & O_CLOEXEC)
		d2->flags = d_flags | FD_CLOEXEC;
	      else
		/* dup clears FD_CLOEXEC.  */
		d2->flags = d_flags & ~FD_CLOEXEC;
	      _hurd_port_set (&d2->ctty, ctty);
	      _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
	    }
	}

      _hurd_port_free (&d->port, &ulink, port);
      if (ctty != MACH_PORT_NULL)
	_hurd_port_free (&d->ctty, &ctty_ulink, port);
    }

  HURD_CRITICAL_END;

  return fd2;
}
Пример #9
0
kern_return_t
diskfs_S_file_exec (struct protid *cred,
                    task_t task,
                    int flags,
                    char *argv,
                    size_t argvlen,
                    char *envp,
                    size_t envplen,
                    mach_port_t *fds,
                    size_t fdslen,
                    mach_port_t *portarray,
                    size_t portarraylen,
                    int *intarray,
                    size_t intarraylen,
                    mach_port_t *deallocnames,
                    size_t deallocnameslen,
                    mach_port_t *destroynames,
                    size_t destroynameslen)
{
    struct node *np;
    uid_t uid;
    gid_t gid;
    mode_t mode;
    int suid, sgid;
    struct protid *newpi;
    struct peropen *newpo;
    error_t err = 0;
    mach_port_t execserver;
    int cached_exec;
    struct hurd_userlink ulink;
    mach_port_t right;

#define RETURN(code) do { err = (code); goto out; } while (0)

    if (!cred)
        return EOPNOTSUPP;

    /* Get a light reference to the cached exec server port.  */
    execserver = _hurd_port_get (&_diskfs_exec_portcell, &ulink);
    cached_exec = (execserver != MACH_PORT_NULL);
    if (execserver == MACH_PORT_NULL)
    {
        /* No cached port.  Look up the canonical naming point.  */
        execserver = file_name_lookup (_SERVERS_EXEC, 0, 0);
        if (execserver == MACH_PORT_NULL)
            return EOPNOTSUPP;	/* No exec server, no exec.  */
        else
        {
            /* Install the newly-gotten exec server port for other
               threads to use, then get a light reference for this call.  */
            _hurd_port_set (&_diskfs_exec_portcell, execserver);
            execserver = _hurd_port_get (&_diskfs_exec_portcell, &ulink);
        }
    }

    np = cred->po->np;

    mutex_lock (&np->lock);
    mode = np->dn_stat.st_mode;
    uid = np->dn_stat.st_uid;
    gid = np->dn_stat.st_gid;
    mutex_unlock (&np->lock);

    if (_diskfs_noexec)
        RETURN (EACCES);

    if ((cred->po->openstat & O_EXEC) == 0)
        RETURN (EBADF);

    if (!((mode & (S_IXUSR|S_IXGRP|S_IXOTH))
            || ((mode & S_IUSEUNK) && (mode & (S_IEXEC << S_IUNKSHIFT)))))
        RETURN (EACCES);

    if ((mode & S_IFMT) == S_IFDIR)
        RETURN (EACCES);

    suid = mode & S_ISUID;
    sgid = mode & S_ISGID;
    if (!_diskfs_nosuid && (suid || sgid))
    {
        int secure = 0;
        error_t get_file_ids (struct idvec *uids, struct idvec *gids)
        {
            error_t err = idvec_merge (uids, cred->user->uids);
            if (! err)
                err = idvec_merge (gids, cred->user->gids);
            return err;
        }
Пример #10
0
int
main (int argc, char **argv, char **envp)
{
  mach_port_t boot;
  error_t err;
  mach_port_t pset, psetcntl;
  void *genport;
  process_t startup_port;
  struct argp argp = { 0, 0, 0, "Hurd process server" };

  argp_parse (&argp, argc, argv, 0, 0, 0);

  initialize_version_info ();

  err = task_get_bootstrap_port (mach_task_self (), &boot);
  assert_perror (err);
  if (boot == MACH_PORT_NULL)
    error (2, 0, "proc server can only be run by init during boot");

  proc_bucket = ports_create_bucket ();
  proc_class = ports_create_class (0, 0);
  generic_port_class = ports_create_class (0, 0);
  exc_class = ports_create_class (exc_clean, 0);
  ports_create_port (generic_port_class, proc_bucket,
		     sizeof (struct port_info), &genport);
  generic_port = ports_get_right (genport);

  /* Create the initial proc object for init (PID 1).  */
  startup_proc = create_startup_proc ();

  /* Create our own proc object (we are PID 0).  */
  self_proc = allocate_proc (mach_task_self ());
  assert (self_proc);

  complete_proc (self_proc, 0);

  startup_port = ports_get_send_right (startup_proc);
  err = startup_procinit (boot, startup_port, &startup_proc->p_task,
			  &authserver, &master_host_port, &master_device_port);
  assert_perror (err);
  mach_port_deallocate (mach_task_self (), startup_port);

  mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1);
  _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
  mach_port_deallocate (mach_task_self (), boot);

  proc_death_notify (startup_proc);
  add_proc_to_hash (startup_proc); /* Now that we have the task port.  */

  /* Set our own argv and envp locations.  */
  self_proc->p_argv = (vm_address_t) argv;
  self_proc->p_envp = (vm_address_t) envp;

  /* Give ourselves good scheduling performance, because we are so
     important. */
  err = thread_get_assignment (mach_thread_self (), &pset);
  assert_perror (err);
  err = host_processor_set_priv (master_host_port, pset, &psetcntl);
  assert_perror (err);
  thread_max_priority (mach_thread_self (), psetcntl, 0);
  assert_perror (err);
  err = task_priority (mach_task_self (), 2, 1);
  assert_perror (err);

  mach_port_deallocate (mach_task_self (), pset);
  mach_port_deallocate (mach_task_self (), psetcntl);

  {
    /* Get our stderr set up to print on the console, in case we have
       to panic or something.  */
    mach_port_t cons;
    error_t err;
    err = device_open (master_device_port, D_READ|D_WRITE, "console", &cons);
    assert_perror (err);
    stdin = mach_open_devstream (cons, "r");
    stdout = stderr = mach_open_devstream (cons, "w");
    mach_port_deallocate (mach_task_self (), cons);
  }

  while (1)
    ports_manage_port_operations_multithread (proc_bucket,
					      message_demuxer,
					      0, 0, 0);
}