Esempio n. 1
0
int
_zexec_init_template(void)
{
	int fd;
	int err = 0;

	fd = open64(CTFS_ROOT "/process/template", O_RDWR);
	if (fd == -1) {
		return (-1);
	}

	/*
	 * zlogin doesn't do anything with the contract.
	 * Deliver no events, don't inherit, and allow it to be orphaned.
	 */
	err |= ct_tmpl_set_critical(fd, 0);
	err |= ct_tmpl_set_informative(fd, 0);
	err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
	err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
	if (err || ct_tmpl_activate(fd)) {
		(void) close(fd);
		return (-1);
	}

	return (fd);
}
void
solaris_contract_pre_fork(void)
{
	if ((tmpl_fd = open64(CT_TEMPLATE, O_RDWR)) == -1) {
		error("%s: open %s: %s", __func__,
		    CT_TEMPLATE, strerror(errno));
		return;
	}

	debug2("%s: setting up process contract template on fd %d",
	    __func__, tmpl_fd);

	/* First we set the template parameters and event sets. */
	if (ct_pr_tmpl_set_param(tmpl_fd, CT_PR_PGRPONLY) != 0) {
		error("%s: Error setting process contract parameter set "
		    "(pgrponly): %s", __func__, strerror(errno));
		goto fail;
	}
	if (ct_pr_tmpl_set_fatal(tmpl_fd, CT_PR_EV_HWERR) != 0) {
		error("%s: Error setting process contract template "
		    "fatal events: %s", __func__, strerror(errno));
		goto fail;
	}
	if (ct_tmpl_set_critical(tmpl_fd, 0) != 0) {
		error("%s: Error setting process contract template "
		    "critical events: %s", __func__, strerror(errno));
		goto fail;
	}
	if (ct_tmpl_set_informative(tmpl_fd, CT_PR_EV_HWERR) != 0) {
		error("%s: Error setting process contract template "
		    "informative events: %s", __func__, strerror(errno));
		goto fail;
	}

	/* Now make this the active template for this process. */
	if (ct_tmpl_activate(tmpl_fd) != 0) {
		error("%s: Error activating process contract "
		    "template: %s", __func__, strerror(errno));
		goto fail;
	}
	return;

 fail:
	if (tmpl_fd != -1) {
		close(tmpl_fd);
		tmpl_fd = -1;
	}
}
Esempio n. 3
0
static int
init_template(void) {
  int fd = 0;
  int err = 0;

  fd = open(CTFS_ROOT "/process/template", O_RDWR);
  if (fd == -1)
    return (-1);

  err |= ct_tmpl_set_critical(fd, 0);
  err |= ct_tmpl_set_informative(fd, 0);
  err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
  err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
  if (err || ct_tmpl_activate(fd)) {
    (void) close(fd);
    return (-1);
  }

  return (fd);
}
Esempio n. 4
0
/** @todo the error reporting of the Solaris process contract code could be
 * a lot better, but essentially it is not meant to run into errors after
 * the debugging phase. */
