Ejemplo n.º 1
0
/*===========================================================================*
 *				do_reboot				     *
 *===========================================================================*/
int do_reboot()
{
    message m;

    /* Check permission to abort the system. */
    if (mp->mp_effuid != SUPER_USER) return(EPERM);

    /* See how the system should be aborted. */
    abort_flag = m_in.m_lc_pm_reboot.how;

    /* notify readclock (some arm systems power off via RTC alarms) */
    if (abort_flag & RB_POWERDOWN) {
        endpoint_t readclock_ep;
        if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) {
            message m; /* no params to set, nothing we can do if it fails */
            _taskcall(readclock_ep, RTCDEV_PWR_OFF, &m);
        }
    }

    /* Order matters here. When VFS is told to reboot, it exits all its
     * processes, and then would be confused if they're exited again by
     * SIGKILL. So first kill, then reboot.
     */

    check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */
    sys_stop(INIT_PROC_NR);		   /* stop init, but keep it around */

    /* Tell VFS to reboot */
    memset(&m, 0, sizeof(m));
    m.m_type = VFS_PM_REBOOT;

    tell_vfs(&mproc[VFS_PROC_NR], &m);

    return(SUSPEND);			/* don't reply to caller */
}
Ejemplo n.º 2
0
/*===========================================================================*
 *				do_exec					     *
 *===========================================================================*/
PUBLIC int do_exec()
{
	message m;

	/* Forward call to VFS */
	m.m_type = PM_EXEC;
	m.PM_PROC = mp->mp_endpoint;
	m.PM_PATH = m_in.exec_name;
	m.PM_PATH_LEN = m_in.exec_len;
	m.PM_FRAME = m_in.frame_ptr;
	m.PM_FRAME_LEN = m_in.frame_len;

	tell_vfs(mp, &m);

	/* Do not reply */
	return SUSPEND;
}
Ejemplo n.º 3
0
Archivo: exec.c Proyecto: Hooman3/minix
/*===========================================================================*
 *				do_exec					     *
 *===========================================================================*/
int do_exec()
{
	message m;

	/* Forward call to VFS */
	memset(&m, 0, sizeof(m));
	m.m_type = VFS_PM_EXEC;
	m.VFS_PM_ENDPT = mp->mp_endpoint;
	m.VFS_PM_PATH = (void *)m_in.m_lc_pm_exec.name;
	m.VFS_PM_PATH_LEN = m_in.m_lc_pm_exec.namelen;
	m.VFS_PM_FRAME = (void *)m_in.m_lc_pm_exec.frame;
	m.VFS_PM_FRAME_LEN = m_in.m_lc_pm_exec.framelen;
	m.VFS_PM_PS_STR = m_in.m_lc_pm_exec.ps_str;

	tell_vfs(mp, &m);

	/* Do not reply */
	return SUSPEND;
}
Ejemplo n.º 4
0
/*===========================================================================*
 *				do_set					     *
 *===========================================================================*/
