示例#1
0
void add_fork(child_pipe *child, int value, vertex *v)
/* Procedure forks vertex. Child process will be initialized with [value] as *
 * value, count equal to one and pipes duped into {0, 1} descriptors.        *
 * Parent process populates [child] structure with analogical descriptors    *
 * providing way to communication. Then sends confirmation signal into       *
 * output.                                                                   *
 *                                                                           *
 * MUTABLE PARAMETERS: v, child                                              */
{
  int result = 1;
  int *in = make_pipe(), *out = make_pipe();
  switch(fork())
  {
    case -1:
      syserr("fork failed");
      break;
    case 0:
      setup_child(in, out);
      vertex_init(v, value);
      break;
    default:
      setup_parent(child, in, out);
      checked_write(1, &result, sizeof(result));
      break;
  }
  free(in);
  free(out);
  return ;
}
示例#2
0
文件: pty.c 项目: myra/kmscon
/*
 * This is functionally equivalent to forkpty(3). We do it manually to obtain
 * a little bit more control of the process, and as a bonus avoid linking to
 * the libutil library in glibc.
 */
static int pty_spawn(struct kmscon_pty *pty, int master,
			unsigned short width, unsigned short height)
{
	pid_t pid;
	struct winsize ws;

	memset(&ws, 0, sizeof(ws));
	ws.ws_col = width;
	ws.ws_row = height;

	log_debug("forking child");
	pid = fork();
	switch (pid) {
	case -1:
		log_err("cannot fork: %m");
		return -errno;
	case 0:
		setup_child(master, &ws);
		exec_child(pty->fd);
		exit(EXIT_FAILURE);
	default:
		pty->fd = master;
		pty->child = pid;
		break;
	}

	return 0;
}
示例#3
0
void setup_domain_child(struct winbindd_domain *domain,
			struct winbindd_child *child)
{
	setup_child(child, domain_dispatch_table,
		    "log.wb", domain->name);

