- * Determine whether td may debug p. * Returns: 0 for permitted, an errno value otherwise * Locks: Sufficient locks to protect various components of td and p * must be held. td must be curthread, and a lock must * be held for p. * References: td and p must be valid for the lifetime of the call */
| 1677 | * References: td and p must be valid for the lifetime of the call |
| 1678 | */ |
| 1679 | int |
| 1680 | p_candebug(struct thread *td, struct proc *p) |
| 1681 | { |
| 1682 | int credentialchanged, error, grpsubset, i, uidsubset; |
| 1683 | |
| 1684 | KASSERT(td == curthread, ("%s: td not curthread", __func__)); |
| 1685 | PROC_LOCK_ASSERT(p, MA_OWNED); |
| 1686 | if ((error = priv_check(td, PRIV_DEBUG_UNPRIV))) |
| 1687 | return (error); |
| 1688 | if (td->td_proc == p) |
| 1689 | return (0); |
| 1690 | if ((error = prison_check(td->td_ucred, p->p_ucred))) |
| 1691 | return (error); |
| 1692 | #ifdef MAC |
| 1693 | if ((error = mac_proc_check_debug(td->td_ucred, p))) |
| 1694 | return (error); |
| 1695 | #endif |
| 1696 | if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) |
| 1697 | return (error); |
| 1698 | if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred))) |
| 1699 | return (error); |
| 1700 | |
| 1701 | /* |
| 1702 | * Is p's group set a subset of td's effective group set? This |
| 1703 | * includes p's egid, group access list, rgid, and svgid. |
| 1704 | */ |
| 1705 | grpsubset = 1; |
| 1706 | for (i = 0; i < p->p_ucred->cr_ngroups; i++) { |
| 1707 | if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { |
| 1708 | grpsubset = 0; |
| 1709 | break; |
| 1710 | } |
| 1711 | } |
| 1712 | grpsubset = grpsubset && |
| 1713 | groupmember(p->p_ucred->cr_rgid, td->td_ucred) && |
| 1714 | groupmember(p->p_ucred->cr_svgid, td->td_ucred); |
| 1715 | |
| 1716 | /* |
| 1717 | * Are the uids present in p's credential equal to td's |
| 1718 | * effective uid? This includes p's euid, svuid, and ruid. |
| 1719 | */ |
| 1720 | uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && |
| 1721 | td->td_ucred->cr_uid == p->p_ucred->cr_svuid && |
| 1722 | td->td_ucred->cr_uid == p->p_ucred->cr_ruid); |
| 1723 | |
| 1724 | /* |
| 1725 | * Has the credential of the process changed since the last exec()? |
| 1726 | */ |
| 1727 | credentialchanged = (p->p_flag & P_SUGID); |
| 1728 | |
| 1729 | /* |
| 1730 | * If p's gids aren't a subset, or the uids aren't a subset, |
| 1731 | * or the credential has changed, require appropriate privilege |
| 1732 | * for td to debug p. |
| 1733 | */ |
| 1734 | if (!grpsubset || !uidsubset) { |
| 1735 | error = priv_check(td, PRIV_DEBUG_DIFFCRED); |
| 1736 | if (error) |
no test coverage detected