PUBLIC int do_set()
{
/* Handle SETUID, SETEUID, SETGID, SETEGID, SETSID. These calls have in common
 * that, if successful, they will be forwarded to VFS as well.
 */
  register struct mproc *rmp = mp;
  message m;
  int r, i;
  int ngroups;
  char sgroups[NGROUPS_MAX];	/* XXX: Temp storage for SETGROUPS_O */


  switch(call_nr) {
	case SETUID:
	case SETEUID:
		if (rmp->mp_realuid != (uid_t) m_in.usr_id && 
				rmp->mp_effuid != SUPER_USER)
			return(EPERM);
		if(call_nr == SETUID) rmp->mp_realuid = (uid_t) m_in.usr_id;
		rmp->mp_effuid = (uid_t) m_in.usr_id;

		m.m_type = PM_SETUID;
		m.PM_PROC = rmp->mp_endpoint;
		m.PM_EID = rmp->mp_effuid;
		m.PM_RID = rmp->mp_realuid;

		break;

	case SETGID:
	case SETEGID:
		if (rmp->mp_realgid != (gid_t) m_in.grp_id && 
				rmp->mp_effuid != SUPER_USER)
			return(EPERM);
		if(call_nr == SETGID) rmp->mp_realgid = (gid_t) m_in.grp_id;
		rmp->mp_effgid = (gid_t) m_in.grp_id;

		m.m_type = PM_SETGID;
		m.PM_PROC = rmp->mp_endpoint;
		m.PM_EID = rmp->mp_effgid;
		m.PM_RID = rmp->mp_realgid;

		break;
	case SETGROUPS:
		if (rmp->mp_effuid != SUPER_USER)
			return(EPERM);

		ngroups = m_in.grp_no;

		if (ngroups > NGROUPS_MAX || ngroups < 0) 
			return(EINVAL);

		if (m_in.groupsp == NULL) 
			return(EFAULT);

		r = sys_datacopy(who_e, (vir_bytes) m_in.groupsp, SELF,
			     (vir_bytes) rmp->mp_sgroups,
			     ngroups * sizeof(gid_t));
		if (r != OK) 
			return(r);

		for (i = 0; i < ngroups; i++) {
			if (rmp->mp_sgroups[i] > GID_MAX)
				return(EINVAL);
		}
		for (i = ngroups; i < NGROUPS_MAX; i++) {
			rmp->mp_sgroups[i] = 0;
		}
		rmp->mp_ngroups = ngroups;

		m.m_type = PM_SETGROUPS;
		m.PM_PROC = rmp->mp_endpoint;
		m.PM_GROUP_NO = rmp->mp_ngroups;
		m.PM_GROUP_ADDR = (char *) rmp->mp_sgroups;

		break;
	case SETGROUPS_O:
		if (rmp->mp_effuid != SUPER_USER)
			return(EPERM);

		ngroups = m_in.grp_no;

		if (ngroups > NGROUPS_MAX || ngroups < 0)
			return(EINVAL);

		if (m_in.groupsp == NULL)
			return(EFAULT);

		r = sys_datacopy(who_e, (vir_bytes) m_in.groupsp, SELF,
			     (vir_bytes) &sgroups, ngroups * sizeof(char));
		if (r != OK)
			return(r);

		for (i = 0; i < ngroups; i++)
			rmp->mp_sgroups[i] = (gid_t) sgroups[i];
		for (i = ngroups; i < NGROUPS_MAX; i++)
			rmp->mp_sgroups[i] = 0;
		rmp->mp_ngroups = ngroups;

		m.m_type = PM_SETGROUPS;
		m.PM_PROC = rmp->mp_endpoint;
		m.PM_GROUP_NO = rmp->mp_ngroups;
		m.PM_GROUP_ADDR = (char *) rmp->mp_sgroups;

		break;
	case SETSID:
		if (rmp->mp_procgrp == rmp->mp_pid) return(EPERM);
		rmp->mp_procgrp = rmp->mp_pid;

		m.m_type = PM_SETSID;
		m.PM_PROC = rmp->mp_endpoint;

		break;

	default:
		return(EINVAL);
  }

  /* Send the request to VFS */
  tell_vfs(rmp, &m);

  /* Do not reply until VFS has processed the request */
  return(SUSPEND);
}
Ejemplo n.º 5
0
/*===========================================================================*
 *				do_fork					     *
 *===========================================================================*/