	child->domain = domain;
}
示例#4
0
文件: image.c 项目: albfan/w3m
static int
openImgdisplay()
{
    Imgdisplay_pid = open_pipe_rw(&Imgdisplay_rf, &Imgdisplay_wf);
    if (Imgdisplay_pid < 0)
	goto err0;
    if (Imgdisplay_pid == 0) {
	/* child */
	char *cmd;
	setup_child(FALSE, 2, -1);
	if (!strchr(Imgdisplay, '/'))
	    cmd = Strnew_m_charp(w3m_auxbin_dir(), "/", Imgdisplay, NULL)->ptr;
	else
	    cmd = Imgdisplay;
	myExec(cmd);
	/* XXX: ifdef __EMX__, use start /f ? */
    }
    activeImage = TRUE;
    return TRUE;
  err0:
    Imgdisplay_pid = 0;
    activeImage = FALSE;
    return FALSE;
}
示例#5
0
void init_locator_child(void)
{
	setup_child(&static_locator_child,
		    locator_dispatch_table,
		    "log.winbindd", "locator");
}
static SysRes do_clone (ThreadId ptid, 
                        UInt flags, Addr sp, 
                        Int * parent_tidptr,
                        Int * child_tidptr, 
                        Addr child_tls) 
{
   const Bool debug = False;
   ThreadId ctid = VG_ (alloc_ThreadState) ();
   ThreadState * ptst = VG_ (get_ThreadState) (ptid);
   ThreadState * ctst = VG_ (get_ThreadState) (ctid);
   UInt ret = 0;
   UWord * stack;
   SysRes res;
   vki_sigset_t blockall, savedmask;

   VG_ (sigfillset) (&blockall);
   vg_assert (VG_ (is_running_thread) (ptid));
   vg_assert (VG_ (is_valid_tid) (ctid));
   stack = (UWord *) ML_ (allocstack) (ctid);
   if (stack == NULL) {
      res = VG_ (mk_SysRes_Error) (VKI_ENOMEM);
      goto out;
   }
   setup_child (&ctst->arch, &ptst->arch);

   /* on MIPS we need to set V0 and A3 to zero */ 
   ctst->arch.vex.guest_r2 = 0;
   ctst->arch.vex.guest_r7 = 0;
   if (sp != 0)
      ctst->arch.vex.guest_r29 = sp;

   ctst->os_state.parent = ptid;
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* Start the child with its threadgroup being the same as the
      parent's.  This is so that any exit_group calls that happen
      after the child is created but before it sets its
      os_state.threadgroup field for real (in thread_wrapper in
      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
      a race condition in which the thread is unkillable (via
      exit_group) because its threadgroup is not set.  The race window
      is probably only a few hundred or a few thousand cycles long.
      See #226116. */ 

   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (sp, ctst);

   VG_TRACK (pre_thread_ll_create, ptid, ctid);
   if (flags & VKI_CLONE_SETTLS) {
      if (debug)
        VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
      ctst->arch.vex.guest_r27 = child_tls;
      res = sys_set_tls(ctid, child_tls);
      if (sr_isError(res))
         goto out;
      ctst->arch.vex.guest_r27 = child_tls;
  }

   flags &= ~VKI_CLONE_SETTLS;
   VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
   /* Create the new thread */ 
   ret = do_syscall_clone_mips_linux (ML_ (start_thread_NORETURN),
                                    stack, flags, &VG_ (threads)[ctid], 
                                    child_tidptr, parent_tidptr,
                                    0 /*child_tls*/);

   /* High half word64 is syscall return value.  Low half is
      the entire CR, from which we need to extract CR0.SO. */ 
   if (debug)
      VG_(printf)("ret: 0x%x\n", ret);

   res = VG_ (mk_SysRes_mips32_linux) (/*val */ ret, 0, /*errflag */ 0);

   VG_ (sigprocmask) (VKI_SIG_SETMASK, &savedmask, NULL);

   out:
   if (sr_isError (res)) {
      VG_(cleanup_thread) (&ctst->arch);
      ctst->status = VgTs_Empty;
      VG_TRACK (pre_thread_ll_exit, ctid);
   }
   ptst->arch.vex.guest_r2 = 0;

   return res;
}
示例#7
0
/* 
   When a client clones, we need to keep track of the new thread.  This means:
   1. allocate a ThreadId+ThreadState+stack for the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested,
   but using the scheduler entrypoint for EIP, and a separate stack
   for ESP.
 */
static SysRes do_clone ( ThreadId ptid, 
                         ULong flags, Addr rsp, 
                         Long* parent_tidptr, 
                         Long* child_tidptr, 
                         Addr tlsaddr )
{
   static const Bool debug = False;

   ThreadId     ctid = VG_(alloc_ThreadState)();
   ThreadState* ptst = VG_(get_ThreadState)(ptid);
   ThreadState* ctst = VG_(get_ThreadState)(ctid);
   UWord*       stack;
   SysRes       res;
   Long         rax;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);

   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));

   stack = (UWord*)ML_(allocstack)(ctid);
   if (stack == NULL) {
      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
      goto out;
   }

   /* Copy register state

      Both parent and child return to the same place, and the code
      following the clone syscall works out which is which, so we
      don't need to worry about it.

      The parent gets the child's new tid returned from clone, but the
      child gets 0.

      If the clone call specifies a NULL rsp for the new thread, then
      it actually gets a copy of the parent's rsp.
   */
   setup_child( &ctst->arch, &ptst->arch );

   /* Make sys_clone appear to have returned Success(0) in the
      child. */
   ctst->arch.vex.guest_RAX = 0;

   if (rsp != 0)
      ctst->arch.vex.guest_RSP = rsp;

   ctst->os_state.parent = ptid;

   /* inherit signal mask */
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* Start the child with its threadgroup being the same as the
      parent's.  This is so that any exit_group calls that happen
      after the child is created but before it sets its
      os_state.threadgroup field for real (in thread_wrapper in
      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
      a race condition in which the thread is unkillable (via
      exit_group) because its threadgroup is not set.  The race window
      is probably only a few hundred or a few thousand cycles long.
      See #226116. */
   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (rsp, ctst);

   /* Assume the clone will succeed, and tell any tool that wants to
      know that this thread has come into existence.  If the clone
      fails, we'll send out a ll_exit notification for it at the out:
      label below, to clean up. */
   vg_assert(VG_(owns_BigLock_LL)(ptid));
   VG_TRACK ( pre_thread_ll_create, ptid, ctid );

   if (flags & VKI_CLONE_SETTLS) {
      if (debug)
	 VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr);
      ctst->arch.vex.guest_FS_CONST = tlsaddr;
   }

   flags &= ~VKI_CLONE_SETTLS;

   /* start the thread with everything blocked */
   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);

   /* Create the new thread */
   rax = do_syscall_clone_amd64_linux(
            ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
            child_tidptr, parent_tidptr, NULL
         );
   res = VG_(mk_SysRes_amd64_linux)( rax );

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

  out:
   if (sr_isError(res)) {
      /* clone failed */
      VG_(cleanup_thread)(&ctst->arch);
      ctst->status = VgTs_Empty;
      /* oops.  Better tell the tool the thread exited in a hurry :-) */
      VG_TRACK( pre_thread_ll_exit, ctid );
   }

   return res;
}
/* 
   When a client clones, we need to keep track of the new thread.  This means:
   1. allocate a ThreadId+ThreadState+stack for the the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested,
   but using the scheduler entrypoint for EIP, and a separate stack
   for ESP.
 */
