Mercurial > illumos > fmac
changeset 7890:da5be6cc4191 fmac_alpha3
fmac-gate merge before push
author | John Weeks <john.weeks@sun.com> |
---|---|
date | Wed, 29 Oct 2008 11:52:47 -0700 |
parents | a5fda081c83b (current diff) dc5a88b1d093 (diff) |
children | 15405b8c3bd3 |
files | |
diffstat | 22 files changed, 473 insertions(+), 439 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libcmdutils/common/process_xattrs.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/lib/libcmdutils/common/process_xattrs.c Wed Oct 29 11:52:47 2008 -0700 @@ -286,15 +286,16 @@ cmd, fname); return (NULL); } - pair = NULL; - while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { + pair = nvlist_next_nvpair(response, NULL); + while (pair != NULL) { + nvpair_t *next = nvlist_next_nvpair(response, pair); name = nvpair_name(pair); if (name != NULL) fattr = name_to_attr(name); else - return (response); + goto next; type = nvpair_type(pair); switch (type) { @@ -305,22 +306,33 @@ dgettext(TEXT_DOMAIN, "%s " "nvpair_value_boolean_value " "failed\n"), cmd); - continue; + goto next; } if (value && fattr != F_ARCHIVE && fattr != F_AV_MODIFIED) - return (response); + goto next; break; case DATA_TYPE_UINT64_ARRAY: if (fattr != F_CRTIME) - return (response); + goto next; break; case DATA_TYPE_NVLIST: default: - return (response); - break; + goto next; } + + /* Remove any default attributes. */ + (void) nvlist_remove(response, name, type); + +next: + pair = next; } + + /* If non-empty, return the response. */ + pair = nvlist_next_nvpair(response, NULL); + if (pair) + return (response); + if (response != NULL) nvlist_free(response); return (NULL);
--- a/usr/src/uts/common/contract/process.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/contract/process.c Wed Oct 29 11:52:47 2008 -0700 @@ -492,7 +492,7 @@ cankill = hasprocperm(tp->p_cred, ctp->conp_cred, PROCESS__SIGKILL); mutex_exit(&tp->p_crlock); if (cankill || (sp && prochasprocperm(tp, sp, CRED(), - PROCESS__SIGKILL))) + PROCESS__SIGKILL))) return (1); return (0);
--- a/usr/src/uts/common/disp/class.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/disp/class.c Wed Oct 29 11:52:47 2008 -0700 @@ -261,7 +261,7 @@ * Check basic permissions. */ if (!prochasprocperm(targpp, reqpp, reqpcredp, - PROCESS__SETSCHED)) { + PROCESS__SETSCHED)) { crfree(reqpcredp); return (EPERM); }
--- a/usr/src/uts/common/fmac/avc.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fmac/avc.c Wed Oct 29 11:52:47 2008 -0700 @@ -49,6 +49,8 @@ #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/systm.h> +#include <sys/kstat.h> +#include <sys/atomic.h> #include <sys/note.h> #include <sys/fmac/fmac.h> #include <sys/fmac/avc.h> @@ -58,7 +60,19 @@ #include <sys/fmac/av_inherit.h> #include <sys/fmac/av_perm_to_string.h> -static kmutex_t avc_lock; +static krwlock_t avc_lock; +static kmutex_t avc_audit_lock; + +/* + * An entry in the AVC. + */ +typedef struct avc_entry { + security_id_t ssid; + security_id_t tsid; + security_class_t tclass; + struct av_decision avd; + int used; /* used recently */ +} avc_entry_t; typedef struct avc_node { struct avc_entry ae; @@ -85,39 +99,30 @@ static char *avc_audit_buffer = NULL; -unsigned avc_cache_stats[AVC_NSTATS]; - -#ifdef AVC_CACHE_STATS -#define avc_cache_stats_incr(x) avc_cache_stats[(x)]++ -#define avc_cache_stats_add(x, y) avc_cache_stats[(x)] += (y) -#else -#define avc_cache_stats_incr(x) -#define avc_cache_stats_add(x, y) -#endif /* AVC_CACHE_STATS */ - /* - * Display the cache statistics + * AVC statistics */ -void -avc_dump_stats(char *tag) -{ - printf("%s avc: entry: %d lookups == %d hits + %d misses " - "(%d discards)\n", - tag, avc_cache_stats[AVC_ENTRY_LOOKUPS], - avc_cache_stats[AVC_ENTRY_HITS], avc_cache_stats[AVC_ENTRY_MISSES], - avc_cache_stats[AVC_ENTRY_DISCARDS]); +static struct { + kstat_named_t avclookups; + kstat_named_t avchits; + kstat_named_t avcprobes; + kstat_named_t avcmisses; +} avcstats = { + { "avclookups", KSTAT_DATA_UINT64 }, + { "avchits", KSTAT_DATA_UINT64 }, + { "avcprobes", KSTAT_DATA_UINT64 }, + { "avcmisses", KSTAT_DATA_UINT64 } +}; - printf("%s avc: cav: %d lookups == %d hits + %d misses\n", - tag, avc_cache_stats[AVC_CAV_LOOKUPS], - avc_cache_stats[AVC_CAV_HITS], avc_cache_stats[AVC_CAV_MISSES]); +kstat_named_t *avcstats_ptr = (kstat_named_t *)&avcstats; +uint_t avcstats_ndata = sizeof (avcstats) / sizeof (kstat_named_t); - printf("%s avc: cav: %d/%d probe/hit ratio\n", - tag, avc_cache_stats[AVC_CAV_PROBES], - avc_cache_stats[AVC_CAV_HITS]); -} +#define avc_cache_stats_incr(stat) atomic_inc_64(&avcstats.stat.value.ui64) +#define avc_cache_stats_add(stat, x) atomic_add_64(&avcstats.stat.value.ui64, x) static void avc_audit_start(void) { + mutex_enter(&avc_audit_lock); (void) memset(avc_audit_buffer, 0, PAGESIZE); } @@ -136,12 +141,13 @@ static void avc_audit_end(void) { (void) printf("%s\n", avc_audit_buffer); + mutex_exit(&avc_audit_lock); } /* * Display an access vector in human-readable form. */ -void +static void avc_dump_av(security_class_t tclass, access_vector_t av) { char **common_pts = 0; @@ -182,7 +188,7 @@ } if (i2 < AV_PERM_TO_STRING_SIZE) avc_audit_append(" %s", - av_perm_to_string[i2].name); + av_perm_to_string[i2].name); } i++; perm <<= 1; @@ -194,7 +200,7 @@ /* * Display a SID pair and a class in human-readable form. */ -void +static void avc_dump_query( security_id_t ssid, /* IN */ security_id_t tsid, /* IN */ @@ -228,14 +234,23 @@ void avc_init(void) { + kstat_t *ksp; avc_node_t *new; int i; if (!fmac_enabled) return; - for (i = 0; i < AVC_NSTATS; i++) - avc_cache_stats[i] = 0; + rw_init(&avc_lock, NULL, RW_DEFAULT, NULL); + mutex_init(&avc_audit_lock, NULL, MUTEX_DEFAULT, NULL); + + ksp = kstat_create("avc", 0, "avcstats", "misc", KSTAT_TYPE_NAMED, + avcstats_ndata, KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE); + + if (ksp) { + ksp->ks_data = avcstats_ptr; + kstat_install(ksp); + } for (i = 0; i < AVC_CACHE_SLOTS; i++) avc_cache.slots[i] = 0; @@ -244,7 +259,7 @@ avc_cache.latest_notif = 0; for (i = 0; i < AVC_CACHE_MAXNODES; i++) { - new = (avc_node_t *) kmem_zalloc(sizeof (avc_node_t), KM_SLEEP); + new = (avc_node_t *)kmem_zalloc(sizeof (avc_node_t), KM_SLEEP); if (!new) { cmn_err(CE_WARN, "avc: only able to allocate %d entries\n", i); @@ -271,7 +286,7 @@ int slots_used; avc_node_t *node; - mutex_enter(&avc_lock); + rw_enter(&avc_lock, RW_READER); slots_used = 0; max_chain_len = 0; @@ -289,7 +304,7 @@ } } - mutex_exit(&avc_lock); + rw_exit(&avc_lock); printf("\n%s avc: %d entries and %d/%d buckets used, longest " "chain length %d\n", @@ -312,8 +327,6 @@ int slots_used; avc_node_t *node; - avc_dump_stats(tag); - slots_used = 0; max_chain_len = 0; for (i = 0; i < AVC_CACHE_SLOTS; i++) { @@ -463,32 +476,31 @@ * `requested' permissions between the SID pair * (`ssid', `tsid'), interpreting the permissions * based on `tclass'. If a valid AVC entry exists, - * then this function updates `aeref' to refer to the - * entry and returns 0. Otherwise, this function + * then this function copies the av_decision into `avd' + * and returns 0. Otherwise, this function * returns ENOENT. */ -int -avc_lookup( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t requested, /* IN */ - avc_entry_ref_t *aeref) /* OUT */ +static int +avc_lookup(security_id_t ssid, security_id_t tsid, security_class_t tclass, + access_vector_t requested, struct av_decision *avd) { avc_node_t *node; int probes; - avc_cache_stats_incr(AVC_CAV_LOOKUPS); + avc_cache_stats_incr(avclookups); + + rw_enter(&avc_lock, RW_READER); node = avc_search_node(ssid, tsid, tclass, &probes); - if (node && ((node->ae.avd.decided & requested) == requested)) { - avc_cache_stats_incr(AVC_CAV_HITS); - avc_cache_stats_add(AVC_CAV_PROBES, probes); - aeref->ae = &node->ae; + (void) memcpy(avd, &node->ae.avd, sizeof (*avd)); + rw_exit(&avc_lock); + avc_cache_stats_incr(avchits); + avc_cache_stats_add(avcprobes, probes); return (0); } + rw_exit(&avc_lock); - avc_cache_stats_incr(AVC_CAV_MISSES); + avc_cache_stats_incr(avcmisses); return (ENOENT); } @@ -504,54 +516,43 @@ * `aeref' to refer to the entry, and returns 0. * Otherwise, this function returns EAGAIN. */ -int -avc_insert( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - struct avc_entry *ae, /* IN */ - avc_entry_ref_t *aeref) /* OUT */ +static int +avc_insert(security_id_t ssid, security_id_t tsid, security_class_t tclass, + struct av_decision *avd) { avc_node_t *node; - if (ae->avd.seqno < avc_cache.latest_notif) { - printf("avc: seqno %d < latest_notif %d\n", ae->avd.seqno, + rw_enter(&avc_lock, RW_WRITER); + if (avd->seqno < avc_cache.latest_notif) { + printf("avc: seqno %d < latest_notif %d\n", avd->seqno, avc_cache.latest_notif); + rw_exit(&avc_lock); return (EAGAIN); } node = avc_claim_node(ssid, tsid, tclass); if (!node) { + rw_exit(&avc_lock); return (ENOMEM); } - node->ae.avd.allowed = ae->avd.allowed; - node->ae.avd.decided = ae->avd.decided; - node->ae.avd.auditallow = ae->avd.auditallow; - node->ae.avd.auditdeny = ae->avd.auditdeny; - node->ae.avd.seqno = ae->avd.seqno; - aeref->ae = &node->ae; + (void) memcpy(&node->ae.avd, avd, sizeof (*avd)); + rw_exit(&avc_lock); return (0); } /* * Audit the granting or denial of permissions. */ -void -avc_audit( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t audited, /* IN */ - struct avc_entry *ae, /* IN */ - uint32_t denied, /* IN */ - avc_audit_data_t *a) /* IN */ +#define AVC_AUDITALLOW 0 +#define AVC_AUDITDENY 1 +static void +avc_audit(security_id_t ssid, security_id_t tsid, security_class_t tclass, + access_vector_t audited, uint32_t denied, avc_audit_data_t *a) { struct proc *p = curproc; struct vnode *vp; - _NOTE(ARGUNUSED(ae)); - if (a && a->type == AVC_AUDIT_DATA_DONTAUDIT) return; @@ -608,7 +609,7 @@ { avc_callback_node_t *c; - c = (avc_callback_node_t *) kmem_alloc(sizeof (avc_callback_node_t), + c = (avc_callback_node_t *)kmem_alloc(sizeof (avc_callback_node_t), KM_SLEEP); c->callback = callback; @@ -664,17 +665,13 @@ * `perms'. */ static int -avc_update_cache( - uint32_t event, /* IN */ - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t perms) /* IN */ +avc_update_cache(uint32_t event, security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t perms) { avc_node_t *node; int i; - mutex_enter(&avc_lock); + rw_enter(&avc_lock, RW_WRITER); if (ssid == SECSID_WILD || tsid == SECSID_WILD) { /* apply to all matching nodes */ @@ -696,7 +693,7 @@ } } - mutex_exit(&avc_lock); + rw_exit(&avc_lock); return (0); } @@ -754,10 +751,10 @@ *out_retained = tretained; } - mutex_enter(&avc_lock); + rw_enter(&avc_lock, RW_WRITER); if (seqno > avc_cache.latest_notif) avc_cache.latest_notif = seqno; - mutex_exit(&avc_lock); + rw_exit(&avc_lock); return (0); } @@ -823,7 +820,7 @@ avc_hash_eval("reset"); - mutex_enter(&avc_lock); + rw_enter(&avc_lock, RW_WRITER); for (i = 0; i < AVC_CACHE_SLOTS; i++) { node = avc_cache.slots[i]; @@ -843,24 +840,21 @@ } avc_cache.lru_hint = 0; - mutex_exit(&avc_lock); - - for (i = 0; i < AVC_NSTATS; i++) - avc_cache_stats[i] = 0; + rw_exit(&avc_lock); for (c = avc_callbacks; c; c = c->next) { if (c->events & AVC_CALLBACK_RESET) { rc = c->callback(AVC_CALLBACK_RESET, - 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0); if (rc) return (rc); } } - mutex_enter(&avc_lock); + rw_enter(&avc_lock, RW_WRITER); if (seqno > avc_cache.latest_notif) avc_cache.latest_notif = seqno; - mutex_exit(&avc_lock); + rw_exit(&avc_lock); return (0); } @@ -877,10 +871,10 @@ { if (enable) return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE, - ssid, tsid, tclass, perms, seqno, 0); + ssid, tsid, tclass, perms, seqno, 0); else return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE, - ssid, tsid, tclass, perms, seqno, 0); + ssid, tsid, tclass, perms, seqno, 0); } /* Enable or disable auditing of denied permissions */ @@ -895,107 +889,69 @@ { if (enable) return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE, - ssid, tsid, tclass, perms, seqno, 0); + ssid, tsid, tclass, perms, seqno, 0); else return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE, - ssid, tsid, tclass, perms, seqno, 0); + ssid, tsid, tclass, perms, seqno, 0); } /* - * Check permissions using an AVC entry ref. - * - * If the ref is null or the underlying AVC entry has been invalidated - * or the underlying AVC entry does not contain all the requested - * decisions, then this code falls through to avc_lookup. In - * this case, the AVC entry ref will be updated appropriately. + * Compute an entire access vector. */ int -avc_has_perm_ref_audit( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t requested, /* IN */ - avc_entry_ref_t *aeref, /* IN */ - avc_audit_data_t *auditdata) /* IN */ +avc_compute_av(security_id_t ssid, security_id_t tsid, security_class_t tclass, + access_vector_t requested, struct av_decision *avd) { - struct avc_entry *ae; int rc; - struct avc_entry entry; - access_vector_t denied; if (!fmac_enabled) return (0); - mutex_enter(&avc_lock); - avc_cache_stats_incr(AVC_ENTRY_LOOKUPS); - ae = aeref->ae; - if (ae) { - if (ae->ssid == ssid && - ae->tsid == tsid && - ae->tclass == tclass && - ((ae->avd.decided & requested) == requested)) { - avc_cache_stats_incr(AVC_ENTRY_HITS); - ae->used = 1; - } else { - avc_cache_stats_incr(AVC_ENTRY_DISCARDS); - ae = 0; - } + rc = avc_lookup(ssid, tsid, tclass, requested, avd); + if (rc) { + rc = security_compute_av(ssid, tsid, tclass, requested, avd); + if (rc) + return (rc); + rc = avc_insert(ssid, tsid, tclass, avd); + if (rc) + return (rc); } - if (!ae) { - avc_cache_stats_incr(AVC_ENTRY_MISSES); - rc = avc_lookup(ssid, tsid, tclass, requested, aeref); - if (rc) { - mutex_exit(&avc_lock); - rc = security_compute_av(ssid, tsid, tclass, requested, - &entry.avd); - if (rc) - return (rc); - mutex_enter(&avc_lock); - rc = avc_insert(ssid, tsid, tclass, &entry, aeref); - if (rc) { - mutex_exit(&avc_lock); - return (rc); - } - } - ae = aeref->ae; - } + return (0); +} + +int +avc_has_perm(security_id_t ssid, security_id_t tsid, security_class_t tclass, + access_vector_t requested, avc_audit_data_t *auditdata) +{ + struct av_decision avd; + access_vector_t denied; + int rc; - denied = requested & ~(ae->avd.allowed); + ASSERT(requested); + + rc = avc_compute_av(ssid, tsid, tclass, requested, &avd); + if (rc) + return (rc); - if (!requested || denied) { - if (!requested || (denied & ae->avd.auditdeny)) - avc_audit(ssid, tsid, tclass, denied, ae, AVC_AUDITDENY, + denied = requested & ~avd.allowed; + + if (denied) { + if (denied & avd.auditdeny) + avc_audit(ssid, tsid, tclass, denied, AVC_AUDITDENY, auditdata); if (fmac_enforcing) { - mutex_exit(&avc_lock); return (EACCES); } else { - ae->avd.allowed |= requested; - mutex_exit(&avc_lock); + (void) avc_update_cache(AVC_CALLBACK_GRANT, ssid, tsid, + tclass, requested); return (0); } } - if (requested & ae->avd.auditallow) - avc_audit(ssid, tsid, tclass, requested, ae, AVC_AUDITALLOW, + if (requested & avd.auditallow) + avc_audit(ssid, tsid, tclass, requested, AVC_AUDITALLOW, auditdata); - mutex_exit(&avc_lock); return (0); } - -/* Check permissions */ -int -avc_has_perm_audit( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t requested, /* IN */ - avc_audit_data_t *auditdata) /* IN */ -{ - avc_entry_ref_t ref; - AVC_ENTRY_REF_INIT(&ref); - return (avc_has_perm_ref_audit(ssid, tsid, tclass, requested, &ref, - auditdata)); -}
--- a/usr/src/uts/common/fmac/fmac.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fmac/fmac.c Wed Oct 29 11:52:47 2008 -0700 @@ -35,6 +35,7 @@ #include <sys/param.h> #include <sys/kobj.h> #include <sys/vfs.h> +#include <sys/acl.h> #include <sys/fmac/security.h> #include <sys/fmac/fmac.h> #include <sys/fmac/avc.h> @@ -174,6 +175,8 @@ return (0); if (vp->v_secid != SECINITSID_UNLABELED) return (0); /* already set */ + if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) + return (0); xva_init(&xvattr); if ((xoap = xva_getxoptattr(&xvattr)) == NULL) @@ -186,7 +189,7 @@ if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { error = security_context_to_sid(xoap->xoa_secctx, - strlen(xoap->xoa_secctx), &secid); + strlen(xoap->xoa_secctx), &secid); if (error) return (error); } else { @@ -202,6 +205,23 @@ return (0); } +void +fmac_vnode_init_secid(vnode_t *vp, char *secctx) +{ + security_id_t secid; + + if (!fmac_enabled) + return; + + /* + * Called before vp is put in dnlc, so no need to hold v_lock. + */ + if (security_context_to_sid(secctx, strlen(secctx), &secid)) + vp->v_secid = SECINITSID_UNLABELED; + else + vp->v_secid = secid; +} + int fmac_vfs_root(vfs_t *vfsp, vnode_t *vp) { @@ -215,6 +235,7 @@ security_id_t cr_secid, old_secid, new_secid; security_class_t sclass; int error; + avc_audit_data_t ad; if (!fmac_enabled) return (EINVAL); @@ -235,24 +256,60 @@ */ mutex_enter(&(vp->v_lock)); old_secid = vp->v_secid; + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; error = avc_has_perm(cr_secid, old_secid, sclass, - FILE__RELABELFROM); + FILE__RELABELFROM, &ad); if (!error) error = avc_has_perm(cr_secid, new_secid, sclass, - FILE__RELABELTO); + FILE__RELABELTO, &ad); if (!error) vp->v_secid = new_secid; mutex_exit(&(vp->v_lock)); } else { /* Creating a new file. */ error = avc_has_perm(cr_secid, new_secid, sclass, - FILE__CREATE); + FILE__CREATE, NULL); } return (error); } int +fmac_vnode_get_secctx(vnode_t *vp, vattr_t *vap) +{ + xvattr_t *xvap = (xvattr_t *)vap; + xoptattr_t *xoap; + security_context_t scontext; + uint32_t scontext_len; + int error; + + if (!fmac_enabled) + return (0); + + xoap = xva_getxoptattr(xvap); + if (!xoap) + return (0); + + if (!XVA_ISSET_REQ(xvap, XAT_SECCTX)) + return (0); + + error = security_sid_to_context(vp->v_secid, &scontext, &scontext_len); + if (error) + return (error); + + if (scontext_len > sizeof (xoap->xoa_secctx)) { + security_context_free(scontext); + return (EINVAL); + } + + (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); + XVA_SET_RTN(xvap, XAT_SECCTX); + security_context_free(scontext); + return (0); +} + +int fmac_vnode_create(vnode_t *dvp, char *name, xvattr_t *xvap, vattr_t **vapp, cred_t *cr, security_id_t *secidp) { @@ -260,6 +317,7 @@ security_class_t sclass; security_context_t scontext; uint32_t scontext_len; + vattr_t *vap = *vapp; xoptattr_t *xoap; int error; avc_audit_data_t ad; @@ -277,7 +335,7 @@ if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR) == 0) return (0); - sclass = fmac_vtype_to_sclass((*vapp)->va_type); + sclass = fmac_vtype_to_sclass(vap->va_type); if (!sclass) return (0); @@ -292,42 +350,46 @@ ad.u.fs.vp = dvp; ad.u.fs.name = name; - error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, + error = avc_has_perm(cr_secid, dvp->v_secid, SECCLASS_DIR, DIR__ADD_NAME, &ad); if (error) return (error); - error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); + error = avc_has_perm(cr_secid, secid, sclass, FILE__CREATE, &ad); if (error) return (error); - /* - * Wrap the vattr with an xvattr so we can pass the - * secctx to the fs code. - */ - xva_init(xvap); - (void) memcpy(&xvap->xva_vattr, *vapp, sizeof (vattr_t)); - xvap->xva_vattr.va_mask |= AT_XVATTR; /* reset after memcpy */ - XVA_SET_REQ(xvap, XAT_SECCTX); + if (!xvap) { + /* + * Caller only wants the secid, not an xvattr w/ secctx. + * tmpfs is one such example. + */ + *secidp = secid; + return (0); + } + + if (!(vap->va_mask & AT_XVATTR)) { + /* + * If the vattr is not already an xvattr, then wrap the + * vattr with an xvattr so we can pass the secctx to + * the fs code. + */ + xva_from_va(xvap, vap); + *vapp = &xvap->xva_vattr; + } else { + xvap = (xvattr_t *)vap; + } error = security_sid_to_context(secid, &scontext, &scontext_len); if (error) return (error); - if (scontext_len > sizeof (xoap->xoa_secctx)) - goto inval; - xoap = xva_getxoptattr(xvap); - if (!xoap) + if (!xoap || scontext_len > sizeof (xoap->xoa_secctx)) goto inval; (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); + XVA_SET_REQ(xvap, XAT_SECCTX); - /* - * Switch the vap pointer to the newly populated xvattr. - * fop_create/fop_mkdir will then pass the xvattr along to - * the underlying fs code. The original vattr is not mutated. - */ - *vapp = &xvap->xva_vattr; *secidp = secid; security_context_free(scontext); return (0); @@ -347,13 +409,11 @@ } int -fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, - caller_context_t *ct) +fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr) { security_id_t cr_secid; security_class_t sclass; int error; - vnode_t *realvp; avc_audit_data_t ad; if (!fmac_enabled) @@ -363,22 +423,19 @@ if (!sclass) return (0); - if (VOP_REALVP(svp, &realvp, ct) == 0) - svp = realvp; - cr_secid = crgetsecid(cr); AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = tdvp; ad.u.fs.name = name; - error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR, + error = avc_has_perm(cr_secid, tdvp->v_secid, SECCLASS_DIR, DIR__ADD_NAME, &ad); if (error) return (error); ad.u.fs.vp = svp; - return (avc_has_perm_audit(cr_secid, svp->v_secid, sclass, - FILE__LINK, &ad)); + return (avc_has_perm(cr_secid, svp->v_secid, sclass, + FILE__LINK, &ad)); } int @@ -402,7 +459,7 @@ AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = dvp; ad.u.fs.name = name; - error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, + error = avc_has_perm(cr_secid, dvp->v_secid, SECCLASS_DIR, DIR__REMOVE_NAME, &ad); if (error) return (error); @@ -412,7 +469,7 @@ av = DIR__RMDIR; else av = FILE__UNLINK; - return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av, &ad)); } int @@ -437,19 +494,19 @@ AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = sdvp; - error = avc_has_perm_audit(cr_secid, sdvp->v_secid, SECCLASS_DIR, + error = avc_has_perm(cr_secid, sdvp->v_secid, SECCLASS_DIR, DIR__REMOVE_NAME, &ad); if (error) return (error); ad.u.fs.vp = svp; - error = avc_has_perm_audit(cr_secid, svp->v_secid, sclass, + error = avc_has_perm(cr_secid, svp->v_secid, sclass, FILE__RENAME, &ad); if (error) return (error); ad.u.fs.vp = tdvp; - error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR, + error = avc_has_perm(cr_secid, tdvp->v_secid, SECCLASS_DIR, DIR__ADD_NAME, &ad); if (error) return (error); @@ -465,7 +522,7 @@ av = FILE__UNLINK; ad.u.fs.vp = tvp; - error = avc_has_perm_audit(cr_secid, tvp->v_secid, tclass, av, + error = avc_has_perm(cr_secid, tvp->v_secid, tclass, av, &ad); if (error) return (error); @@ -492,8 +549,8 @@ AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = vp; - return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, - FILE__SETATTR, &ad)); + return (avc_has_perm(cr_secid, vp->v_secid, sclass, + FILE__SETATTR, &ad)); } int @@ -516,32 +573,32 @@ return (error); } + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; + if (prev_secid == secid) { - AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.vp = vp; - error = avc_has_perm_audit(prev_secid, vp->v_secid, + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); if (error) return (error); *execsetid = B_FALSE; *setsecid = B_FALSE; + *prev_secidp = *secidp = secid; return (0); } error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, - PROCESS__TRANSITION); + PROCESS__TRANSITION, &ad); if (error) return (error); - AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.vp = vp; - error = avc_has_perm_audit(secid, vp->v_secid, SECCLASS_FILE, + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, FILE__ENTRYPOINT, &ad); if (error) return (error); error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, - PROCESS__EXECSETID); + PROCESS__EXECSETID, &ad); if (error) *execsetid = B_TRUE; else @@ -553,6 +610,17 @@ return (0); } +#define fmac_ace_to_av(mask, perm) \ + if (mode & (mask)) { \ + mode &= ~(mask); \ + av |= (perm); \ + } + +#define ACE_GETATTR_MASK (ACE_READ_NAMED_ATTRS | ACE_READ_ATTRIBUTES | \ + ACE_READ_ACL) +#define ACE_SETATTR_MASK (ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ATTRIBUTES | \ + ACE_WRITE_ACL | ACE_WRITE_OWNER) + int fmac_vnode_access(vnode_t *vp, int mode, int flags, cred_t *cr, boolean_t audit) @@ -572,17 +640,43 @@ return (0); av = 0; - if (mode & VREAD) - av |= FILE__READ; - if (flags & V_APPEND) - av |= FILE__APPEND; - else if (mode & VWRITE) - av |= FILE__WRITE; - if (mode & VEXEC) { - if (sclass == SECCLASS_DIR) - av |= DIR__SEARCH; - else - av |= FILE__EXECUTE; + + if (flags & V_ACE_MASK) { + mode &= ~ACE_SYNCHRONIZE; /* ignore synchronize bit */ + fmac_ace_to_av(ACE_READ_DATA, FILE__READ); + fmac_ace_to_av(ACE_GETATTR_MASK, FILE__GETATTR); + fmac_ace_to_av(ACE_SETATTR_MASK, FILE__SETATTR); + if (sclass == SECCLASS_DIR) { + fmac_ace_to_av((ACE_ADD_FILE | ACE_ADD_SUBDIRECTORY), + DIR__ADD_NAME); + fmac_ace_to_av(ACE_DELETE_CHILD, DIR__REMOVE_NAME); + fmac_ace_to_av(ACE_DELETE, DIR__RMDIR); + fmac_ace_to_av(ACE_EXECUTE, DIR__SEARCH); + } else { + fmac_ace_to_av(ACE_APPEND_DATA, FILE__APPEND); + fmac_ace_to_av(ACE_WRITE_DATA, (flags & V_APPEND) ? + FILE__APPEND : FILE__WRITE); + fmac_ace_to_av(ACE_EXECUTE, FILE__EXECUTE); + fmac_ace_to_av(ACE_DELETE, FILE__UNLINK); + } + if (mode) { + cmn_err(CE_WARN, "FMAC: Unknown ACE mask 0x%x\n", + mode); + return (EACCES); + } + } else { + if (mode & VREAD) + av |= FILE__READ; + if (flags & V_APPEND) + av |= FILE__APPEND; + else if (mode & VWRITE) + av |= FILE__WRITE; + if (mode & VEXEC) { + if (sclass == SECCLASS_DIR) + av |= DIR__SEARCH; + else + av |= FILE__EXECUTE; + } } if (!av) @@ -593,7 +687,7 @@ ad.u.fs.vp = vp; } else AVC_AUDIT_DATA_INIT(&ad, DONTAUDIT); - return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av, &ad)); } int @@ -604,7 +698,7 @@ if (!fmac_enabled) return (0); return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), - SECCLASS_PROCESS, PROCESS__PTRACE)); + SECCLASS_PROCESS, PROCESS__PTRACE, NULL)); } access_vector_t @@ -632,5 +726,5 @@ tsecid = crgetsecid((cred_t *)tcrp); ssecid = crgetsecid((cred_t *)scrp); - return (avc_has_perm(ssecid, tsecid, SECCLASS_PROCESS, perms)); + return (avc_has_perm(ssecid, tsecid, SECCLASS_PROCESS, perms, NULL)); }
--- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c Wed Oct 29 11:52:47 2008 -0700 @@ -42,6 +42,7 @@ #include <sys/kmem.h> #include <sys/atomic.h> #include <sys/policy.h> +#include <sys/fmac/fmac.h> #include <sys/fs/tmp.h> #include <sys/fs/tmpnode.h> @@ -52,6 +53,8 @@ { struct tmpnode *tp = vtp; int shift = 0; + int error = 0; + /* * Check access based on owner, group and * public permissions in tmpnode. @@ -65,10 +68,14 @@ /* compute missing mode bits */ mode &= ~(tp->tn_mode << shift); - if (mode == 0) - return (0); + if (mode) + error = secpolicy_vnode_access(cred, TNTOV(tp), tp->tn_uid, + mode); - return (secpolicy_vnode_access(cred, TNTOV(tp), tp->tn_uid, mode)); + if (!error) + error = fmac_vnode_access(TNTOV(tp), mode, 0, cred, B_TRUE); + + return (error); } /* @@ -86,15 +93,19 @@ struct cred *cr) { uid_t uid = crgetuid(cr); + int error = 0; if ((dir->tn_mode & S_ISVTX) && uid != dir->tn_uid && uid != entry->tn_uid && (entry->tn_type != VREG || tmp_taccess(entry, VWRITE, cr) != 0)) - return (secpolicy_vnode_remove(cr)); + error = secpolicy_vnode_remove(cr); - return (0); + if (!error) + error = fmac_vnode_remove(TNTOV(dir), TNTOV(entry), NULL, cr); + + return (error); } /*
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c Wed Oct 29 11:52:47 2008 -0700 @@ -342,6 +342,7 @@ rw_enter(&tp->tn_rwlock, RW_WRITER); TNTOV(tp)->v_flag |= VROOT; + TNTOV(tp)->v_secid = mvp->v_secid; /* * If the getattr succeeded, use its results. Otherwise allow
--- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c Wed Oct 29 11:52:47 2008 -0700 @@ -64,6 +64,7 @@ #include <sys/vm.h> #include <sys/vtrace.h> #include <sys/policy.h> +#include <sys/fmac/fmac.h> #include <fs/fs_subr.h> static int tmp_getapage(struct vnode *, u_offset_t, size_t, uint_t *, @@ -702,7 +703,8 @@ */ vap->va_nblocks = (fsblkcnt64_t)btodb(ptob(btopr(vap->va_size))); mutex_exit(&tp->tn_tlock); - return (0); + + return (fmac_vnode_get_secctx(vp, vap)); } /*ARGSUSED4*/ @@ -718,14 +720,38 @@ struct tmpnode *tp = (struct tmpnode *)VTOTN(vp); int error = 0; struct vattr *get; + xvattr_t *xvap = (xvattr_t *)vap; long mask; /* * Cannot set these attributes */ - if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR)) + if (vap->va_mask & AT_NOSET) return (EINVAL); + /* + * Only support XAT_SECCTX presently. + */ + if (vap->va_mask & AT_XVATTR) { + if (XVA_ISSET_REQ(xvap, XAT_CREATETIME) || + XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || + XVA_ISSET_REQ(xvap, XAT_SYSTEM) || + XVA_ISSET_REQ(xvap, XAT_READONLY) || + XVA_ISSET_REQ(xvap, XAT_HIDDEN) || + XVA_ISSET_REQ(xvap, XAT_NOUNLINK) || + XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) || + XVA_ISSET_REQ(xvap, XAT_APPENDONLY) || + XVA_ISSET_REQ(xvap, XAT_NODUMP) || + XVA_ISSET_REQ(xvap, XAT_OPAQUE) || + XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) || + XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) + return (EINVAL); + } + + error = fmac_vnode_setattr(vp, cred); + if (error) + return (error); + mutex_enter(&tp->tn_tlock); get = &tp->tn_attr; @@ -741,6 +767,11 @@ mask = vap->va_mask; + if ((mask & AT_XVATTR) && XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + /* vnode secid was updated during the secpolicy call. */ + XVA_SET_RTN(xvap, XAT_SECCTX); + } + if (mask & AT_MODE) { get->va_mode &= S_IFMT; get->va_mode |= vap->va_mode & ~S_IFMT; @@ -937,6 +968,7 @@ struct tmpnode *self; int error; struct tmpnode *oldtp; + security_id_t secid; again: parent = (struct tmpnode *)VTOTN(dvp); @@ -1021,6 +1053,10 @@ if (error != ENOENT) return (error); + error = fmac_vnode_create(dvp, nm, NULL, &vap, cred, &secid); + if (error) + return (error); + rw_enter(&parent->tn_rwlock, RW_WRITER); error = tdirenter(tm, parent, nm, DE_CREATE, (struct tmpnode *)NULL, (struct tmpnode *)NULL, @@ -1057,6 +1093,8 @@ return (ENOSYS); *vpp = newvp; } + + fmac_vnode_post_create(*vpp, secid); TRACE_3(TR_FAC_TMPFS, TR_TMPFS_CREATE, "tmpfs create:dvp %p nm %s vpp %p", dvp, nm, vpp); return (0); @@ -1117,6 +1155,10 @@ if (VOP_REALVP(srcvp, &realvp, ct) == 0) srcvp = realvp; + error = fmac_vnode_link(dvp, srcvp, tnm, cred); + if (error) + return (error); + parent = (struct tmpnode *)VTOTN(dvp); from = (struct tmpnode *)VTOTN(srcvp); @@ -1300,6 +1342,11 @@ struct tmpnode *self = NULL; struct tmount *tm = (struct tmount *)VTOTM(dvp); int error; + security_id_t secid; + + error = fmac_vnode_create(dvp, nm, NULL, &va, cred, &secid); + if (error) + return (error); /* no new dirs allowed in xattr dirs */ if (parent->tn_flags & ISXATTR) @@ -1333,6 +1380,7 @@ } rw_exit(&parent->tn_rwlock); *vpp = TNTOV(self); + fmac_vnode_post_create(*vpp, secid); return (0); }
--- a/usr/src/uts/common/fs/vnode.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/vnode.c Wed Oct 29 11:52:47 2008 -0700 @@ -381,6 +381,18 @@ } /* + * Populate an xvattr from a vattr. + */ +void +xva_from_va(xvattr_t *xvap, vattr_t *vap) +{ + ASSERT(!(vap->va_mask & AT_XVATTR)); + xva_init(xvap); + (void) memcpy(&xvap->xva_vattr, vap, sizeof (vattr_t)); + xvap->xva_vattr.va_mask |= AT_XVATTR; +} + +/* * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t * structure. Otherwise, returns NULL. */ @@ -3275,10 +3287,6 @@ return (EINVAL); } - err = fmac_vnode_setattr(vp, cr); - if (err) - return (err); - err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct); VOPSTATS_UPDATE(vp, setattr); return (err); @@ -3303,9 +3311,7 @@ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); VOPSTATS_UPDATE(vp, access); - if (err) - return (err); - return (fmac_vnode_access(vp, mode, flags, cr, B_TRUE)); + return (err); } int @@ -3367,8 +3373,6 @@ vsecattr_t *vsecp) /* ACL to set during create */ { int ret; - xvattr_t xvattr; - security_id_t secid; if (vsecp != NULL && vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) { @@ -3383,16 +3387,11 @@ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) return (EINVAL); - ret = fmac_vnode_create(dvp, name, &xvattr, &vap, cr, &secid); - if (ret) - return (ret); - VOPXID_MAP_CR(dvp, cr); ret = (*(dvp)->v_op->vop_create) (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp); if (ret == 0 && *vpp) { - fmac_vnode_post_create(*vpp, secid); VOPSTATS_UPDATE(*vpp, create); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, name, strlen(name)); @@ -3450,10 +3449,6 @@ VOPXID_MAP_CR(tdvp, cr); - err = fmac_vnode_link(tdvp, svp, tnm, cr, ct); - if (err) - return (err); - err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags); VOPSTATS_UPDATE(tdvp, link); return (err); @@ -3499,8 +3494,6 @@ int flags, vsecattr_t *vsecp) /* ACL to set during create */ { - xvattr_t xvattr; - security_id_t secid; int ret; if (vsecp != NULL && @@ -3516,16 +3509,11 @@ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) return (EINVAL); - ret = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); - if (ret) - return (ret); - VOPXID_MAP_CR(dvp, cr); ret = (*(dvp)->v_op->vop_mkdir) (dvp, dirname, vap, vpp, cr, ct, flags, vsecp); if (ret == 0 && *vpp) { - fmac_vnode_post_create(*vpp, secid); VOPSTATS_UPDATE(*vpp, mkdir); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, dirname, @@ -4075,10 +4063,6 @@ return (EINVAL); } - err = fmac_vnode_setattr(vp, cr); - if (err) - return (err); - err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct); VOPSTATS_UPDATE(vp, setsecattr); return (err);
--- a/usr/src/uts/common/fs/xattr.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/xattr.c Wed Oct 29 11:52:47 2008 -0700 @@ -683,13 +683,13 @@ break; case F_SECCTX: if (!secctx || - strlen(secctx) >= sizeof (xoap->xoa_secctx)) { + strlen(secctx) >= sizeof (xoap->xoa_secctx)) { nvlist_free(nvp); return (EINVAL); } XVA_SET_REQ(&xvattr, XAT_SECCTX); (void) strncpy(xoap->xoa_secctx, secctx, - sizeof (xoap->xoa_secctx)); + sizeof (xoap->xoa_secctx)); break; default: break;
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c Wed Oct 29 11:52:47 2008 -0700 @@ -42,6 +42,7 @@ #include <sys/fs/zfs.h> #include <sys/mode.h> #include <sys/policy.h> +#include <sys/fmac/fmac.h> #include <sys/zfs_znode.h> #include <sys/zfs_fuid.h> #include <sys/zfs_acl.h> @@ -2353,11 +2354,8 @@ } if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, - &check_privs, skipaclchk, cr)) == 0) { - if (is_attr) - VN_RELE(ZTOV(xzp)); - return (0); - } + &check_privs, skipaclchk, cr)) == 0) + goto out; if (error && !check_privs) { if (is_attr) @@ -2424,6 +2422,11 @@ } } +out: + if (!error) + error = fmac_vnode_access(ZTOV(check_zp), mode, + flags|V_ACE_MASK, cr, B_TRUE); + if (is_attr) VN_RELE(ZTOV(xzp));
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c Wed Oct 29 11:52:47 2008 -0700 @@ -1159,6 +1159,8 @@ int error; zfs_acl_t *aclp = NULL; zfs_fuid_info_t *fuidp = NULL; + xvattr_t xvattr; + security_id_t secid; /* * If we have an ephemeral id, ACL, or XVATTR then @@ -1241,6 +1243,11 @@ goto out; } + error = fmac_vnode_create(dvp, name, &xvattr, &vap, cr, + &secid); + if (error) + goto out; + /* * We only support the creation of regular files in * extended attribute directories. @@ -1298,6 +1305,7 @@ if (fuidp) zfs_fuid_info_free(fuidp); dmu_tx_commit(tx); + fmac_vnode_post_create(ZTOV(zp), secid); } else { int aflags = (flag & FAPPEND) ? V_APPEND : 0; @@ -1610,6 +1618,8 @@ zfs_acl_t *aclp = NULL; zfs_fuid_info_t *fuidp = NULL; int zf = ZNEW; + xvattr_t xvattr; + security_id_t secid; ASSERT(vap->va_type == VDIR); @@ -1665,6 +1675,13 @@ return (error); } + error = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); + if (error) { + zfs_dirent_unlock(dl); + ZFS_EXIT(zfsvfs); + return (error); + } + if (vsecp && aclp == NULL) { error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, &aclp); if (error) { @@ -1734,6 +1751,8 @@ zfs_fuid_info_free(fuidp); dmu_tx_commit(tx); + fmac_vnode_post_create(ZTOV(zp), secid); + zfs_dirent_unlock(dl); ZFS_EXIT(zfsvfs); @@ -2499,6 +2518,13 @@ * First validate permissions */ + + err = fmac_vnode_setattr(vp, cr); + if (err) { + ZFS_EXIT(zfsvfs); + return (err); + } + if (mask & AT_SIZE) { err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr); if (err) { @@ -3455,6 +3481,12 @@ if (VOP_REALVP(svp, &realvp, ct) == 0) svp = realvp; + error = fmac_vnode_link(tdvp, svp, name, cr); + if (error) { + ZFS_EXIT(zfsvfs); + return (error); + } + if (svp->v_vfsp != tdvp->v_vfsp) { ZFS_EXIT(zfsvfs); return (EXDEV);
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c Wed Oct 29 11:52:47 2008 -0700 @@ -56,6 +56,7 @@ #include <sys/zfs_fuid.h> #include <sys/fs/zfs.h> #include <sys/kidmap.h> +#include <sys/fmac/fmac.h> #endif /* _KERNEL */ #include <sys/dmu.h> @@ -968,6 +969,7 @@ dmu_object_info_t doi; dmu_buf_t *db; znode_t *zp; + znode_phys_t *pzp; int err; *zpp = NULL; @@ -1016,6 +1018,13 @@ * Not found create new znode/vnode */ zp = zfs_znode_alloc(zfsvfs, db, doi.doi_data_block_size); + + /* + * Compute FMAC security identifier + */ + pzp = zp->z_phys; + if (ZTOV(zp)->v_type != VLNK && pzp->zp_flags & ZFS_BONUS_SECCTX) + fmac_vnode_init_secid(ZTOV(zp), (char *)(pzp + 1)); ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); *zpp = zp; return (0);
--- a/usr/src/uts/common/os/cpu.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/os/cpu.c Wed Oct 29 11:52:47 2008 -0700 @@ -2505,7 +2505,7 @@ * or hasprocperm() fails. */ if (tp->t_cid == 0 || !hasprocperm(tp->t_cred, CRED(), - PROCESS__SETSCHED)) { + PROCESS__SETSCHED)) { *error = EPERM; thread_unlock(tp); return (0);
--- a/usr/src/uts/common/os/exec.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/os/exec.c Wed Oct 29 11:52:47 2008 -0700 @@ -580,8 +580,8 @@ if (level == 0 && privflags != 0) { newcred = cred = crdup(cred); + cred->cr_prev_secid = prev_secid; if (setsecid) { - cred->cr_prev_secid = prev_secid; cred->cr_secid = secid; cred->cr_exec_secid = SECSID_NULL; } @@ -623,6 +623,9 @@ CR_EPRIV(cred) = CR_PPRIV(cred) = CR_IPRIV(cred); priv_adjust_PA(cred); } + } else if (level == 0 && cred->cr_prev_secid != prev_secid) { + newcred = cred = crdup(cred); + cred->cr_prev_secid = prev_secid; } /* SunOS 4.x buy-back */
--- a/usr/src/uts/common/os/klpd.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/os/klpd.c Wed Oct 29 11:52:47 2008 -0700 @@ -550,7 +550,7 @@ mutex_enter(&pidlock); p = prfind(pid); if (p == NULL || !prochasprocperm(p, curproc, CRED(), - PROCESS__PTRACE)) { + PROCESS__PTRACE)) { mutex_exit(&pidlock); klpd_rele(kpd); return (set_errno(p == NULL ? ESRCH : EPERM));
--- a/usr/src/uts/common/sys/fmac/avc.h Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/sys/fmac/avc.h Wed Oct 29 11:52:47 2008 -0700 @@ -45,32 +45,6 @@ #include <sys/fmac/av_permissions.h> #include <sys/fmac/security.h> -/* - * An entry in the AVC. - */ -typedef struct avc_entry { - security_id_t ssid; - security_id_t tsid; - security_class_t tclass; - struct av_decision avd; - int used; /* used recently */ -} avc_entry_t; - - -/* - * A reference to an AVC entry. - */ -typedef struct avc_entry_ref { - avc_entry_t *ae; -} avc_entry_ref_t; - -#define AVC_ENTRY_REF_NULL { NULL } - -/* Initialize an AVC entry reference before first use. */ -#define AVC_ENTRY_REF_INIT(h) { (h)->ae = NULL; } - -#define AVC_ENTRY_REF_CPY(dst, src) (dst)->ae = (src)->ae - struct vnode; typedef struct avc_audit_data { @@ -96,36 +70,6 @@ } /* - * AVC statistics - */ -#define AVC_ENTRY_LOOKUPS 0 -#define AVC_ENTRY_HITS 1 -#define AVC_ENTRY_MISSES 2 -#define AVC_ENTRY_DISCARDS 3 -#define AVC_CAV_LOOKUPS 4 -#define AVC_CAV_HITS 5 -#define AVC_CAV_PROBES 6 -#define AVC_CAV_MISSES 7 -#define AVC_NSTATS 8 -extern unsigned avc_cache_stats[AVC_NSTATS]; -void avc_dump_stats(char *tag); - -/* - * AVC display support - */ -void avc_dump_av( - security_class_t tclass, /* IN */ - access_vector_t av); /* IN */ - -void avc_dump_query( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass); /* IN */ - -void avc_dump_cache(char *tag); - - -/* * AVC operations */ @@ -133,84 +77,16 @@ void avc_init(void); /* - * Look up an AVC entry that is valid for the - * `requested' permissions between the SID pair - * (`ssid', `tsid'), interpreting the permissions - * based on `tclass'. If a valid AVC entry exists, - * then this function updates `aeref' to refer to the - * entry and returns 0. Otherwise, this function - * returns -ENOENT. + * Compute an entire access vector. */ -int avc_lookup( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t requested, /* IN */ - avc_entry_ref_t *aeref); /* OUT */ - -/* - * Insert an AVC entry for the SID pair - * (`ssid', `tsid') and class `tclass'. - * The access vectors and the sequence number are - * normally provided by the security server in - * response to a security_compute_av call. If the - * sequence number `ae->avd.seqno' is not less than the latest - * revocation notification, then the function copies - * the access vectors into a cache entry, updates - * `aeref' to refer to the entry, and returns 0. - * Otherwise, this function returns -EAGAIN. - */ -int avc_insert( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - struct avc_entry *ae, /* IN */ - avc_entry_ref_t *out_aeref); /* OUT */ - +extern int avc_compute_av(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct av_decision *avd); -/* Audit the checking of permissions */ -#define AVC_AUDITALLOW 0 -#define AVC_AUDITDENY 1 -void avc_audit( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t perms, /* IN */ - struct avc_entry *ae, /* IN */ - uint32_t denied, /* IN */ - avc_audit_data_t *auditdata); /* IN */ - -/* - * Check permissions using an AVC entry ref. - * - * If the ref is null or the underlying AVC entry has been invalidated - * or the underlying AVC entry does not contain all the requested - * decisions, then this code falls through to avc_lookup. In - * this case, the AVC entry ref will be updated appropriately. - */ -int avc_has_perm_ref_audit( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t requested, /* IN */ - avc_entry_ref_t *aeref, /* IN */ - avc_audit_data_t *auditdata); /* IN */ - -#define avc_has_perm_ref(ssid, tsid, tclass, requested, aeref) \ - avc_has_perm_ref_audit(ssid, tsid, tclass, requested, aeref, 0) - - -/* Check permissions */ -int -avc_has_perm_audit( - security_id_t ssid, /* IN */ - security_id_t tsid, /* IN */ - security_class_t tclass, /* IN */ - access_vector_t requested, /* IN */ - avc_audit_data_t *auditdata); /* IN */ - -#define avc_has_perm(ssid, tsid, tclass, requested) \ - avc_has_perm_audit(ssid, tsid, tclass, requested, 0) +/* Check requested permissions. */ +extern int avc_has_perm(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + avc_audit_data_t *auditdata); #define AVC_CALLBACK_GRANT 1 #define AVC_CALLBACK_TRY_REVOKE 2 @@ -240,6 +116,9 @@ security_class_t tclass, access_vector_t perms); +/* Dump cache contents. */ +extern void avc_dump_cache(char *tag); + #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/sys/fmac/fmac.h Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/sys/fmac/fmac.h Wed Oct 29 11:52:47 2008 -0700 @@ -86,13 +86,14 @@ void fmac_init(void); int fmac_load_policy(char *file); int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); +void fmac_vnode_init_secid(vnode_t *vp, char *secctx); int fmac_vfs_root(vfs_t *, vnode_t *); int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); +int fmac_vnode_get_secctx(vnode_t *vp, vattr_t *vap); int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, security_id_t *); void fmac_vnode_post_create(vnode_t *, security_id_t); -int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, - caller_context_t *ct); +int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr); int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr); int fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, cred_t *cr);
--- a/usr/src/uts/common/sys/vnode.h Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/sys/vnode.h Wed Oct 29 11:52:47 2008 -0700 @@ -1259,6 +1259,7 @@ * xva_getxoptattr() returns a ponter to the xoptattr_t section of xvattr_t */ void xva_init(xvattr_t *); +void xva_from_va(xvattr_t *, vattr_t *); xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */ void xattr_init(void); /* Initialize vnodeops for xattrs */
--- a/usr/src/uts/common/syscall/corectl.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/syscall/corectl.c Wed Oct 29 11:52:47 2008 -0700 @@ -287,7 +287,7 @@ mutex_exit(&pidlock); mutex_enter(&p->p_crlock); if (!hasprocperm(p->p_cred, CRED(), - PROCESS__GETCORE)) + PROCESS__GETCORE)) error = EPERM; else if (p->p_corefile != NULL) rp = corectl_path_value(p->p_corefile); @@ -437,7 +437,7 @@ mutex_enter(&p->p_crlock); if (!(p->p_flag & SSYS) && hasprocperm(p->p_cred, CRED(), - PROCESS__SETCORE)) { + PROCESS__SETCORE)) { mutex_exit(&p->p_crlock); counterp->cc_count++; if (counterp->cc_path != NULL) {
--- a/usr/src/uts/common/syscall/fmacsys.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/syscall/fmacsys.c Wed Oct 29 11:52:47 2008 -0700 @@ -59,7 +59,7 @@ return (set_errno(EINVAL)); if (err = avc_has_perm(crgetsecid(CRED()), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__SETENFORCE)) + SECCLASS_SECURITY, SECURITY__SETENFORCE, NULL)) return (set_errno(err)); switch (mode) { @@ -92,7 +92,7 @@ return (set_errno(EINVAL)); if (err = avc_has_perm(crgetsecid(CRED()), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__LOAD_POLICY)) + SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL)) return (set_errno(err)); kpath = kmem_alloc(MAXPATHLEN, KM_SLEEP); @@ -136,7 +136,7 @@ int err; if (err = avc_has_perm(crgetsecid(CRED()), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__COMPUTE_AV)) + SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL)) return (set_errno(err)); kscontext = kmem_alloc(FMAC_MAX_CONTEXT_LEN, KM_SLEEP); @@ -183,7 +183,7 @@ int err; if (err = avc_has_perm(crgetsecid(CRED()), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT)) + SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL)) return (set_errno(err)); kscontext = kmem_alloc(FMAC_MAX_CONTEXT_LEN, KM_SLEEP); @@ -227,7 +227,7 @@ } if (err = avc_has_perm(crgetsecid(CRED()), sid, SECCLASS_PROCESS, - PROCESS__GETATTR)) + PROCESS__GETATTR, NULL)) return (set_errno(err)); if ((err = security_sid_to_context(sid, &pcontext, @@ -285,7 +285,7 @@ int err; if (err = avc_has_perm(crgetsecid(CRED()), crgetsecid(CRED()), - SECCLASS_PROCESS, PROCESS__SETEXEC)) + SECCLASS_PROCESS, PROCESS__SETEXEC, NULL)) return (set_errno(err)); if (scontext == 0) {
--- a/usr/src/uts/common/syscall/lgrpsys.c Wed Oct 29 08:20:16 2008 -0700 +++ b/usr/src/uts/common/syscall/lgrpsys.c Wed Oct 29 11:52:47 2008 -0700 @@ -345,7 +345,7 @@ * affinity for LWP */ if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED(), - PROCESS__SETSCHED)) { + PROCESS__SETSCHED)) { thread_unlock(t); return (set_errno(EPERM)); } @@ -588,7 +588,7 @@ * thread */ if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED(), - PROCESS__SETSCHED)) { + PROCESS__SETSCHED)) { thread_unlock(t); return (set_errno(EPERM)); } @@ -960,7 +960,7 @@ * thread */ if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED(), - PROCESS__SETSCHED)) { + PROCESS__SETSCHED)) { thread_unlock(t); return (set_errno(EPERM)); }