PUBLIC int do_fork()
{
/* The process pointed to by 'mp' has forked.  Create a child process. */
  register struct mproc *rmp;	/* pointer to parent */
  register struct mproc *rmc;	/* pointer to child */
  pid_t new_pid;
  static int next_child;
  int i, n = 0, s;
  endpoint_t child_ep;
  message m;

 /* If tables might fill up during FORK, don't even start since recovery half
  * way through is such a nuisance.
  */
  rmp = mp;
  if ((procs_in_use == NR_PROCS) || 
  		(procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
  {
  	printf("PM: warning, process table is full!\n");
  	return(EAGAIN);
  }

  /* Find a slot in 'mproc' for the child process.  A slot must exist. */
  do {
        next_child = (next_child+1) % NR_PROCS;
	n++;
  } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
  if(n > NR_PROCS)
	panic("do_fork can't find child slot");
  if(next_child < 0 || next_child >= NR_PROCS
 || (mproc[next_child].mp_flags & IN_USE))
	panic("do_fork finds wrong child slot: %d", next_child);

  /* Memory part of the forking. */
  if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
	printf("PM: vm_fork failed: %d\n", s);
	return s;
  }

  /* PM may not fail fork after call to vm_fork(), as VM calls sys_fork(). */

  rmc = &mproc[next_child];
  /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
  procs_in_use++;
  *rmc = *rmp;			/* copy parent's process slot to child's */
  rmc->mp_parent = who_p;			/* record child's parent */
  if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
	rmc->mp_tracer = NO_TRACER;		/* no tracer attached */
	rmc->mp_trace_flags = 0;
	(void) sigemptyset(&rmc->mp_sigtrace);
  }

  /* Some system servers like to call regular fork, such as RS spawning
   * recovery scripts; in this case PM will take care of their scheduling
   * because RS cannot do so for non-system processes */
  if (rmc->mp_flags & PRIV_PROC) {
	assert(rmc->mp_scheduler == NONE);
	rmc->mp_scheduler = SCHED_PROC_NR;
  }

  /* Inherit only these flags. In normal fork(), PRIV_PROC is not inherited. */
  rmc->mp_flags &= (IN_USE|DELAY_CALL);
  rmc->mp_child_utime = 0;		/* reset administration */
  rmc->mp_child_stime = 0;		/* reset administration */
  rmc->mp_exitstatus = 0;
  rmc->mp_sigstatus = 0;
  rmc->mp_endpoint = child_ep;		/* passed back by VM */
  for (i = 0; i < NR_ITIMERS; i++)
	rmc->mp_interval[i] = 0;	/* reset timer intervals */

  /* Find a free pid for the child and put it in the table. */
  new_pid = get_free_pid();
  rmc->mp_pid = new_pid;	/* assign pid to child */

  m.m_type = PM_FORK;
  m.PM_PROC = rmc->mp_endpoint;
  m.PM_PPROC = rmp->mp_endpoint;
  m.PM_CPID = rmc->mp_pid;

  tell_vfs(rmc, &m);

  /* Tell the tracer, if any, about the new child */
  if (rmc->mp_tracer != NO_TRACER)
	sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);

  /* Do not reply until VFS is ready to process the fork
  * request
  */
  return SUSPEND;
}
Ejemplo n.º 6
0
/*===========================================================================*
 *				do_srv_fork				     *
 *===========================================================================*/
PUBLIC int do_srv_fork()
{
/* The process pointed to by 'mp' has forked.  Create a child process. */
  register struct mproc *rmp;	/* pointer to parent */
  register struct mproc *rmc;	/* pointer to child */
  int s;
  pid_t new_pid;
  static int next_child;
  int i, n = 0;
  endpoint_t child_ep;
  message m;

  /* Only RS is allowed to use srv_fork. */
  if (mp->mp_endpoint != RS_PROC_NR)
	return EPERM;

 /* If tables might fill up during FORK, don't even start since recovery half
  * way through is such a nuisance.
  */
  rmp = mp;
  if ((procs_in_use == NR_PROCS) || 
  		(procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
  {
  	printf("PM: warning, process table is full!\n");
  	return(EAGAIN);
  }

  /* Find a slot in 'mproc' for the child process.  A slot must exist. */
  do {
        next_child = (next_child+1) % NR_PROCS;
	n++;
  } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
  if(n > NR_PROCS)
	panic("do_fork can't find child slot");
  if(next_child < 0 || next_child >= NR_PROCS
 || (mproc[next_child].mp_flags & IN_USE))
	panic("do_fork finds wrong child slot: %d", next_child);

  if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
	printf("PM: vm_fork failed: %d\n", s);
	return s;
  }

  rmc = &mproc[next_child];
  /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
  procs_in_use++;
  *rmc = *rmp;			/* copy parent's process slot to child's */
  rmc->mp_parent = who_p;			/* record child's parent */
  if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
	rmc->mp_tracer = NO_TRACER;		/* no tracer attached */
	rmc->mp_trace_flags = 0;
	(void) sigemptyset(&rmc->mp_sigtrace);
  }
  /* inherit only these flags */
  rmc->mp_flags &= (IN_USE|PRIV_PROC|DELAY_CALL);
  rmc->mp_child_utime = 0;		/* reset administration */
  rmc->mp_child_stime = 0;		/* reset administration */
  rmc->mp_exitstatus = 0;
  rmc->mp_sigstatus = 0;
  rmc->mp_endpoint = child_ep;		/* passed back by VM */
  for (i = 0; i < NR_ITIMERS; i++)
	rmc->mp_interval[i] = 0;	/* reset timer intervals */

  /* Find a free pid for the child and put it in the table. */
  new_pid = get_free_pid();
  rmc->mp_pid = new_pid;	/* assign pid to child */

  m.m_type = PM_SRV_FORK;
  m.PM_PROC = rmc->mp_endpoint;
  m.PM_PPROC = rmp->mp_endpoint;
  m.PM_CPID = rmc->mp_pid;

  tell_vfs(rmc, &m);

  /* Tell the tracer, if any, about the new child */
  if (rmc->mp_tracer != NO_TRACER)
	sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);

  /* Wakeup the newly created process */
  setreply(rmc-mproc, OK);

  return rmc->mp_pid;
}
Ejemplo n.º 7
0
Archivo: trace.c Proyecto: Sciumo/minix
/*===========================================================================*
 *				do_trace  				     *
 *===========================================================================*/