static SysRes do_clone ( ThreadId ptid, 
                         ULong flags, Addr rsp, 
                         Long* parent_tidptr, 
                         Long* child_tidptr, 
                         Addr tlsaddr )
{
   static const Bool debug = False;

   ThreadId     ctid = VG_(alloc_ThreadState)();
   ThreadState* ptst = VG_(get_ThreadState)(ptid);
   ThreadState* ctst = VG_(get_ThreadState)(ctid);
   UWord*       stack;
   NSegment*    seg;
   SysRes       res;
   Long         rax;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);

   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));

   stack = (UWord*)ML_(allocstack)(ctid);
   if (stack == NULL) {
      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
      goto out;
   }

   /* Copy register state

      Both parent and child return to the same place, and the code
      following the clone syscall works out which is which, so we
      don't need to worry about it.

      The parent gets the child's new tid returned from clone, but the
      child gets 0.

      If the clone call specifies a NULL rsp for the new thread, then
      it actually gets a copy of the parent's rsp.
   */
   setup_child( &ctst->arch, &ptst->arch );

   /* Make sys_clone appear to have returned Success(0) in the
      child. */
   ctst->arch.vex.guest_RAX = 0;

   if (rsp != 0)
      ctst->arch.vex.guest_RSP = rsp;

   ctst->os_state.parent = ptid;

   /* inherit signal mask */
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* We don't really know where the client stack is, because its
      allocated by the client.  The best we can do is look at the
      memory mappings and try to derive some useful information.  We
      assume that esp starts near its highest possible value, and can
      only go down to the start of the mmaped segment. */
   seg = VG_(am_find_nsegment)((Addr)rsp);
   if (seg && seg->kind != SkResvn) {
      ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(rsp);
      ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;

      if (debug)
	 VG_(printf)("tid %d: guessed client stack range %p-%p\n",
		     ctid, seg->start, VG_PGROUNDUP(rsp));
   } else {
      VG_(message)(Vg_UserMsg, "!? New thread %d starts with RSP(%p) unmapped\n",
		   ctid, rsp);
      ctst->client_stack_szB  = 0;
   }

   if (flags & VKI_CLONE_SETTLS) {
      if (debug)
	 VG_(printf)("clone child has SETTLS: tls at %p\n", tlsaddr);
      ctst->arch.vex.guest_FS_ZERO = tlsaddr;
   }

   flags &= ~VKI_CLONE_SETTLS;

   /* start the thread with everything blocked */
   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);

   /* Create the new thread */
   rax = do_syscall_clone_amd64_linux(
            ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
            child_tidptr, parent_tidptr, NULL
         );
   res = VG_(mk_SysRes_amd64_linux)( rax );

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

  out:
   if (res.isError) {
      /* clone failed */
      VG_(cleanup_thread)(&ctst->arch);
      ctst->status = VgTs_Empty;
   }

   return res;
}
示例#9
0
文件: ldap_init.c 项目: scaria/sssd
int sssm_ldap_id_init(struct be_ctx *bectx,
                      struct bet_ops **ops,
                      void **pvt_data)
{
    struct sdap_id_ctx *ctx;
    const char *urls;
    const char *dns_service_name;
    const char *sasl_mech;
    int ret;

    /* If we're already set up, just return that */
    if(bectx->bet_info[BET_ID].mod_name &&
       strcmp("ldap", bectx->bet_info[BET_ID].mod_name) == 0) {
        DEBUG(8, ("Re-using sdap_id_ctx for this provider\n"));
        *ops = bectx->bet_info[BET_ID].bet_ops;
        *pvt_data = bectx->bet_info[BET_ID].pvt_bet_data;
        return EOK;
    }

    ctx = talloc_zero(bectx, struct sdap_id_ctx);
    if (!ctx) return ENOMEM;

    ctx->be = bectx;

    ret = ldap_get_options(ctx, bectx->cdb,
                           bectx->conf_path, &ctx->opts);
    if (ret != EOK) {
        goto done;
    }

    dns_service_name = dp_opt_get_string(ctx->opts->basic,
                                         SDAP_DNS_SERVICE_NAME);
    DEBUG(7, ("Service name for discovery set to %s\n", dns_service_name));

    urls = dp_opt_get_string(ctx->opts->basic, SDAP_URI);
    if (!urls) {
        DEBUG(1, ("Missing ldap_uri, will use service discovery\n"));
    }

    ret = sdap_service_init(ctx, ctx->be, "LDAP",
                            dns_service_name, urls, &ctx->service);
    if (ret != EOK) {
        DEBUG(1, ("Failed to initialize failover service!\n"));
        goto done;
    }

    sasl_mech = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_MECH);
    if (sasl_mech && strcasecmp(sasl_mech, "GSSAPI") == 0) {
        if (dp_opt_get_bool(ctx->opts->basic, SDAP_KRB5_KINIT)) {
            ret = sdap_gssapi_init(ctx, ctx->opts->basic,
                                   ctx->be, ctx->service,
                                   &ctx->krb5_service);
            if (ret !=  EOK) {
                DEBUG(1, ("sdap_gssapi_init failed [%d][%s].\n",
                            ret, strerror(ret)));
                goto done;
            }
        }
    }

    ret = setup_tls_config(ctx->opts->basic);
    if (ret != EOK) {
        DEBUG(1, ("setup_tls_config failed [%d][%s].\n",
                  ret, strerror(ret)));
        goto done;
    }

    ret = sdap_id_conn_cache_create(ctx, ctx, &ctx->conn_cache);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_id_setup_tasks(ctx);
    if (ret != EOK) {
        goto done;
    }

    ret = setup_child(ctx);
    if (ret != EOK) {
        DEBUG(1, ("setup_child failed [%d][%s].\n",
                  ret, strerror(ret)));
        goto done;
    }

    *ops = &sdap_id_ops;
    *pvt_data = ctx;
    ret = EOK;