static int rtSolarisContractPreFork(void)
{
    int templateFd = open64(CTFS_ROOT "/process/template", O_RDWR);
    if (templateFd < 0)
        return -1;

    /* Set template parameters and event sets. */
    if (ct_pr_tmpl_set_param(templateFd, CT_PR_PGRPONLY))
    {
        close(templateFd);
        return -1;
    }
    if (ct_pr_tmpl_set_fatal(templateFd, CT_PR_EV_HWERR))
    {
        close(templateFd);
        return -1;
    }
    if (ct_tmpl_set_critical(templateFd, 0))
    {
        close(templateFd);
        return -1;
    }
    if (ct_tmpl_set_informative(templateFd, CT_PR_EV_HWERR))
    {
        close(templateFd);
        return -1;
    }

    /* Make this the active template for the process. */
    if (ct_tmpl_activate(templateFd))
    {
        close(templateFd);
        return -1;
    }

    return templateFd;
}
Esempio n. 5
0
static int
init_template(int flag)
{
    int fd;

    if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) == -1) {
        fatal(ERR_CONTRACT, "open %s/process/template failed: %s\n",
            CTFS_ROOT, strerror(errno));
    }

    if (ct_tmpl_set_critical(fd, 0) != 0) {
        fatal(ERR_CONTRACT, "ct_tmpl_set_critical failed: %s\n",
            strerror(errno));
    }
    if (ct_tmpl_set_informative(fd, 0) != 0) {
        fatal(ERR_CONTRACT, "ct_tmpl_set_informative failed: %s\n",
            strerror(errno));
    }
    if (ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR) != 0) {
        fatal(ERR_CONTRACT, "ct_pr_tmpl_set_fatal failed: %s\n",
            strerror(errno));
    }
    if (ct_pr_tmpl_set_param(fd, flag) != 0) {
        fatal(ERR_CONTRACT, "ct_pr_tmpl_set_param failed: %s\n",
            strerror(errno));
    }

    /* requires PRIV_CONTRACT_IDENTITY so ignore error if it fails */
    (void) ct_pr_tmpl_set_svc_fmri(fd, "svc:/dockerinit/child:default");

    if (ct_tmpl_activate(fd) != 0) {
        fatal(ERR_CONTRACT, "ct_tmpl_activate failed: %s\n",
            strerror(errno));
    }

    return (fd);
}
Esempio n. 6
0
/*
 * int method_ready_contract(restarter_inst_t *, int, method_restart_t, int)
 *
 *   Activate a contract template for the type method of inst.  type,
 *   restart_on, and cte_mask dictate the critical events term of the contract.
 *   Returns
 *     0 - success
 *     ECANCELED - inst has been deleted from the repository
 */
static int
method_ready_contract(restarter_inst_t *inst, int type,
    method_restart_t restart_on, uint_t cte_mask)
{
	int tmpl, err, istrans, iswait, ret;
	uint_t cevents, fevents;

	/*
	 * Correctly supporting wait-style services is tricky without
	 * rearchitecting startd to cope with multiple event sources
	 * simultaneously trying to stop an instance.  Until a better
	 * solution is implemented, we avoid this problem for
	 * wait-style services by making contract events fatal and
	 * letting the wait code alone handle stopping the service.
	 */
	iswait = instance_is_wait_style(inst);
	istrans = method_is_transient(inst, type);

	tmpl = open64(CTFS_ROOT "/process/template", O_RDWR);
	if (tmpl == -1)
		uu_die("Could not create contract template");

	/*
	 * We assume non-login processes are unlikely to create
	 * multiple process groups, and set CT_PR_PGRPONLY for all
	 * wait-style services' contracts.
	 */
	err = ct_pr_tmpl_set_param(tmpl, CT_PR_INHERIT | CT_PR_REGENT |
	    (iswait ? CT_PR_PGRPONLY : 0));
	assert(err == 0);

	if (istrans) {
		cevents = 0;
		fevents = 0;
	} else {
		assert(restart_on >= 0);
		assert(restart_on <= METHOD_RESTART_ANY_FAULT);
		cevents = method_events[restart_on] & ~cte_mask;
		fevents = iswait ?
		    (method_events[restart_on] & ~cte_mask & CT_PR_ALLFATAL) :
		    0;
	}

	err = ct_tmpl_set_critical(tmpl, cevents);
	assert(err == 0);

	err = ct_tmpl_set_informative(tmpl, 0);
	assert(err == 0);
	err = ct_pr_tmpl_set_fatal(tmpl, fevents);
	assert(err == 0);

	err = ct_tmpl_set_cookie(tmpl, istrans ?  METHOD_OTHER_COOKIE :
	    METHOD_START_COOKIE);
	assert(err == 0);

	if (type == METHOD_START && inst->ri_i.i_primary_ctid != 0) {
		ret = ct_pr_tmpl_set_transfer(tmpl, inst->ri_i.i_primary_ctid);
		switch (ret) {
		case 0:
			break;

		case ENOTEMPTY:
			/* No contracts for you! */
			method_remove_contract(inst, B_TRUE, B_TRUE);
			if (inst->ri_mi_deleted) {
				ret = ECANCELED;
				goto out;
			}
			break;

		case EINVAL:
		case ESRCH:
		case EACCES:
		default:
			bad_error("ct_pr_tmpl_set_transfer", ret);
		}
	}

	err = ct_tmpl_activate(tmpl);
	assert(err == 0);

	ret = 0;

out:
	err = close(tmpl);
	assert(err == 0);

	return (ret);
}
Esempio n. 7
0
/*
 * Execute an operation on filename relative to zoneid's zone root.  If the
 * file is in the global zone, then the zfcb() callback will simply be called
 * directly.  If the file is in a non-global zone, then zfcb() will be called
 * both from the global zone's context, and from the non-global zone's context
 * (from a fork()'ed child that has entered the non-global zone).  This is
 * done to allow the callback to communicate with itself if needed (e.g. to
 * pass back the file descriptor of an opened file).
 */
