1d8a7b7a3SRobert Watson /*- 2a1b9471aSRobert Watson * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson 3a203d978STom Rhodes * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 4458f818fSRobert Watson * Copyright (c) 2005 Tom Rhodes 530d239bcSRobert Watson * Copyright (c) 2006 SPARTA, Inc. 6d8a7b7a3SRobert Watson * All rights reserved. 7d8a7b7a3SRobert Watson * 8d8a7b7a3SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 9a203d978STom Rhodes * It was later enhanced by Tom Rhodes for the TrustedBSD Project. 10d8a7b7a3SRobert Watson * 11dc858fcaSRobert Watson * This software was developed for the FreeBSD Project in part by Network 12dc858fcaSRobert Watson * Associates Laboratories, the Security Research Division of Network 13dc858fcaSRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 14dc858fcaSRobert Watson * as part of the DARPA CHATS research program. 15d8a7b7a3SRobert Watson * 1630d239bcSRobert Watson * This software was enhanced by SPARTA ISSO under SPAWAR contract 1730d239bcSRobert Watson * N66001-04-C-6019 ("SEFOS"). 1830d239bcSRobert Watson * 19d8a7b7a3SRobert Watson * Redistribution and use in source and binary forms, with or without 20d8a7b7a3SRobert Watson * modification, are permitted provided that the following conditions 21d8a7b7a3SRobert Watson * are met: 22d8a7b7a3SRobert Watson * 1. Redistributions of source code must retain the above copyright 23d8a7b7a3SRobert Watson * notice, this list of conditions and the following disclaimer. 24d8a7b7a3SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 25d8a7b7a3SRobert Watson * notice, this list of conditions and the following disclaimer in the 26d8a7b7a3SRobert Watson * documentation and/or other materials provided with the distribution. 27d8a7b7a3SRobert Watson * 28d8a7b7a3SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29d8a7b7a3SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30d8a7b7a3SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31d8a7b7a3SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32d8a7b7a3SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33d8a7b7a3SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34d8a7b7a3SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35d8a7b7a3SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36d8a7b7a3SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37d8a7b7a3SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38d8a7b7a3SRobert Watson * SUCH DAMAGE. 39d8a7b7a3SRobert Watson */ 4046e23372SRobert Watson 41d8a7b7a3SRobert Watson /* 42d8a7b7a3SRobert Watson * Developed by the TrustedBSD Project. 43458f818fSRobert Watson * 44458f818fSRobert Watson * "BSD Extended" MAC policy, allowing the administrator to impose mandatory 45458f818fSRobert Watson * firewall-like rules regarding users and file system objects. 46d8a7b7a3SRobert Watson */ 47d8a7b7a3SRobert Watson 48d8a7b7a3SRobert Watson #include <sys/param.h> 49d8a7b7a3SRobert Watson #include <sys/acl.h> 50d8a7b7a3SRobert Watson #include <sys/kernel.h> 5189ddbd45SDavid Malone #include <sys/jail.h> 52a203d978STom Rhodes #include <sys/lock.h> 53d8a7b7a3SRobert Watson #include <sys/malloc.h> 547405fcc3SRobert Watson #include <sys/module.h> 55d8a7b7a3SRobert Watson #include <sys/mount.h> 56a203d978STom Rhodes #include <sys/mutex.h> 57c2259ba4SRobert Watson #include <sys/priv.h> 58413628a7SBjoern A. Zeeb #include <sys/proc.h> 59d8a7b7a3SRobert Watson #include <sys/systm.h> 60d8a7b7a3SRobert Watson #include <sys/vnode.h> 61d8a7b7a3SRobert Watson #include <sys/sysctl.h> 6260673f35STom Rhodes #include <sys/syslog.h> 63dfa7fd1dSEdward Tomasz Napierala #include <sys/stat.h> 64d8a7b7a3SRobert Watson 650efd6615SRobert Watson #include <security/mac/mac_policy.h> 66d8a7b7a3SRobert Watson #include <security/mac_bsdextended/mac_bsdextended.h> 6734f6230eSRobert Watson #include <security/mac_bsdextended/ugidfw_internal.h> 68d8a7b7a3SRobert Watson 693f1a7a90SRobert Watson static struct mtx ugidfw_mtx; 70a203d978STom Rhodes 717029da5cSPawel Biernacki static SYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, 727029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 73d8a7b7a3SRobert Watson "TrustedBSD extended BSD MAC policy controls"); 74d8a7b7a3SRobert Watson 753f1a7a90SRobert Watson static int ugidfw_enabled = 1; 76af3b2549SHans Petter Selasky SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RWTUN, 773f1a7a90SRobert Watson &ugidfw_enabled, 0, "Enforce extended BSD policy"); 78d8a7b7a3SRobert Watson 79d745c852SEd Schouten static MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", 80d745c852SEd Schouten "BSD Extended MAC rule"); 81d8a7b7a3SRobert Watson 82d8a7b7a3SRobert Watson #define MAC_BSDEXTENDED_MAXRULES 250 83d8a7b7a3SRobert Watson static struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES]; 84d8a7b7a3SRobert Watson static int rule_count = 0; 85d8a7b7a3SRobert Watson static int rule_slots = 0; 8689ddbd45SDavid Malone static int rule_version = MB_VERSION; 87d8a7b7a3SRobert Watson 88d8a7b7a3SRobert Watson SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD, 89*6b62e00dSEd Maste &rule_count, 0, "Number of defined rules"); 90d8a7b7a3SRobert Watson SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD, 91*6b62e00dSEd Maste &rule_slots, 0, "Number of used rule slots"); 9289ddbd45SDavid Malone SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_version, CTLFLAG_RD, 93*6b62e00dSEd Maste &rule_version, 0, "Version number for API"); 94d8a7b7a3SRobert Watson 9560673f35STom Rhodes /* 96458f818fSRobert Watson * This is just used for logging purposes, eventually we would like to log 97458f818fSRobert Watson * much more then failed requests. 9860673f35STom Rhodes */ 993f1a7a90SRobert Watson static int ugidfw_logging; 10060673f35STom Rhodes SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW, 1013f1a7a90SRobert Watson &ugidfw_logging, 0, "Log failed authorization requests"); 10260673f35STom Rhodes 10360673f35STom Rhodes /* 104458f818fSRobert Watson * This tunable is here for compatibility. It will allow the user to switch 105458f818fSRobert Watson * between the new mode (first rule matches) and the old functionality (all 106458f818fSRobert Watson * rules match). 107fa31f180STom Rhodes */ 1083f1a7a90SRobert Watson static int ugidfw_firstmatch_enabled; 109fa31f180STom Rhodes SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled, 1103f1a7a90SRobert Watson CTLFLAG_RW, &ugidfw_firstmatch_enabled, 1, 111fa31f180STom Rhodes "Disable/enable match first rule functionality"); 112fa31f180STom Rhodes 113d8a7b7a3SRobert Watson static int 1143f1a7a90SRobert Watson ugidfw_rule_valid(struct mac_bsdextended_rule *rule) 115d8a7b7a3SRobert Watson { 116d8a7b7a3SRobert Watson 11789ddbd45SDavid Malone if ((rule->mbr_subject.mbs_flags | MBS_ALL_FLAGS) != MBS_ALL_FLAGS) 118d8a7b7a3SRobert Watson return (EINVAL); 11989ddbd45SDavid Malone if ((rule->mbr_subject.mbs_neg | MBS_ALL_FLAGS) != MBS_ALL_FLAGS) 12089ddbd45SDavid Malone return (EINVAL); 12189ddbd45SDavid Malone if ((rule->mbr_object.mbo_flags | MBO_ALL_FLAGS) != MBO_ALL_FLAGS) 12289ddbd45SDavid Malone return (EINVAL); 12389ddbd45SDavid Malone if ((rule->mbr_object.mbo_neg | MBO_ALL_FLAGS) != MBO_ALL_FLAGS) 12489ddbd45SDavid Malone return (EINVAL); 125993114ddSEd Maste if (((rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) != 0) && 12689ddbd45SDavid Malone (rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE) 127d8a7b7a3SRobert Watson return (EINVAL); 1282e74bca1SRobert Watson if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM) 129d8a7b7a3SRobert Watson return (EINVAL); 130d8a7b7a3SRobert Watson return (0); 131d8a7b7a3SRobert Watson } 132d8a7b7a3SRobert Watson 133d8a7b7a3SRobert Watson static int 134d8a7b7a3SRobert Watson sysctl_rule(SYSCTL_HANDLER_ARGS) 135d8a7b7a3SRobert Watson { 136d8a7b7a3SRobert Watson struct mac_bsdextended_rule temprule, *ruleptr; 137d8a7b7a3SRobert Watson u_int namelen; 138d8a7b7a3SRobert Watson int error, index, *name; 139d8a7b7a3SRobert Watson 140a203d978STom Rhodes error = 0; 141d8a7b7a3SRobert Watson name = (int *)arg1; 142d8a7b7a3SRobert Watson namelen = arg2; 143d8a7b7a3SRobert Watson if (namelen != 1) 144d8a7b7a3SRobert Watson return (EINVAL); 145d8a7b7a3SRobert Watson index = name[0]; 146e1216740SChristian S.J. Peron if (index >= MAC_BSDEXTENDED_MAXRULES) 147d8a7b7a3SRobert Watson return (ENOENT); 148d8a7b7a3SRobert Watson 149a203d978STom Rhodes ruleptr = NULL; 150a203d978STom Rhodes if (req->newptr && req->newlen != 0) { 151d8a7b7a3SRobert Watson error = SYSCTL_IN(req, &temprule, sizeof(temprule)); 152d8a7b7a3SRobert Watson if (error) 153d8a7b7a3SRobert Watson return (error); 154e11e3f18SDag-Erling Smørgrav ruleptr = malloc(sizeof(*ruleptr), M_MACBSDEXTENDED, 155e11e3f18SDag-Erling Smørgrav M_WAITOK | M_ZERO); 156a203d978STom Rhodes } 157d8a7b7a3SRobert Watson 1583f1a7a90SRobert Watson mtx_lock(&ugidfw_mtx); 159a203d978STom Rhodes if (req->oldptr) { 160a203d978STom Rhodes if (index < 0 || index > rule_slots + 1) { 161a203d978STom Rhodes error = ENOENT; 162a203d978STom Rhodes goto out; 163a203d978STom Rhodes } 164a203d978STom Rhodes if (rules[index] == NULL) { 165a203d978STom Rhodes error = ENOENT; 166a203d978STom Rhodes goto out; 167a203d978STom Rhodes } 168a203d978STom Rhodes temprule = *rules[index]; 169a203d978STom Rhodes } 170a203d978STom Rhodes if (req->newptr && req->newlen == 0) { 171a203d978STom Rhodes KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL")); 172a203d978STom Rhodes ruleptr = rules[index]; 173a203d978STom Rhodes if (ruleptr == NULL) { 174a203d978STom Rhodes error = ENOENT; 175a203d978STom Rhodes goto out; 176a203d978STom Rhodes } 177a203d978STom Rhodes rule_count--; 178a203d978STom Rhodes rules[index] = NULL; 179a203d978STom Rhodes } else if (req->newptr) { 1803f1a7a90SRobert Watson error = ugidfw_rule_valid(&temprule); 181d8a7b7a3SRobert Watson if (error) 182a203d978STom Rhodes goto out; 183d8a7b7a3SRobert Watson if (rules[index] == NULL) { 184d8a7b7a3SRobert Watson *ruleptr = temprule; 185d8a7b7a3SRobert Watson rules[index] = ruleptr; 186a203d978STom Rhodes ruleptr = NULL; 187d8a7b7a3SRobert Watson if (index + 1 > rule_slots) 188d8a7b7a3SRobert Watson rule_slots = index + 1; 189d8a7b7a3SRobert Watson rule_count++; 190458f818fSRobert Watson } else 191d8a7b7a3SRobert Watson *rules[index] = temprule; 192d8a7b7a3SRobert Watson } 193a203d978STom Rhodes out: 1943f1a7a90SRobert Watson mtx_unlock(&ugidfw_mtx); 195a203d978STom Rhodes if (ruleptr != NULL) 1961ede983cSDag-Erling Smørgrav free(ruleptr, M_MACBSDEXTENDED); 197096dd406STom Rhodes if (req->oldptr && error == 0) 198a203d978STom Rhodes error = SYSCTL_OUT(req, &temprule, sizeof(temprule)); 199096dd406STom Rhodes return (error); 200d8a7b7a3SRobert Watson } 201d8a7b7a3SRobert Watson 2026472ac3dSEd Schouten static SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules, 203095b4d26SChristian S.J. Peron CTLFLAG_MPSAFE | CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules"); 204d8a7b7a3SRobert Watson 205d8a7b7a3SRobert Watson static void 2063f1a7a90SRobert Watson ugidfw_init(struct mac_policy_conf *mpc) 207d8a7b7a3SRobert Watson { 208d8a7b7a3SRobert Watson 2093f1a7a90SRobert Watson mtx_init(&ugidfw_mtx, "mac_bsdextended lock", NULL, MTX_DEF); 210d8a7b7a3SRobert Watson } 211d8a7b7a3SRobert Watson 212d8a7b7a3SRobert Watson static void 2133f1a7a90SRobert Watson ugidfw_destroy(struct mac_policy_conf *mpc) 214d8a7b7a3SRobert Watson { 215168a6ae7SRobert Watson int i; 216d8a7b7a3SRobert Watson 217168a6ae7SRobert Watson for (i = 0; i < MAC_BSDEXTENDED_MAXRULES; i++) { 218168a6ae7SRobert Watson if (rules[i] != NULL) 219168a6ae7SRobert Watson free(rules[i], M_MACBSDEXTENDED); 220168a6ae7SRobert Watson } 2213f1a7a90SRobert Watson mtx_destroy(&ugidfw_mtx); 222d8a7b7a3SRobert Watson } 223d8a7b7a3SRobert Watson 224d8a7b7a3SRobert Watson static int 2253f1a7a90SRobert Watson ugidfw_rulecheck(struct mac_bsdextended_rule *rule, 22689ddbd45SDavid Malone struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode) 227d8a7b7a3SRobert Watson { 228cecd8edbSAttilio Rao int mac_granted, match, priv_granted; 22989ddbd45SDavid Malone int i; 230d8a7b7a3SRobert Watson 231d8a7b7a3SRobert Watson /* 232d8a7b7a3SRobert Watson * Is there a subject match? 233d8a7b7a3SRobert Watson */ 2343f1a7a90SRobert Watson mtx_assert(&ugidfw_mtx, MA_OWNED); 23589ddbd45SDavid Malone if (rule->mbr_subject.mbs_flags & MBS_UID_DEFINED) { 23689ddbd45SDavid Malone match = ((cred->cr_uid <= rule->mbr_subject.mbs_uid_max && 23789ddbd45SDavid Malone cred->cr_uid >= rule->mbr_subject.mbs_uid_min) || 23889ddbd45SDavid Malone (cred->cr_ruid <= rule->mbr_subject.mbs_uid_max && 23989ddbd45SDavid Malone cred->cr_ruid >= rule->mbr_subject.mbs_uid_min) || 24089ddbd45SDavid Malone (cred->cr_svuid <= rule->mbr_subject.mbs_uid_max && 24189ddbd45SDavid Malone cred->cr_svuid >= rule->mbr_subject.mbs_uid_min)); 24289ddbd45SDavid Malone if (rule->mbr_subject.mbs_neg & MBS_UID_DEFINED) 243d8a7b7a3SRobert Watson match = !match; 244d8a7b7a3SRobert Watson if (!match) 245d8a7b7a3SRobert Watson return (0); 246d8a7b7a3SRobert Watson } 247d8a7b7a3SRobert Watson 24889ddbd45SDavid Malone if (rule->mbr_subject.mbs_flags & MBS_GID_DEFINED) { 24989ddbd45SDavid Malone match = ((cred->cr_rgid <= rule->mbr_subject.mbs_gid_max && 25089ddbd45SDavid Malone cred->cr_rgid >= rule->mbr_subject.mbs_gid_min) || 25189ddbd45SDavid Malone (cred->cr_svgid <= rule->mbr_subject.mbs_gid_max && 25289ddbd45SDavid Malone cred->cr_svgid >= rule->mbr_subject.mbs_gid_min)); 25389ddbd45SDavid Malone if (!match) { 254458f818fSRobert Watson for (i = 0; i < cred->cr_ngroups; i++) { 25589ddbd45SDavid Malone if (cred->cr_groups[i] 25689ddbd45SDavid Malone <= rule->mbr_subject.mbs_gid_max && 25789ddbd45SDavid Malone cred->cr_groups[i] 25889ddbd45SDavid Malone >= rule->mbr_subject.mbs_gid_min) { 25989ddbd45SDavid Malone match = 1; 26089ddbd45SDavid Malone break; 26189ddbd45SDavid Malone } 26289ddbd45SDavid Malone } 263458f818fSRobert Watson } 26489ddbd45SDavid Malone if (rule->mbr_subject.mbs_neg & MBS_GID_DEFINED) 26589ddbd45SDavid Malone match = !match; 26689ddbd45SDavid Malone if (!match) 26789ddbd45SDavid Malone return (0); 26889ddbd45SDavid Malone } 26989ddbd45SDavid Malone 27089ddbd45SDavid Malone if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) { 2710304c731SJamie Gritton match = 2720304c731SJamie Gritton (cred->cr_prison->pr_id == rule->mbr_subject.mbs_prison); 27389ddbd45SDavid Malone if (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED) 274d8a7b7a3SRobert Watson match = !match; 275d8a7b7a3SRobert Watson if (!match) 276d8a7b7a3SRobert Watson return (0); 277d8a7b7a3SRobert Watson } 278d8a7b7a3SRobert Watson 279d8a7b7a3SRobert Watson /* 280d8a7b7a3SRobert Watson * Is there an object match? 281d8a7b7a3SRobert Watson */ 28289ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) { 28389ddbd45SDavid Malone match = (vap->va_uid <= rule->mbr_object.mbo_uid_max && 28489ddbd45SDavid Malone vap->va_uid >= rule->mbr_object.mbo_uid_min); 28589ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_UID_DEFINED) 286d8a7b7a3SRobert Watson match = !match; 287d8a7b7a3SRobert Watson if (!match) 288d8a7b7a3SRobert Watson return (0); 289d8a7b7a3SRobert Watson } 290d8a7b7a3SRobert Watson 29189ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) { 29289ddbd45SDavid Malone match = (vap->va_gid <= rule->mbr_object.mbo_gid_max && 29389ddbd45SDavid Malone vap->va_gid >= rule->mbr_object.mbo_gid_min); 29489ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_GID_DEFINED) 295d8a7b7a3SRobert Watson match = !match; 296d8a7b7a3SRobert Watson if (!match) 297d8a7b7a3SRobert Watson return (0); 298d8a7b7a3SRobert Watson } 299d8a7b7a3SRobert Watson 30089ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) { 301245bfd34SRyan Moeller match = (fsidcmp(&vp->v_mount->mnt_stat.f_fsid, 302245bfd34SRyan Moeller &rule->mbr_object.mbo_fsid) == 0); 30389ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED) 30489ddbd45SDavid Malone match = !match; 30589ddbd45SDavid Malone if (!match) 306458f818fSRobert Watson return (0); 30789ddbd45SDavid Malone } 30889ddbd45SDavid Malone 30989ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_SUID) { 310dfa7fd1dSEdward Tomasz Napierala match = (vap->va_mode & S_ISUID); 31189ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_SUID) 31289ddbd45SDavid Malone match = !match; 31389ddbd45SDavid Malone if (!match) 314458f818fSRobert Watson return (0); 31589ddbd45SDavid Malone } 31689ddbd45SDavid Malone 31789ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_SGID) { 318dfa7fd1dSEdward Tomasz Napierala match = (vap->va_mode & S_ISGID); 31989ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_SGID) 32089ddbd45SDavid Malone match = !match; 32189ddbd45SDavid Malone if (!match) 322458f818fSRobert Watson return (0); 32389ddbd45SDavid Malone } 32489ddbd45SDavid Malone 32589ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) { 32689ddbd45SDavid Malone match = (vap->va_uid == cred->cr_uid || 32789ddbd45SDavid Malone vap->va_uid == cred->cr_ruid || 32889ddbd45SDavid Malone vap->va_uid == cred->cr_svuid); 32989ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT) 33089ddbd45SDavid Malone match = !match; 33189ddbd45SDavid Malone if (!match) 332458f818fSRobert Watson return (0); 33389ddbd45SDavid Malone } 33489ddbd45SDavid Malone 33589ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) { 33689ddbd45SDavid Malone match = (groupmember(vap->va_gid, cred) || 33789ddbd45SDavid Malone vap->va_gid == cred->cr_rgid || 33889ddbd45SDavid Malone vap->va_gid == cred->cr_svgid); 33989ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT) 34089ddbd45SDavid Malone match = !match; 34189ddbd45SDavid Malone if (!match) 342458f818fSRobert Watson return (0); 34389ddbd45SDavid Malone } 34489ddbd45SDavid Malone 34589ddbd45SDavid Malone if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) { 34689ddbd45SDavid Malone switch (vap->va_type) { 34789ddbd45SDavid Malone case VREG: 34889ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_REG); 34989ddbd45SDavid Malone break; 35089ddbd45SDavid Malone case VDIR: 35189ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_DIR); 35289ddbd45SDavid Malone break; 35389ddbd45SDavid Malone case VBLK: 35489ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_BLK); 35589ddbd45SDavid Malone break; 35689ddbd45SDavid Malone case VCHR: 35789ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_CHR); 35889ddbd45SDavid Malone break; 35989ddbd45SDavid Malone case VLNK: 36089ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_LNK); 36189ddbd45SDavid Malone break; 36289ddbd45SDavid Malone case VSOCK: 36389ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_SOCK); 36489ddbd45SDavid Malone break; 36589ddbd45SDavid Malone case VFIFO: 36689ddbd45SDavid Malone match = (rule->mbr_object.mbo_type & MBO_TYPE_FIFO); 36789ddbd45SDavid Malone break; 36889ddbd45SDavid Malone default: 36989ddbd45SDavid Malone match = 0; 37089ddbd45SDavid Malone } 37189ddbd45SDavid Malone if (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED) 37289ddbd45SDavid Malone match = !match; 37389ddbd45SDavid Malone if (!match) 374458f818fSRobert Watson return (0); 37589ddbd45SDavid Malone } 37689ddbd45SDavid Malone 377d8a7b7a3SRobert Watson /* 378cecd8edbSAttilio Rao * MBI_APPEND should not be here as it should get converted to 379cecd8edbSAttilio Rao * MBI_WRITE. 380cecd8edbSAttilio Rao */ 381cecd8edbSAttilio Rao priv_granted = 0; 382cecd8edbSAttilio Rao mac_granted = rule->mbr_mode; 383cecd8edbSAttilio Rao if ((acc_mode & MBI_ADMIN) && (mac_granted & MBI_ADMIN) == 0 && 384cc426dd3SMateusz Guzik priv_check_cred(cred, PRIV_VFS_ADMIN) == 0) 385cecd8edbSAttilio Rao priv_granted |= MBI_ADMIN; 386cecd8edbSAttilio Rao if ((acc_mode & MBI_EXEC) && (mac_granted & MBI_EXEC) == 0 && 387cc426dd3SMateusz Guzik priv_check_cred(cred, (vap->va_type == VDIR) ? PRIV_VFS_LOOKUP : PRIV_VFS_EXEC) == 0) 388cecd8edbSAttilio Rao priv_granted |= MBI_EXEC; 389cecd8edbSAttilio Rao if ((acc_mode & MBI_READ) && (mac_granted & MBI_READ) == 0 && 390cc426dd3SMateusz Guzik priv_check_cred(cred, PRIV_VFS_READ) == 0) 391cecd8edbSAttilio Rao priv_granted |= MBI_READ; 392cecd8edbSAttilio Rao if ((acc_mode & MBI_STAT) && (mac_granted & MBI_STAT) == 0 && 393cc426dd3SMateusz Guzik priv_check_cred(cred, PRIV_VFS_STAT) == 0) 394cecd8edbSAttilio Rao priv_granted |= MBI_STAT; 395cecd8edbSAttilio Rao if ((acc_mode & MBI_WRITE) && (mac_granted & MBI_WRITE) == 0 && 396cc426dd3SMateusz Guzik priv_check_cred(cred, PRIV_VFS_WRITE) == 0) 397cecd8edbSAttilio Rao priv_granted |= MBI_WRITE; 398cecd8edbSAttilio Rao /* 399d8a7b7a3SRobert Watson * Is the access permitted? 400d8a7b7a3SRobert Watson */ 401cecd8edbSAttilio Rao if (((mac_granted | priv_granted) & acc_mode) != acc_mode) { 4023f1a7a90SRobert Watson if (ugidfw_logging) 40360673f35STom Rhodes log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d" 40460673f35STom Rhodes " on %d:%d failed. \n", cred->cr_ruid, 405458f818fSRobert Watson cred->cr_rgid, acc_mode, vap->va_uid, 406458f818fSRobert Watson vap->va_gid); 407458f818fSRobert Watson return (EACCES); 408d8a7b7a3SRobert Watson } 409a203d978STom Rhodes 410fa31f180STom Rhodes /* 411a203d978STom Rhodes * If the rule matched, permits access, and first match is enabled, 412a203d978STom Rhodes * return success. 413fa31f180STom Rhodes */ 4143f1a7a90SRobert Watson if (ugidfw_firstmatch_enabled) 415fa31f180STom Rhodes return (EJUSTRETURN); 416fa31f180STom Rhodes else 417d8a7b7a3SRobert Watson return (0); 418d8a7b7a3SRobert Watson } 419d8a7b7a3SRobert Watson 42034f6230eSRobert Watson int 4213f1a7a90SRobert Watson ugidfw_check(struct ucred *cred, struct vnode *vp, struct vattr *vap, 422b914de36SRobert Watson int acc_mode) 423d8a7b7a3SRobert Watson { 424d8a7b7a3SRobert Watson int error, i; 425d8a7b7a3SRobert Watson 426acd3428bSRobert Watson /* 427d24c76d1SRobert Watson * Since we do not separately handle append, map append to write. 4285bf93d25SRobert Watson */ 4292e74bca1SRobert Watson if (acc_mode & MBI_APPEND) { 4302e74bca1SRobert Watson acc_mode &= ~MBI_APPEND; 4312e74bca1SRobert Watson acc_mode |= MBI_WRITE; 4325bf93d25SRobert Watson } 4333f1a7a90SRobert Watson mtx_lock(&ugidfw_mtx); 434d24c76d1SRobert Watson for (i = 0; i < rule_slots; i++) { 435d24c76d1SRobert Watson if (rules[i] == NULL) 436d24c76d1SRobert Watson continue; 4373f1a7a90SRobert Watson error = ugidfw_rulecheck(rules[i], cred, 43889ddbd45SDavid Malone vp, vap, acc_mode); 439fa31f180STom Rhodes if (error == EJUSTRETURN) 440fa31f180STom Rhodes break; 441a203d978STom Rhodes if (error) { 4423f1a7a90SRobert Watson mtx_unlock(&ugidfw_mtx); 443d8a7b7a3SRobert Watson return (error); 444d8a7b7a3SRobert Watson } 445a203d978STom Rhodes } 4463f1a7a90SRobert Watson mtx_unlock(&ugidfw_mtx); 447d8a7b7a3SRobert Watson return (0); 448d8a7b7a3SRobert Watson } 449d8a7b7a3SRobert Watson 45034f6230eSRobert Watson int 4513f1a7a90SRobert Watson ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode) 45296c33a0cSRobert Watson { 45396c33a0cSRobert Watson int error; 45442ae38e9SDavid Malone struct vattr vap; 45596c33a0cSRobert Watson 4563f1a7a90SRobert Watson if (!ugidfw_enabled) 45796c33a0cSRobert Watson return (0); 4580359a12eSAttilio Rao error = VOP_GETATTR(vp, &vap, cred); 45996c33a0cSRobert Watson if (error) 46096c33a0cSRobert Watson return (error); 4613f1a7a90SRobert Watson return (ugidfw_check(cred, vp, &vap, acc_mode)); 46242ae38e9SDavid Malone } 46342ae38e9SDavid Malone 464a1b9471aSRobert Watson int 465a1b9471aSRobert Watson ugidfw_accmode2mbi(accmode_t accmode) 466a1b9471aSRobert Watson { 467a1b9471aSRobert Watson int mbi; 468a1b9471aSRobert Watson 469a1b9471aSRobert Watson mbi = 0; 470a1b9471aSRobert Watson if (accmode & VEXEC) 471a1b9471aSRobert Watson mbi |= MBI_EXEC; 472a1b9471aSRobert Watson if (accmode & VWRITE) 473a1b9471aSRobert Watson mbi |= MBI_WRITE; 474a1b9471aSRobert Watson if (accmode & VREAD) 475a1b9471aSRobert Watson mbi |= MBI_READ; 4766180d318SEdward Tomasz Napierala if (accmode & VADMIN_PERMS) 477a1b9471aSRobert Watson mbi |= MBI_ADMIN; 4786180d318SEdward Tomasz Napierala if (accmode & VSTAT_PERMS) 479a1b9471aSRobert Watson mbi |= MBI_STAT; 480a1b9471aSRobert Watson if (accmode & VAPPEND) 481a1b9471aSRobert Watson mbi |= MBI_APPEND; 482a1b9471aSRobert Watson return (mbi); 483a1b9471aSRobert Watson } 484a1b9471aSRobert Watson 4853f1a7a90SRobert Watson static struct mac_policy_ops ugidfw_ops = 486d8a7b7a3SRobert Watson { 4873f1a7a90SRobert Watson .mpo_destroy = ugidfw_destroy, 4883f1a7a90SRobert Watson .mpo_init = ugidfw_init, 4893f1a7a90SRobert Watson .mpo_system_check_acct = ugidfw_system_check_acct, 4903f1a7a90SRobert Watson .mpo_system_check_auditctl = ugidfw_system_check_auditctl, 4913f1a7a90SRobert Watson .mpo_system_check_swapon = ugidfw_system_check_swapon, 4923f1a7a90SRobert Watson .mpo_vnode_check_access = ugidfw_vnode_check_access, 4933f1a7a90SRobert Watson .mpo_vnode_check_chdir = ugidfw_vnode_check_chdir, 4943f1a7a90SRobert Watson .mpo_vnode_check_chroot = ugidfw_vnode_check_chroot, 4953f1a7a90SRobert Watson .mpo_vnode_check_create = ugidfw_check_create_vnode, 4963f1a7a90SRobert Watson .mpo_vnode_check_deleteacl = ugidfw_vnode_check_deleteacl, 4973f1a7a90SRobert Watson .mpo_vnode_check_deleteextattr = ugidfw_vnode_check_deleteextattr, 4983f1a7a90SRobert Watson .mpo_vnode_check_exec = ugidfw_vnode_check_exec, 4993f1a7a90SRobert Watson .mpo_vnode_check_getacl = ugidfw_vnode_check_getacl, 5003f1a7a90SRobert Watson .mpo_vnode_check_getextattr = ugidfw_vnode_check_getextattr, 5013f1a7a90SRobert Watson .mpo_vnode_check_link = ugidfw_vnode_check_link, 5023f1a7a90SRobert Watson .mpo_vnode_check_listextattr = ugidfw_vnode_check_listextattr, 5033f1a7a90SRobert Watson .mpo_vnode_check_lookup = ugidfw_vnode_check_lookup, 5043f1a7a90SRobert Watson .mpo_vnode_check_open = ugidfw_vnode_check_open, 5053f1a7a90SRobert Watson .mpo_vnode_check_readdir = ugidfw_vnode_check_readdir, 5063f1a7a90SRobert Watson .mpo_vnode_check_readlink = ugidfw_vnode_check_readdlink, 5073f1a7a90SRobert Watson .mpo_vnode_check_rename_from = ugidfw_vnode_check_rename_from, 5083f1a7a90SRobert Watson .mpo_vnode_check_rename_to = ugidfw_vnode_check_rename_to, 5093f1a7a90SRobert Watson .mpo_vnode_check_revoke = ugidfw_vnode_check_revoke, 5103f1a7a90SRobert Watson .mpo_vnode_check_setacl = ugidfw_check_setacl_vnode, 5113f1a7a90SRobert Watson .mpo_vnode_check_setextattr = ugidfw_vnode_check_setextattr, 5123f1a7a90SRobert Watson .mpo_vnode_check_setflags = ugidfw_vnode_check_setflags, 5133f1a7a90SRobert Watson .mpo_vnode_check_setmode = ugidfw_vnode_check_setmode, 5143f1a7a90SRobert Watson .mpo_vnode_check_setowner = ugidfw_vnode_check_setowner, 5153f1a7a90SRobert Watson .mpo_vnode_check_setutimes = ugidfw_vnode_check_setutimes, 5163f1a7a90SRobert Watson .mpo_vnode_check_stat = ugidfw_vnode_check_stat, 5173f1a7a90SRobert Watson .mpo_vnode_check_unlink = ugidfw_vnode_check_unlink, 518d8a7b7a3SRobert Watson }; 519d8a7b7a3SRobert Watson 5203f1a7a90SRobert Watson MAC_POLICY_SET(&ugidfw_ops, mac_bsdextended, "TrustedBSD MAC/BSD Extended", 5219162f64bSRobert Watson MPC_LOADTIME_FLAG_UNLOADOK, NULL); 522