done:
    if (ret != EOK) {
        talloc_free(ctx);
    }
    return ret;
}
示例#10
0
static int
start_daemon (pam_handle_t *ph, struct passwd *pwd, const char *password)
{
	struct sigaction defsact, oldsact, ignpipe, oldpipe;
	int inp[2] = { -1, -1 };
	int outp[2] = { -1, -1 };
	int errp[2] = { -1, -1 };
	int ret = PAM_SERVICE_ERR;
	pid_t pid;
	char *output = NULL;
	char *outerr = NULL;
	int failed, status;
	
	assert (pwd);

	/* 
	 * Make sure that SIGCHLD occurs. Otherwise our waitpid below
	 * doesn't work properly. We need to wait on the process to 
	 * get the daemon exit status.
	 */
	memset (&defsact, 0, sizeof (defsact));
	memset (&oldsact, 0, sizeof (oldsact));
	defsact.sa_handler = SIG_DFL;
	sigaction (SIGCHLD, &defsact, &oldsact);
	
	/*
	 * Make sure we don't exit with a SIGPIPE while doing this, that 
	 * would be very annoying to a user trying to log in.
	 */	
	memset (&ignpipe, 0, sizeof (ignpipe));
	memset (&oldpipe, 0, sizeof (oldpipe));
	ignpipe.sa_handler = SIG_IGN;
	sigaction (SIGPIPE, &ignpipe, &oldpipe);
	
	/* Create the necessary pipes */
	if (pipe (inp) < 0 || pipe (outp) < 0 || pipe (errp) < 0) {
	    	syslog (GKR_LOG_ERR, "gkr-pam: couldn't create pipes: %s", 
	    	        strerror (errno));
	    	goto done;
	}

	/* Start up daemon child process */
	switch (pid = fork ()) {
	case -1:
		syslog (GKR_LOG_ERR, "gkr-pam: couldn't fork: %s", 
		        strerror (errno));
		goto done;
		
	/* This is the child */
	case 0:
		setup_child (inp, outp, errp, ph, pwd);
		/* Should never be reached */
		break;
		
	/* This is the parent */
	default:
		break;
	};

	/* Close our unneeded ends of the pipes */
	close (inp[READ_END]);
	close (outp[WRITE_END]);
	close (errp[WRITE_END]);
	inp[READ_END] = outp[WRITE_END] = errp[WRITE_END] = -1; 

	/*
	 * We always pass in a --login argument, even when we have a NULL password
	 * since this controls the startup behavior. When using --login daemon waits
	 * for a password. Closing input signifies password is done.
	 */

	if (password)
		write_string (inp[WRITE_END], password);
	close (inp[WRITE_END]);

	/* 
	 * Note that we're not using select() or any such. We know how the 
	 * daemon sends its data.
	 */

	/* Read any stdout and stderr data */
	output = read_string (outp[READ_END]);
	outerr = read_string (errp[READ_END]);
	if (!output || !outerr) {
		syslog (GKR_LOG_ERR, "gkr-pam: couldn't read data from mate-keyring-daemon: %s", 
		        strerror (errno));
		goto done;
	}

	/* Wait for the initial process to exit */
	if (waitpid (pid, &status, 0) < 0) {
		syslog (GKR_LOG_ERR, "gkr-pam: couldn't wait on mate-keyring-daemon process: %s",
		        strerror (errno));
		goto done;
	}
	
	failed = !WIFEXITED (status) || WEXITSTATUS (status) != 0;
	if (outerr && outerr[0])
		foreach_line (outerr, log_problem, &failed);
	
	/* Failure from process */
	if (failed) {
		syslog (GKR_LOG_ERR, "gkr-pam: mate-keyring-daemon didn't start properly properly");
		goto done;
	}
		
	ret = foreach_line (output, setup_environment, ph);

done:
	/* Restore old handler */
	sigaction (SIGCHLD, &oldsact, NULL);
	sigaction (SIGPIPE, &oldpipe, NULL);
	
	close_safe (inp[0]);
	close_safe (inp[1]);
	close_safe (outp[0]);
	close_safe (outp[1]);
	close_safe (errp[0]);
	close_safe (errp[1]);
	
	free_safe (output);
	free_safe (outerr);

	return ret;
}
/* When a client clones, we need to keep track of the new thread. This means:
   1. allocate a ThreadId+ThreadState+stack for the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested, but using
      the scheduler entrypoint for IP, and a separate stack for SP. */