static int
dlmgmt_zfop(const char *filename, zoneid_t zoneid, zfcb_t *zfcb,
    zfoparg_t *zfoparg)
{
	int		ctfd;
	int		err;
	pid_t		childpid;
	siginfo_t	info;
	zfarg_t		zfarg;
	ctid_t		ct;

	if (zoneid != GLOBAL_ZONEID) {
		/*
		 * We need to access a file that isn't in the global zone.
		 * Accessing non-global zone files from the global zone is
		 * unsafe (due to symlink attacks), we'll need to fork a child
		 * that enters the zone in question and executes the callback
		 * that will operate on the file.
		 *
		 * Before we proceed with this zone tango, we need to create a
		 * new process contract for the child, as required by
		 * zone_enter().
		 */
		errno = 0;
		ctfd = open64("/system/contract/process/template", O_RDWR);
		if (ctfd == -1)
			return (errno);
		if ((err = ct_tmpl_set_critical(ctfd, 0)) != 0 ||
		    (err = ct_tmpl_set_informative(ctfd, 0)) != 0 ||
		    (err = ct_pr_tmpl_set_fatal(ctfd, CT_PR_EV_HWERR)) != 0 ||
		    (err = ct_pr_tmpl_set_param(ctfd, CT_PR_PGRPONLY)) != 0 ||
		    (err = ct_tmpl_activate(ctfd)) != 0) {
			(void) close(ctfd);
			return (err);
		}
		childpid = fork();
		switch (childpid) {
		case -1:
			(void) ct_tmpl_clear(ctfd);
			(void) close(ctfd);
			return (err);
		case 0:
			(void) ct_tmpl_clear(ctfd);
			(void) close(ctfd);
			/*
			 * Elevate our privileges as zone_enter() requires all
			 * privileges.
			 */
			if ((err = dlmgmt_elevate_privileges()) != 0)
				_exit(err);
			if (zone_enter(zoneid) == -1)
				_exit(errno);
			if ((err = dlmgmt_drop_privileges()) != 0)
				_exit(err);
			break;
		default:
			if (contract_latest(&ct) == -1)
				ct = -1;
			(void) ct_tmpl_clear(ctfd);
			(void) close(ctfd);
			if (waitid(P_PID, childpid, &info, WEXITED) == -1) {
				(void) contract_abandon_id(ct);
				return (errno);
			}
			(void) contract_abandon_id(ct);
			if (info.si_status != 0)
				return (info.si_status);
		}
	}

	zfarg.zfarg_inglobalzone = (zoneid == GLOBAL_ZONEID || childpid != 0);
	zfarg.zfarg_finglobalzone = (zoneid == GLOBAL_ZONEID);
	zfarg.zfarg_filename = filename;
	zfarg.zfarg_oparg = zfoparg;
	err = zfcb(&zfarg);
	if (!zfarg.zfarg_inglobalzone)
		_exit(err);
	return (err);
}