Esempio n. 1
0
/*
 * Interface to set the effective and permitted privileges for
 * a credential; this interface does no security checks and is
 * intended for kernel (file)servers creating credentials with
 * specific privileges.
 */
int
crsetpriv(cred_t *cr, ...)
{
	va_list ap;
	const char *privnm;

	ASSERT(cr->cr_ref <= 2);

	priv_set_PA(cr);

	va_start(ap, cr);

	while ((privnm = va_arg(ap, const char *)) != NULL) {
		int priv = priv_getbyname(privnm, 0);
		if (priv < 0)
			return (-1);

		priv_addset(&CR_PPRIV(cr), priv);
		priv_addset(&CR_EPRIV(cr), priv);
	}
	priv_adjust_PA(cr);
	va_end(ap);
	return (0);
}
Esempio n. 2
0
int
setpflags(uint_t flag, uint_t val, cred_t *tcr)
{
	cred_t *cr, *pcr;
	proc_t *p = curproc;
	uint_t newflags;
	boolean_t use_curcred = (tcr == NULL);

	if (val > 1 || (flag != PRIV_DEBUG && flag != PRIV_AWARE &&
	    flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT &&
	    flag != __PROC_PROTECT && flag != PRIV_XPOLICY &&
	    flag != PRIV_AWARE_RESET && flag != PRIV_PFEXEC)) {
		return (EINVAL);
	}

	if (flag == __PROC_PROTECT) {
		mutex_enter(&p->p_lock);
		if (val == 0)
			p->p_flag &= ~SNOCD;
		else
			p->p_flag |= SNOCD;
		mutex_exit(&p->p_lock);
		return (0);
	}

	if (use_curcred) {
		cr = cralloc();
		mutex_enter(&p->p_crlock);
		pcr = p->p_cred;
	} else {
		cr = pcr = tcr;
	}

	newflags = CR_FLAGS(pcr);

	if (val != 0) {
		if (flag == PRIV_AWARE)
			newflags &= ~PRIV_AWARE_RESET;
		newflags |= flag;
	} else {
		newflags &= ~flag;
	}

	/* No change */
	if (CR_FLAGS(pcr) == newflags) {
		if (use_curcred) {
			mutex_exit(&p->p_crlock);
			crfree(cr);
		}
		return (0);
	}

	/*
	 * Setting either the NET_MAC_AWARE or NET_MAC_AWARE_INHERIT
	 * flags is a restricted operation.
	 *
	 * When invoked via the PRIVSYS_SETPFLAGS syscall
	 * we require that the current cred has the net_mac_aware
	 * privilege in its effective set.
	 *
	 * When called from within the kernel by label-aware
	 * services such as NFS, we don't require a privilege check.
	 *
	 */
	if ((flag == NET_MAC_AWARE || flag == NET_MAC_AWARE_INHERIT) &&
	    (val == 1) && use_curcred) {
		if (secpolicy_net_mac_aware(pcr) != 0) {
			mutex_exit(&p->p_crlock);
			crfree(cr);
			return (EPERM);
		}
	}

	/* Trying to unset PA; if we can't, return an error */
	if (flag == PRIV_AWARE && val == 0 && !priv_can_clear_PA(pcr)) {
		if (use_curcred) {
			mutex_exit(&p->p_crlock);
			crfree(cr);
		}
		return (EPERM);
	}

	/* Committed to changing the flag */
	if (use_curcred)
		crcopy_to(pcr, cr);
	if (flag == PRIV_AWARE) {
		if (val != 0)
			priv_set_PA(cr);
		else
			priv_adjust_PA(cr);
	} else {
		CR_FLAGS(cr) = newflags;
	}

	/*
	 * Unsetting the flag has as side effect getting rid of
	 * the per-credential policy.
	 */
	if (flag == PRIV_XPOLICY && val == 0)
		crsetcrklpd(cr, NULL);

	if (use_curcred) {
		p->p_cred = cr;
		mutex_exit(&p->p_crlock);
		crset(p, cr);
	}

	return (0);
}
Esempio n. 3
0
/*
 * Guts of pr_spriv:
 *
 * Set the privileges of a process.
 *
 * In order to set the privileges, the setting process will need to
 * have those privileges in its effective set in order to prevent
 * specially privileged processes to easily gain additional privileges.
 * Pre-existing privileges can be retained.  To change any privileges,
 * PRIV_PROC_OWNER needs to be asserted.
 *
 * In formula:
 *
 *	S' <= S || S' <= S + Ea
 *
 * the new set must either be subset of the old set or a subset of
 * the oldset merged with the effective set of the acting process; or just:
 *
 *	S' <= S + Ea
 *
 * It's not legal to grow the limit set this way.
 *
 */