static SysRes do_clone ( ThreadId ptid,
                         UInt flags, Addr sp,
                         Int* parent_tidptr,
                         Int* child_tidptr,
                         Addr child_tls )
{
   const Bool debug = False;
   ThreadId ctid = VG_ (alloc_ThreadState) ();
   ThreadState * ptst = VG_ (get_ThreadState) (ptid);
   ThreadState * ctst = VG_ (get_ThreadState) (ctid);
   UInt ret = 0;
   UWord * stack;
   SysRes res;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);
   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));
   stack = (UWord *)ML_(allocstack)(ctid);
   if (stack == NULL) {
      res = VG_(mk_SysRes_Error)(VKI_ENOMEM);
      goto out;
   }
   setup_child(&ctst->arch, &ptst->arch);

   /* on MIPS we need to set V0 and A3 to zero */
   ctst->arch.vex.guest_r2 = 0;
   ctst->arch.vex.guest_r7 = 0;
   if (sp != 0)
      ctst->arch.vex.guest_r29 = sp;

   ctst->os_state.parent = ptid;
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (sp, ctst);

   VG_TRACK(pre_thread_ll_create, ptid, ctid);
   if (flags & VKI_CLONE_SETTLS) {
       if (debug)
         VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
       res = sys_set_tls(ctid, child_tls);
       if (sr_isError(res))
          goto out;
       ctst->arch.vex.guest_r27 = child_tls;
   }

   flags &= ~VKI_CLONE_SETTLS;
   VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
   /* Create the new thread */
   ret = do_syscall_clone_mips64_linux(ML_(start_thread_NORETURN),
                                       stack, flags, &VG_(threads)[ctid],
                                       parent_tidptr, NULL /*child_tls*/,
                                       child_tidptr);
   if (debug)
     VG_(printf)("ret: 0x%x\n", ret);

   res = VG_(mk_SysRes_mips64_linux)( /* val */ ret, 0, /* errflag */ 0);

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

   out:
   if (sr_isError (res)) {
      VG_ (cleanup_thread) (&ctst->arch);
      ctst->status = VgTs_Empty;
      VG_TRACK (pre_thread_ll_exit, ctid);
   }
   ptst->arch.vex.guest_r2 = 0;

   return res;
}
示例#12
0
文件: command.c 项目: Onway/anoj
void
execute_command()
{
    int signo;
    int status;
    pid_t child;
    struct rusage used;
    struct user_regs_struct regs;

    child = fork();
    if (child == 0)
        setup_child();

    wait3(&status, 0, &used);

    /* 子进程在exec之前退出 */
    if (WIFEXITED(status)) {
        switch (WEXITSTATUS(status)) {
        case 0 :
            g_string_assign(result->err, "drop privileges error");
            break;
        case 1 :
            g_string_assign(result->err, "execvpe error");
            break;
        case 2 :
            g_string_assign(result->err, "open input file error");
            break;
        case 3 :
            g_string_assign(result->err, "open output file error");
            break;
        case 4 :
            g_string_assign(result->err, "dup2 input error");
            break;
        case 5 :
            g_string_assign(result->err, "dup2 ouput error");
            break;
        }
        result->code = EXIT_IE;
        return;
    }

    /* 期待子进程被停止,如果不是,则 */
    if (!WIFSTOPPED(status)) {
        kill(child, SIGKILL);
        result->code = EXIT_IE;
        g_string_assign(result->err,
                        "unknow child status before execve");
        return;
    }

    /* 子进程停止原因,期待是SYS_execve和SIGTRAP停止 */
    signo = WSTOPSIG(status);
    ptrace(PTRACE_GETREGS, child, NULL, &regs);
    if (signo != SIGTRAP || regs.orig_rax != SYS_execve) {
        kill(child, SIGKILL);
        result->code = EXIT_IE;
        g_string_assign(result->err,
                        "unexpected child stop before execve");
        return;

    }

    /*
     * 注册父进程挂种时间及超时回跳位置
     * 超挂种时间直接判超时,检查内存没有必要了。
     */
    signal(SIGALRM, alarm_func);
    if (setjmp(jbuf)) {
        kill(child, SIGKILL);
        result->time = ltime;
        result->code = EXIT_TLE;
        return;
    }
    alarm(ltime / 1000 + 2);

    /* 继续并跟踪子进程 */
    ptrace(PTRACE_SYSCALL, child, NULL, NULL);
    trace_child(child);

    /* 非超时返回 */
    alarm(0);

    if (strcmp(lang, "python") == 0)
        python_filter();
    return;
}
示例#13
0
/* When a client clones, we need to keep track of the new thread. This means:
   1. allocate a ThreadId+ThreadState+stack for the the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested, but using
      the scheduler entrypoint for IP, and a separate stack for SP. */
static SysRes do_clone ( ThreadId ptid,
                         UInt flags, Addr sp,
                         Int* parent_tidptr,
                         Int* child_tidptr,
                         Addr child_tls )
{
   const Bool debug = False;
   ThreadId ctid = VG_ (alloc_ThreadState) ();
   ThreadState * ptst = VG_ (get_ThreadState) (ptid);
   ThreadState * ctst = VG_ (get_ThreadState) (ctid);
   UInt ret = 0;
   UWord * stack;
   NSegment const *seg;
   SysRes res;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);
   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));
   stack = (UWord *)ML_(allocstack)(ctid);
   if (stack == NULL) {
      res = VG_(mk_SysRes_Error)(VKI_ENOMEM);
      goto out;
   }
   setup_child(&ctst->arch, &ptst->arch);

   /* on MIPS we need to set V0 and A3 to zero */
   ctst->arch.vex.guest_r2 = 0;
   ctst->arch.vex.guest_r7 = 0;
   if (sp != 0)
      ctst->arch.vex.guest_r29 = sp;

   ctst->os_state.parent = ptid;
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
   seg = VG_(am_find_nsegment)((Addr)sp);

   if (seg && seg->kind != SkResvn) {
      ctst->client_stack_highest_word = sp;
      ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;
      VG_(register_stack)(seg->start, ctst->client_stack_highest_word);
      if (debug)
        VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
                    ctid, seg->start, sp /* VG_PGROUNDUP (sp) */ );
   } else {
      VG_(message)(Vg_UserMsg,
                    "!? New thread %d starts with sp+%#lx) unmapped\n",
                    ctid, sp);
      ctst->client_stack_szB = 0;
   }

   VG_TRACK(pre_thread_ll_create, ptid, ctid);
   if (flags & VKI_CLONE_SETTLS) {
       if (debug)
         VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
       res = sys_set_tls(ctid, child_tls);
       if (sr_isError(res))
          goto out;
       ctst->arch.vex.guest_r27 = child_tls;
   }

   flags &= ~VKI_CLONE_SETTLS;
   VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
   /* Create the new thread */
   ret = do_syscall_clone_mips64_linux(ML_(start_thread_NORETURN),
                                       stack, flags, &VG_(threads)[ctid],
                                       parent_tidptr, NULL /*child_tls*/,
                                       child_tidptr);
   if (debug)
     VG_(printf)("ret: 0x%x\n", ret);

   res = VG_(mk_SysRes_mips64_linux)( /* val */ ret, 0, /* errflag */ 0);

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

   out:
   if (sr_isError (res)) {
      VG_ (cleanup_thread) (&ctst->arch);
      ctst->status = VgTs_Empty;
      VG_TRACK (pre_thread_ll_exit, ctid);
   }
   ptst->arch.vex.guest_r2 = 0;

   return res;
}
/* 
   When a client clones, we need to keep track of the new thread.  This means:
   1. allocate a ThreadId+ThreadState+stack for the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested,
   but using the scheduler entrypoint for IP, and a separate stack
   for SP.
 */