int do_trace()
{
  register struct mproc *child;
  struct ptrace_range pr;
  int i, r, seg, req;
  message m;

  req = m_in.request;

  /* The T_OK call is made by the child fork of the debugger before it execs
   * the process to be traced. The T_ATTACH call is made by the debugger itself
   * to attach to an existing process.
   */
  switch (req) {
  case T_OK:		/* enable tracing by parent for this proc */
	if (mp->mp_tracer != NO_TRACER) return(EBUSY);

	mp->mp_tracer = mp->mp_parent;
	mp->mp_reply.reply_trace = 0;
	return(OK);

  case T_ATTACH:	/* attach to an existing process */
	if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH);
	if (child->mp_flags & EXITING) return(ESRCH);

	/* For non-root processes, user and group ID must match. */
	if (mp->mp_effuid != SUPER_USER &&
		(mp->mp_effuid != child->mp_effuid ||
		 mp->mp_effgid != child->mp_effgid ||
		 child->mp_effuid != child->mp_realuid ||
		 child->mp_effgid != child->mp_realgid)) return(EPERM);

	/* Only root may trace system servers. */
	if (mp->mp_effuid != SUPER_USER && (child->mp_flags & PRIV_PROC))
		return(EPERM);

	/* System servers may not trace anyone. They can use sys_trace(). */
	if (mp->mp_flags & PRIV_PROC) return(EPERM);

	/* Can't trace self, PM or VM. */
	if (child == mp || child->mp_endpoint == PM_PROC_NR ||
		child->mp_endpoint == VM_PROC_NR) return(EPERM);

	/* Can't trace a process that is already being traced. */
	if (child->mp_tracer != NO_TRACER) return(EBUSY);

	child->mp_tracer = who_p;
	child->mp_trace_flags = TO_NOEXEC;

	sig_proc(child, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);

	mp->mp_reply.reply_trace = 0;
	return(OK);

  case T_DUMPCORE:
	if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH);

	/* Allow dumpcore only if traced! */
	if (child->mp_tracer != who_p) return(EPERM);

	/* Tell VFS to dump the core. */
	m.m_type = PM_DUMPCORE;
	m.PM_PROC = mp->mp_endpoint;
	m.PM_TRACED_PROC = child->mp_endpoint;
	/* Note that m.PM_PROC != m.PM_TRACED_PROC
	 * (we use this to differentiate between a VFS core dump reply for a
	 * an exiting process and the one for a traced process) */

	m.PM_TERM_SIG = child->mp_sigstatus;
	m.PM_PATH = child->mp_name;

	tell_vfs(mp, &m);

	return(SUSPEND); /* Suspend the process until we receive reply from VFS */

  case T_STOP:		/* stop the process */
	/* This call is not exposed to user programs, because its effect can be
	 * achieved better by sending the traced process a signal with kill(2).
	 */
	return(EINVAL);

  case T_READB_INS:	/* special hack for reading text segments */
	if (mp->mp_effuid != SUPER_USER) return(EPERM);
	if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH);
	if (child->mp_flags & EXITING) return(ESRCH);

	r = sys_trace(req, child->mp_endpoint, m_in.PMTRACE_ADDR, &m_in.data);
	if (r != OK) return(r);

	mp->mp_reply.reply_trace = m_in.data;
	return(OK);

  case T_WRITEB_INS:	/* special hack for patching text segments */
	if (mp->mp_effuid != SUPER_USER) return(EPERM);
	if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH);
	if (child->mp_flags & EXITING) return(ESRCH);