int
priv_pr_spriv(proc_t *p, prpriv_t *prpriv, const cred_t *cr)
{
	cred_t *oldcred;
	cred_t *newcred;
	int i;
	int err = EPERM;
	cred_priv_t *cp, *ocp;
	priv_set_t eset;

	ASSERT(MUTEX_HELD(&p->p_lock));

	/*
	 * Set must have proper dimension; infosize must be absent
	 * or properly sized.
	 */
	if (prpriv->pr_nsets != PRIV_NSET ||
	    prpriv->pr_setsize != PRIV_SETSIZE ||
	    (prpriv->pr_infosize & (sizeof (uint32_t) - 1)) != 0 ||
	    prpriv->pr_infosize > priv_info->priv_infosize ||
	    prpriv->pr_infosize < 0)
		return (EINVAL);

	mutex_exit(&p->p_lock);

	if (priv_proc_cred_perm(cr, p, &oldcred, VWRITE) != 0) {
		mutex_enter(&p->p_lock);
		return (EPERM);
	}

	newcred = crdup(oldcred);

	/* Copy the privilege sets from prpriv to newcred */
	bcopy(prpriv->pr_sets, CR_PRIVSETS(newcred), PRIV_SETBYTES);

	cp = &newcred->cr_priv;
	ocp = &oldcred->cr_priv;
	eset = CR_OEPRIV(cr);

	priv_intersect(&CR_LPRIV(oldcred), &eset);

	/*
	 * Verify the constraints laid out:
	 * for the limit set, we require that the new set is a subset
	 * of the old limit set.
	 * for all other sets, we require that the new set is either a
	 * subset of the old set or a subset of the intersection of
	 * the old limit set and the effective set of the acting process.
	 */
	for (i = 0; i < PRIV_NSET; i++)
		if (!priv_issubset(&cp->crprivs[i], &ocp->crprivs[i]) &&
		    (i == PRIV_LIMIT || !priv_issubset(&cp->crprivs[i], &eset)))
			break;

	crfree(oldcred);

	if (i < PRIV_NSET || !priv_valid(newcred))
		goto err;

	/* Load the settable privilege information */
	if (prpriv->pr_infosize > 0) {
		char *x = (char *)prpriv + PRIV_PRPRIV_INFO_OFFSET(prpriv);
		char *lastx = x + prpriv->pr_infosize;

		while (x < lastx) {
			priv_info_t *pi = (priv_info_t *)x;
			priv_info_uint_t *pii;

			switch (pi->priv_info_type) {
			case PRIV_INFO_FLAGS:
				pii = (priv_info_uint_t *)x;
				if (pii->info.priv_info_size != sizeof (*pii)) {
					err = EINVAL;
					goto err;
				}
				CR_FLAGS(newcred) &= ~PRIV_USER;
				CR_FLAGS(newcred) |= (pii->val & PRIV_USER);
				break;
			default:
				err = EINVAL;
				goto err;
			}
			/* Guarantee alignment and forward progress */
			if ((pi->priv_info_size & (sizeof (uint32_t) - 1)) ||
			    pi->priv_info_size < sizeof (*pi) ||
			    lastx - x > pi->priv_info_size) {
				err = EINVAL;
				goto err;
			}

			x += pi->priv_info_size;
		}
	}

	/*
	 * We'll try to copy the privilege aware flag; but since the
	 * privileges sets are all individually set, they are set
	 * as if we're privilege aware.  If PRIV_AWARE wasn't set
	 * or was explicitely unset, we need to set the flag and then
	 * try to get rid of it.
	 */
	if ((CR_FLAGS(newcred) & PRIV_AWARE) == 0) {
		CR_FLAGS(newcred) |= PRIV_AWARE;
		priv_adjust_PA(newcred);
	}

	mutex_enter(&p->p_crlock);
	oldcred = p->p_cred;
	p->p_cred = newcred;
	mutex_exit(&p->p_crlock);
	crfree(oldcred);

	mutex_enter(&p->p_lock);
	return (0);

err:
	crfree(newcred);
	mutex_enter(&p->p_lock);
	return (err);
}