static SysRes do_clone ( ThreadId ptid, 
                         UInt flags, Addr sp, 
                         Int *parent_tidptr, 
                         Int *child_tidptr, 
                         Addr child_tls)
{
   ThreadId ctid = VG_(alloc_ThreadState)();
   ThreadState* ptst = VG_(get_ThreadState)(ptid);
   ThreadState* ctst = VG_(get_ThreadState)(ctid);
   UInt r0;
   UWord *stack;
   SysRes res;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);

   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));

   stack = (UWord*)ML_(allocstack)(ctid);

   if(stack == NULL) {
      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
      goto out;
   }

   setup_child( &ctst->arch, &ptst->arch );

   ctst->arch.vex.guest_R0 = 0;
   if(sp != 0)
      ctst->arch.vex.guest_R13 = sp;

   ctst->os_state.parent = ptid;

   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* Start the child with its threadgroup being the same as the
      parent's.  This is so that any exit_group calls that happen
      after the child is created but before it sets its
      os_state.threadgroup field for real (in thread_wrapper in
      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
      a race condition in which the thread is unkillable (via
      exit_group) because its threadgroup is not set.  The race window
      is probably only a few hundred or a few thousand cycles long.
      See #226116. */
   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (sp, ctst);

   vg_assert(VG_(owns_BigLock_LL)(ptid));
   VG_TRACK ( pre_thread_ll_create, ptid, ctid );

   if (flags & VKI_CLONE_SETTLS) {
      /* Just assign the tls pointer in the guest TPIDRURO. */
      assign_guest_tls(ctid, child_tls);
   }
    
   flags &= ~VKI_CLONE_SETTLS;

   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);

   r0 = do_syscall_clone_arm_linux(
      ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
      child_tidptr, parent_tidptr, NULL
   );
   //VG_(printf)("AFTER SYSCALL, %x and %x  CHILD: %d PARENT: %d\n",child_tidptr, parent_tidptr,*child_tidptr,*parent_tidptr);
    
   res = VG_(mk_SysRes_arm_linux)( r0 );

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

out:
   if (sr_isError(res)) {
      VG_(cleanup_thread)(&ctst->arch);
      ctst->status = VgTs_Empty;
      VG_TRACK( pre_thread_ll_exit, ctid );
   }

   return res;
}
示例#15
0
/* 
   When a client clones, we need to keep track of the new thread.  This means:
   1. allocate a ThreadId+ThreadState+stack for the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested,
   but using the scheduler entrypoint for IP, and a separate stack
   for SP.
 */
static SysRes do_clone ( ThreadId ptid, 
                         UInt flags, Addr sp, 
                         Int *parent_tidptr, 
                         Int *child_tidptr, 
                         Addr child_tls)
{
   const Bool debug = False;

   ThreadId     ctid = VG_(alloc_ThreadState)();
   ThreadState* ptst = VG_(get_ThreadState)(ptid);
   ThreadState* ctst = VG_(get_ThreadState)(ctid);
   ULong        word64;
   UWord*       stack;
   SysRes       res;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);

   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));

   stack = (UWord*)ML_(allocstack)(ctid);
   if (stack == NULL) {
      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
      goto out;
   }