#if 0
	/* Should check for shared text */

	/* Make sure the text segment is not used as a source for shared
	 * text.
	 */
	child->mp_ino = 0;
	child->mp_dev = 0;
	child->mp_ctime = 0;
#endif

	r = sys_trace(req, child->mp_endpoint, m_in.PMTRACE_ADDR, &m_in.data);
	if (r != OK) return(r);

	mp->mp_reply.reply_trace = m_in.data;
	return(OK);
  }

  /* All the other calls are made by the tracing process to control execution
   * of the child. For all these calls, the child must be stopped.
   */
  if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH);
  if (child->mp_flags & EXITING) return(ESRCH);
  if (child->mp_tracer != who_p) return(ESRCH);
  if (!(child->mp_flags & STOPPED)) return(EBUSY);

  switch (req) {
  case T_EXIT:		/* exit */
	child->mp_flags |= TRACE_EXIT;

	/* Defer the exit if the traced process has an VFS call pending. */
	if (child->mp_flags & VFS_CALL)
		child->mp_exitstatus = (int) m_in.data;	/* save for later */
	else
		exit_proc(child, (int) m_in.data, FALSE /*dump_core*/);

	/* Do not reply to the caller until VFS has processed the exit
	 * request.
	 */
	return(SUSPEND);

  case T_SETOPT:	/* set trace options */
	child->mp_trace_flags = m_in.data;

	mp->mp_reply.reply_trace = 0;
	return(OK);

  case T_GETRANGE:
  case T_SETRANGE:	/* get/set range of values */
	r = sys_datacopy(who_e, (vir_bytes) m_in.PMTRACE_ADDR,
			SELF, (vir_bytes) &pr, (phys_bytes) sizeof(pr));
	if (r != OK) return(r);

	if (pr.pr_space != TS_INS && pr.pr_space != TS_DATA) return(EINVAL);
	if (pr.pr_size == 0 || pr.pr_size > LONG_MAX) return(EINVAL);

	seg = (pr.pr_space == TS_INS) ? T : D;
	if (req == T_GETRANGE)
		r = sys_vircopy(child->mp_endpoint, seg, (vir_bytes) pr.pr_addr,
			who_e, D, (vir_bytes) pr.pr_ptr,
			(phys_bytes) pr.pr_size);
	else
		r = sys_vircopy(who_e, D, (vir_bytes) pr.pr_ptr,
			child->mp_endpoint, seg, (vir_bytes) pr.pr_addr,
			(phys_bytes) pr.pr_size);

	if (r != OK) return(r);

	mp->mp_reply.reply_trace = 0;
	return(OK);

  case T_DETACH:	/* detach from traced process */
	if (m_in.data < 0 || m_in.data >= _NSIG) return(EINVAL);

	child->mp_tracer = NO_TRACER;

	/* Let all tracer-pending signals through the filter. */
	for (i = 1; i < _NSIG; i++) {
		if (sigismember(&child->mp_sigtrace, i)) {
			sigdelset(&child->mp_sigtrace, i);
			check_sig(child->mp_pid, i, FALSE /* ksig */);
		}
	}

	if (m_in.data > 0) {		/* issue signal */
		sig_proc(child, (int) m_in.data, TRUE /*trace*/, 
			FALSE /* ksig */);
	}

	/* Resume the child as if nothing ever happened. */ 
	child->mp_flags &= ~STOPPED;
	child->mp_trace_flags = 0;

	check_pending(child);

	break;

  case T_RESUME: 
  case T_STEP:
  case T_SYSCALL:	/* resume execution */
	if (m_in.data < 0 || m_in.data >= _NSIG) return(EINVAL);

	if (m_in.data > 0) {		/* issue signal */
		sig_proc(child, (int) m_in.data, FALSE /*trace*/,
			FALSE /* ksig */);
	}

	/* If there are any other signals waiting to be delivered,
	 * feign a successful resumption.
	 */
	for (i = 1; i < _NSIG; i++) {
		if (sigismember(&child->mp_sigtrace, i)) {
			mp->mp_reply.reply_trace = 0;
			return(OK);
		}
	}

	child->mp_flags &= ~STOPPED;

	check_pending(child);

	break;
  }
  r = sys_trace(req, child->mp_endpoint, m_in.PMTRACE_ADDR, &m_in.data);
  if (r != OK) return(r);

  mp->mp_reply.reply_trace = m_in.data;
  return(OK);
}