Пример #1
0
static ephemeral_zsd_t *
get_ephemeral_zsd(zone_t *zone)
{
	ephemeral_zsd_t *eph_zsd;

	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
	if (eph_zsd != NULL) {
		return (eph_zsd);
	}

	mutex_enter(&ephemeral_zone_mutex);
	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
	if (eph_zsd == NULL) {
		eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
		eph_zsd->min_uid = MAXUID;
		eph_zsd->last_uid = IDMAP_WK__MAX_UID;
		eph_zsd->min_gid = MAXUID;
		eph_zsd->last_gid = IDMAP_WK__MAX_GID;
		mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);

		/*
		 * nobody is used to map SID containing CRs.
		 */
		eph_zsd->eph_nobody = crdup(zone->zone_kcred);
		(void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
		CR_FLAGS(eph_zsd->eph_nobody) = 0;
		eph_zsd->eph_nobody->cr_zone = zone;

		(void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
	}
	mutex_exit(&ephemeral_zone_mutex);
	return (eph_zsd);
}
Пример #2
0
/*ARGSUSED*/
void
priv_getinfo(const cred_t *cr, void *buf)
{
	struct priv_info_uint *ii;

	ii = buf;
	ii->val = CR_FLAGS(cr);
	ii->info.priv_info_size = (uint32_t)sizeof (*ii);
	ii->info.priv_info_type = PRIV_INFO_FLAGS;
}
Пример #3
0
/*
 * Getpflags.  Currently only implements single bit flags.
 */
uint_t
getpflags(uint_t flag, const cred_t *cr)
{
	if (flag != PRIV_DEBUG && flag != PRIV_AWARE &&
	    flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT &&
	    flag != PRIV_XPOLICY && flag != PRIV_PFEXEC &&
	    flag != PRIV_AWARE_RESET)
		return ((uint_t)-1);

	return ((CR_FLAGS(cr) & flag) != 0);
}
Пример #4
0
/*
 * Return the nth privilege set
 */
const priv_set_t *
priv_getset(const cred_t *cr, int set)
{
	ASSERT(PRIV_VALIDSET(set));

	if ((CR_FLAGS(cr) & PRIV_AWARE) == 0)
		switch (set) {
		case PRIV_EFFECTIVE:
			return (&CR_OEPRIV(cr));
		case PRIV_PERMITTED:
			return (&CR_OPPRIV(cr));
		}
	return (&CR_PRIVS(cr)->crprivs[set]);
}
Пример #5
0
/*
 * Register the klpd.
 * If the pid_t passed in is positive, update the registration for
 * the specific process; that is only possible if the process already
 * has a registration on it.  This change of registration will affect
 * all processes which share common ancestry.
 *
 * MY_PID (pid 0) can be used to create or change the context for
 * the current process, typically done after fork().
 *
 * A negative value can be used to register a klpd globally.
 *
 * The per-credential klpd needs to be cleaned up when entering
 * a zone or unsetting the flag.
 */
int
klpd_reg(int did, idtype_t type, id_t id, priv_set_t *psetbuf)
{
	cred_t *cr = CRED();
	door_handle_t dh;
	klpd_reg_t *kpd;
	priv_set_t pset;
	door_info_t di;
	credklpd_t *ckp = NULL;
	pid_t pid = -1;
	projid_t proj = -1;
	kproject_t *kpp = NULL;

	if (CR_FLAGS(cr) & PRIV_XPOLICY)
		return (set_errno(EINVAL));

	if (copyin(psetbuf, &pset, sizeof (priv_set_t)))
		return (set_errno(EFAULT));

	if (!priv_issubset(&pset, &CR_OEPRIV(cr)))
		return (set_errno(EPERM));

	switch (type) {
	case P_PID:
		pid = (pid_t)id;
		if (pid == P_MYPID)
			pid = curproc->p_pid;
		if (pid == curproc->p_pid)
			ckp = crklpd_alloc();
		break;
	case P_PROJID:
		proj = (projid_t)id;
		kpp = project_hold_by_id(proj, crgetzone(cr),
		    PROJECT_HOLD_FIND);
		if (kpp == NULL)
			return (set_errno(ESRCH));
		break;
	default:
		return (set_errno(ENOTSUP));
	}


	/*
	 * Verify the door passed in; it must be a door and we won't
	 * allow processes to be called on their own behalf.
	 */
	dh = door_ki_lookup(did);
	if (dh == NULL || door_ki_info(dh, &di) != 0) {
		if (ckp != NULL)
			crklpd_rele(ckp);
		if (kpp != NULL)
			project_rele(kpp);
		return (set_errno(EBADF));
	}
	if (type == P_PID && pid == di.di_target) {
		if (ckp != NULL)
			crklpd_rele(ckp);
		ASSERT(kpp == NULL);
		return (set_errno(EINVAL));
	}

	kpd = kmem_zalloc(sizeof (*kpd), KM_SLEEP);
	crhold(kpd->klpd_cred = cr);
	kpd->klpd_door = dh;
	kpd->klpd_door_pid = di.di_target;
	kpd->klpd_ref = 1;
	kpd->klpd_pset = pset;

	if (kpp != NULL) {
		mutex_enter(&klpd_mutex);
		kpd = klpd_link(kpd, &kpp->kpj_klpd, B_TRUE);
		mutex_exit(&klpd_mutex);
		if (kpd != NULL)
			klpd_rele(kpd);
		project_rele(kpp);
	} else if ((int)pid < 0) {
		/* Global daemon */
		mutex_enter(&klpd_mutex);
		(void) klpd_link(kpd, &klpd_list, B_FALSE);
		mutex_exit(&klpd_mutex);
	} else if (pid == curproc->p_pid) {
		proc_t *p = curproc;
		cred_t *newcr = cralloc();

		/* No need to lock, sole reference to ckp */
		kpd = klpd_link(kpd, &ckp->crkl_reg, B_TRUE);

		if (kpd != NULL)
			klpd_rele(kpd);

		mutex_enter(&p->p_crlock);
		cr = p->p_cred;
		crdup_to(cr, newcr);
		crsetcrklpd(newcr, ckp);
		p->p_cred = newcr;	/* Already held for p_cred */

		crhold(newcr);		/* Hold once for the current thread */
		mutex_exit(&p->p_crlock);
		crfree(cr);		/* One for the p_cred */
		crset(p, newcr);
	} else {
		proc_t *p;
		cred_t *pcr;
		mutex_enter(&pidlock);
		p = prfind(pid);
		if (p == NULL || !prochasprocperm(p, curproc, CRED())) {
			mutex_exit(&pidlock);
			klpd_rele(kpd);
			return (set_errno(p == NULL ? ESRCH : EPERM));
		}
		mutex_enter(&p->p_crlock);
		crhold(pcr = p->p_cred);
		mutex_exit(&pidlock);
		mutex_exit(&p->p_crlock);
		/*
		 * We're going to update the credential's ckp in place;
		 * this requires that it exists.
		 */
		ckp = crgetcrklpd(pcr);
		if (ckp == NULL) {
			crfree(pcr);
			klpd_rele(kpd);
			return (set_errno(EINVAL));
		}
		crklpd_setreg(ckp, kpd);
		crfree(pcr);
	}

	return (0);
}
Пример #6
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);
}
Пример #7
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);
}
Пример #8
0
void
cred_init(void)
{
	priv_init();

	crsize = sizeof (cred_t);

	if (get_c2audit_load() > 0) {
#ifdef _LP64
		/* assure audit context is 64-bit aligned */
		audoff = (crsize +
		    sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
#else	/* _LP64 */
		audoff = crsize;
#endif	/* _LP64 */
		crsize = audoff + sizeof (auditinfo_addr_t);
		crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
	}

	cred_cache = kmem_cache_create("cred_cache", crsize, 0,
	    NULL, NULL, NULL, NULL, NULL, 0);

	/*
	 * dummycr is used to copy initial state for creds.
	 */
	dummycr = cralloc();
	bzero(dummycr, crsize);
	dummycr->cr_ref = 1;
	dummycr->cr_uid = (uid_t)-1;
	dummycr->cr_gid = (gid_t)-1;
	dummycr->cr_ruid = (uid_t)-1;
	dummycr->cr_rgid = (gid_t)-1;
	dummycr->cr_suid = (uid_t)-1;
	dummycr->cr_sgid = (gid_t)-1;


	/*
	 * kcred is used by anything that needs all privileges; it's
	 * also the template used for crget as it has all the compatible
	 * sets filled in.
	 */
	kcred = cralloc();

	bzero(kcred, crsize);
	kcred->cr_ref = 1;

	/* kcred is never freed, so we don't need zone_cred_hold here */
	kcred->cr_zone = &zone0;

	priv_fillset(&CR_LPRIV(kcred));
	CR_IPRIV(kcred) = *priv_basic;

	/* Not a basic privilege, if chown is not restricted add it to I0 */
	if (!rstchown)
		priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);

	/* Basic privilege, if link is restricted remove it from I0 */
	if (rstlink)
		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);

	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);

	CR_FLAGS(kcred) = NET_MAC_AWARE;

	/*
	 * Set up credentials of p0.
	 */
	ttoproc(curthread)->p_cred = kcred;
	curthread->t_cred = kcred;

	ucredsize = UCRED_SIZE;

	mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
	zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
}