//?   /* make a stack frame */
//?   stack -= 16;
//?   *(UWord *)stack = 0;


   /* Copy register state

      Both parent and child return to the same place, and the code
      following the clone syscall works out which is which, so we
      don't need to worry about it.

      The parent gets the child's new tid returned from clone, but the
      child gets 0.

      If the clone call specifies a NULL SP for the new thread, then
      it actually gets a copy of the parent's SP.

      The child's TLS register (r2) gets set to the tlsaddr argument
      if the CLONE_SETTLS flag is set.
   */
   setup_child( &ctst->arch, &ptst->arch );

   /* Make sys_clone appear to have returned Success(0) in the
      child. */
   { UInt old_cr = LibVEX_GuestPPC64_get_CR( &ctst->arch.vex );
     /* %r3 = 0 */
     ctst->arch.vex.guest_GPR3 = 0;
     /* %cr0.so = 0 */
     LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
   }

   if (sp != 0)
      ctst->arch.vex.guest_GPR1 = sp;

   ctst->os_state.parent = ptid;

   /* inherit signal mask */
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* Start the child with its threadgroup being the same as the
      parent's.  This is so that any exit_group calls that happen
      after the child is created but before it sets its
      os_state.threadgroup field for real (in thread_wrapper in
      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
      a race condition in which the thread is unkillable (via
      exit_group) because its threadgroup is not set.  The race window
      is probably only a few hundred or a few thousand cycles long.
      See #226116. */
   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (sp, ctst);

   /* Assume the clone will succeed, and tell any tool that wants to
      know that this thread has come into existence.  If the clone
      fails, we'll send out a ll_exit notification for it at the out:
      label below, to clean up. */
   vg_assert(VG_(owns_BigLock_LL)(ptid));
   VG_TRACK ( pre_thread_ll_create, ptid, ctid );

   if (flags & VKI_CLONE_SETTLS) {
      if (debug)
         VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
      ctst->arch.vex.guest_GPR13 = child_tls;
   }

   flags &= ~VKI_CLONE_SETTLS;

   /* start the thread with everything blocked */
   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);

   /* Create the new thread */
   word64 = do_syscall_clone_ppc64_linux(
               ML_(start_thread_NORETURN),
               stack, flags, &VG_(threads)[ctid],
               child_tidptr, parent_tidptr, NULL
            );

   /* Low half word64 is syscall return value.  Hi half is
      the entire CR, from which we need to extract CR0.SO. */
   /* VG_(printf)("word64 = 0x%llx\n", word64); */
   res = VG_(mk_SysRes_ppc64_linux)( 
            /*val*/(UInt)(word64 & 0xFFFFFFFFULL), 
            /*errflag*/ (UInt)((word64 >> (32+28)) & 1)
         );

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

  out:
   if (sr_isError(res)) {
      /* clone failed */
      VG_(cleanup_thread)(&ctst->arch);
      ctst->status = VgTs_Empty;
      /* oops.  Better tell the tool the thread exited in a hurry :-) */
      VG_TRACK( pre_thread_ll_exit, ctid );
   }

   return res;
}
示例#16
0
文件: cthelper.c 项目: Chaz6/futty
int
main(int argc, char *const *argv)
{
  int
    c,      /* control descriptor (stdin) */
    s;      /* socket descriptor (PuTTY) */
  Buffer
    cbuf,   /* control buffer */
    pbuf,   /* pty buffer */
    sbuf;   /* socket buffer */

  DBUG_INIT_ENV("main",argv[0],"DBUG_OPTS");

#ifndef DBUG_OFF
  setvbuf(DBUG_FILE, 0, _IONBF, 0);
#endif

  /* General steps:
    1. connect to cygterm backend
    2. create pty
    3. fork child process (/bin/bash)
    4. select on pty, cygterm backend forwarding pty data and messages
  */

  if (argc < 4) {
    DBUG_PRINT("error", ("Too few arguments"));
    DBUG_RETURN(CthelperInvalidUsage);
  }

  DBUG_PRINT("startup", ("isatty: (%d,%d,%d)",
    isatty(STDIN_FILENO), isatty(STDOUT_FILENO), isatty(STDERR_FILENO)));
  DBUG_PRINT("startup", (
    "cmdline: [%s] %s %s %s ...", argv[0], argv[1], argv[2], argv[3]));
  {
    extern char **environ;
    char **envp;
    for (envp = environ; *envp; envp++)
      DBUG_PRINT("startup", ("%s", *envp));
  }

  /* It is not necessary to close all open descriptors.  There are no
   * files inherited from the PuTTY process except standard input.
   */
#ifndef DEBUG
  close(STDERR_FILENO);
#endif

  /* Duplicate c and open /dev/null as 0 so that 0 can mean "closed". */
  c = dup(STDIN_FILENO); close(STDIN_FILENO);
  open("/dev/null", O_RDWR);

  /* Command line:
   * argv[1] =  port number
   * argv[2] =  terminal name
   * argv[3] =  terminal characteristics string
   * Any remaining arguments are the command to execute.  If there are no
   * other arguments, use the user's default login shell with a - prefix
   * for its argv[0].
   */
/*
cthelper command line parameters:

cthelper PORT TERM ATTRS [COMMAND [ARGS]]

    PORT
        port number for PuTTY pty input data socket
    TERM
        name of terminal (set TERM environment variable)
    ATTRS
    a colon-separated list of terminal attributes
    See init_pty() for details.
    COMMAND
        Runs COMMAND with ARGS as child process.  If COMMAND is not
        supplied, cthelper will run the user's login shell as specified in
        /etc/passwd specifying "-" for its argv[0] as typical.
*/


  /* connect to cygterm */
  {
    int ct_port = strtol(argv[1], 0, 0);
#ifdef DEBUG
    if (ct_port == 0) {
      /* For debugging purposes, make the tty we are started
       * in the "socket". This allows to test cthelper without
       * putty.exe */
      assert(isatty(STDOUT_FILENO));
      raw();
      atexit(restore);
      c = open("/dev/null", O_RDONLY);
      s = dup(STDOUT_FILENO);
    }
    else 
#endif
    if (ct_port <= 0) {
      DBUG_PRINT("startup", ("invalid port"));
      DBUG_RETURN(CthelperInvalidPort);
    }
    DBUG_PRINT("startup", ("connect cygterm"));
    if (0 > (s = connect_cygterm(ct_port))) {
      DBUG_PRINT("startup", ("connect_cygterm: bad"));
      DBUG_RETURN(CthelperConnectFailed);
    }
    DBUG_PRINT("startup", ("OK"));
  }

  /* initialize buffers */
  DBUG_PRINT("startup", ("initialize buffers"));
  BUFFER_ALLOCA(cbuf, CTLBUF);
  BUFFER_ALLOCA(pbuf, PTOBUF);
  BUFFER_ALLOCA(sbuf, PTIBUF);

  /* set up signal handling */
  signal(SIGCHLD, handle_sigchld);

  /* start child process */
  if (0 > (t = setup_child(&child, argv[2], argv[3], argv + 4))) {
    DBUG_PRINT("startup", ("setup_child failed: %s", strerror(-t)));
    DBUG_RETURN(CthelperPtyforkFailure);
  }

  /*  To explain what is happening here:
   *  's' is the socket between PuTTY and cthelper; it is read to get
   *  input for the tty and written to display output from the pty.
   *  't' is the pseudo terminal; it is read to get pty input which is sent to
   *  PuTTY and written to pass input from PuTTY to the pty.
   *  'c' is standard input, which is a one-way anonymous pipe from PuTTY.
   *  It is read to receive special messages from PuTTY such as
   *  terminal resize events.
   *
   *  This is the flow of data through the buffers:
   *      s => sbuf => t
   *      t => pbuf => s
   *      c => cbuf => process_message()
   *
   *  When 't' is closed, we close(s) to signal PuTTY we are done.
   *  When 's' is closed, we kill(child, HUP) to kill the child process.
   */

  setnonblock(c);
  setnonblock(s);
  setnonblock(t);

  DBUG_PRINT("info", ("c==%d, s==%d, t==%d", c, s, t));
  /* allow easy select() and FD_ISSET() stuff */
  assert(0 < c && c < s && s < t);
  DBUG_PRINT("startup", ("starting select loop"));
  while (s || t) {
    int n = 0;
    fd_set r, w;
    DBUG_ENTER("select");
    FD_ZERO(&r); FD_ZERO(&w);
    if (c && !buffer_isfull(cbuf)) { FD_SET(c, &r); n = c; }
    if (s && !buffer_isfull(sbuf)) { FD_SET(s, &r); n = s; }
    if (s && !buffer_isempty(pbuf)) { FD_SET(s, &w); n = s; }
    if (t && !buffer_isfull(pbuf)) { FD_SET(t, &r); n = t; }
    if (t && !buffer_isempty(sbuf)) { FD_SET(t, &w); n = t; }
    switch (n = select(n + 1, &r, &w, 0, 0)) {
    case -1:
      DBUG_PRINT("error", ("%s", strerror(errno)));
      if (errno != EINTR) {
        /* Something bad happened */
        close(c); c = 0;
        close(s); s = 0;
        close(t); t = 0;
      }
      break;
    case 0:
      DBUG_PRINT("info", ("select timeout"));
      break;
    default:
      DBUG_PRINT("info", ("%d ready descriptors [[r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w));
      if (FD_ISSET(c, &r)) {
        DBUG_ENTER("c=>cbuf");
        switch (buffer_read(cbuf, c)) {
        case -1:
          DBUG_PRINT("error", ("error reading c: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the message pipe */
          DBUG_PRINT("io", ("c closed"));
          close(c); c = 0;
          break;
        default:
          DBUG_PRINT("io", ("cbuf => process_message()"));
          process_message(cbuf, t);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(s, &r)) {
        DBUG_ENTER("s=>sbuf");
        switch (buffer_read(sbuf, s)) {
        case -1:
          DBUG_PRINT("error", ("error reading s: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the socket */
          DBUG_PRINT("io", ("s closed"));
          close(s); s = 0;
          break;
        default:
          FD_SET(t, &w);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(t, &r)) {
        DBUG_ENTER("t=>pbuf");
        switch (buffer_read(pbuf, t)) {
        case -1:
          DBUG_PRINT("error", ("error reading t: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* pty closed */
          DBUG_PRINT("io", ("t closed"));
          if (!FD_ISSET(t, &w)) {
            close(t); t = 0;
          }
          break;
        default:
          FD_SET(s, &w);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(t, &w)) {
        DBUG_ENTER("sbuf=>t");
        switch (buffer_write(sbuf, t)) {
        case -1:
          DBUG_PRINT("error", ("error writing t: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* pty closed */
          DBUG_PRINT("io", ("t closed"));
          close(t); t = 0;
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(s, &w)) {
        DBUG_ENTER("pbuf=>s");
        switch (buffer_write(pbuf, s)) {
        case -1:
          DBUG_PRINT("error", ("error writing s: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the socket */
          DBUG_PRINT("io", ("s closed"));
          close(s); s = 0;
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      DBUG_PRINT("info", ("[[n==%d,r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w));
      assert(n == 0);
      break;
    }

    if (child_signalled) check_child();

    if (!t && buffer_isempty(pbuf)) {
      DBUG_PRINT("info", ("shutdown socket"));
      shutdown(s, SHUT_WR);
    }

    if (!s && buffer_isempty(sbuf) && child_alive()) {
      DBUG_PRINT("sig", ("kill child"));
      kill(child, SIGHUP);
      /* handle_sigchld() will close(t) */
    }
    DBUG_LEAVE;
  }
  DBUG_PRINT("info", ("end of select loop"));

  /* ensure child process killed */
  /* XXX I'm not sure if all of this is necessary, but it probably won't
   * hurt anything. */
  if (child_alive() && sleep(1) == 0) {
    DBUG_PRINT("sig", ("waiting for child"));
    waitpid(child, 0, WNOHANG);
  }

  DBUG_PRINT("info", ("goodbye"));
  if (exit_status == 111)
    DBUG_RETURN(CthelperExecFailure);
  DBUG_RETURN(EXIT_SUCCESS);
}