From sds at tycho.nsa.gov Wed Oct 1 06:08:01 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 01 Oct 2008 09:08:01 -0400 Subject: [fmac-discuss] FMAC and sockets? In-Reply-To: <48E2AA47.1060502@sun.com> References: <48DBDE88.5060104@sun.com> <1222780321.19676.50.camel@moss-spartans.epoch.ncsc.mil> <48E2AA47.1060502@sun.com> Message-ID: <1222866481.29743.19.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-09-30 at 15:37 -0700, Erik Nordmark wrote: > Stephen Smalley wrote: > > > In modern SELinux, the socket-related API extensions are: > > 1) A setsockcreatecon() interface for specifying the security context to > > apply to new sockets on subsequent socket(2) calls by the process. This > > is only when the application needs to specify a context other than the > > default one that would be applied by the policy, and is limited to > > security-aware applications with appropriate permissions. > > Does that apply to sockets created by accept() as well as by connect()? The security context of a new connection socket is computed from a combination of the listening socket's security context (which may have been labeled via setsockcreatecon) and the peer's security context. > > 2) A SO_PEERSEC socket option for getsockopt(2) in order to get the > > security context of a connected peer. > > > > 3) A SO_PASSEC socket option and SCM_SECURITY control message in order > > to get the security context of a datagram. > > OK. > > > Fanout of inbound packets/connections based on security context would be > > nice to support, but we don't presently support that in SELinux, so it > > isn't necessary up front. Also, it wouldn't necessarily be on a > > one-to-one basis; we would likely map a given set of security contexts > > to a given destination context. > > > > Long term I think it would make sense to replace ts_label_t with a > > security context that includes the MLS label as a component, but not in > > the initial version. > > Makes sense. Do you think this means that cr_label would be replaced by > a reference from the cred to the security context, or will be security > context be more dynamic than the current cred_t? Putting it in the cred is fine; in the current fmac-gate, there is a separate cr_secid (security identifier, handle to a security context) field added to the cred structure. This could ultimately obsolete the cr_label. > FWIW I?m looking at refactoring the TCP/IP fanout to explicitly use > ts_label_t (instead of the label in the cred) but that could easily > change to some other explicit thing down the road. Ok, great. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Oct 1 06:18:46 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 01 Oct 2008 09:18:46 -0400 Subject: [fmac-discuss] [PATCH] Set user's security context in pam_unix_cred.so.1 In-Reply-To: <48E2830C.5030103@sun.com> References: <48D3D59F.5020107@sun.com> <1221852804.25857.93.camel@moss-spartans.epoch.ncsc.mil> <48D428AB.3090303@sun.com> <48D5753D.3050309@sun.com> <48D91098.2000606@sun.com> <48DAC5B5.40507@sun.com> <48DB1BF7.3020203@sun.com> <1222778743.19676.25.camel@moss-spartans.epoch.ncsc.mil> <48E2830C.5030103@sun.com> Message-ID: <1222867126.29743.32.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-09-30 at 12:50 -0700, Glenn Faden wrote: > Stephen Smalley wrote: > > > > For the benefit of those who are following along on the list, I wanted > > to summarize the key design decisions from a face-to-face meeting held > > with the Solaris security team last week when I was in Santa Clara to > > give presentations on OpenSolaris FMAC. Feel free to correct or clarify > > as needed. The key decisions were: > > > > - FMAC will support granting of privileges via exec-time computation of > > the authorized privilege set based on the subject security context, and > > will support restricting the set of objects on which a subject can act > > via access-time permission checks based on both the subject security > > context and the object security context. This should eliminate the need > > for the separate FGAP mechanism since it will address both granting of > > privileges and object-based checks. Privilege granting is kept at > > exec-time in order to apply the usual safeguards when privileges are > > elevated to prevent the caller from influencing/controlling the more > > privileged subject. > > > > - Solaris RBAC will be integrated with FMAC by mapping role uids to FMAC > > roles, and by changing both the role uid and the role in the FMAC > > security context upon role changes by su or newrole. Changing to a > > non-role uid via su will not affect the FMAC security context. Separate > > Unix uids will continue to be used for roles in Solaris in order to > > easily support per-role environment settings and preferences. > > > > - Solaris authorizations will be integrated with FMAC by replacing the > > existing authorizing checking calls/logic with calls to the FMAC > > interfaces for performing permission checks, and by defining Flask > > classes and permissions for the existing set of Solaris authorizations. > > > > - Support will be provided for converting the existing *attr config > > files and manifests to equivalent FMAC policy. FMAC could also possibly > > export a pseudo filesystem interface that would present the conventional > > *attr config file format to legacy userspace. > > > > - A design goal will be to have FMAC always enabled (i.e. no disabled > > mode at all), with an initial default policy that at a minimum emulates > > the existing Solaris RBAC, privilege, and authorization configurations. > > > > > Stephen, > > Thanks for writing up this summary. I think your summary accurately > reflects what we agreed on, but I wanted clarify a few points. > > The existing authorization interface, chkauthattr(3SECDB), needs to be > preserved for compatibility reasons. While it may be possible to > reimplement this function to rely on the FMAC-defined policy, I suspect > we will need a new function for this purpose which passes additional > parameters, like the security context (or sid) of the subject, along > with that of the object. This implies some kind of transition strategy > for existing authorization-aware applications. Ok, that makes sense. > While we plan to express existing privilege specifications currently in > exec_attr and SMF manifests in the FMAC policy, we will need a similar > transition which allows such privilege specifications to be interpreted > by legacy code. For example, the pfexec program should be preserved to > interpret the legacy exec_attr file. > > Some security-relevant user and role attributes will not be represented > in the FMAC policy, so we will need to preserve the *_attr files and > schemas, for backward compatibility and for LDAP-based administration. > This area needs further research. Ok. As noted, we may be able to present a pseudo file interface from FMAC that provides the *_attr file format to userland from the internal policy representation. -- Stephen Smalley National Security Agency From Darren.Moffat at Sun.COM Wed Oct 1 06:43:54 2008 From: Darren.Moffat at Sun.COM (Darren J Moffat) Date: Wed, 01 Oct 2008 14:43:54 +0100 Subject: [fmac-discuss] [PATCH] Set user's security context in pam_unix_cred.so.1 In-Reply-To: <1222867126.29743.32.camel@moss-spartans.epoch.ncsc.mil> References: <48D3D59F.5020107@sun.com> <1221852804.25857.93.camel@moss-spartans.epoch.ncsc.mil> <48D428AB.3090303@sun.com> <48D5753D.3050309@sun.com> <48D91098.2000606@sun.com> <48DAC5B5.40507@sun.com> <48DB1BF7.3020203@sun.com> <1222778743.19676.25.camel@moss-spartans.epoch.ncsc.mil> <48E2830C.5030103@sun.com> <1222867126.29743.32.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48E37E9A.8090506@Sun.COM> Stephen Smalley wrote: >> Some security-relevant user and role attributes will not be represented >> in the FMAC policy, so we will need to preserve the *_attr files and >> schemas, for backward compatibility and for LDAP-based administration. >> This area needs further research. > > Ok. As noted, we may be able to present a pseudo file interface from > FMAC that provides the *_attr file format to userland from the internal > policy representation. That doesn't help with centralizing the policy in LDAP though (in fact it is NIS and NIS+ too but those are less important). -- Darren J Moffat From sds at tycho.nsa.gov Wed Oct 1 07:28:49 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 01 Oct 2008 10:28:49 -0400 Subject: [fmac-discuss] [PATCH] Set user's security context in pam_unix_cred.so.1 In-Reply-To: <48E37E9A.8090506@Sun.COM> References: <48D3D59F.5020107@sun.com> <1221852804.25857.93.camel@moss-spartans.epoch.ncsc.mil> <48D428AB.3090303@sun.com> <48D5753D.3050309@sun.com> <48D91098.2000606@sun.com> <48DAC5B5.40507@sun.com> <48DB1BF7.3020203@sun.com> <1222778743.19676.25.camel@moss-spartans.epoch.ncsc.mil> <48E2830C.5030103@sun.com> <1222867126.29743.32.camel@moss-spartans.epoch.ncsc.mil> <48E37E9A.8090506@Sun.COM> Message-ID: <1222871329.29743.40.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-10-01 at 14:43 +0100, Darren J Moffat wrote: > Stephen Smalley wrote: > >> Some security-relevant user and role attributes will not be represented > >> in the FMAC policy, so we will need to preserve the *_attr files and > >> schemas, for backward compatibility and for LDAP-based administration. > >> This area needs further research. > > > > Ok. As noted, we may be able to present a pseudo file interface from > > FMAC that provides the *_attr file format to userland from the internal > > policy representation. > > That doesn't help with centralizing the policy in LDAP though (in fact > it is NIS and NIS+ too but those are less important). As long as you can have a userland agent on the individual systems that pulls policy info from LDAP, converts it as needed and pushes the resulting policy into the kernel, it doesn't seem like a major problem. As to whether or not that is actually safe is of course another matter... -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Wed Oct 1 09:17:09 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Wed, 01 Oct 2008 09:17:09 -0700 Subject: [fmac-discuss] [PATCH] Set user's security context in pam_unix_cred.so.1 In-Reply-To: <48E37E9A.8090506@Sun.COM> References: <48D3D59F.5020107@sun.com> <1221852804.25857.93.camel@moss-spartans.epoch.ncsc.mil> <48D428AB.3090303@sun.com> <48D5753D.3050309@sun.com> <48D91098.2000606@sun.com> <48DAC5B5.40507@sun.com> <48DB1BF7.3020203@sun.com> <1222778743.19676.25.camel@moss-spartans.epoch.ncsc.mil> <48E2830C.5030103@sun.com> <1222867126.29743.32.camel@moss-spartans.epoch.ncsc.mil> <48E37E9A.8090506@Sun.COM> Message-ID: <48E3A285.80502@sun.com> Darren J Moffat wrote: > Stephen Smalley wrote: >>> Some security-relevant user and role attributes will not be >>> represented in the FMAC policy, so we will need to preserve the >>> *_attr files and schemas, for backward compatibility and for >>> LDAP-based administration. This area needs further research. >> >> Ok. As noted, we may be able to present a pseudo file interface from >> FMAC that provides the *_attr file format to userland from the internal >> policy representation. > > That doesn't help with centralizing the policy in LDAP though (in fact > it is NIS and NIS+ too but those are less important). Unlike the current *_attr databases, the full FMAC policy doesn't need to be exposed via LDAP queries, since it is only interpreted by the security server in the kernel. As Stephen said, aspects of the policy that are needed by userland components can be made available via a pseudo filesystem. These would be read-only queries, similar to /proc or mnttab. Two examples are presenting a list of roles from which the user may select, or choosing a more restrictive clearance at login. We have been discussing in another thread whether the various keywords in user_attr should also be supported in prof_attr, too. The rationale is to factor out all the common settings for users into profiles. Today in Solaris, it is possible to configure in nsswitch so that the prof_attr declarations come from the local policy, while the user_attr declarations can come from LDAP. I think this is closer to the model we need for FMAC. For scalability (thousands of users) we need to store per-user attributes in LDAP. Most of the settings currently stored in the prof_attr and exec_attr should be expressed in the FMAC policy, instead of representing them in LDAP. --Glenn From Darren.Moffat at Sun.COM Wed Oct 1 09:19:06 2008 From: Darren.Moffat at Sun.COM (Darren J Moffat) Date: Wed, 01 Oct 2008 17:19:06 +0100 Subject: [fmac-discuss] [PATCH] Set user's security context in pam_unix_cred.so.1 In-Reply-To: <48E3A285.80502@sun.com> References: <48D3D59F.5020107@sun.com> <1221852804.25857.93.camel@moss-spartans.epoch.ncsc.mil> <48D428AB.3090303@sun.com> <48D5753D.3050309@sun.com> <48D91098.2000606@sun.com> <48DAC5B5.40507@sun.com> <48DB1BF7.3020203@sun.com> <1222778743.19676.25.camel@moss-spartans.epoch.ncsc.mil> <48E2830C.5030103@sun.com> <1222867126.29743.32.camel@moss-spartans.epoch.ncsc.mil> <48E37E9A.8090506@Sun.COM> <48E3A285.80502@sun.com> Message-ID: <48E3A2FA.3060906@Sun.COM> Glenn Faden wrote: > We have been discussing in another thread whether the various keywords > in user_attr should also be supported in prof_attr, too. The rationale > is to factor out all the common settings for users into profiles. Today > in Solaris, it is possible to configure in nsswitch so that the > prof_attr declarations come from the local policy, while the user_attr > declarations can come from LDAP. I think this is closer to the model we > need for FMAC. For scalability (thousands of users) we need to store > per-user attributes in LDAP. Most of the settings currently stored in > the prof_attr and exec_attr should be expressed in the FMAC policy, > instead of representing them in LDAP. We need prof_attr and auth_attr (or there new FMAC equivalents) in LDAP too though. -- Darren J Moffat From sds at tycho.nsa.gov Thu Oct 2 06:19:40 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 02 Oct 2008 09:19:40 -0400 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open Message-ID: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> Move the FMAC fmac_vnode_create() and post_create() hooks from fop_create() into zfs_create() so that they are only applied on new file creation not opening of an existing file, and call the fmac_vnode_access() hook from zfs_create() to mediate opening an existing file. Similar hooking will be needed for other filesystem types like tmpfs as well. Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() for consistency with create although we don't have the same problem there with distinguishing create from open. Given the current need to place several of the hooks (create, unlink/rmdir, rename) in the filesystem code, I'm inclined to move the remaining FMAC vnode hooks in the fop layer into the filesystem code (like the existing DAC checking and secpolicy hooks) rather than having a mixture of some FMAC hooks in the fop_ layer and some in the filesystem code. This patch is less invasive than the prior one, placing the FMAC hooks entirely within the zfs vnode ops rather than pushing fmac_vnode_post_create() down to zfs_perm_init(). The wrapping of the vattr with an xvattr is pulled out of fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) now to make it clearer and less prone to bugs. A xva_from_va() helper function is introduced for populating an xvattr from vattr. Webrev is available at: http://cr.opensolaris.org/~sds/create/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -253,13 +253,14 @@ } int -fmac_vnode_create(vnode_t *dvp, char *name, xvattr_t *xvap, vattr_t **vapp, - cred_t *cr, security_id_t *secidp) +fmac_vnode_create(vnode_t *dvp, char *name, vattr_t *vap, cred_t *cr, + security_id_t *secidp) { security_id_t cr_secid, secid; security_class_t sclass; security_context_t scontext; uint32_t scontext_len; + xvattr_t *xvap = (xvattr_t *)vap; xoptattr_t *xoap; int error; avc_audit_data_t ad; @@ -277,7 +278,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); @@ -301,13 +302,7 @@ 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 */ + ASSERT(vap->va_mask & AT_XVATTR); XVA_SET_REQ(xvap, XAT_SECCTX); error = security_sid_to_context(secid, &scontext, &scontext_len); @@ -322,12 +317,6 @@ goto inval; (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_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); diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -378,6 +378,18 @@ xvap->xva_magic = XVA_MAGIC; xvap->xva_vattr.va_mask = AT_XVATTR; xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0]; +} + +/* + * 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; } /* @@ -3367,8 +3379,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) { @@ -3382,17 +3392,12 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && 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)); @@ -3499,8 +3504,6 @@ int flags, vsecattr_t *vsecp) /* ACL to set during create */ { - xvattr_t xvattr; - security_id_t secid; int ret; if (vsecp != NULL && @@ -3515,17 +3518,12 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && 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, diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -1159,6 +1159,13 @@ int error; zfs_acl_t *aclp = NULL; zfs_fuid_info_t *fuidp = NULL; + xvattr_t xvattr; + security_id_t secid; + + if (!(vap->va_mask & AT_XVATTR)) { + xva_from_va(&xvattr, vap); + vap = &xvattr.xva_vattr; + } /* * If we have an ephemeral id, ACL, or XVATTR then @@ -1240,6 +1247,10 @@ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { goto out; } + + error = fmac_vnode_create(dvp, name, vap, cr, &secid); + if (error) + goto out; /* * We only support the creation of regular files in @@ -1298,6 +1309,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; @@ -1324,6 +1336,10 @@ if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) { goto out; } + + error = fmac_vnode_access(ZTOV(zp), mode, aflags, cr, B_TRUE); + if (error) + goto out; mutex_enter(&dzp->z_lock); dzp->z_seq++; @@ -1610,6 +1626,13 @@ zfs_acl_t *aclp = NULL; zfs_fuid_info_t *fuidp = NULL; int zf = ZNEW; + xvattr_t xvattr; + security_id_t secid; + + if (!(vap->va_mask & AT_XVATTR)) { + xva_from_va(&xvattr, vap); + vap = &xvattr.xva_vattr; + } ASSERT(vap->va_type == VDIR); @@ -1660,6 +1683,13 @@ } if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) { + zfs_dirent_unlock(dl); + ZFS_EXIT(zfsvfs); + return (error); + } + + error = fmac_vnode_create(dvp, dirname, vap, cr, &secid); + if (error) { zfs_dirent_unlock(dl); ZFS_EXIT(zfsvfs); return (error); @@ -1733,6 +1763,8 @@ if (fuidp) zfs_fuid_info_free(fuidp); dmu_tx_commit(tx); + + fmac_vnode_post_create(ZTOV(zp), secid); zfs_dirent_unlock(dl); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -88,8 +88,7 @@ int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); int fmac_vfs_root(vfs_t *, vnode_t *); int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); -int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, - security_id_t *); +int fmac_vnode_create(vnode_t *, char *, 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); diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -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 */ -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Oct 2 06:42:24 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 02 Oct 2008 09:42:24 -0400 Subject: [fmac-discuss] fmac_vnode_access handling of ACE_ permissions? Message-ID: <1222954944.6528.39.camel@moss-spartans.epoch.ncsc.mil> The fmac_vnode_access() hook, presently called from fop_access(), only understands the traditional VREAD/VWRITE/VEXEC modes and the V_APPEND flag presently. However, in looking at zfs_access(), I see that it interprets the mode differently depending on whether V_ACE_MASK is set in the flags. Thus I assume I need to alter fmac_vnode_access() to likewise check for V_ACE_MASK and, if set, interpret the mode in terms of the ACE_ permissions rather than the V* permissions, mapping the ACE_ permissions to corresponding FMAC permissions. Looks like the ACE_ permissions are used by nfs, smbsrv, and zfs. For reference, the fmac_vnode_access() hook was originally introduced by this patch: http://mail.opensolaris.org/pipermail/fmac-discuss/2008-September/000230.html and was part of this webrev (for all 5 patches in that series): http://cr.opensolaris.org/~sds/vnode/ -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 2 09:04:01 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 02 Oct 2008 10:04:01 -0600 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open In-Reply-To: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> References: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48E4F0F1.5010304@Sun.COM> Stephen Smalley wrote: > Move the FMAC fmac_vnode_create() and post_create() hooks from > fop_create() into zfs_create() so that they are only applied on new file > creation not opening of an existing file, and call the > fmac_vnode_access() hook from zfs_create() to mediate opening an > existing file. Similar hooking will be needed for other filesystem > types like tmpfs as well. > > Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > for consistency with create although we don't have the same problem > there with distinguishing create from open. Given the current need to > place several of the hooks (create, unlink/rmdir, rename) in the > filesystem code, I'm inclined to move the remaining FMAC vnode hooks in > the fop layer into the filesystem code (like the existing DAC checking > and secpolicy hooks) rather than having a mixture of some FMAC hooks in > the fop_ layer and some in the filesystem code. > Even if fop_create() new that the file already existed or not doesn't really help. It could have been removed/added by the time the actual file system xxx_create() function was called. I don't suppose it would be possible at some point in the future to merge the secpolicy and fmac calls together? > This patch is less invasive than the prior one, placing the FMAC hooks > entirely within the zfs vnode ops rather than pushing > fmac_vnode_post_create() down to zfs_perm_init(). > > The wrapping of the vattr with an xvattr is pulled out of > fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) > now to make it clearer and less prone to bugs. A xva_from_va() helper > function is introduced for populating an xvattr from vattr. > I don't like converting every vattr_t that comes into zfs_create/zfs_mkdir into an xvattr. That should only be done when necessary and is probably still best done in fmac_vnode_create(). I think I've asked this before, but why isn't fmac_vnode_access() not in zfs_zaccess()? > Webrev is available at: http://cr.opensolaris.org/~sds/create/ From sds at tycho.nsa.gov Thu Oct 2 10:06:27 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 02 Oct 2008 13:06:27 -0400 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open In-Reply-To: <48E4F0F1.5010304@Sun.COM> References: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> <48E4F0F1.5010304@Sun.COM> Message-ID: <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-02 at 10:04 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Move the FMAC fmac_vnode_create() and post_create() hooks from > > fop_create() into zfs_create() so that they are only applied on new file > > creation not opening of an existing file, and call the > > fmac_vnode_access() hook from zfs_create() to mediate opening an > > existing file. Similar hooking will be needed for other filesystem > > types like tmpfs as well. > > > > Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > > for consistency with create although we don't have the same problem > > there with distinguishing create from open. Given the current need to > > place several of the hooks (create, unlink/rmdir, rename) in the > > filesystem code, I'm inclined to move the remaining FMAC vnode hooks in > > the fop layer into the filesystem code (like the existing DAC checking > > and secpolicy hooks) rather than having a mixture of some FMAC hooks in > > the fop_ layer and some in the filesystem code. > > > > Even if fop_create() new that the file already existed or not doesn't > really help. It could have been removed/added by the time the actual > file system xxx_create() function was called. Linux VFS performs the lookup first (open with create intent), and only invokes the create code path if the lookup fails. I understand though that Solaris is different at present. > I don't suppose it would be possible at some point in the future to > merge the secpolicy and fmac calls together? Possibly, but not trivially. The secpolicy hooks are currently only invoked if the base DAC checks fail, so the callers would have to be changed to always invoke them (passing in the DAC decision as an argument), and then the secpolicy functions would have to be changed to first apply the FMAC logic, then only perform the existing secpolicy privilege tests if DAC failed. Also, the secpolicy hook interface would have to be mappable to the FMAC checks; one secpolicy hook per vnode operation would be best for our purposes, whereas today there are multiple secpolicy hooks called at different points under different conditions on a given operation's code path. > > This patch is less invasive than the prior one, placing the FMAC hooks > > entirely within the zfs vnode ops rather than pushing > > fmac_vnode_post_create() down to zfs_perm_init(). > > > > The wrapping of the vattr with an xvattr is pulled out of > > fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) > > now to make it clearer and less prone to bugs. A xva_from_va() helper > > function is introduced for populating an xvattr from vattr. > > > > I don't like converting every vattr_t that comes into > zfs_create/zfs_mkdir into an xvattr. That should only be done when > necessary and is probably still best done in fmac_vnode_create(). For FMAC, we need to assign a secctx to every file, so we do need this on every vattr that comes into zfs_create/mkdir (and ultimately the other file creation operations) if we are using xvattrs as the mechanism for conveying the secctx. I can however move the logic back into fmac_vnode_create() if desired. I moved it up into the caller so that it would be clear that the vap is being switched to refer to an xvattr declared/allocated in the caller vs. hiding that down inside of the fmac code. > I think I've asked this before, but why isn't fmac_vnode_access() not in > zfs_zaccess()? Originally I had hoped to keep things in the fop layer, so I put it in fop_access(). Given the trend toward moving hooks into the filesystem code, taking it down into zfs_access() or all the way down into zfs_zaccess() becomes a possibility. Taking it all the way down into zfs_zaccess() however seems problematic because we don't always want to apply the same FMAC permission check in every case where ZFS applies the same zfs_zaccess* check (e.g. consider the rename case), and we have additional checks that have no parallel in ZFS at all. On the other side of it, I see that zfs_zaccess() deals with ensuring that checks on attributes are redirected to the base file, which we would presumably also want to do. I suppose one option would be to align the FMAC permission checks as much as possible with the ZFS access checks. That would simplify the integration into ZFS but make compatibility with SELinux in policy more problematic. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Oct 2 10:14:25 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 02 Oct 2008 13:14:25 -0400 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open In-Reply-To: <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> References: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> <48E4F0F1.5010304@Sun.COM> <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <1222967665.6528.90.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-02 at 13:06 -0400, Stephen Smalley wrote: > On Thu, 2008-10-02 at 10:04 -0600, Mark Shellenbaum wrote: > > Stephen Smalley wrote: > > > Move the FMAC fmac_vnode_create() and post_create() hooks from > > > fop_create() into zfs_create() so that they are only applied on new file > > > creation not opening of an existing file, and call the > > > fmac_vnode_access() hook from zfs_create() to mediate opening an > > > existing file. Similar hooking will be needed for other filesystem > > > types like tmpfs as well. > > > > > > Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > > > for consistency with create although we don't have the same problem > > > there with distinguishing create from open. Given the current need to > > > place several of the hooks (create, unlink/rmdir, rename) in the > > > filesystem code, I'm inclined to move the remaining FMAC vnode hooks in > > > the fop layer into the filesystem code (like the existing DAC checking > > > and secpolicy hooks) rather than having a mixture of some FMAC hooks in > > > the fop_ layer and some in the filesystem code. > > > > > > > Even if fop_create() new that the file already existed or not doesn't > > really help. It could have been removed/added by the time the actual > > file system xxx_create() function was called. > > Linux VFS performs the lookup first (open with create intent), and only > invokes the create code path if the lookup fails. I understand though > that Solaris is different at present. > > > I don't suppose it would be possible at some point in the future to > > merge the secpolicy and fmac calls together? > > Possibly, but not trivially. The secpolicy hooks are currently only > invoked if the base DAC checks fail, so the callers would have to be > changed to always invoke them (passing in the DAC decision as an > argument), and then the secpolicy functions would have to be changed to > first apply the FMAC logic, then only perform the existing secpolicy > privilege tests if DAC failed. Also, the secpolicy hook interface would > have to be mappable to the FMAC checks; one secpolicy hook per vnode > operation would be best for our purposes, whereas today there are > multiple secpolicy hooks called at different points under different > conditions on a given operation's code path. > > > > This patch is less invasive than the prior one, placing the FMAC hooks > > > entirely within the zfs vnode ops rather than pushing > > > fmac_vnode_post_create() down to zfs_perm_init(). > > > > > > The wrapping of the vattr with an xvattr is pulled out of > > > fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) > > > now to make it clearer and less prone to bugs. A xva_from_va() helper > > > function is introduced for populating an xvattr from vattr. > > > > > > > I don't like converting every vattr_t that comes into > > zfs_create/zfs_mkdir into an xvattr. That should only be done when > > necessary and is probably still best done in fmac_vnode_create(). > > For FMAC, we need to assign a secctx to every file, so we do need this > on every vattr that comes into zfs_create/mkdir (and ultimately the > other file creation operations) if we are using xvattrs as the mechanism > for conveying the secctx. I can however move the logic back into > fmac_vnode_create() if desired. I moved it up into the caller so that > it would be clear that the vap is being switched to refer to an xvattr > declared/allocated in the caller vs. hiding that down inside of the fmac > code. > > > I think I've asked this before, but why isn't fmac_vnode_access() not in > > zfs_zaccess()? > > Originally I had hoped to keep things in the fop layer, so I put it in > fop_access(). Given the trend toward moving hooks into the filesystem > code, taking it down into zfs_access() or all the way down into > zfs_zaccess() becomes a possibility. Taking it all the way down into > zfs_zaccess() however seems problematic because we don't always want to > apply the same FMAC permission check in every case where ZFS applies the > same zfs_zaccess* check (e.g. consider the rename case), and we have > additional checks that have no parallel in ZFS at all. > > On the other side of it, I see that zfs_zaccess() deals with ensuring > that checks on attributes are redirected to the base file, which we > would presumably also want to do. > > I suppose one option would be to align the FMAC permission checks as > much as possible with the ZFS access checks. That would simplify the > integration into ZFS but make compatibility with SELinux in policy more > problematic. Also, I'm not sure what that would mean for non-ZFS filesystems where we also want to apply FMAC permission checking, like tmpfs. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 2 10:16:43 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 02 Oct 2008 11:16:43 -0600 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open In-Reply-To: <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> References: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> <48E4F0F1.5010304@Sun.COM> <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48E501FB.2010709@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-02 at 10:04 -0600, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> Move the FMAC fmac_vnode_create() and post_create() hooks from >>> fop_create() into zfs_create() so that they are only applied on new file >>> creation not opening of an existing file, and call the >>> fmac_vnode_access() hook from zfs_create() to mediate opening an >>> existing file. Similar hooking will be needed for other filesystem >>> types like tmpfs as well. >>> >>> Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() >>> for consistency with create although we don't have the same problem >>> there with distinguishing create from open. Given the current need to >>> place several of the hooks (create, unlink/rmdir, rename) in the >>> filesystem code, I'm inclined to move the remaining FMAC vnode hooks in >>> the fop layer into the filesystem code (like the existing DAC checking >>> and secpolicy hooks) rather than having a mixture of some FMAC hooks in >>> the fop_ layer and some in the filesystem code. >>> >> Even if fop_create() new that the file already existed or not doesn't >> really help. It could have been removed/added by the time the actual >> file system xxx_create() function was called. > > Linux VFS performs the lookup first (open with create intent), and only > invokes the create code path if the lookup fails. I understand though > that Solaris is different at present. > Does Linux then have the ability to stop deletion/additions to directories at their VFS layer? Is their some coarse VFS level lock they apply? >> I don't suppose it would be possible at some point in the future to >> merge the secpolicy and fmac calls together? > > Possibly, but not trivially. The secpolicy hooks are currently only > invoked if the base DAC checks fail, so the callers would have to be > changed to always invoke them (passing in the DAC decision as an > argument), and then the secpolicy functions would have to be changed to > first apply the FMAC logic, then only perform the existing secpolicy > privilege tests if DAC failed. Also, the secpolicy hook interface would > have to be mappable to the FMAC checks; one secpolicy hook per vnode > operation would be best for our purposes, whereas today there are > multiple secpolicy hooks called at different points under different > conditions on a given operation's code path. > >>> This patch is less invasive than the prior one, placing the FMAC hooks >>> entirely within the zfs vnode ops rather than pushing >>> fmac_vnode_post_create() down to zfs_perm_init(). >>> >>> The wrapping of the vattr with an xvattr is pulled out of >>> fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) >>> now to make it clearer and less prone to bugs. A xva_from_va() helper >>> function is introduced for populating an xvattr from vattr. >>> >> I don't like converting every vattr_t that comes into >> zfs_create/zfs_mkdir into an xvattr. That should only be done when >> necessary and is probably still best done in fmac_vnode_create(). > > For FMAC, we need to assign a secctx to every file, so we do need this > on every vattr that comes into zfs_create/mkdir (and ultimately the > other file creation operations) if we are using xvattrs as the mechanism > for conveying the secctx. I can however move the logic back into > fmac_vnode_create() if desired. I moved it up into the caller so that > it would be clear that the vap is being switched to refer to an xvattr > declared/allocated in the caller vs. hiding that down inside of the fmac > code. > I'm concerned about the cost of doing the memory copies when fmac isn't enabled. Its going to slow down the create code path in ZFS. Another alternative would be do do the xvattr allocation in fop_create(), but only when fmac is enabled. -Mark From sds at tycho.nsa.gov Thu Oct 2 10:36:10 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 02 Oct 2008 13:36:10 -0400 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open In-Reply-To: <48E501FB.2010709@Sun.COM> References: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> <48E4F0F1.5010304@Sun.COM> <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> <48E501FB.2010709@Sun.COM> Message-ID: <1222968970.6528.103.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-02 at 11:16 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Thu, 2008-10-02 at 10:04 -0600, Mark Shellenbaum wrote: > >> Stephen Smalley wrote: > >>> Move the FMAC fmac_vnode_create() and post_create() hooks from > >>> fop_create() into zfs_create() so that they are only applied on new file > >>> creation not opening of an existing file, and call the > >>> fmac_vnode_access() hook from zfs_create() to mediate opening an > >>> existing file. Similar hooking will be needed for other filesystem > >>> types like tmpfs as well. > >>> > >>> Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > >>> for consistency with create although we don't have the same problem > >>> there with distinguishing create from open. Given the current need to > >>> place several of the hooks (create, unlink/rmdir, rename) in the > >>> filesystem code, I'm inclined to move the remaining FMAC vnode hooks in > >>> the fop layer into the filesystem code (like the existing DAC checking > >>> and secpolicy hooks) rather than having a mixture of some FMAC hooks in > >>> the fop_ layer and some in the filesystem code. > >>> > >> Even if fop_create() new that the file already existed or not doesn't > >> really help. It could have been removed/added by the time the actual > >> file system xxx_create() function was called. > > > > Linux VFS performs the lookup first (open with create intent), and only > > invokes the create code path if the lookup fails. I understand though > > that Solaris is different at present. > > > > Does Linux then have the ability to stop deletion/additions to > directories at their VFS layer? Is their some coarse VFS level lock > they apply? They take a per-directory mutex prior to the lookup, and hold it until after the create. > >> I don't suppose it would be possible at some point in the future to > >> merge the secpolicy and fmac calls together? > > > > Possibly, but not trivially. The secpolicy hooks are currently only > > invoked if the base DAC checks fail, so the callers would have to be > > changed to always invoke them (passing in the DAC decision as an > > argument), and then the secpolicy functions would have to be changed to > > first apply the FMAC logic, then only perform the existing secpolicy > > privilege tests if DAC failed. Also, the secpolicy hook interface would > > have to be mappable to the FMAC checks; one secpolicy hook per vnode > > operation would be best for our purposes, whereas today there are > > multiple secpolicy hooks called at different points under different > > conditions on a given operation's code path. > > > >>> This patch is less invasive than the prior one, placing the FMAC hooks > >>> entirely within the zfs vnode ops rather than pushing > >>> fmac_vnode_post_create() down to zfs_perm_init(). > >>> > >>> The wrapping of the vattr with an xvattr is pulled out of > >>> fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) > >>> now to make it clearer and less prone to bugs. A xva_from_va() helper > >>> function is introduced for populating an xvattr from vattr. > >>> > >> I don't like converting every vattr_t that comes into > >> zfs_create/zfs_mkdir into an xvattr. That should only be done when > >> necessary and is probably still best done in fmac_vnode_create(). > > > > For FMAC, we need to assign a secctx to every file, so we do need this > > on every vattr that comes into zfs_create/mkdir (and ultimately the > > other file creation operations) if we are using xvattrs as the mechanism > > for conveying the secctx. I can however move the logic back into > > fmac_vnode_create() if desired. I moved it up into the caller so that > > it would be clear that the vap is being switched to refer to an xvattr > > declared/allocated in the caller vs. hiding that down inside of the fmac > > code. > > > > I'm concerned about the cost of doing the memory copies when fmac isn't > enabled. Its going to slow down the create code path in ZFS. Another > alternative would be do do the xvattr allocation in fop_create(), but > only when fmac is enabled. For now I can take the memory copying back into fmac_vnode_create(), although I do need the xvattr structure to be declared/allocated in the caller (fop_create or zfs_create) in order to have the right lifecycle. But I'm a little worried that such a small fixed overhead is of concern to you, given that we'd like FMAC to ultimately be a default-enabled feature of OpenSolaris (just as SELinux is a default-enabled feature of Linux) and that the Solaris security team would actually prefer to not have to support a disabled mode at all. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 2 10:51:06 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 02 Oct 2008 11:51:06 -0600 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate existing file open In-Reply-To: <1222968970.6528.103.camel@moss-spartans.epoch.ncsc.mil> References: <1222953580.6528.18.camel@moss-spartans.epoch.ncsc.mil> <48E4F0F1.5010304@Sun.COM> <1222967187.6528.84.camel@moss-spartans.epoch.ncsc.mil> <48E501FB.2010709@Sun.COM> <1222968970.6528.103.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48E50A0A.7040806@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-02 at 11:16 -0600, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> On Thu, 2008-10-02 at 10:04 -0600, Mark Shellenbaum wrote: >>>> Stephen Smalley wrote: >>>>> Move the FMAC fmac_vnode_create() and post_create() hooks from >>>>> fop_create() into zfs_create() so that they are only applied on new file >>>>> creation not opening of an existing file, and call the >>>>> fmac_vnode_access() hook from zfs_create() to mediate opening an >>>>> existing file. Similar hooking will be needed for other filesystem >>>>> types like tmpfs as well. >>>>> >>>>> Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() >>>>> for consistency with create although we don't have the same problem >>>>> there with distinguishing create from open. Given the current need to >>>>> place several of the hooks (create, unlink/rmdir, rename) in the >>>>> filesystem code, I'm inclined to move the remaining FMAC vnode hooks in >>>>> the fop layer into the filesystem code (like the existing DAC checking >>>>> and secpolicy hooks) rather than having a mixture of some FMAC hooks in >>>>> the fop_ layer and some in the filesystem code. >>>>> >>>> Even if fop_create() new that the file already existed or not doesn't >>>> really help. It could have been removed/added by the time the actual >>>> file system xxx_create() function was called. >>> Linux VFS performs the lookup first (open with create intent), and only >>> invokes the create code path if the lookup fails. I understand though >>> that Solaris is different at present. >>> >> Does Linux then have the ability to stop deletion/additions to >> directories at their VFS layer? Is their some coarse VFS level lock >> they apply? > > They take a per-directory mutex prior to the lookup, and hold it until > after the create. > >>>> I don't suppose it would be possible at some point in the future to >>>> merge the secpolicy and fmac calls together? >>> Possibly, but not trivially. The secpolicy hooks are currently only >>> invoked if the base DAC checks fail, so the callers would have to be >>> changed to always invoke them (passing in the DAC decision as an >>> argument), and then the secpolicy functions would have to be changed to >>> first apply the FMAC logic, then only perform the existing secpolicy >>> privilege tests if DAC failed. Also, the secpolicy hook interface would >>> have to be mappable to the FMAC checks; one secpolicy hook per vnode >>> operation would be best for our purposes, whereas today there are >>> multiple secpolicy hooks called at different points under different >>> conditions on a given operation's code path. >>> >>>>> This patch is less invasive than the prior one, placing the FMAC hooks >>>>> entirely within the zfs vnode ops rather than pushing >>>>> fmac_vnode_post_create() down to zfs_perm_init(). >>>>> >>>>> The wrapping of the vattr with an xvattr is pulled out of >>>>> fmac_vnode_create() and handled by the callers (zfs_create, zfs_mkdir) >>>>> now to make it clearer and less prone to bugs. A xva_from_va() helper >>>>> function is introduced for populating an xvattr from vattr. >>>>> >>>> I don't like converting every vattr_t that comes into >>>> zfs_create/zfs_mkdir into an xvattr. That should only be done when >>>> necessary and is probably still best done in fmac_vnode_create(). >>> For FMAC, we need to assign a secctx to every file, so we do need this >>> on every vattr that comes into zfs_create/mkdir (and ultimately the >>> other file creation operations) if we are using xvattrs as the mechanism >>> for conveying the secctx. I can however move the logic back into >>> fmac_vnode_create() if desired. I moved it up into the caller so that >>> it would be clear that the vap is being switched to refer to an xvattr >>> declared/allocated in the caller vs. hiding that down inside of the fmac >>> code. >>> >> I'm concerned about the cost of doing the memory copies when fmac isn't >> enabled. Its going to slow down the create code path in ZFS. Another >> alternative would be do do the xvattr allocation in fop_create(), but >> only when fmac is enabled. > > For now I can take the memory copying back into fmac_vnode_create(), > although I do need the xvattr structure to be declared/allocated in the > caller (fop_create or zfs_create) in order to have the right lifecycle. > But I'm a little worried that such a small fixed overhead is of concern > to you, given that we'd like FMAC to ultimately be a default-enabled > feature of OpenSolaris (just as SELinux is a default-enabled feature of > Linux) and that the Solaris security team would actually prefer to not > have to support a disabled mode at all. > I hadn't realized that fmac would be enabled by default. Since fmac will need xvattr_t in create, mkdir and other vops then maybe its time to consider changing the signature of those VOPS to pass an xvattr_t instead of a vattr_t. There is no point passing around a vattr_t, when we really need an xvattr_t. You don't need to do this now, but this will need to be cleaned up at some point. -Mark From sommerfeld at sun.com Thu Oct 2 16:12:57 2008 From: sommerfeld at sun.com (Bill Sommerfeld) Date: Thu, 02 Oct 2008 16:12:57 -0700 Subject: [fmac-discuss] FMAC and sockets? In-Reply-To: <1222780321.19676.50.camel@moss-spartans.epoch.ncsc.mil> References: <48DBDE88.5060104@sun.com> <1222780321.19676.50.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <1222989177.1033.44.camel@localhost> On Tue, 2008-09-30 at 09:12 -0400, Stephen Smalley wrote: > Long term I think it would make sense to replace ts_label_t with a > security context that includes the MLS label as a component, but not in > the initial version. IMHO this can't happen too quickly. in the long run it would be good to shield more of the networking code from implementation details of credentials and labels; there are some cases (CIPSO being a big one today, and labeled IPsec being my current project) where you need to translate labels to and from one or more external representations but it would be better if we can add better abstractions for labels for code that just needs to do access checks. (look at the code under is_system_labeled() checks in NFS for one). - Bill From sds at tycho.nsa.gov Mon Oct 6 07:14:13 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 06 Oct 2008 10:14:13 -0400 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate open of existing file Message-ID: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> Move the fmac_vnode_create() and post_create() hooks from fop_create() into zfs_create() so that they are only applied on new file creation, and call the fmac_vnode_access() hook from zfs_create() when opening an existing file. Similar hooking will be needed for other filesystem types like tmpfs as well. Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() for consistency with create although we don't have the same problem there with distinguishing create from open at the fop layer. The wrapping of the vattr with an xvattr is put back into fmac_vnode_create() as it was before. Ultimately all callers of VOP_CREATE will likely be changed to pass xvattrs in the first place, thereby eliminating the need for such wrapping by the FMAC code. Taking the call to fmac_vnode_access() into zfs_zaccess() will be explored in subsequent patches. Webrev is available at: http://cr.opensolaris.org/~sds/create/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -260,6 +260,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 +278,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); @@ -301,33 +302,28 @@ 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 (!(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); diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -378,6 +378,18 @@ xvap->xva_magic = XVA_MAGIC; xvap->xva_vattr.va_mask = AT_XVATTR; xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0]; +} + +/* + * 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; } /* @@ -3367,8 +3379,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) { @@ -3382,17 +3392,12 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && 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)); @@ -3499,8 +3504,6 @@ int flags, vsecattr_t *vsecp) /* ACL to set during create */ { - xvattr_t xvattr; - security_id_t secid; int ret; if (vsecp != NULL && @@ -3515,17 +3518,12 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && 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, diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -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 @@ -1240,6 +1242,11 @@ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { 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 @@ -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; @@ -1324,6 +1332,10 @@ if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) { goto out; } + + error = fmac_vnode_access(ZTOV(zp), mode, aflags, cr, B_TRUE); + if (error) + goto out; mutex_enter(&dzp->z_lock); dzp->z_seq++; @@ -1610,6 +1622,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); @@ -1660,6 +1674,13 @@ } if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) { + zfs_dirent_unlock(dl); + ZFS_EXIT(zfsvfs); + return (error); + } + + error = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); + if (error) { zfs_dirent_unlock(dl); ZFS_EXIT(zfsvfs); return (error); @@ -1733,6 +1754,8 @@ if (fuidp) zfs_fuid_info_free(fuidp); dmu_tx_commit(tx); + + fmac_vnode_post_create(ZTOV(zp), secid); zfs_dirent_unlock(dl); diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -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 */ -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Mon Oct 6 12:54:25 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 06 Oct 2008 15:54:25 -0400 Subject: [fmac-discuss] [PATCH] Move fmac_vnode_access() hook to zfs_zaccess() Message-ID: <1223322865.7712.106.camel@moss-spartans.epoch.ncsc.mil> Extend fmac_vnode_access() to understand ACE masks as well as traditional modes, and move the calls to it from fop_access() and zfs_create() into zfs_zaccess(). The access functions of other filesystems would need to be similarly instrumented, although they can pass conventional modes rather than ACE masks since fmac_vnode_access() understands both and distinguishes them based on flags. Note btw that extending fmac_vnode_access() to understand ACE masks is required regardless of whether we call it from fop_access() or zfs_zaccess() since callers of VOP_ACCESS() can pass ACE masks (as in the nfs4 and smbsrv cases). fmac_vnode_access() is only called if the normal zfs_zaccess() logic would grant the access (i.e. either the base DAC logic or the secpolicy hook authorized it). The secpolicy hook is not allowed to override a FMAC denial. One immediate benefit of taking the FMAC hook into zfs_zaccess is that we get proper checking against the base file when a named attribute is accessed, e.g. runat /etc/passwd cp /tmp/foo attr.1 fails as expected with a setattr denial. We also gain more complete coverage of file operations. I looked at moving the fmac_vnode_access() hook inside of zfs_zaccess_common(), but it seemed better to do it in zfs_zaccess() because: 1) We can then place it after both the base DAC logic and the privilege check. 2) We do not gain any benefit from checking all calls to zfs_zaccess_common() since other callers like zfs_zaccess_delete() and _rename() short-circuit their checking if access to the directory is granted, whereas we want checking against the target file in all cases and thus still need our separate hooks for those operations. Some of the other FMAC checks may be obsoleted by taking fmac_vnode_access() into zfs_zaccess(), but this requires a case-by-case review and testing as callers of zfs_zaccess() do not always honor a denial from it (can be overridden by other secpolicy calls), as in the setattr case. This is relative to the prior patch for the create hooks. Webrev is available at: http://cr.opensolaris.org/~sds/zaccess/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -549,6 +550,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) @@ -568,17 +580,42 @@ 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, 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) diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -3315,9 +3315,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 diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -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) @@ -2423,6 +2421,11 @@ } } } + +out: + if (!error) + error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, + B_TRUE); if (is_attr) VN_RELE(ZTOV(xzp)); diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -1333,10 +1333,6 @@ goto out; } - error = fmac_vnode_access(ZTOV(zp), mode, aflags, cr, B_TRUE); - if (error) - goto out; - mutex_enter(&dzp->z_lock); dzp->z_seq++; mutex_exit(&dzp->z_lock); -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Tue Oct 7 06:51:51 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 07 Oct 2008 09:51:51 -0400 Subject: [fmac-discuss] [PATCH] Distinguish append vs. write in fmac_vnode_access() Message-ID: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> The prior patch that extended fmac_vnode_access() to understand ACE masks and moved the call to it from fop_access() to zfs_zaccess() did not properly distinguish append vs. write access unlike the original fmac_vnode_access() handling of traditional modes. This patch, on top of the prior one, passes the flags down from zfs_zaccess() to fmac_vnode_access() and handles the V_APPEND flag by remapping ACE_WRITE_DATA mode to FILE__APPEND permission when it is set. Webrev is available at: http://cr.opensolaris.org/~sds/append diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -554,7 +554,7 @@ if (mode & (mask)) { \ mode &= ~(mask); \ av |= (perm); \ - } \ + } #define ACE_GETATTR_MASK (ACE_READ_NAMED_ATTRS | ACE_READ_ATTRIBUTES | \ ACE_READ_ACL) @@ -594,7 +594,8 @@ 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, FILE__WRITE); + 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); } diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -2424,8 +2424,8 @@ out: if (!error) - error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, - B_TRUE); + error = fmac_vnode_access(ZTOV(check_zp), mode, + flags|V_ACE_MASK, cr, B_TRUE); if (is_attr) VN_RELE(ZTOV(xzp)); From Mark.Shellenbaum at Sun.COM Tue Oct 7 07:30:38 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 07 Oct 2008 08:30:38 -0600 Subject: [fmac-discuss] [PATCH] Move fmac_vnode_access() hook to zfs_zaccess() In-Reply-To: <1223322865.7712.106.camel@moss-spartans.epoch.ncsc.mil> References: <1223322865.7712.106.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EB728E.2020901@Sun.COM> Stephen Smalley wrote: > Extend fmac_vnode_access() to understand ACE masks as well as > traditional modes, and move the calls to it from fop_access() and > zfs_create() into zfs_zaccess(). The access functions of other > filesystems would need to be similarly instrumented, although they can > pass conventional modes rather than ACE masks since fmac_vnode_access() > understands both and distinguishes them based on flags. > > Note btw that extending fmac_vnode_access() to understand ACE masks is > required regardless of whether we call it from fop_access() or > zfs_zaccess() since callers of VOP_ACCESS() can pass ACE masks (as in > the nfs4 and smbsrv cases). > > fmac_vnode_access() is only called if the normal zfs_zaccess() logic > would grant the access (i.e. either the base DAC logic or the secpolicy > hook authorized it). The secpolicy hook is not allowed to override a > FMAC denial. > > One immediate benefit of taking the FMAC hook into zfs_zaccess is that > we get proper checking against the base file when a named attribute is > accessed, e.g. runat /etc/passwd cp /tmp/foo attr.1 fails as expected > with a setattr denial. We also gain more complete coverage of file > operations. > > I looked at moving the fmac_vnode_access() hook inside of > zfs_zaccess_common(), but it seemed better to do it in zfs_zaccess() > because: > 1) We can then place it after both the base DAC logic and the privilege > check. > 2) We do not gain any benefit from checking all calls to > zfs_zaccess_common() since other callers like zfs_zaccess_delete() and > _rename() short-circuit their checking if access to the directory is > granted, whereas we want checking against the target file in all cases > and thus still need our separate hooks for those operations. > > Some of the other FMAC checks may be obsoleted by taking > fmac_vnode_access() into zfs_zaccess(), but this requires a case-by-case > review and testing as callers of zfs_zaccess() do not always honor a > denial from it (can be overridden by other secpolicy calls), as in the > setattr case. > > This is relative to the prior patch for the create hooks. > + > +#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) > + A standard VOP_GETATTR() would only require ACE_READ_ATTRIBUTES, whereas a VOP_GETSECATTR() would require ACE_READ_ACL. ACE_READ_NAMED_ATTRS is used for "search" permission in the hidden extended attribute directory. In the setattr case it really depends on what operation is being performed as to what permissions *may* be required. -Mark From sds at tycho.nsa.gov Tue Oct 7 07:40:19 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 07 Oct 2008 10:40:19 -0400 Subject: [fmac-discuss] [PATCH] Move fmac_vnode_access() hook to zfs_zaccess() In-Reply-To: <48EB728E.2020901@Sun.COM> References: <1223322865.7712.106.camel@moss-spartans.epoch.ncsc.mil> <48EB728E.2020901@Sun.COM> Message-ID: <1223390420.4104.3.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-07 at 08:30 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Extend fmac_vnode_access() to understand ACE masks as well as > > traditional modes, and move the calls to it from fop_access() and > > zfs_create() into zfs_zaccess(). The access functions of other > > filesystems would need to be similarly instrumented, although they can > > pass conventional modes rather than ACE masks since fmac_vnode_access() > > understands both and distinguishes them based on flags. > > > > Note btw that extending fmac_vnode_access() to understand ACE masks is > > required regardless of whether we call it from fop_access() or > > zfs_zaccess() since callers of VOP_ACCESS() can pass ACE masks (as in > > the nfs4 and smbsrv cases). > > > > fmac_vnode_access() is only called if the normal zfs_zaccess() logic > > would grant the access (i.e. either the base DAC logic or the secpolicy > > hook authorized it). The secpolicy hook is not allowed to override a > > FMAC denial. > > > > One immediate benefit of taking the FMAC hook into zfs_zaccess is that > > we get proper checking against the base file when a named attribute is > > accessed, e.g. runat /etc/passwd cp /tmp/foo attr.1 fails as expected > > with a setattr denial. We also gain more complete coverage of file > > operations. > > > > I looked at moving the fmac_vnode_access() hook inside of > > zfs_zaccess_common(), but it seemed better to do it in zfs_zaccess() > > because: > > 1) We can then place it after both the base DAC logic and the privilege > > check. > > 2) We do not gain any benefit from checking all calls to > > zfs_zaccess_common() since other callers like zfs_zaccess_delete() and > > _rename() short-circuit their checking if access to the directory is > > granted, whereas we want checking against the target file in all cases > > and thus still need our separate hooks for those operations. > > > > Some of the other FMAC checks may be obsoleted by taking > > fmac_vnode_access() into zfs_zaccess(), but this requires a case-by-case > > review and testing as callers of zfs_zaccess() do not always honor a > > denial from it (can be overridden by other secpolicy calls), as in the > > setattr case. > > > > This is relative to the prior patch for the create hooks. > > > + > > +#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) > > + > > A standard VOP_GETATTR() would only require ACE_READ_ATTRIBUTES, whereas > a VOP_GETSECATTR() would require ACE_READ_ACL. ACE_READ_NAMED_ATTRS is > used for "search" permission in the hidden extended attribute directory. > > In the setattr case it really depends on what operation is being > performed as to what permissions *may* be required. Ok. At present, I am just mapping all of the ACE modes defined in the ACE_GETATTR_MASK above to a single FMAC permission check, FILE__GETATTR, and all of the ACE modes defined in the ACE_SETATTR_MASK above to a single FMAC permission check, FILE__SETATTR. We could introduce separate FMAC/Flask permission checks for each ACE mode in future patches, but for now we just map them to the existing set of permissions. Whether or not we split them up in FMAC will depend on how useful it is to distinguish among them and how compatible we want to be with SELinux policy. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Tue Oct 7 07:38:37 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 07 Oct 2008 08:38:37 -0600 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate open of existing file In-Reply-To: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> References: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EB746D.5030600@Sun.COM> Stephen Smalley wrote: > Move the fmac_vnode_create() and post_create() hooks from fop_create() > into zfs_create() so that they are only applied on new file creation, > and call the fmac_vnode_access() hook from zfs_create() when opening an > existing file. Similar hooking will be needed for other filesystem > types like tmpfs as well. > > Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > for consistency with create although we don't have the same problem > there with distinguishing create from open at the fop layer. > > The wrapping of the vattr with an xvattr is put back into > fmac_vnode_create() as it was before. Ultimately all callers of > VOP_CREATE will likely be changed to pass xvattrs in the first place, > thereby eliminating the need for such wrapping by the FMAC code. > > Taking the call to fmac_vnode_access() into zfs_zaccess() will be > explored in subsequent patches. > > Webrev is available at: http://cr.opensolaris.org/~sds/create/ In zfs_create()/zfs_mkdir() you have a local xvattr that is initialized by fmac_vnode_create(), but I don't see where in zfs_create() or zfs_mkdir() that variable is actually used. -Mark From sds at tycho.nsa.gov Tue Oct 7 07:44:49 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 07 Oct 2008 10:44:49 -0400 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate open of existing file In-Reply-To: <48EB746D.5030600@Sun.COM> References: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> <48EB746D.5030600@Sun.COM> Message-ID: <1223390689.4104.5.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-07 at 08:38 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Move the fmac_vnode_create() and post_create() hooks from fop_create() > > into zfs_create() so that they are only applied on new file creation, > > and call the fmac_vnode_access() hook from zfs_create() when opening an > > existing file. Similar hooking will be needed for other filesystem > > types like tmpfs as well. > > > > Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > > for consistency with create although we don't have the same problem > > there with distinguishing create from open at the fop layer. > > > > The wrapping of the vattr with an xvattr is put back into > > fmac_vnode_create() as it was before. Ultimately all callers of > > VOP_CREATE will likely be changed to pass xvattrs in the first place, > > thereby eliminating the need for such wrapping by the FMAC code. > > > > Taking the call to fmac_vnode_access() into zfs_zaccess() will be > > explored in subsequent patches. > > > > Webrev is available at: http://cr.opensolaris.org/~sds/create/ > > In zfs_create()/zfs_mkdir() you have a local xvattr that is initialized > by fmac_vnode_create(), but I don't see where in zfs_create() or > zfs_mkdir() that variable is actually used. fmac_vnode_create() switches the vap pointer to refer to it if the original one did not refer to an xvattr. So they end up using it via subsequent use of the vap, which causes the secctx value to be passed down and set on the file. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Tue Oct 7 07:46:13 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 07 Oct 2008 08:46:13 -0600 Subject: [fmac-discuss] [PATCH] Distinguish append vs. write in fmac_vnode_access() In-Reply-To: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> References: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> Message-ID: <48EB7635.20404@Sun.COM> > out: > if (!error) > - error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, > - B_TRUE); > + error = fmac_vnode_access(ZTOV(check_zp), mode, > + flags|V_ACE_MASK, cr, B_TRUE); why are you doing this "flags|V_ACE_MASK"? the flags field should always be either 0 or V_ACE_MASK. Don't you just want to pass "flags"? -Mark From Mark.Shellenbaum at Sun.COM Tue Oct 7 07:48:34 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 07 Oct 2008 08:48:34 -0600 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate open of existing file In-Reply-To: <1223390689.4104.5.camel@moss-spartans.epoch.ncsc.mil> References: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> <48EB746D.5030600@Sun.COM> <1223390689.4104.5.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EB76C2.10108@Sun.COM> Stephen Smalley wrote: > On Tue, 2008-10-07 at 08:38 -0600, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> Move the fmac_vnode_create() and post_create() hooks from fop_create() >>> into zfs_create() so that they are only applied on new file creation, >>> and call the fmac_vnode_access() hook from zfs_create() when opening an >>> existing file. Similar hooking will be needed for other filesystem >>> types like tmpfs as well. >>> >>> Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() >>> for consistency with create although we don't have the same problem >>> there with distinguishing create from open at the fop layer. >>> >>> The wrapping of the vattr with an xvattr is put back into >>> fmac_vnode_create() as it was before. Ultimately all callers of >>> VOP_CREATE will likely be changed to pass xvattrs in the first place, >>> thereby eliminating the need for such wrapping by the FMAC code. >>> >>> Taking the call to fmac_vnode_access() into zfs_zaccess() will be >>> explored in subsequent patches. >>> >>> Webrev is available at: http://cr.opensolaris.org/~sds/create/ >> In zfs_create()/zfs_mkdir() you have a local xvattr that is initialized >> by fmac_vnode_create(), but I don't see where in zfs_create() or >> zfs_mkdir() that variable is actually used. > > fmac_vnode_create() switches the vap pointer to refer to it if the > original one did not refer to an xvattr. So they end up using it via > subsequent use of the vap, which causes the secctx value to be passed > down and set on the file. > Ok, I see now. -Mark From sds at tycho.nsa.gov Tue Oct 7 07:56:33 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 07 Oct 2008 10:56:33 -0400 Subject: [fmac-discuss] [PATCH] Distinguish append vs. write in fmac_vnode_access() In-Reply-To: <48EB7635.20404@Sun.COM> References: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> <48EB7635.20404@Sun.COM> Message-ID: <1223391393.4104.14.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-07 at 08:46 -0600, Mark Shellenbaum wrote: > > out: > > if (!error) > > - error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, > > - B_TRUE); > > + error = fmac_vnode_access(ZTOV(check_zp), mode, > > + flags|V_ACE_MASK, cr, B_TRUE); > > why are you doing this "flags|V_ACE_MASK"? > > the flags field should always be either 0 or V_ACE_MASK. Don't you just > want to pass "flags"? No - we need to tell fmac_vnode_access() that the mode is an ACE mask (since we are being called from zfs_zaccess() and that always takes an ACE mask as input regardless of flags) and we need to convey V_APPEND if it was set in the flags (just as zfs_zaccess checks for V_APPEND in flags to decide whether to call zfs_zaccess_append). When fmac_vnode_access() was being called from fop_access(), we did just pass flags as is, but since it has been moved to zfs_zaccess(), we have to explicitly tell it that we are passing the ACE mask as well as convey the append flag information. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Tue Oct 7 08:02:14 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 07 Oct 2008 09:02:14 -0600 Subject: [fmac-discuss] [PATCH] Distinguish append vs. write in fmac_vnode_access() In-Reply-To: <1223391393.4104.14.camel@moss-spartans.epoch.ncsc.mil> References: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> <48EB7635.20404@Sun.COM> <1223391393.4104.14.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EB79F6.30502@Sun.COM> Stephen Smalley wrote: > On Tue, 2008-10-07 at 08:46 -0600, Mark Shellenbaum wrote: >>> out: >>> if (!error) >>> - error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, >>> - B_TRUE); >>> + error = fmac_vnode_access(ZTOV(check_zp), mode, >>> + flags|V_ACE_MASK, cr, B_TRUE); >> why are you doing this "flags|V_ACE_MASK"? >> >> the flags field should always be either 0 or V_ACE_MASK. Don't you just >> want to pass "flags"? > > No - we need to tell fmac_vnode_access() that the mode is an ACE mask > (since we are being called from zfs_zaccess() and that always takes an > ACE mask as input regardless of flags) and we need to convey V_APPEND if > it was set in the flags (just as zfs_zaccess checks for V_APPEND in > flags to decide whether to call zfs_zaccess_append). > > When fmac_vnode_access() was being called from fop_access(), we did just > pass flags as is, but since it has been moved to zfs_zaccess(), we have > to explicitly tell it that we are passing the ACE mask as well as convey > the append flag information. > Ok. Sorry, I didn't read your overview close enough before looking at the code change. -Mark From sds at tycho.nsa.gov Tue Oct 7 08:06:25 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 07 Oct 2008 11:06:25 -0400 Subject: [fmac-discuss] [PATCH] Distinguish append vs. write in fmac_vnode_access() In-Reply-To: <48EB79F6.30502@Sun.COM> References: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> <48EB7635.20404@Sun.COM> <1223391393.4104.14.camel@moss-spartans.epoch.ncsc.mil> <48EB79F6.30502@Sun.COM> Message-ID: <1223391985.2524.0.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-07 at 09:02 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Tue, 2008-10-07 at 08:46 -0600, Mark Shellenbaum wrote: > >>> out: > >>> if (!error) > >>> - error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, > >>> - B_TRUE); > >>> + error = fmac_vnode_access(ZTOV(check_zp), mode, > >>> + flags|V_ACE_MASK, cr, B_TRUE); > >> why are you doing this "flags|V_ACE_MASK"? > >> > >> the flags field should always be either 0 or V_ACE_MASK. Don't you just > >> want to pass "flags"? > > > > No - we need to tell fmac_vnode_access() that the mode is an ACE mask > > (since we are being called from zfs_zaccess() and that always takes an > > ACE mask as input regardless of flags) and we need to convey V_APPEND if > > it was set in the flags (just as zfs_zaccess checks for V_APPEND in > > flags to decide whether to call zfs_zaccess_append). > > > > When fmac_vnode_access() was being called from fop_access(), we did just > > pass flags as is, but since it has been moved to zfs_zaccess(), we have > > to explicitly tell it that we are passing the ACE mask as well as convey > > the append flag information. > > > > Ok. Sorry, I didn't read your overview close enough before looking at > the code change. No worries - thanks for the review. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Tue Oct 7 13:11:10 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 07 Oct 2008 16:11:10 -0400 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support Message-ID: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> Add FMAC labeling support and basic permission checking to tmpfs. Further hooks will be added later for the finer-grained checks. The root directory of a tmpfs mount is initially labeled from the mount point directory, as with the existing uid/gid/mode assignment. Thus, for example, one can umount /tmp from single-user mode and setfilecon the mount point directory to system_u:object_r:tmp_t in order to get the tmpfs mount to pick up that context on subsequent mounts. However, unmounting other tmpfs mounts didn't seem to be possible even from single user mode, so we may have to relabel them at boot after the tmpfs mount is created. Files and directories created in the tmpfs mount are then labeled via the fmac_vnode_create and post_create hooks as in ZFS, except that we do need to set up an xvattr on the file creation code path since there is no storage of the secctx and we only need to set up the incore secid on the vnode. Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the secctx from the secid in order to pass back to userspace. Upon tmp_setattr, we only need to remove the prohibition of AT_XVATTR and then the existing call to secpolicy_vnode_setattr -> secpolicy_xvattr will ultimately reach fmac_vnode_set_secctx() as with ZFS in order to check permissions and update the secid. A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a FMAC permission check whenever the existing tmpfs permission checks would grant access. This uses conventional modes and thus does not pass V_ACE_MASK. A call to fmac_vnode_remove() is inserted into tmp_sticky_remove_access() as an initial cut at mediating removal of files in tmpfs, although this may need to be taken to the callers when rename checking is introduced. Webrev available at: http://cr.opensolaris.org/~sds/tmpfs1/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -254,6 +254,40 @@ } 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) { @@ -302,6 +336,15 @@ error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); if (error) return (error); + + 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)) { /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -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); } /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c @@ -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 diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c @@ -64,6 +64,7 @@ #include #include #include +#include #include 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*/ @@ -723,7 +725,7 @@ /* * Cannot set these attributes */ - if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR)) + if ((vap->va_mask & AT_NOSET)) return (EINVAL); mutex_enter(&tp->tn_tlock); @@ -937,6 +939,7 @@ struct tmpnode *self; int error; struct tmpnode *oldtp; + security_id_t secid; again: parent = (struct tmpnode *)VTOTN(dvp); @@ -1021,6 +1024,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 +1064,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); @@ -1300,6 +1309,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 +1347,7 @@ } rw_exit(&parent->tn_rwlock); *vpp = TNTOV(self); + fmac_vnode_post_create(*vpp, secid); return (0); } diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -88,6 +88,7 @@ int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); 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); -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Wed Oct 8 07:37:27 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Wed, 08 Oct 2008 08:37:27 -0600 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support In-Reply-To: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> References: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48ECC5A7.8040505@Sun.COM> Stephen Smalley wrote: > Add FMAC labeling support and basic permission checking to tmpfs. > Further hooks will be added later for the finer-grained checks. > > The root directory of a tmpfs mount is initially labeled from the mount > point directory, as with the existing uid/gid/mode assignment. Thus, > for example, one can umount /tmp from single-user mode and setfilecon > the mount point directory to system_u:object_r:tmp_t in order to get the > tmpfs mount to pick up that context on subsequent mounts. However, > unmounting other tmpfs mounts didn't seem to be possible even from > single user mode, so we may have to relabel them at boot after the tmpfs > mount is created. > > Files and directories created in the tmpfs mount are then labeled via > the fmac_vnode_create and post_create hooks as in ZFS, except that we do > need to set up an xvattr on the file creation code path since there is > no storage of the secctx and we only need to set up the incore secid on > the vnode. > > Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the > secctx from the secid in order to pass back to userspace. Upon > tmp_setattr, we only need to remove the prohibition of AT_XVATTR and > then the existing call to secpolicy_vnode_setattr -> secpolicy_xvattr > will ultimately reach fmac_vnode_set_secctx() as with ZFS in order to > check permissions and update the secid. > > A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a > FMAC permission check whenever the existing tmpfs permission checks > would grant access. This uses conventional modes and thus does not pass > V_ACE_MASK. A call to fmac_vnode_remove() is inserted into > tmp_sticky_remove_access() as an initial cut at mediating removal of > files in tmpfs, although this may need to be taken to the callers when > rename checking is introduced. > > Webrev available at: http://cr.opensolaris.org/~sds/tmpfs1/ I believe the changes in tmp_vnops.c will introduce a regression in extended attribute aware utilities. The following test should confirm it. # cd to ZFS file system $ touch aaa $ chmod S+cR aaa $ mv aaa /tmp mv: Failed to copy extended system attributes from aaa to /tmp/aaa With your tmp_setattr() change the error message from "mv" won't be displayed. The reason for this is that xattr_file_write() calls VOP_SETATTR() and in the case of tmpfs it should fail with EINVAL, but you removed the AT_XVATTR check that was returning EINVAL. This can probably be fixed by making sure in tmp_setattr() by checking which xvattr bits are set and then returning EINVAL when appropriate. There is also a change in snv_100+ that you should be aware of. PSARC/2008/588 VFSFT_SYSATTR_VIEWS 6739967 New VFSFT needed for sysattr "view" interface (VFSFT_XVATTR currently overloaded) With this change tmpfs and ufs no longer register support for the VFSFT_XVATTR feature, but instead only register VFSFT_SYSATTR_VIEWS. this lets the extended attribute code (xattr.c) expose the SUNWattr_rw/SUNWattr_ro files, but it doesn't necessarily mean you support setting attributes such as immutable, readonly, and so on. If tmpfs is changed to once again register support for VFSFT_XVATTR then its going to break some code in the CIFS server which uses that feature to determine if a file system supports the "DOS" attributes. We could probably break up xvattr feature into multiple feature registrations (i.e. VFSFT_DOS, VFSFT_FMAC, ...) I'm not really sure what the right solution is right now. -Mark From sds at tycho.nsa.gov Wed Oct 8 08:01:32 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 08 Oct 2008 11:01:32 -0400 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support In-Reply-To: <48ECC5A7.8040505@Sun.COM> References: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> <48ECC5A7.8040505@Sun.COM> Message-ID: <1223478092.7192.99.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-10-08 at 08:37 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Add FMAC labeling support and basic permission checking to tmpfs. > > Further hooks will be added later for the finer-grained checks. > > > > The root directory of a tmpfs mount is initially labeled from the mount > > point directory, as with the existing uid/gid/mode assignment. Thus, > > for example, one can umount /tmp from single-user mode and setfilecon > > the mount point directory to system_u:object_r:tmp_t in order to get the > > tmpfs mount to pick up that context on subsequent mounts. However, > > unmounting other tmpfs mounts didn't seem to be possible even from > > single user mode, so we may have to relabel them at boot after the tmpfs > > mount is created. > > > > Files and directories created in the tmpfs mount are then labeled via > > the fmac_vnode_create and post_create hooks as in ZFS, except that we do > > need to set up an xvattr on the file creation code path since there is > > no storage of the secctx and we only need to set up the incore secid on > > the vnode. > > > > Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the > > secctx from the secid in order to pass back to userspace. Upon > > tmp_setattr, we only need to remove the prohibition of AT_XVATTR and > > then the existing call to secpolicy_vnode_setattr -> secpolicy_xvattr > > will ultimately reach fmac_vnode_set_secctx() as with ZFS in order to > > check permissions and update the secid. > > > > A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a > > FMAC permission check whenever the existing tmpfs permission checks > > would grant access. This uses conventional modes and thus does not pass > > V_ACE_MASK. A call to fmac_vnode_remove() is inserted into > > tmp_sticky_remove_access() as an initial cut at mediating removal of > > files in tmpfs, although this may need to be taken to the callers when > > rename checking is introduced. > > > > Webrev available at: http://cr.opensolaris.org/~sds/tmpfs1/ > > I believe the changes in tmp_vnops.c will introduce a regression in > extended attribute aware utilities. > > The following test should confirm it. > # cd to ZFS file system > $ touch aaa > $ chmod S+cR aaa > $ mv aaa /tmp > mv: Failed to copy extended system attributes from aaa to /tmp/aaa > > With your tmp_setattr() change the error message from "mv" won't be > displayed. > > The reason for this is that xattr_file_write() calls VOP_SETATTR() and > in the case of tmpfs it should fail with EINVAL, but you removed the > AT_XVATTR check that was returning EINVAL. This can probably be fixed > by making sure in tmp_setattr() by checking which xvattr bits are set > and then returning EINVAL when appropriate. Ok, I'll add those checks in the next revision of the patch. > There is also a change in snv_100+ that you should be aware of. > PSARC/2008/588 VFSFT_SYSATTR_VIEWS > 6739967 New VFSFT needed for sysattr "view" interface (VFSFT_XVATTR > currently overloaded) > > With this change tmpfs and ufs no longer register support for the > VFSFT_XVATTR feature, but instead only register VFSFT_SYSATTR_VIEWS. > this lets the extended attribute code (xattr.c) expose the > SUNWattr_rw/SUNWattr_ro files, but it doesn't necessarily mean you > support setting attributes such as immutable, readonly, and so on. > > If tmpfs is changed to once again register support for VFSFT_XVATTR then > its going to break some code in the CIFS server which uses that feature > to determine if a file system supports the "DOS" attributes. > We could probably break up xvattr feature into multiple feature > registrations (i.e. VFSFT_DOS, VFSFT_FMAC, ...) I'm not really sure what > the right solution is right now. Is there any particular reason tmpfs couldn't support setting of those attributes on its tnodes? With appropriate logic added to test for immutable, rdonly, etc where needed? -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Wed Oct 8 08:08:03 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Wed, 08 Oct 2008 09:08:03 -0600 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support In-Reply-To: <1223478092.7192.99.camel@moss-spartans.epoch.ncsc.mil> References: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> <48ECC5A7.8040505@Sun.COM> <1223478092.7192.99.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48ECCCD3.7040304@Sun.COM> Stephen Smalley wrote: > On Wed, 2008-10-08 at 08:37 -0600, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> Add FMAC labeling support and basic permission checking to tmpfs. >>> Further hooks will be added later for the finer-grained checks. >>> >>> The root directory of a tmpfs mount is initially labeled from the mount >>> point directory, as with the existing uid/gid/mode assignment. Thus, >>> for example, one can umount /tmp from single-user mode and setfilecon >>> the mount point directory to system_u:object_r:tmp_t in order to get the >>> tmpfs mount to pick up that context on subsequent mounts. However, >>> unmounting other tmpfs mounts didn't seem to be possible even from >>> single user mode, so we may have to relabel them at boot after the tmpfs >>> mount is created. >>> >>> Files and directories created in the tmpfs mount are then labeled via >>> the fmac_vnode_create and post_create hooks as in ZFS, except that we do >>> need to set up an xvattr on the file creation code path since there is >>> no storage of the secctx and we only need to set up the incore secid on >>> the vnode. >>> >>> Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the >>> secctx from the secid in order to pass back to userspace. Upon >>> tmp_setattr, we only need to remove the prohibition of AT_XVATTR and >>> then the existing call to secpolicy_vnode_setattr -> secpolicy_xvattr >>> will ultimately reach fmac_vnode_set_secctx() as with ZFS in order to >>> check permissions and update the secid. >>> >>> A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a >>> FMAC permission check whenever the existing tmpfs permission checks >>> would grant access. This uses conventional modes and thus does not pass >>> V_ACE_MASK. A call to fmac_vnode_remove() is inserted into >>> tmp_sticky_remove_access() as an initial cut at mediating removal of >>> files in tmpfs, although this may need to be taken to the callers when >>> rename checking is introduced. >>> >>> Webrev available at: http://cr.opensolaris.org/~sds/tmpfs1/ >> I believe the changes in tmp_vnops.c will introduce a regression in >> extended attribute aware utilities. >> >> The following test should confirm it. >> # cd to ZFS file system >> $ touch aaa >> $ chmod S+cR aaa >> $ mv aaa /tmp >> mv: Failed to copy extended system attributes from aaa to /tmp/aaa >> >> With your tmp_setattr() change the error message from "mv" won't be >> displayed. >> >> The reason for this is that xattr_file_write() calls VOP_SETATTR() and >> in the case of tmpfs it should fail with EINVAL, but you removed the >> AT_XVATTR check that was returning EINVAL. This can probably be fixed >> by making sure in tmp_setattr() by checking which xvattr bits are set >> and then returning EINVAL when appropriate. > > Ok, I'll add those checks in the next revision of the patch. > >> There is also a change in snv_100+ that you should be aware of. >> PSARC/2008/588 VFSFT_SYSATTR_VIEWS >> 6739967 New VFSFT needed for sysattr "view" interface (VFSFT_XVATTR >> currently overloaded) >> >> With this change tmpfs and ufs no longer register support for the >> VFSFT_XVATTR feature, but instead only register VFSFT_SYSATTR_VIEWS. >> this lets the extended attribute code (xattr.c) expose the >> SUNWattr_rw/SUNWattr_ro files, but it doesn't necessarily mean you >> support setting attributes such as immutable, readonly, and so on. >> >> If tmpfs is changed to once again register support for VFSFT_XVATTR then >> its going to break some code in the CIFS server which uses that feature >> to determine if a file system supports the "DOS" attributes. >> We could probably break up xvattr feature into multiple feature >> registrations (i.e. VFSFT_DOS, VFSFT_FMAC, ...) I'm not really sure what >> the right solution is right now. > > Is there any particular reason tmpfs couldn't support setting of those > attributes on its tnodes? With appropriate logic added to test for > immutable, rdonly, etc where needed? > Those attributes weren't added to tmpfs primarily because the CIFS server won't be sharing tmpfs file system. what are your plans for UFS? Is the security context going to be based on the mount or will it be per vnode. -Mark From sds at tycho.nsa.gov Wed Oct 8 08:15:50 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 08 Oct 2008 11:15:50 -0400 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support In-Reply-To: <48ECCCD3.7040304@Sun.COM> References: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> <48ECC5A7.8040505@Sun.COM> <1223478092.7192.99.camel@moss-spartans.epoch.ncsc.mil> <48ECCCD3.7040304@Sun.COM> Message-ID: <1223478950.7192.106.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-10-08 at 09:08 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Wed, 2008-10-08 at 08:37 -0600, Mark Shellenbaum wrote: > >> Stephen Smalley wrote: > >>> Add FMAC labeling support and basic permission checking to tmpfs. > >>> Further hooks will be added later for the finer-grained checks. > >>> > >>> The root directory of a tmpfs mount is initially labeled from the mount > >>> point directory, as with the existing uid/gid/mode assignment. Thus, > >>> for example, one can umount /tmp from single-user mode and setfilecon > >>> the mount point directory to system_u:object_r:tmp_t in order to get the > >>> tmpfs mount to pick up that context on subsequent mounts. However, > >>> unmounting other tmpfs mounts didn't seem to be possible even from > >>> single user mode, so we may have to relabel them at boot after the tmpfs > >>> mount is created. > >>> > >>> Files and directories created in the tmpfs mount are then labeled via > >>> the fmac_vnode_create and post_create hooks as in ZFS, except that we do > >>> need to set up an xvattr on the file creation code path since there is > >>> no storage of the secctx and we only need to set up the incore secid on > >>> the vnode. > >>> > >>> Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the > >>> secctx from the secid in order to pass back to userspace. Upon > >>> tmp_setattr, we only need to remove the prohibition of AT_XVATTR and > >>> then the existing call to secpolicy_vnode_setattr -> secpolicy_xvattr > >>> will ultimately reach fmac_vnode_set_secctx() as with ZFS in order to > >>> check permissions and update the secid. > >>> > >>> A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a > >>> FMAC permission check whenever the existing tmpfs permission checks > >>> would grant access. This uses conventional modes and thus does not pass > >>> V_ACE_MASK. A call to fmac_vnode_remove() is inserted into > >>> tmp_sticky_remove_access() as an initial cut at mediating removal of > >>> files in tmpfs, although this may need to be taken to the callers when > >>> rename checking is introduced. > >>> > >>> Webrev available at: http://cr.opensolaris.org/~sds/tmpfs1/ > >> I believe the changes in tmp_vnops.c will introduce a regression in > >> extended attribute aware utilities. > >> > >> The following test should confirm it. > >> # cd to ZFS file system > >> $ touch aaa > >> $ chmod S+cR aaa > >> $ mv aaa /tmp > >> mv: Failed to copy extended system attributes from aaa to /tmp/aaa > >> > >> With your tmp_setattr() change the error message from "mv" won't be > >> displayed. > >> > >> The reason for this is that xattr_file_write() calls VOP_SETATTR() and > >> in the case of tmpfs it should fail with EINVAL, but you removed the > >> AT_XVATTR check that was returning EINVAL. This can probably be fixed > >> by making sure in tmp_setattr() by checking which xvattr bits are set > >> and then returning EINVAL when appropriate. > > > > Ok, I'll add those checks in the next revision of the patch. > > > >> There is also a change in snv_100+ that you should be aware of. > >> PSARC/2008/588 VFSFT_SYSATTR_VIEWS > >> 6739967 New VFSFT needed for sysattr "view" interface (VFSFT_XVATTR > >> currently overloaded) > >> > >> With this change tmpfs and ufs no longer register support for the > >> VFSFT_XVATTR feature, but instead only register VFSFT_SYSATTR_VIEWS. > >> this lets the extended attribute code (xattr.c) expose the > >> SUNWattr_rw/SUNWattr_ro files, but it doesn't necessarily mean you > >> support setting attributes such as immutable, readonly, and so on. > >> > >> If tmpfs is changed to once again register support for VFSFT_XVATTR then > >> its going to break some code in the CIFS server which uses that feature > >> to determine if a file system supports the "DOS" attributes. > >> We could probably break up xvattr feature into multiple feature > >> registrations (i.e. VFSFT_DOS, VFSFT_FMAC, ...) I'm not really sure what > >> the right solution is right now. > > > > Is there any particular reason tmpfs couldn't support setting of those > > attributes on its tnodes? With appropriate logic added to test for > > immutable, rdonly, etc where needed? > > > > Those attributes weren't added to tmpfs primarily because the CIFS > server won't be sharing tmpfs file system. Ok, seems easy enough to add though if it would allow us to keep VFSFT_XVATTR enabled for tmpfs. > what are your plans for UFS? Is the security context going to be based > on the mount or will it be per vnode. >From the prior discussions, I was assuming it would only be per-mount. If there are reasons for people to keeping using UFS rather than ZFS (and those same people would want to use FMAC), then we might revisit it down the road and try to use the shadow inode to store a secctx as well as the ACL. -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Wed Oct 8 08:59:06 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Wed, 08 Oct 2008 08:59:06 -0700 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support In-Reply-To: <1223478950.7192.106.camel@moss-spartans.epoch.ncsc.mil> References: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> <48ECC5A7.8040505@Sun.COM> <1223478092.7192.99.camel@moss-spartans.epoch.ncsc.mil> <48ECCCD3.7040304@Sun.COM> <1223478950.7192.106.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48ECD8CA.2050105@sun.com> Stephen Smalley wrote: > On Wed, 2008-10-08 at 09:08 -0600, Mark Shellenbaum wrote: > > >> what are your plans for UFS? Is the security context going to be based >> on the mount or will it be per vnode. >> > > >From the prior discussions, I was assuming it would only be per-mount. > If there are reasons for people to keeping using UFS rather than ZFS > (and those same people would want to use FMAC), then we might revisit it > down the road and try to use the shadow inode to store a secctx as well > as the ACL. > > I agree with Stephen that it is not worth extending UFS. --Glenn From john.weeks at sun.com Wed Oct 8 09:10:37 2008 From: john.weeks at sun.com (John Weeks) Date: Wed, 08 Oct 2008 09:10:37 -0700 Subject: [fmac-discuss] [PATCH] Labeled tmpfs support In-Reply-To: <48ECD8CA.2050105@sun.com> References: <1223410270.2524.22.camel@moss-spartans.epoch.ncsc.mil> <48ECC5A7.8040505@Sun.COM> <1223478092.7192.99.camel@moss-spartans.epoch.ncsc.mil> <48ECCCD3.7040304@Sun.COM> <1223478950.7192.106.camel@moss-spartans.epoch.ncsc.mil> <48ECD8CA.2050105@sun.com> Message-ID: <48ECDB7D.3090008@sun.com> On 10/08/08 08:59, Glenn Faden wrote: > Stephen Smalley wrote: >> On Wed, 2008-10-08 at 09:08 -0600, Mark Shellenbaum wrote: >> >>> what are your plans for UFS? Is the security context going to be >>> based on the mount or will it be per vnode. >>> >> >> >From the prior discussions, I was assuming it would only be per-mount. >> If there are reasons for people to keeping using UFS rather than ZFS >> (and those same people would want to use FMAC), then we might revisit it >> down the road and try to use the shadow inode to store a secctx as well >> as the ACL. >> >> > I agree with Stephen that it is not worth extending UFS. Same here. > > --Glenn From sds at tycho.nsa.gov Thu Oct 9 06:57:28 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 09:57:28 -0400 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support Message-ID: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> Revised patch for labeled tmpfs support that takes into account Mark's concern with making sure that trying to set other system attributes still fails with EINVAL. When we rebase to snv_100+ we will further need to address his other concern with respect to tmpfs no longer registering support for VFSFT_XVATTR; we will either need to introduce a separate VFSFT_XVATTR_SECCTX feature at that point or implement full xvattr support in tmpfs. The root directory of a tmpfs mount is initially labeled from the mount point directory, as with the existing uid/gid/mode assignment. Thus, for example, one can umount /tmp from single-user mode and setfilecon the mount point directory to system_u:object_r:tmp_t in order to get the tmpfs mount to pick up that context on subsequent mounts. However, unmounting other tmpfs mounts didn't seem to be possible even from single user mode, so we may have to relabel them at boot after the tmpfs mount is created. Files and directories created in the tmpfs mount are then labeled via the fmac_vnode_create and post_create hooks as in ZFS, except that we do not need to set up an xvattr on the file creation code path since there is no storage of the secctx and we only need to set up the incore secid on the vnode. Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the secctx from the secid in order to pass back to userspace. Upon tmp_setattr, if an xvattr is passed and _only_ the XAT_SECCTX attribute is requested, then the existing call to secpolicy_vnode_setattr -> secpolicy_xvattr will ultimately reach fmac_vnode_set_secctx() as with ZFS in order to check permissions and update the secid. A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a FMAC permission check whenever the existing tmpfs permission checks would grant access. This uses conventional modes and thus does not pass V_ACE_MASK. A call to fmac_vnode_remove() is inserted into tmp_sticky_remove_access() as an initial cut at mediating removal of files in tmpfs, although this may need to be taken to the callers when rename checking is introduced. Webrev available at: http://cr.opensolaris.org/~sds/tmpfs2/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -254,6 +254,40 @@ } 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) { @@ -302,6 +336,15 @@ error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); if (error) return (error); + + 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)) { /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -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); } /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c @@ -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 diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c @@ -64,6 +64,7 @@ #include #include #include +#include #include 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,13 +720,34 @@ struct tmpnode *tp = (struct tmpnode *)VTOTN(vp); int error = 0; struct vattr *get; + xvattr_t *xvap; 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) { + xvap = (xvattr_t *)vap; + 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); + } mutex_enter(&tp->tn_tlock); @@ -937,6 +960,7 @@ struct tmpnode *self; int error; struct tmpnode *oldtp; + security_id_t secid; again: parent = (struct tmpnode *)VTOTN(dvp); @@ -1021,6 +1045,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 +1085,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); @@ -1300,6 +1330,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 +1368,7 @@ } rw_exit(&parent->tn_rwlock); *vpp = TNTOV(self); + fmac_vnode_post_create(*vpp, secid); return (0); } diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -88,6 +88,7 @@ int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); 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); -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Oct 9 07:15:26 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 10:15:26 -0400 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support In-Reply-To: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-09 at 09:57 -0400, Stephen Smalley wrote: > Revised patch for labeled tmpfs support that takes into account Mark's > concern with making sure that trying to set other system attributes > still fails with EINVAL. Actually, this doesn't yield the desired behavior - we'll get EINVAL on setting other system attributes (as desired), but we'll also get EINVAL on cp -p or mv of any ZFS file to tmpfs even if no system attributes were ever explicitly set on the ZFS file because cp/mv will request all attributes and zfs_getattr() will supply values for all of them, even ones that are zero/unset (plus the create time, which I suppose always has a value). Why is it that callers rely on getting EINVAL vs. checking the return flags set by XVA_SET_RTN() to determine whether the attributes of interest were actually set? If we could eliminate the need for returning EINVAL but only call XVA_SET_RTN() for the secctx, then the caller could still probe for support for setting the DOS attributes based on the return flags. > When we rebase to snv_100+ we will further > need to address his other concern with respect to tmpfs no longer > registering support for VFSFT_XVATTR; we will either need to introduce a > separate VFSFT_XVATTR_SECCTX feature at that point or implement full > xvattr support in tmpfs. > > The root directory of a tmpfs mount is initially labeled from the mount > point directory, as with the existing uid/gid/mode assignment. Thus, > for example, one can umount /tmp from single-user mode and setfilecon > the mount point directory to system_u:object_r:tmp_t in order to get the > tmpfs mount to pick up that context on subsequent mounts. However, > unmounting other tmpfs mounts didn't seem to be possible even from > single user mode, so we may have to relabel them at boot after the tmpfs > mount is created. > > Files and directories created in the tmpfs mount are then labeled via > the fmac_vnode_create and post_create hooks as in ZFS, except that we do > not need to set up an xvattr on the file creation code path since there > is no storage of the secctx and we only need to set up the incore secid > on the vnode. > > Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the > secctx from the secid in order to pass back to userspace. Upon > tmp_setattr, if an xvattr is passed and _only_ the XAT_SECCTX attribute > is requested, then the existing call to secpolicy_vnode_setattr -> > secpolicy_xvattr will ultimately reach fmac_vnode_set_secctx() as with > ZFS in order to check permissions and update the secid. > > A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a > FMAC permission check whenever the existing tmpfs permission checks > would grant access. This uses conventional modes and thus does not pass > V_ACE_MASK. A call to fmac_vnode_remove() is inserted into > tmp_sticky_remove_access() as an initial cut at mediating removal of > files in tmpfs, although this may need to be taken to the callers when > rename checking is introduced. > > Webrev available at: http://cr.opensolaris.org/~sds/tmpfs2/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -254,6 +254,40 @@ > } > > 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) > { > @@ -302,6 +336,15 @@ > error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); > if (error) > return (error); > + > + 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)) { > /* > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c > @@ -42,6 +42,7 @@ > #include > #include > #include > +#include > #include > #include > > @@ -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); > } > > /* > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > @@ -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 > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > @@ -64,6 +64,7 @@ > #include > #include > #include > +#include > #include > > 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,13 +720,34 @@ > struct tmpnode *tp = (struct tmpnode *)VTOTN(vp); > int error = 0; > struct vattr *get; > + xvattr_t *xvap; > 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) { > + xvap = (xvattr_t *)vap; > + 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); > + } > > mutex_enter(&tp->tn_tlock); > > @@ -937,6 +960,7 @@ > struct tmpnode *self; > int error; > struct tmpnode *oldtp; > + security_id_t secid; > > again: > parent = (struct tmpnode *)VTOTN(dvp); > @@ -1021,6 +1045,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 +1085,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); > @@ -1300,6 +1330,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 +1368,7 @@ > } > rw_exit(&parent->tn_rwlock); > *vpp = TNTOV(self); > + fmac_vnode_post_create(*vpp, secid); > return (0); > } > > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -88,6 +88,7 @@ > int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); > 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); > -- Stephen Smalley National Security Agency From john.weeks at sun.com Thu Oct 9 07:19:59 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 07:19:59 -0700 Subject: [fmac-discuss] [PATCH] Move create hooks into filesystem code, mediate open of existing file In-Reply-To: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> References: <1223302453.7712.47.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE130F.90004@sun.com> Acked-by: John Weeks On 10/06/08 07:14, Stephen Smalley wrote: > Move the fmac_vnode_create() and post_create() hooks from fop_create() > into zfs_create() so that they are only applied on new file creation, > and call the fmac_vnode_access() hook from zfs_create() when opening an > existing file. Similar hooking will be needed for other filesystem > types like tmpfs as well. > > Also move the corresponding hook calls from fop_mkdir() into zfs_mkdir() > for consistency with create although we don't have the same problem > there with distinguishing create from open at the fop layer. > > The wrapping of the vattr with an xvattr is put back into > fmac_vnode_create() as it was before. Ultimately all callers of > VOP_CREATE will likely be changed to pass xvattrs in the first place, > thereby eliminating the need for such wrapping by the FMAC code. > > Taking the call to fmac_vnode_access() into zfs_zaccess() will be > explored in subsequent patches. > > Webrev is available at: http://cr.opensolaris.org/~sds/create/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -260,6 +260,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 +278,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); > > @@ -301,33 +302,28 @@ > 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 (!(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); > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -378,6 +378,18 @@ > xvap->xva_magic = XVA_MAGIC; > xvap->xva_vattr.va_mask = AT_XVATTR; > xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0]; > +} > + > +/* > + * 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; > } > > /* > @@ -3367,8 +3379,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) { > @@ -3382,17 +3392,12 @@ > (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && > 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)); > @@ -3499,8 +3504,6 @@ > int flags, > vsecattr_t *vsecp) /* ACL to set during create */ > { > - xvattr_t xvattr; > - security_id_t secid; > int ret; > > if (vsecp != NULL && > @@ -3515,17 +3518,12 @@ > (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && > 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, > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -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 > @@ -1240,6 +1242,11 @@ > if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { > 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 > @@ -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; > > @@ -1324,6 +1332,10 @@ > if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) { > goto out; > } > + > + error = fmac_vnode_access(ZTOV(zp), mode, aflags, cr, B_TRUE); > + if (error) > + goto out; > > mutex_enter(&dzp->z_lock); > dzp->z_seq++; > @@ -1610,6 +1622,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); > > @@ -1660,6 +1674,13 @@ > } > > if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) { > + zfs_dirent_unlock(dl); > + ZFS_EXIT(zfsvfs); > + return (error); > + } > + > + error = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); > + if (error) { > zfs_dirent_unlock(dl); > ZFS_EXIT(zfsvfs); > return (error); > @@ -1733,6 +1754,8 @@ > if (fuidp) > zfs_fuid_info_free(fuidp); > dmu_tx_commit(tx); > + > + fmac_vnode_post_create(ZTOV(zp), secid); > > zfs_dirent_unlock(dl); > > diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h > --- a/usr/src/uts/common/sys/vnode.h > +++ b/usr/src/uts/common/sys/vnode.h > @@ -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 */ > > > From john.weeks at sun.com Thu Oct 9 07:20:51 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 07:20:51 -0700 Subject: [fmac-discuss] [PATCH] Move fmac_vnode_access() hook to zfs_zaccess() In-Reply-To: <1223322865.7712.106.camel@moss-spartans.epoch.ncsc.mil> References: <1223322865.7712.106.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE1343.8050305@sun.com> Acked-by: John Weeks On 10/06/08 12:54, Stephen Smalley wrote: > Extend fmac_vnode_access() to understand ACE masks as well as > traditional modes, and move the calls to it from fop_access() and > zfs_create() into zfs_zaccess(). The access functions of other > filesystems would need to be similarly instrumented, although they can > pass conventional modes rather than ACE masks since fmac_vnode_access() > understands both and distinguishes them based on flags. > > Note btw that extending fmac_vnode_access() to understand ACE masks is > required regardless of whether we call it from fop_access() or > zfs_zaccess() since callers of VOP_ACCESS() can pass ACE masks (as in > the nfs4 and smbsrv cases). > > fmac_vnode_access() is only called if the normal zfs_zaccess() logic > would grant the access (i.e. either the base DAC logic or the secpolicy > hook authorized it). The secpolicy hook is not allowed to override a > FMAC denial. > > One immediate benefit of taking the FMAC hook into zfs_zaccess is that > we get proper checking against the base file when a named attribute is > accessed, e.g. runat /etc/passwd cp /tmp/foo attr.1 fails as expected > with a setattr denial. We also gain more complete coverage of file > operations. > > I looked at moving the fmac_vnode_access() hook inside of > zfs_zaccess_common(), but it seemed better to do it in zfs_zaccess() > because: > 1) We can then place it after both the base DAC logic and the privilege > check. > 2) We do not gain any benefit from checking all calls to > zfs_zaccess_common() since other callers like zfs_zaccess_delete() and > _rename() short-circuit their checking if access to the directory is > granted, whereas we want checking against the target file in all cases > and thus still need our separate hooks for those operations. > > Some of the other FMAC checks may be obsoleted by taking > fmac_vnode_access() into zfs_zaccess(), but this requires a case-by-case > review and testing as callers of zfs_zaccess() do not always honor a > denial from it (can be overridden by other secpolicy calls), as in the > setattr case. > > This is relative to the prior patch for the create hooks. > > Webrev is available at: > http://cr.opensolaris.org/~sds/zaccess/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -35,6 +35,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -549,6 +550,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) > @@ -568,17 +580,42 @@ > 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, 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) > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -3315,9 +3315,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 > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -42,6 +42,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -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) > @@ -2423,6 +2421,11 @@ > } > } > } > + > +out: > + if (!error) > + error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, > + B_TRUE); > > if (is_attr) > VN_RELE(ZTOV(xzp)); > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -1333,10 +1333,6 @@ > goto out; > } > > - error = fmac_vnode_access(ZTOV(zp), mode, aflags, cr, B_TRUE); > - if (error) > - goto out; > - > mutex_enter(&dzp->z_lock); > dzp->z_seq++; > mutex_exit(&dzp->z_lock); > From john.weeks at sun.com Thu Oct 9 07:21:40 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 07:21:40 -0700 Subject: [fmac-discuss] [PATCH] Distinguish append vs. write in fmac_vnode_access() In-Reply-To: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> References: <1223387511.29420.7.camel@moss-clownfish.epoch.ncsc.mil> Message-ID: <48EE1374.5020502@sun.com> Acked-by: John Weeks On 10/07/08 06:51, Stephen Smalley wrote: > The prior patch that extended fmac_vnode_access() to understand ACE > masks and moved the call to it from fop_access() to zfs_zaccess() did > not properly distinguish append vs. write access unlike the original > fmac_vnode_access() handling of traditional modes. This patch, on top > of the prior one, passes the flags down from zfs_zaccess() to > fmac_vnode_access() and handles the V_APPEND flag by remapping > ACE_WRITE_DATA mode to FILE__APPEND permission when it is set. > > Webrev is available at: http://cr.opensolaris.org/~sds/append > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -554,7 +554,7 @@ > if (mode & (mask)) { \ > mode &= ~(mask); \ > av |= (perm); \ > - } \ > + } > > #define ACE_GETATTR_MASK (ACE_READ_NAMED_ATTRS | ACE_READ_ATTRIBUTES | \ > ACE_READ_ACL) > @@ -594,7 +594,8 @@ > 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, FILE__WRITE); > + 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); > } > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -2424,8 +2424,8 @@ > > out: > if (!error) > - error = fmac_vnode_access(ZTOV(check_zp), mode, V_ACE_MASK, cr, > - B_TRUE); > + error = fmac_vnode_access(ZTOV(check_zp), mode, > + flags|V_ACE_MASK, cr, B_TRUE); > > if (is_attr) > VN_RELE(ZTOV(xzp)); > > > _______________________________________________ > fmac-discuss mailing list > fmac-discuss at opensolaris.org > http://mail.opensolaris.org/mailman/listinfo/fmac-discuss From Mark.Shellenbaum at Sun.COM Thu Oct 9 07:44:43 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 08:44:43 -0600 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support In-Reply-To: <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE18DB.8080003@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-09 at 09:57 -0400, Stephen Smalley wrote: >> Revised patch for labeled tmpfs support that takes into account Mark's >> concern with making sure that trying to set other system attributes >> still fails with EINVAL. > > Actually, this doesn't yield the desired behavior - we'll get EINVAL on > setting other system attributes (as desired), but we'll also get EINVAL > on cp -p or mv of any ZFS file to tmpfs even if no system attributes > were ever explicitly set on the ZFS file because cp/mv will request all > attributes and zfs_getattr() will supply values for all of them, even > ones that are zero/unset (plus the create time, which I suppose always > has a value). > > Why is it that callers rely on getting EINVAL vs. checking the return > flags set by XVA_SET_RTN() to determine whether the attributes of > interest were actually set? If we could eliminate the need for > returning EINVAL but only call XVA_SET_RTN() for the secctx, then the > caller could still probe for support for setting the DOS attributes > based on the return flags. > Actually its a bug that xattr_file_write() doesn't check XVA_SET_RTN() after doing the VOP_SETATTR(). I will open a bug for this. I would suspect that cp -p is failing because it tries to preserve the security context. There is a helper function that mv/cp uses called sysattr_list that determines whether or not the sysattrs are in a "default" or trivial state. Since the security context will be present the cp code will attempt to preserve all of the attributes. -Mark From john.weeks at sun.com Thu Oct 9 10:19:05 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 10:19:05 -0700 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support In-Reply-To: <48EE1ED7.3000104@Sun.COM> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <48EE1ED7.3000104@Sun.COM> Message-ID: <48EE3D09.40204@sun.com> >> I would suspect that cp -p is failing because it tries to preserve the >> security context. There is a helper function that mv/cp uses called >> sysattr_list that determines whether or not the sysattrs are in a >> "default" or trivial state. Since the security context will be >> present the cp code will attempt to preserve all of the attributes. >> >> -Mark > > In looking at sysattr_list() I think that probably what it should do is > return a list of *just* the non-default attributes. Then when > fsetattr()/setattrat() is called only a subset of the attributes would > be written to the SUNWattr_rw file. This function is in libcmdutils. > > -Mark This sounds like it would fix mv and friends, but what about other consumers of the system attribute get/set interfaces. Do we need to worry about the case where one gets the current list of attributes, add/mods the list, then passes the list to fsetattr()/setattrat()? I looked at the fgetattr(3C) man page and I didn't see anything that indicated that this was invalid. Should we allow set requests if the requested value is the same as what the attribute is already set to? diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -235,6 +235,10 @@ * Relabeling an existing file. */ mutex_enter(&(vp->v_lock)); + if (vp->v_secid == new_secid) { + mutex_exit(&(vp->v_lock)); + return (0); + } old_secid = vp->v_secid; error = avc_has_perm(cr_secid, old_secid, sclass, FILE__RELABELFROM); diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -2599,26 +2599,56 @@ oldva.va_mode = pzp->zp_mode; zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid); if (mask & AT_XVATTR) { + + if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && + xoap->xoa_appendonly != + ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_APPENDONLY); + } + + if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && + xoap->xoa_nounlink != + ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_NOUNLINK); + } + + if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && + xoap->xoa_immutable != + ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_IMMUTABLE); + } + + if (XVA_ISSET_REQ(xvap, XAT_NODUMP) && + xoap->xoa_nodump != + ((pzp->zp_flags & ZFS_NODUMP) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_NODUMP); + } + + if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && + xoap->xoa_av_modified != + ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_AV_MODIFIED); + } + + if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && + xoap->xoa_av_quarantined != + ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_AV_QUARANTINED); + } + if ((need_policy == FALSE) && - (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && - xoap->xoa_appendonly != - ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) || - (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && - xoap->xoa_nounlink != - ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) || - (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && - xoap->xoa_immutable != - ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) || - (XVA_ISSET_REQ(xvap, XAT_NODUMP) && - xoap->xoa_nodump != - ((pzp->zp_flags & ZFS_NODUMP) != 0)) || - (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && - xoap->xoa_av_modified != - ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) || - ((XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && - ((vp->v_type != VREG && xoap->xoa_av_quarantined) || - xoap->xoa_av_quarantined != - ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -623,6 +623,15 @@ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \ ASSERT((xvap)->xva_magic == XVA_MAGIC); \ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr) + +/* + * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap + * of requested attributes (xva_reqattrmap[]). + */ +#define XVA_CLR_REQ(xvap, attr) \ + ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \ + ASSERT((xvap)->xva_magic == XVA_MAGIC); \ + (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr) /* * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap -John From john.weeks at sun.com Thu Oct 9 11:22:08 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 11:22:08 -0700 Subject: [fmac-discuss] rm (zfs_remove) failing Message-ID: <48EE4BD0.1000807@sun.com> Hi, I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? Thanks, John From john.weeks at sun.com Thu Oct 9 11:31:06 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 11:31:06 -0700 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <48EE4BD0.1000807@sun.com> References: <48EE4BD0.1000807@sun.com> Message-ID: <48EE4DEA.9030402@sun.com> On 10/09/08 11:22, John Weeks wrote: > Hi, > > I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. > > We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. > > Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? > > Thanks, > John > _______________________________________________ > fmac-discuss mailing list > fmac-discuss at opensolaris.org > http://mail.opensolaris.org/mailman/listinfo/fmac-discuss Oops, VOP_GETATTR not VOP_LOOKUP. From Mark.Shellenbaum at Sun.COM Thu Oct 9 11:38:27 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 12:38:27 -0600 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support In-Reply-To: <48EE3D09.40204@sun.com> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <48EE1ED7.3000104@Sun.COM> <48EE3D09.40204@sun.com> Message-ID: <48EE4FA3.7000806@Sun.COM> John Weeks wrote: >>> I would suspect that cp -p is failing because it tries to preserve the >>> security context. There is a helper function that mv/cp uses called >>> sysattr_list that determines whether or not the sysattrs are in a >>> "default" or trivial state. Since the security context will be >>> present the cp code will attempt to preserve all of the attributes. >>> >>> -Mark >> In looking at sysattr_list() I think that probably what it should do is >> return a list of *just* the non-default attributes. Then when >> fsetattr()/setattrat() is called only a subset of the attributes would >> be written to the SUNWattr_rw file. This function is in libcmdutils. >> >> -Mark > > This sounds like it would fix mv and friends, but what about other consumers of the system attribute get/set interfaces. Do we need to worry about the case where one gets the current list of attributes, add/mods the list, then passes the list to fsetattr()/setattrat()? I looked at the fgetattr(3C) man page and I didn't see anything that indicated that this was invalid. > Yes, that is allowed. You don't need to use getattrat() to create the list of attributes. For example chmod(1) just creates a list of what you want to set and calls setattrat(). > Should we allow set requests if the requested value is the same as what the attribute is already set to? I believe so. This is the way it currently works, and then the file system can do proper locking to verify what is actually changing. -Mark From Mark.Shellenbaum at Sun.COM Thu Oct 9 11:42:19 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 12:42:19 -0600 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <48EE4BD0.1000807@sun.com> References: <48EE4BD0.1000807@sun.com> Message-ID: <48EE508B.5060004@Sun.COM> John Weeks wrote: > Hi, > > I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. > > We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. > > Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? > > Thanks, > John Let me make sure I'm following you on this. We created a file and set the SECCTX during the create of the file. But the vnode doesn't have the v_secid populated because you haven't yet done the VOP_GETATTR to retrieve it? If thats the case then I would think that as part of create operation in zfs_xvattr_set() it should probably set that on the vnode for you. -Mark From sds at tycho.nsa.gov Thu Oct 9 11:47:03 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 14:47:03 -0400 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <48EE18DB.8080003@Sun.COM> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> Message-ID: <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> Per Mark's suggestion, change sysattr_list() in libcmdutils to only return non-default attributes. This appears to fix the problems with cp -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries to set the other system attributes. I just changed the logic to remove any attributes from the response list that had the default values and then return the modified response list rather than immediately returning the entire response list whenever a non-default attribute was found. Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ diff --git a/usr/src/lib/libcmdutils/common/process_xattrs.c b/usr/src/lib/libcmdutils/common/process_xattrs.c --- a/usr/src/lib/libcmdutils/common/process_xattrs.c +++ b/usr/src/lib/libcmdutils/common/process_xattrs.c @@ -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); -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Oct 9 11:52:09 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 14:52:09 -0400 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <48EE508B.5060004@Sun.COM> References: <48EE4BD0.1000807@sun.com> <48EE508B.5060004@Sun.COM> Message-ID: <1223578329.20579.18.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-09 at 12:42 -0600, Mark Shellenbaum wrote: > John Weeks wrote: > > Hi, > > > > I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. > > > > We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. > > > > Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? > > > > Thanks, > > John > > Let me make sure I'm following you on this. > > We created a file and set the SECCTX during the create of the file. But > the vnode doesn't have the v_secid populated because you haven't yet > done the VOP_GETATTR to retrieve it? > > If thats the case then I would think that as part of create operation in > zfs_xvattr_set() it should probably set that on the vnode for you. fmac_vnode_post_create() hook sets the secid on the vnode at create time. Called from zfs_create() and zfs_mkdir() presently. I think the situation here is a file that was created at some prior time is being fetched via zfs_dirent_lock() on the remove, rename, or create (for existing file) cases, and since that doesn't go through fop_lookup(), it doesn't get caught by our fmac_vnode_lookup() hook there. So we need a hook in the filesystem lookup code, maybe in zfs_dirent_lock(). -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 9 11:55:40 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 12:55:40 -0600 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <1223578329.20579.18.camel@moss-spartans.epoch.ncsc.mil> References: <48EE4BD0.1000807@sun.com> <48EE508B.5060004@Sun.COM> <1223578329.20579.18.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE53AC.9060005@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-09 at 12:42 -0600, Mark Shellenbaum wrote: >> John Weeks wrote: >>> Hi, >>> >>> I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. >>> >>> We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. >>> >>> Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? >>> >>> Thanks, >>> John >> Let me make sure I'm following you on this. >> >> We created a file and set the SECCTX during the create of the file. But >> the vnode doesn't have the v_secid populated because you haven't yet >> done the VOP_GETATTR to retrieve it? >> >> If thats the case then I would think that as part of create operation in >> zfs_xvattr_set() it should probably set that on the vnode for you. > > fmac_vnode_post_create() hook sets the secid on the vnode at create > time. Called from zfs_create() and zfs_mkdir() presently. > > I think the situation here is a file that was created at some prior time > is being fetched via zfs_dirent_lock() on the remove, rename, or create > (for existing file) cases, and since that doesn't go through > fop_lookup(), it doesn't get caught by our fmac_vnode_lookup() hook > there. So we need a hook in the filesystem lookup code, maybe in > zfs_dirent_lock(). > Ok, that makes sense then. You may want to just hook it in zfs_zget() then, since there are other places besides zfs_dirent_lock() that may fetch the znode. This is usually for an extended attribute file/dir in zfs_setattr() and for access control on an extended attribute. -Mark From sds at tycho.nsa.gov Thu Oct 9 11:59:40 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 14:59:40 -0400 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <48EE53AC.9060005@Sun.COM> References: <48EE4BD0.1000807@sun.com> <48EE508B.5060004@Sun.COM> <1223578329.20579.18.camel@moss-spartans.epoch.ncsc.mil> <48EE53AC.9060005@Sun.COM> Message-ID: <1223578780.20579.19.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-09 at 12:55 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Thu, 2008-10-09 at 12:42 -0600, Mark Shellenbaum wrote: > >> John Weeks wrote: > >>> Hi, > >>> > >>> I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. > >>> > >>> We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. > >>> > >>> Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? > >>> > >>> Thanks, > >>> John > >> Let me make sure I'm following you on this. > >> > >> We created a file and set the SECCTX during the create of the file. But > >> the vnode doesn't have the v_secid populated because you haven't yet > >> done the VOP_GETATTR to retrieve it? > >> > >> If thats the case then I would think that as part of create operation in > >> zfs_xvattr_set() it should probably set that on the vnode for you. > > > > fmac_vnode_post_create() hook sets the secid on the vnode at create > > time. Called from zfs_create() and zfs_mkdir() presently. > > > > I think the situation here is a file that was created at some prior time > > is being fetched via zfs_dirent_lock() on the remove, rename, or create > > (for existing file) cases, and since that doesn't go through > > fop_lookup(), it doesn't get caught by our fmac_vnode_lookup() hook > > there. So we need a hook in the filesystem lookup code, maybe in > > zfs_dirent_lock(). > > > > Ok, that makes sense then. You may want to just hook it in zfs_zget() > then, since there are other places besides zfs_dirent_lock() that may > fetch the znode. This is usually for an extended attribute file/dir in > zfs_setattr() and for access control on an extended attribute. Is there any problem with calling VOP_GETATTR() from zfs_zget()? -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 9 11:57:24 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 12:57:24 -0600 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE5414.9030100@Sun.COM> Stephen Smalley wrote: > Per Mark's suggestion, change sysattr_list() in libcmdutils to only > return non-default attributes. This appears to fix the problems with cp > -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries > to set the other system attributes. > > I just changed the logic to remove any attributes from the response list > that had the default values and then return the modified response list > rather than immediately returning the entire response list whenever a > non-default attribute was found. > > Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ > This looks fine. -Mark From Mark.Shellenbaum at Sun.COM Thu Oct 9 12:09:21 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 13:09:21 -0600 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <1223578780.20579.19.camel@moss-spartans.epoch.ncsc.mil> References: <48EE4BD0.1000807@sun.com> <48EE508B.5060004@Sun.COM> <1223578329.20579.18.camel@moss-spartans.epoch.ncsc.mil> <48EE53AC.9060005@Sun.COM> <1223578780.20579.19.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE56E1.2050601@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-09 at 12:55 -0600, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> On Thu, 2008-10-09 at 12:42 -0600, Mark Shellenbaum wrote: >>>> John Weeks wrote: >>>>> Hi, >>>>> >>>>> I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. >>>>> >>>>> We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. >>>>> >>>>> Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? >>>>> >>>>> Thanks, >>>>> John >>>> Let me make sure I'm following you on this. >>>> >>>> We created a file and set the SECCTX during the create of the file. But >>>> the vnode doesn't have the v_secid populated because you haven't yet >>>> done the VOP_GETATTR to retrieve it? >>>> >>>> If thats the case then I would think that as part of create operation in >>>> zfs_xvattr_set() it should probably set that on the vnode for you. >>> fmac_vnode_post_create() hook sets the secid on the vnode at create >>> time. Called from zfs_create() and zfs_mkdir() presently. >>> >>> I think the situation here is a file that was created at some prior time >>> is being fetched via zfs_dirent_lock() on the remove, rename, or create >>> (for existing file) cases, and since that doesn't go through >>> fop_lookup(), it doesn't get caught by our fmac_vnode_lookup() hook >>> there. So we need a hook in the filesystem lookup code, maybe in >>> zfs_dirent_lock(). >>> >> Ok, that makes sense then. You may want to just hook it in zfs_zget() >> then, since there are other places besides zfs_dirent_lock() that may >> fetch the znode. This is usually for an extended attribute file/dir in >> zfs_setattr() and for access control on an extended attribute. > > Is there any problem with calling VOP_GETATTR() from zfs_zget()? > I wouldn't recommend calling VOP_GETATTR() from zfs_zget(). There are two locks that could give you problems, and you also could deadlock if the file has a non-trivial ACL. You shouldn't need to call it for all zget()'s, just the ones that actually need to allocate a znode/vnode pair. Can't you just grab the SECCTX and call the appropriate fmac routine? -Mark From john.weeks at sun.com Thu Oct 9 12:12:33 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 12:12:33 -0700 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <48EE508B.5060004@Sun.COM> References: <48EE4BD0.1000807@sun.com> <48EE508B.5060004@Sun.COM> Message-ID: <48EE57A1.20701@sun.com> On 10/09/08 11:42, Mark Shellenbaum wrote: > John Weeks wrote: >> Hi, >> >> I'm seeing random FMAC policy denials when removing files on ZFS file >> systems because v_secid has not yet been set to its real value based >> on SECCTX. The general problem is that fmac_vnode_lookup() may not >> have been called before zfs_zaccess() which can cause a policy denial >> since the default context is set to system_u:object_r:unlabeled_t when >> the initial vnode is allocated. If the vnode is already in the dnlc, >> it seems to be OK and probably explains the randomness of the failures. >> >> We could move the initialization of v_secid closer to where the >> vnode/znode is created, but I'm a little concerned about lock >> contention problems since the current implementation of >> fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. >> >> Mark, do you have any recommendations? Should we be going through VOP >> to set v_secid or just set it directly in the file system >> implementations? >> >> Thanks, >> John > > Let me make sure I'm following you on this. > > We created a file and set the SECCTX during the create of the file. But > the vnode doesn't have the v_secid populated because you haven't yet > done the VOP_GETATTR to retrieve it? File creation is OK and SECCTX is set accordingly. It's the case where zfs_remove (and possibly others) don't set v_secid from SECCTX before doing access checks because they don't go through fop_lookup (where fmac-vnode_lookup is called to set v_secid) when the entry is not found in the dnlc. If the file was previously brought into the dnlc via lookup, the v_secid was already set by the fmac_vnode_lookup hook in fop_lookup and the zfs_remove is OK. So the sequence that's causing the problem is: file is created and SECCTX is set file vnode is eventually removed from the dnlc file is removed (remove(2) or unlink(2) called) zfs_remove gets the znode (internal lookup), but v_secid is not set because it doesn't go through VOP_LOOKUP zfs_remove calls zfs_zaccess that fails because v_secid has not be set from SECCTX > > If thats the case then I would think that as part of create operation in > zfs_xvattr_set() it should probably set that on the vnode for you. > > -Mark From sds at tycho.nsa.gov Thu Oct 9 12:17:12 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 15:17:12 -0400 Subject: [fmac-discuss] rm (zfs_remove) failing In-Reply-To: <48EE56E1.2050601@Sun.COM> References: <48EE4BD0.1000807@sun.com> <48EE508B.5060004@Sun.COM> <1223578329.20579.18.camel@moss-spartans.epoch.ncsc.mil> <48EE53AC.9060005@Sun.COM> <1223578780.20579.19.camel@moss-spartans.epoch.ncsc.mil> <48EE56E1.2050601@Sun.COM> Message-ID: <1223579832.20579.31.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-09 at 13:09 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Thu, 2008-10-09 at 12:55 -0600, Mark Shellenbaum wrote: > >> Stephen Smalley wrote: > >>> On Thu, 2008-10-09 at 12:42 -0600, Mark Shellenbaum wrote: > >>>> John Weeks wrote: > >>>>> Hi, > >>>>> > >>>>> I'm seeing random FMAC policy denials when removing files on ZFS file systems because v_secid has not yet been set to its real value based on SECCTX. The general problem is that fmac_vnode_lookup() may not have been called before zfs_zaccess() which can cause a policy denial since the default context is set to system_u:object_r:unlabeled_t when the initial vnode is allocated. If the vnode is already in the dnlc, it seems to be OK and probably explains the randomness of the failures. > >>>>> > >>>>> We could move the initialization of v_secid closer to where the vnode/znode is created, but I'm a little concerned about lock contention problems since the current implementation of fmac_vnode_lookup will reenter ZFS through VOP_LOOKUP. > >>>>> > >>>>> Mark, do you have any recommendations? Should we be going through VOP to set v_secid or just set it directly in the file system implementations? > >>>>> > >>>>> Thanks, > >>>>> John > >>>> Let me make sure I'm following you on this. > >>>> > >>>> We created a file and set the SECCTX during the create of the file. But > >>>> the vnode doesn't have the v_secid populated because you haven't yet > >>>> done the VOP_GETATTR to retrieve it? > >>>> > >>>> If thats the case then I would think that as part of create operation in > >>>> zfs_xvattr_set() it should probably set that on the vnode for you. > >>> fmac_vnode_post_create() hook sets the secid on the vnode at create > >>> time. Called from zfs_create() and zfs_mkdir() presently. > >>> > >>> I think the situation here is a file that was created at some prior time > >>> is being fetched via zfs_dirent_lock() on the remove, rename, or create > >>> (for existing file) cases, and since that doesn't go through > >>> fop_lookup(), it doesn't get caught by our fmac_vnode_lookup() hook > >>> there. So we need a hook in the filesystem lookup code, maybe in > >>> zfs_dirent_lock(). > >>> > >> Ok, that makes sense then. You may want to just hook it in zfs_zget() > >> then, since there are other places besides zfs_dirent_lock() that may > >> fetch the znode. This is usually for an extended attribute file/dir in > >> zfs_setattr() and for access control on an extended attribute. > > > > Is there any problem with calling VOP_GETATTR() from zfs_zget()? > > > > I wouldn't recommend calling VOP_GETATTR() from zfs_zget(). > There are two locks that could give you problems, and you also could > deadlock if the file has a non-trivial ACL. > > You shouldn't need to call it for all zget()'s, just the ones that > actually need to allocate a znode/vnode pair. Can't you just grab the > SECCTX and call the appropriate fmac routine? Yes, we likely can introduce a separate fmac hook for this purpose that takes the secctx as input, possibly a fmac_vnode_init_secid() or something. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Oct 9 12:19:11 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 15:19:11 -0400 Subject: [fmac-discuss] [PATCH v3] Labeled tmpfs support Message-ID: <1223579951.20579.34.camel@moss-spartans.epoch.ncsc.mil> Take 3 of the labeled tmpfs support. With the change to sysattr_list(), it is no longer a problem to return EINVAL on any of the default system attributes in tmp_setattr. We will still need to address the removal of VFSFT_XVATTR from tmpfs when we rebase to snv_100+ by introducing a VFSFT_XVATTR_SECCTX or implementing the default system attributes in tmpfs. The root directory of a tmpfs mount is initially labeled from the mount point directory, as with the existing uid/gid/mode assignment. Thus, for example, one can umount /tmp from single-user mode and setfilecon the mount point directory to system_u:object_r:tmp_t in order to get the tmpfs mount to pick up that context on subsequent mounts. John also found that we can label the other tmpfs mount points by moving setfiles to /sbin and invoking it from /lib/svc/method/fs-minimal on /tmp, /var/run and any other tmpfs mount points. Files and directories created in the tmpfs mount are then labeled via the fmac_vnode_create and post_create hooks as in ZFS, except that we do not need to set up an xvattr on the file creation code path since there is no storage of the secctx and we only need to set up the incore secid on the vnode. Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the secctx from the secid in order to pass back to userspace. Upon tmp_setattr, the secpolicy hook will ultimately call fmac_vnode_set_secctx() and update the vnode secid, so we only need to set the return flag for XAT_SECCTX. A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a FMAC permission check whenever the existing tmpfs permission checks would grant access. This uses conventional modes and thus does not pass V_ACE_MASK. A call to fmac_vnode_remove() is inserted into tmp_sticky_remove_access() as an initial cut at mediating removal of files in tmpfs, although this may need to be taken to the callers when rename checking is introduced. Webrev at: http://cr.opensolaris.org/~sds/tmpfs3/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -254,6 +254,40 @@ } 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) { @@ -302,6 +336,15 @@ error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); if (error) return (error); + + 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)) { /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -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); } /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c @@ -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 diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c @@ -64,6 +64,7 @@ #include #include #include +#include #include 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,13 +720,33 @@ 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); + } mutex_enter(&tp->tn_tlock); @@ -740,6 +762,11 @@ goto out; 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; @@ -937,6 +964,7 @@ struct tmpnode *self; int error; struct tmpnode *oldtp; + security_id_t secid; again: parent = (struct tmpnode *)VTOTN(dvp); @@ -1021,6 +1049,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 +1089,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); @@ -1300,6 +1334,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 +1372,7 @@ } rw_exit(&parent->tn_rwlock); *vpp = TNTOV(self); + fmac_vnode_post_create(*vpp, secid); return (0); } diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -88,6 +88,7 @@ int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); 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); -- Stephen Smalley National Security Agency From john.weeks at sun.com Thu Oct 9 12:43:25 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 12:43:25 -0700 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <48EE5414.9030100@Sun.COM> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> <48EE5414.9030100@Sun.COM> Message-ID: <48EE5EDD.3060602@sun.com> On 10/09/08 11:57, Mark Shellenbaum wrote: > Stephen Smalley wrote: >> Per Mark's suggestion, change sysattr_list() in libcmdutils to only >> return non-default attributes. This appears to fix the problems with cp >> -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries >> to set the other system attributes. >> >> I just changed the logic to remove any attributes from the response list >> that had the default values and then return the modified response list >> rather than immediately returning the entire response list whenever a >> non-default attribute was found. >> >> Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ >> > > This looks fine. > > -Mark > Am I just dense or does the patch remove the other system attributes (e.g., NOUNLINK, IMMUTABLE, APPENDONLY, ...) from the list without actually examining their values to determine if they were set to the defaults? -John From Mark.Shellenbaum at Sun.COM Thu Oct 9 12:44:36 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 13:44:36 -0600 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <48EE5EDD.3060602@sun.com> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> <48EE5414.9030100@Sun.COM> <48EE5EDD.3060602@sun.com> Message-ID: <48EE5F24.1010405@Sun.COM> John Weeks wrote: > On 10/09/08 11:57, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> Per Mark's suggestion, change sysattr_list() in libcmdutils to only >>> return non-default attributes. This appears to fix the problems with cp >>> -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries >>> to set the other system attributes. >>> >>> I just changed the logic to remove any attributes from the response list >>> that had the default values and then return the modified response list >>> rather than immediately returning the entire response list whenever a >>> non-default attribute was found. >>> >>> Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ >>> >> This looks fine. >> >> -Mark >> > > Am I just dense or does the patch remove the other system attributes (e.g., NOUNLINK, IMMUTABLE, APPENDONLY, ...) from the list without actually examining their values to determine if they were set to the defaults? > > -John I think your right, it will fall out of the switch statement for those. -Mark From sds at tycho.nsa.gov Thu Oct 9 12:51:51 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 09 Oct 2008 15:51:51 -0400 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <48EE5EDD.3060602@sun.com> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> <48EE5414.9030100@Sun.COM> <48EE5EDD.3060602@sun.com> Message-ID: <1223581911.20579.42.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-09 at 12:43 -0700, John Weeks wrote: > On 10/09/08 11:57, Mark Shellenbaum wrote: > > Stephen Smalley wrote: > >> Per Mark's suggestion, change sysattr_list() in libcmdutils to only > >> return non-default attributes. This appears to fix the problems with cp > >> -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries > >> to set the other system attributes. > >> > >> I just changed the logic to remove any attributes from the response list > >> that had the default values and then return the modified response list > >> rather than immediately returning the entire response list whenever a > >> non-default attribute was found. > >> > >> Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ > >> > > > > This looks fine. > > > > -Mark > > > > Am I just dense or does the patch remove the other system attributes > (e.g., NOUNLINK, IMMUTABLE, APPENDONLY, ...) from the list without > actually examining their values to determine if they were set to the > defaults? It still tests value as in the original logic. The original logic would return immediately with the entire response list if value was set; the new logic proceeds to the next nvpair without removing the current one if the value is set. The default case of the switch statement also jumps to next, skipping over removing the entry. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 9 12:52:04 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 13:52:04 -0600 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <48EE5F24.1010405@Sun.COM> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> <48EE5414.9030100@Sun.COM> <48EE5EDD.3060602@sun.com> <48EE5F24.1010405@Sun.COM> Message-ID: <48EE60E4.1040809@Sun.COM> Mark Shellenbaum wrote: > John Weeks wrote: >> On 10/09/08 11:57, Mark Shellenbaum wrote: >>> Stephen Smalley wrote: >>>> Per Mark's suggestion, change sysattr_list() in libcmdutils to only >>>> return non-default attributes. This appears to fix the problems with cp >>>> -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries >>>> to set the other system attributes. >>>> >>>> I just changed the logic to remove any attributes from the response list >>>> that had the default values and then return the modified response list >>>> rather than immediately returning the entire response list whenever a >>>> non-default attribute was found. >>>> >>>> Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ >>>> >>> This looks fine. >>> >>> -Mark >>> >> Am I just dense or does the patch remove the other system attributes (e.g., NOUNLINK, IMMUTABLE, APPENDONLY, ...) from the list without actually examining their values to determine if they were set to the defaults? >> >> -John > > I think your right, it will fall out of the switch statement for those. > Never mind, it goes to next when its not ARCHIVE or MODIFIED. -Mark From john.weeks at sun.com Thu Oct 9 14:04:48 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 09 Oct 2008 14:04:48 -0700 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <48EE60E4.1040809@Sun.COM> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> <48EE5414.9030100@Sun.COM> <48EE5EDD.3060602@sun.com> <48EE5F24.1010405@Sun.COM> <48EE60E4.1040809@Sun.COM> Message-ID: <48EE71F0.1080603@sun.com> On 10/09/08 12:52, Mark Shellenbaum wrote: > Mark Shellenbaum wrote: >> John Weeks wrote: >>> On 10/09/08 11:57, Mark Shellenbaum wrote: >>>> Stephen Smalley wrote: >>>>> Per Mark's suggestion, change sysattr_list() in libcmdutils to only >>>>> return non-default attributes. This appears to fix the problems with cp >>>>> -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries >>>>> to set the other system attributes. >>>>> >>>>> I just changed the logic to remove any attributes from the response list >>>>> that had the default values and then return the modified response list >>>>> rather than immediately returning the entire response list whenever a >>>>> non-default attribute was found. >>>>> >>>>> Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ >>>>> >>>> This looks fine. >>>> >>>> -Mark >>>> >>> Am I just dense or does the patch remove the other system attributes (e.g., NOUNLINK, IMMUTABLE, APPENDONLY, ...) from the list without actually examining their values to determine if they were set to the defaults? >>> >>> -John >> I think your right, it will fall out of the switch statement for those. >> > > Never mind, it goes to next when its not ARCHIVE or MODIFIED. > > -Mark OK, now I get it: if (value && fattr != F_ARCHIVE && fattr != F_AV_MODIFIED) goto next; But it does assume the default value is always 0. From Mark.Shellenbaum at Sun.COM Thu Oct 9 15:08:26 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 09 Oct 2008 16:08:26 -0600 Subject: [fmac-discuss] [PATCH v3] Labeled tmpfs support In-Reply-To: <1223579951.20579.34.camel@moss-spartans.epoch.ncsc.mil> References: <1223579951.20579.34.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EE80DA.1070306@Sun.COM> Stephen Smalley wrote: > Take 3 of the labeled tmpfs support. With the change to sysattr_list(), > it is no longer a problem to return EINVAL on any of the default system > attributes in tmp_setattr. We will still need to address the removal of > VFSFT_XVATTR from tmpfs when we rebase to snv_100+ by introducing a > VFSFT_XVATTR_SECCTX or implementing the default system attributes in > tmpfs. > > The root directory of a tmpfs mount is initially labeled from the mount > point directory, as with the existing uid/gid/mode assignment. Thus, > for example, one can umount /tmp from single-user mode and setfilecon > the mount point directory to system_u:object_r:tmp_t in order to get the > tmpfs mount to pick up that context on subsequent mounts. John also > found that we can label the other tmpfs mount points by moving setfiles > to /sbin and invoking it from /lib/svc/method/fs-minimal > on /tmp, /var/run and any other tmpfs mount points. > > Files and directories created in the tmpfs mount are then labeled via > the fmac_vnode_create and post_create hooks as in ZFS, except that we do > not need to set up an xvattr on the file creation code path since there > is no storage of the secctx and we only need to set up the incore secid > on the vnode. > > Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the > secctx from the secid in order to pass back to userspace. Upon > tmp_setattr, the secpolicy hook will ultimately call > fmac_vnode_set_secctx() and update the vnode secid, so we only need to > set the return flag for XAT_SECCTX. > > A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a > FMAC permission check whenever the existing tmpfs permission checks > would grant access. This uses conventional modes and thus does not pass > V_ACE_MASK. A call to fmac_vnode_remove() is inserted into > tmp_sticky_remove_access() as an initial cut at mediating removal of > files in tmpfs, although this may need to be taken to the callers when > rename checking is introduced. > > Webrev at: http://cr.opensolaris.org/~sds/tmpfs3/ > > Looks ok. -Mark From john.weeks at sun.com Fri Oct 10 00:44:58 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 10 Oct 2008 00:44:58 -0700 Subject: [fmac-discuss] [PATCH] Change sysattr_list() to only return non-default attributes In-Reply-To: <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <1223578023.20579.11.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EF07FA.2030108@sun.com> Acked-by: John Weeks On 10/09/08 11:47, Stephen Smalley wrote: > Per Mark's suggestion, change sysattr_list() in libcmdutils to only > return non-default attributes. This appears to fix the problems with cp > -p and mv from ZFS to ZFS and from ZFS to tmpfs, as it no longer tries > to set the other system attributes. > > I just changed the logic to remove any attributes from the response list > that had the default values and then return the modified response list > rather than immediately returning the entire response list whenever a > non-default attribute was found. > > Webrev at: http://cr.opensolaris.org/~sds/sysattrlist/ > > diff --git a/usr/src/lib/libcmdutils/common/process_xattrs.c b/usr/src/lib/libcmdutils/common/process_xattrs.c > --- a/usr/src/lib/libcmdutils/common/process_xattrs.c > +++ b/usr/src/lib/libcmdutils/common/process_xattrs.c > @@ -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); > From john.weeks at sun.com Fri Oct 10 00:46:39 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 10 Oct 2008 00:46:39 -0700 Subject: [fmac-discuss] [PATCH v3] Labeled tmpfs support In-Reply-To: <1223579951.20579.34.camel@moss-spartans.epoch.ncsc.mil> References: <1223579951.20579.34.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48EF085F.1040108@sun.com> Acked-by: John Weeks On 10/09/08 12:19, Stephen Smalley wrote: > Take 3 of the labeled tmpfs support. With the change to sysattr_list(), > it is no longer a problem to return EINVAL on any of the default system > attributes in tmp_setattr. We will still need to address the removal of > VFSFT_XVATTR from tmpfs when we rebase to snv_100+ by introducing a > VFSFT_XVATTR_SECCTX or implementing the default system attributes in > tmpfs. > > The root directory of a tmpfs mount is initially labeled from the mount > point directory, as with the existing uid/gid/mode assignment. Thus, > for example, one can umount /tmp from single-user mode and setfilecon > the mount point directory to system_u:object_r:tmp_t in order to get the > tmpfs mount to pick up that context on subsequent mounts. John also > found that we can label the other tmpfs mount points by moving setfiles > to /sbin and invoking it from /lib/svc/method/fs-minimal > on /tmp, /var/run and any other tmpfs mount points. > > Files and directories created in the tmpfs mount are then labeled via > the fmac_vnode_create and post_create hooks as in ZFS, except that we do > not need to set up an xvattr on the file creation code path since there > is no storage of the secctx and we only need to set up the incore secid > on the vnode. > > Upon tmp_getattr, the fmac_vnode_get_secctx() hook is invoked to get the > secctx from the secid in order to pass back to userspace. Upon > tmp_setattr, the secpolicy hook will ultimately call > fmac_vnode_set_secctx() and update the vnode secid, so we only need to > set the return flag for XAT_SECCTX. > > A call to fmac_vnode_access() is inserted into tmp_taccess() to apply a > FMAC permission check whenever the existing tmpfs permission checks > would grant access. This uses conventional modes and thus does not pass > V_ACE_MASK. A call to fmac_vnode_remove() is inserted into > tmp_sticky_remove_access() as an initial cut at mediating removal of > files in tmpfs, although this may need to be taken to the callers when > rename checking is introduced. > > Webrev at: http://cr.opensolaris.org/~sds/tmpfs3/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -254,6 +254,40 @@ > } > > 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) > { > @@ -302,6 +336,15 @@ > error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); > if (error) > return (error); > + > + 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)) { > /* > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c > @@ -42,6 +42,7 @@ > #include > #include > #include > +#include > #include > #include > > @@ -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); > } > > /* > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > @@ -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 > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > @@ -64,6 +64,7 @@ > #include > #include > #include > +#include > #include > > 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,13 +720,33 @@ > 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); > + } > > mutex_enter(&tp->tn_tlock); > > @@ -740,6 +762,11 @@ > goto out; > > 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; > @@ -937,6 +964,7 @@ > struct tmpnode *self; > int error; > struct tmpnode *oldtp; > + security_id_t secid; > > again: > parent = (struct tmpnode *)VTOTN(dvp); > @@ -1021,6 +1049,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 +1089,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); > @@ -1300,6 +1334,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 +1372,7 @@ > } > rw_exit(&parent->tn_rwlock); > *vpp = TNTOV(self); > + fmac_vnode_post_create(*vpp, secid); > return (0); > } > > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -88,6 +88,7 @@ > int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); > 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); > > From john.weeks at sun.com Tue Oct 14 09:06:34 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 14 Oct 2008 09:06:34 -0700 Subject: [fmac-discuss] [PATCH] Initialize v_secid in ZFS before first zfs_zaccess() Message-ID: <48F4C38A.3020009@sun.com> Move the initialization of v_secid for ZFS down to where the znode is initialized to ensure v_secid is valid before the first zfs_zaccess check. This corrects policy failures that were observed when removing files. fmac_vnode_lookup() was trying to retrieve the context on file systems that did not support system attributes, thus setting v_secid to the wrong value (SECINITSID_FILE). webrev http://cr.opensolaris.org/~jweeks/rmbug/ -John diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -175,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) @@ -201,6 +203,23 @@ mutex_exit(&(vp->v_lock)); 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 diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c --- a/usr/src/uts/common/fs/zfs/zfs_znode.c +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c @@ -56,6 +56,7 @@ #include #include #include +#include #endif /* _KERNEL */ #include @@ -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); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -86,6 +86,7 @@ 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); From Mark.Shellenbaum at Sun.COM Tue Oct 14 12:46:57 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 14 Oct 2008 13:46:57 -0600 Subject: [fmac-discuss] [PATCH] Initialize v_secid in ZFS before first zfs_zaccess() In-Reply-To: <48F4C38A.3020009@sun.com> References: <48F4C38A.3020009@sun.com> Message-ID: <48F4F731.9050003@Sun.COM> John Weeks wrote: > Move the initialization of v_secid for ZFS down to where the znode is initialized to ensure v_secid is valid before the first zfs_zaccess check. This corrects policy failures that were observed when removing files. > > fmac_vnode_lookup() was trying to retrieve the context on file systems that did not support system attributes, thus setting v_secid to the wrong value (SECINITSID_FILE). > > webrev http://cr.opensolaris.org/~jweeks/rmbug/ > > -John > @@ -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)); Why didn't you do the initialization in zfs_znode_alloc()? > ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); > *zpp = zp; > return (0); -Mark From sds at tycho.nsa.gov Tue Oct 14 12:59:53 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 14 Oct 2008 15:59:53 -0400 Subject: [fmac-discuss] [PATCH] Initialize v_secid in ZFS before first zfs_zaccess() In-Reply-To: <48F4F731.9050003@Sun.COM> References: <48F4C38A.3020009@sun.com> <48F4F731.9050003@Sun.COM> Message-ID: <1224014393.5193.106.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-14 at 13:46 -0600, Mark Shellenbaum wrote: > John Weeks wrote: > > Move the initialization of v_secid for ZFS down to where the znode is initialized to ensure v_secid is valid before the first zfs_zaccess check. This corrects policy failures that were observed when removing files. > > > > fmac_vnode_lookup() was trying to retrieve the context on file systems that did not support system attributes, thus setting v_secid to the wrong value (SECINITSID_FILE). > > > > webrev http://cr.opensolaris.org/~jweeks/rmbug/ > > > > -John > > > @@ -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)); > > Why didn't you do the initialization in zfs_znode_alloc()? IIUC, here we are setting the secid to match the secctx from the physical znode when an existing znode is fetched. The other caller of zfs_znode_alloc() would seem to be zfs_mknode(), where we are creating a new node (without any secctx at that point) and will subsequently set the secctx upon zfs_perm_init()->zfs_xvattr_set() and later set the secid via fmac_vnode_post_create(). -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Tue Oct 14 14:08:19 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Tue, 14 Oct 2008 15:08:19 -0600 Subject: [fmac-discuss] [PATCH] Initialize v_secid in ZFS before first zfs_zaccess() In-Reply-To: <1224014393.5193.106.camel@moss-spartans.epoch.ncsc.mil> References: <48F4C38A.3020009@sun.com> <48F4F731.9050003@Sun.COM> <1224014393.5193.106.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F50A43.9030004@Sun.COM> Stephen Smalley wrote: > On Tue, 2008-10-14 at 13:46 -0600, Mark Shellenbaum wrote: >> John Weeks wrote: >>> Move the initialization of v_secid for ZFS down to where the znode is initialized to ensure v_secid is valid before the first zfs_zaccess check. This corrects policy failures that were observed when removing files. >>> >>> fmac_vnode_lookup() was trying to retrieve the context on file systems that did not support system attributes, thus setting v_secid to the wrong value (SECINITSID_FILE). >>> >>> webrev http://cr.opensolaris.org/~jweeks/rmbug/ >>> >>> -John >>> @@ -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)); >> Why didn't you do the initialization in zfs_znode_alloc()? > > IIUC, here we are setting the secid to match the secctx from the > physical znode when an existing znode is fetched. The other caller of > zfs_znode_alloc() would seem to be zfs_mknode(), where we are creating a > new node (without any secctx at that point) and will subsequently set > the secctx upon zfs_perm_init()->zfs_xvattr_set() and later set the > secid via fmac_vnode_post_create(). > Right, that makes sense then. -Mark From john.weeks at sun.com Tue Oct 14 16:35:40 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 14 Oct 2008 16:35:40 -0700 Subject: [fmac-discuss] [PATCH] Initialize v_secid in ZFS before first zfs_zaccess() In-Reply-To: <48F50A43.9030004@Sun.COM> References: <48F4C38A.3020009@sun.com> <48F4F731.9050003@Sun.COM> <1224014393.5193.106.camel@moss-spartans.epoch.ncsc.mil> <48F50A43.9030004@Sun.COM> Message-ID: <48F52CCC.90705@sun.com> On 10/14/08 14:08, Mark Shellenbaum wrote: > Stephen Smalley wrote: >> On Tue, 2008-10-14 at 13:46 -0600, Mark Shellenbaum wrote: >>> John Weeks wrote: >>>> Move the initialization of v_secid for ZFS down to where the znode >>>> is initialized to ensure v_secid is valid before the first >>>> zfs_zaccess check. This corrects policy failures that were observed >>>> when removing files. >>>> >>>> fmac_vnode_lookup() was trying to retrieve the context on file >>>> systems that did not support system attributes, thus setting v_secid >>>> to the wrong value (SECINITSID_FILE). >>>> >>>> webrev http://cr.opensolaris.org/~jweeks/rmbug/ >>>> -John >>>> @@ -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)); >>> Why didn't you do the initialization in zfs_znode_alloc()? >> >> IIUC, here we are setting the secid to match the secctx from the >> physical znode when an existing znode is fetched. The other caller of >> zfs_znode_alloc() would seem to be zfs_mknode(), where we are creating a >> new node (without any secctx at that point) and will subsequently set >> the secctx upon zfs_perm_init()->zfs_xvattr_set() and later set the >> secid via fmac_vnode_post_create(). Steve, thank you for providing the rational :-) Since the initialization of v_secid only occurs if ZFS_BONUS_SECCTX is set, it could actually be called from zfs_znode_alloc(). But since that puts it in the creation patch, I'm inclined to leave it in zfs_zget() for now. >> > > Right, that makes sense then. OK, then I'll leave it as is unless you would like it moved into zfs_znode_alloc(). > > -Mark From sds at tycho.nsa.gov Wed Oct 15 07:39:56 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 15 Oct 2008 10:39:56 -0400 Subject: [fmac-discuss] [PATCH] Initialize v_secid in ZFS before first zfs_zaccess() In-Reply-To: <48F4C38A.3020009@sun.com> References: <48F4C38A.3020009@sun.com> Message-ID: <1224081596.15903.40.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-14 at 09:06 -0700, John Weeks wrote: > Move the initialization of v_secid for ZFS down to where the znode is initialized to ensure v_secid is valid before the first zfs_zaccess check. This corrects policy failures that were observed when removing files. > > fmac_vnode_lookup() was trying to retrieve the context on file systems that did not support system attributes, thus setting v_secid to the wrong value (SECINITSID_FILE). > > webrev http://cr.opensolaris.org/~jweeks/rmbug/ Acked-by: Stephen Smalley > > -John > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -175,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) > @@ -201,6 +203,23 @@ > mutex_exit(&(vp->v_lock)); > > 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 > diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c > --- a/usr/src/uts/common/fs/zfs/zfs_znode.c > +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c > @@ -56,6 +56,7 @@ > #include > #include > #include > +#include > #endif /* _KERNEL */ > > #include > @@ -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); > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -86,6 +86,7 @@ > 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); > _______________________________________________ > fmac-discuss mailing list > fmac-discuss at opensolaris.org > http://mail.opensolaris.org/mailman/listinfo/fmac-discuss -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Oct 15 07:43:10 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 15 Oct 2008 10:43:10 -0400 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support In-Reply-To: <48EE3D09.40204@sun.com> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <48EE1ED7.3000104@Sun.COM> <48EE3D09.40204@sun.com> Message-ID: <1224081790.15903.44.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-09 at 10:19 -0700, John Weeks wrote: > >> I would suspect that cp -p is failing because it tries to preserve the > >> security context. There is a helper function that mv/cp uses called > >> sysattr_list that determines whether or not the sysattrs are in a > >> "default" or trivial state. Since the security context will be > >> present the cp code will attempt to preserve all of the attributes. > >> > >> -Mark > > > > In looking at sysattr_list() I think that probably what it should do is > > return a list of *just* the non-default attributes. Then when > > fsetattr()/setattrat() is called only a subset of the attributes would > > be written to the SUNWattr_rw file. This function is in libcmdutils. > > > > -Mark > > This sounds like it would fix mv and friends, but what about other consumers of the system attribute get/set interfaces. Do we need to worry about the case where one gets the current list of attributes, add/mods the list, then passes the list to fsetattr()/setattrat()? I looked at the fgetattr(3C) man page and I didn't see anything that indicated that this was invalid. > > Should we allow set requests if the requested value is the same as what the attribute is already set to? > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -235,6 +235,10 @@ > * Relabeling an existing file. > */ > mutex_enter(&(vp->v_lock)); > + if (vp->v_secid == new_secid) { > + mutex_exit(&(vp->v_lock)); > + return (0); > + } > old_secid = vp->v_secid; > error = avc_has_perm(cr_secid, old_secid, sclass, > FILE__RELABELFROM); > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -2599,26 +2599,56 @@ > oldva.va_mode = pzp->zp_mode; > zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid); > if (mask & AT_XVATTR) { > + > + if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && > + xoap->xoa_appendonly != > + ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) { > + need_policy = TRUE; > + } else { > + XVA_CLR_REQ(xvap, XAT_APPENDONLY); > + } > + > + if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && > + xoap->xoa_nounlink != > + ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) { > + need_policy = TRUE; > + } else { > + XVA_CLR_REQ(xvap, XAT_NOUNLINK); > + } > + > + if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && > + xoap->xoa_immutable != > + ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) { > + need_policy = TRUE; > + } else { > + XVA_CLR_REQ(xvap, XAT_IMMUTABLE); > + } > + > + if (XVA_ISSET_REQ(xvap, XAT_NODUMP) && > + xoap->xoa_nodump != > + ((pzp->zp_flags & ZFS_NODUMP) != 0)) { > + need_policy = TRUE; > + } else { > + XVA_CLR_REQ(xvap, XAT_NODUMP); > + } > + > + if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && > + xoap->xoa_av_modified != > + ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) { > + need_policy = TRUE; > + } else { > + XVA_CLR_REQ(xvap, XAT_AV_MODIFIED); > + } > + > + if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && > + xoap->xoa_av_quarantined != > + ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)) { > + need_policy = TRUE; > + } else { > + XVA_CLR_REQ(xvap, XAT_AV_QUARANTINED); > + } > + > if ((need_policy == FALSE) && > - (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && > - xoap->xoa_appendonly != > - ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) || > - (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && > - xoap->xoa_nounlink != > - ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) || > - (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && > - xoap->xoa_immutable != > - ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) || > - (XVA_ISSET_REQ(xvap, XAT_NODUMP) && > - xoap->xoa_nodump != > - ((pzp->zp_flags & ZFS_NODUMP) != 0)) || > - (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && > - xoap->xoa_av_modified != > - ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) || > - ((XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && > - ((vp->v_type != VREG && xoap->xoa_av_quarantined) || > - xoap->xoa_av_quarantined != > - ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || > (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || > (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || > (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { > diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h > --- a/usr/src/uts/common/sys/vnode.h > +++ b/usr/src/uts/common/sys/vnode.h > @@ -623,6 +623,15 @@ > ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \ > ASSERT((xvap)->xva_magic == XVA_MAGIC); \ > (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr) > + > +/* > + * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap > + * of requested attributes (xva_reqattrmap[]). > + */ > +#define XVA_CLR_REQ(xvap, attr) \ > + ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \ > + ASSERT((xvap)->xva_magic == XVA_MAGIC); \ > + (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr) > > /* > * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap Mark, did you have an opinion on this patch by John to skip policy checks on attributes that are being set to their default values, so that any application that still gets the complete list of attributes (i.e. doesn't use sysattr_list) and then passes the entire list to a setattrat() call won't trigger unnecessary privilege checks when the default system attributes have their default values? -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Wed Oct 15 08:02:08 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Wed, 15 Oct 2008 09:02:08 -0600 Subject: [fmac-discuss] [PATCH v2] Labeled tmpfs support In-Reply-To: <1224081790.15903.44.camel@moss-spartans.epoch.ncsc.mil> References: <1223560648.13181.43.camel@moss-spartans.epoch.ncsc.mil> <1223561726.13181.55.camel@moss-spartans.epoch.ncsc.mil> <48EE18DB.8080003@Sun.COM> <48EE1ED7.3000104@Sun.COM> <48EE3D09.40204@sun.com> <1224081790.15903.44.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F605F0.6020000@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-09 at 10:19 -0700, John Weeks wrote: >>>> I would suspect that cp -p is failing because it tries to preserve the >>>> security context. There is a helper function that mv/cp uses called >>>> sysattr_list that determines whether or not the sysattrs are in a >>>> "default" or trivial state. Since the security context will be >>>> present the cp code will attempt to preserve all of the attributes. >>>> >>>> -Mark >>> In looking at sysattr_list() I think that probably what it should do is >>> return a list of *just* the non-default attributes. Then when >>> fsetattr()/setattrat() is called only a subset of the attributes would >>> be written to the SUNWattr_rw file. This function is in libcmdutils. >>> >>> -Mark >> This sounds like it would fix mv and friends, but what about other consumers of the system attribute get/set interfaces. Do we need to worry about the case where one gets the current list of attributes, add/mods the list, then passes the list to fsetattr()/setattrat()? I looked at the fgetattr(3C) man page and I didn't see anything that indicated that this was invalid. >> >> Should we allow set requests if the requested value is the same as what the attribute is already set to? >> >> diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c >> --- a/usr/src/uts/common/fmac/fmac.c >> +++ b/usr/src/uts/common/fmac/fmac.c >> @@ -235,6 +235,10 @@ >> * Relabeling an existing file. >> */ >> mutex_enter(&(vp->v_lock)); >> + if (vp->v_secid == new_secid) { >> + mutex_exit(&(vp->v_lock)); >> + return (0); >> + } >> old_secid = vp->v_secid; >> error = avc_has_perm(cr_secid, old_secid, sclass, >> FILE__RELABELFROM); >> diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c >> --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c >> +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c >> @@ -2599,26 +2599,56 @@ >> oldva.va_mode = pzp->zp_mode; >> zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid); >> if (mask & AT_XVATTR) { >> + >> + if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && >> + xoap->xoa_appendonly != >> + ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) { >> + need_policy = TRUE; >> + } else { >> + XVA_CLR_REQ(xvap, XAT_APPENDONLY); >> + } >> + >> + if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && >> + xoap->xoa_nounlink != >> + ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) { >> + need_policy = TRUE; >> + } else { >> + XVA_CLR_REQ(xvap, XAT_NOUNLINK); >> + } >> + >> + if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && >> + xoap->xoa_immutable != >> + ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) { >> + need_policy = TRUE; >> + } else { >> + XVA_CLR_REQ(xvap, XAT_IMMUTABLE); >> + } >> + >> + if (XVA_ISSET_REQ(xvap, XAT_NODUMP) && >> + xoap->xoa_nodump != >> + ((pzp->zp_flags & ZFS_NODUMP) != 0)) { >> + need_policy = TRUE; >> + } else { >> + XVA_CLR_REQ(xvap, XAT_NODUMP); >> + } >> + >> + if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && >> + xoap->xoa_av_modified != >> + ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) { >> + need_policy = TRUE; >> + } else { >> + XVA_CLR_REQ(xvap, XAT_AV_MODIFIED); >> + } >> + >> + if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && >> + xoap->xoa_av_quarantined != >> + ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)) { >> + need_policy = TRUE; >> + } else { >> + XVA_CLR_REQ(xvap, XAT_AV_QUARANTINED); >> + } >> + >> if ((need_policy == FALSE) && >> - (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && >> - xoap->xoa_appendonly != >> - ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) || >> - (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && >> - xoap->xoa_nounlink != >> - ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) || >> - (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && >> - xoap->xoa_immutable != >> - ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) || >> - (XVA_ISSET_REQ(xvap, XAT_NODUMP) && >> - xoap->xoa_nodump != >> - ((pzp->zp_flags & ZFS_NODUMP) != 0)) || >> - (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && >> - xoap->xoa_av_modified != >> - ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) || >> - ((XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && >> - ((vp->v_type != VREG && xoap->xoa_av_quarantined) || >> - xoap->xoa_av_quarantined != >> - ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || >> (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || >> (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || >> (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { >> diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h >> --- a/usr/src/uts/common/sys/vnode.h >> +++ b/usr/src/uts/common/sys/vnode.h >> @@ -623,6 +623,15 @@ >> ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \ >> ASSERT((xvap)->xva_magic == XVA_MAGIC); \ >> (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr) >> + >> +/* >> + * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap >> + * of requested attributes (xva_reqattrmap[]). >> + */ >> +#define XVA_CLR_REQ(xvap, attr) \ >> + ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \ >> + ASSERT((xvap)->xva_magic == XVA_MAGIC); \ >> + (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr) >> >> /* >> * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap > > Mark, did you have an opinion on this patch by John to skip policy > checks on attributes that are being set to their default values, so that > any application that still gets the complete list of attributes (i.e. > doesn't use sysattr_list) and then passes the entire list to a > setattrat() call won't trigger unnecessary privilege checks when the > default system attributes have their default values? > Yes, that seems fine. Sorry, I hadn't noticed that change when I looked at it last week. -Mark From sds at tycho.nsa.gov Wed Oct 15 08:18:51 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 15 Oct 2008 11:18:51 -0400 Subject: [fmac-discuss] [PATCH] Rework the AVC interface and locking Message-ID: <1224083931.15903.64.camel@moss-spartans.epoch.ncsc.mil> Rework the AVC interface and locking. Introduce an avc_compute_av() interface for getting complete access vectors from the AVC. Reduce down to a single avc_has_perm() interface rather than supporting multiple variants with different arguments. Drop AVC entry references from the interface. Take more of the AVC definitions and functions private to avc.c. Convert the AVC lock from a mutex to a read-write lock. Introduce a separate lock for the AVC audit buffer. The avc_compute_av() interface should be helpful in e.g. computing privilege sets where we want to do more than get a success/fail for a set of requested permissions. The locking changes should improve scalability although finer-grained locking may be necessary, e.g. taking the locks to the individual avc hash buckets and nodes. Webrev at: http://cr.opensolaris.org/~sds/avc/ diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c --- a/usr/src/uts/common/fmac/avc.c +++ b/usr/src/uts/common/fmac/avc.c @@ -58,7 +58,19 @@ #include #include -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; @@ -101,23 +113,18 @@ 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]); - - 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]); + printf("%s avc: %d lookups == %d hits + %d misses\n", + tag, avc_cache_stats[AVC_LOOKUPS], + avc_cache_stats[AVC_HITS], avc_cache_stats[AVC_MISSES]); printf("%s avc: cav: %d/%d probe/hit ratio\n", - tag, avc_cache_stats[AVC_CAV_PROBES], - avc_cache_stats[AVC_CAV_HITS]); + tag, avc_cache_stats[AVC_PROBES], + avc_cache_stats[AVC_HITS]); } static void avc_audit_start(void) { + mutex_enter(&avc_audit_lock); (void) memset(avc_audit_buffer, 0, PAGESIZE); } @@ -136,6 +143,7 @@ static void avc_audit_end(void) { (void) printf("%s\n", avc_audit_buffer); + mutex_exit(&avc_audit_lock); } /* @@ -234,6 +242,9 @@ if (!fmac_enabled) return; + rw_init(&avc_lock, NULL, RW_DEFAULT, NULL); + mutex_init(&avc_audit_lock, NULL, MUTEX_DEFAULT, NULL); + for (i = 0; i < AVC_NSTATS; i++) avc_cache_stats[i] = 0; @@ -271,7 +282,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 +300,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", @@ -463,32 +474,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(AVC_LOOKUPS); + + 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; + avc_cache_stats_incr(AVC_HITS); + avc_cache_stats_add(AVC_PROBES, probes); + (void) memcpy(avd, &node->ae.avd, sizeof (*avd)); + rw_exit(&avc_lock); return (0); } + rw_exit(&avc_lock); - avc_cache_stats_incr(AVC_CAV_MISSES); + avc_cache_stats_incr(AVC_MISSES); return (ENOENT); } @@ -504,53 +514,42 @@ * `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; @@ -664,17 +663,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 +691,7 @@ } } - mutex_exit(&avc_lock); + rw_exit(&avc_lock); return (0); } @@ -754,10 +749,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 +818,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,7 +838,7 @@ } avc_cache.lru_hint = 0; - mutex_exit(&avc_lock); + rw_exit(&avc_lock); for (i = 0; i < AVC_NSTATS; i++) avc_cache_stats[i] = 0; @@ -857,10 +852,10 @@ } } - 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); } @@ -902,100 +897,62 @@ } /* - * 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); +} - denied = requested & ~(ae->avd.allowed); +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; - if (!requested || denied) { - if (!requested || (denied & ae->avd.auditdeny)) - avc_audit(ssid, tsid, tclass, denied, ae, AVC_AUDITDENY, + ASSERT(requested); + + rc = avc_compute_av(ssid, tsid, tclass, requested, &avd); + if (rc) + return (rc); + + 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)); -} diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -216,6 +216,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); @@ -236,18 +237,20 @@ */ 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); @@ -328,12 +331,12 @@ 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); @@ -411,13 +414,13 @@ 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, + return (avc_has_perm(cr_secid, svp->v_secid, sclass, FILE__LINK, &ad)); } @@ -442,7 +445,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); @@ -452,7 +455,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 @@ -477,19 +480,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); @@ -505,7 +508,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); @@ -532,7 +535,7 @@ AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = vp; - return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, + return (avc_has_perm(cr_secid, vp->v_secid, sclass, FILE__SETATTR, &ad)); } @@ -556,10 +559,11 @@ 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); @@ -569,19 +573,17 @@ } 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 @@ -670,7 +672,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 @@ -681,7 +683,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 @@ -709,5 +711,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)); } diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h --- a/usr/src/uts/common/sys/fmac/avc.h +++ b/usr/src/uts/common/sys/fmac/avc.h @@ -45,32 +45,6 @@ #include #include -/* - * 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 { @@ -98,15 +72,11 @@ /* * 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 +#define AVC_LOOKUPS 1 +#define AVC_HITS 2 +#define AVC_PROBES 3 +#define AVC_MISSES 4 +#define AVC_NSTATS 5 extern unsigned avc_cache_stats[AVC_NSTATS]; void avc_dump_stats(char *tag); @@ -133,84 +103,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 */ +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); -/* - * 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 */ - - -/* 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 diff --git a/usr/src/uts/common/syscall/fmacsys.c b/usr/src/uts/common/syscall/fmacsys.c --- a/usr/src/uts/common/syscall/fmacsys.c +++ b/usr/src/uts/common/syscall/fmacsys.c @@ -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) { -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Oct 15 11:45:03 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 15 Oct 2008 14:45:03 -0400 Subject: [fmac-discuss] [PATCH] Export AVC stats via kstat Message-ID: <1224096303.2628.38.camel@moss-spartans.epoch.ncsc.mil> Export basic AVC statistics using kstat, along with a few other minor cleanups of the AVC. Relative to the prior AVC interface/locking patch. Still to-do: Export avc_hash_stats in some manner upon request by userspace, and either export avc_dump_cache in some manner or drop it. Example output after this patch: $ kstat -m avc module: avc instance: 0 name: avcstats class: misc avchits 498329 avclookups 498582 avcmisses 253 avcprobes 879284 crtime 17.180095603 snaptime 366.184087142 Interpretation of the above output: For permission checks that have occurred thus far while the system is running, we found the desired entry in the AVC 498,329 out of 498,582 times (99.95%), only having to call the security server 253 times. When we found the entry in the AVC, we had to look at an average of 879,284 / 498,329 == 1.76 entries before finding the right one in the hash chain. Webrev at: http://cr.opensolaris.org/~sds/avckstat/ diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c --- a/usr/src/uts/common/fmac/avc.c +++ b/usr/src/uts/common/fmac/avc.c @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -97,30 +99,26 @@ static char *avc_audit_buffer = NULL; -unsigned avc_cache_stats[AVC_NSTATS]; +/* + * AVC statistics + */ +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 } +}; -#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 */ +kstat_named_t *avcstats_ptr = (kstat_named_t *)&avcstats; +uint_t avcstats_ndata = sizeof (avcstats) / sizeof (kstat_named_t); -/* - * Display the cache statistics - */ -void -avc_dump_stats(char *tag) -{ - printf("%s avc: %d lookups == %d hits + %d misses\n", - tag, avc_cache_stats[AVC_LOOKUPS], - avc_cache_stats[AVC_HITS], avc_cache_stats[AVC_MISSES]); - - printf("%s avc: cav: %d/%d probe/hit ratio\n", - tag, avc_cache_stats[AVC_PROBES], - avc_cache_stats[AVC_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) { @@ -149,7 +147,7 @@ /* * 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; @@ -202,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 */ @@ -236,6 +234,7 @@ void avc_init(void) { + kstat_t *ksp; avc_node_t *new; int i; @@ -245,8 +244,13 @@ rw_init(&avc_lock, NULL, RW_DEFAULT, NULL); mutex_init(&avc_audit_lock, NULL, MUTEX_DEFAULT, NULL); - for (i = 0; i < AVC_NSTATS; i++) - avc_cache_stats[i] = 0; + 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; @@ -322,8 +326,6 @@ int max_chain_len; int slots_used; avc_node_t *node; - - avc_dump_stats(tag); slots_used = 0; max_chain_len = 0; @@ -485,20 +487,20 @@ avc_node_t *node; int probes; - avc_cache_stats_incr(AVC_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_HITS); - avc_cache_stats_add(AVC_PROBES, probes); (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_MISSES); + avc_cache_stats_incr(avcmisses); return (ENOENT); } @@ -840,9 +842,6 @@ rw_exit(&avc_lock); - for (i = 0; i < AVC_NSTATS; i++) - avc_cache_stats[i] = 0; - for (c = avc_callbacks; c; c = c->next) { if (c->events & AVC_CALLBACK_RESET) { rc = c->callback(AVC_CALLBACK_RESET, diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h --- a/usr/src/uts/common/sys/fmac/avc.h +++ b/usr/src/uts/common/sys/fmac/avc.h @@ -70,32 +70,6 @@ } /* - * AVC statistics - */ -#define AVC_LOOKUPS 1 -#define AVC_HITS 2 -#define AVC_PROBES 3 -#define AVC_MISSES 4 -#define AVC_NSTATS 5 -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 */ @@ -142,6 +116,9 @@ security_class_t tclass, access_vector_t perms); +/* Dump cache contents. */ +extern void avc_dump_cache(char *tag); + #ifdef __cplusplus } #endif -- Stephen Smalley National Security Agency From pjasiukajtis at opensolaris.com.pl Wed Oct 15 12:27:46 2008 From: pjasiukajtis at opensolaris.com.pl (Piotr Jasiukajtis) Date: Wed, 15 Oct 2008 21:27:46 +0200 Subject: [fmac-discuss] Current state of the project Message-ID: <48F64432.1040103@opensolaris.com.pl> Hi, Where can I find information about the current state of the project? -- Regards, Piotr Jasiukajtis | estibi | SCA OS0072 http://estseg.blogspot.com From sds at tycho.nsa.gov Wed Oct 15 12:41:28 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 15 Oct 2008 15:41:28 -0400 Subject: [fmac-discuss] Current state of the project In-Reply-To: <48F64432.1040103@opensolaris.com.pl> References: <48F64432.1040103@opensolaris.com.pl> Message-ID: <1224099688.2628.71.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-10-15 at 21:27 +0200, Piotr Jasiukajtis wrote: > Hi, > > Where can I find information about the current state of the project? What kind of information are you looking for? I gave a talk on Sep 25th about the project; you can find the slides and video over on the SVOSUG page, http://www.opensolaris.org/os/project/svosug/ Since then we've addressed some issues with the integration into ZFS and added labeled tmpfs support. Two Alpha release have been made thus far, and an Alpha 3 release should be available soon. http://www.opensolaris.org/os/project/fmac/downloads/ -- Stephen Smalley National Security Agency From pjasiukajtis at opensolaris.com.pl Wed Oct 15 13:15:13 2008 From: pjasiukajtis at opensolaris.com.pl (Piotr Jasiukajtis) Date: Wed, 15 Oct 2008 22:15:13 +0200 Subject: [fmac-discuss] Current state of the project In-Reply-To: <1224099688.2628.71.camel@moss-spartans.epoch.ncsc.mil> References: <48F64432.1040103@opensolaris.com.pl> <1224099688.2628.71.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F64F51.4060901@opensolaris.com.pl> Stephen Smalley pisze: > On Wed, 2008-10-15 at 21:27 +0200, Piotr Jasiukajtis wrote: >> Hi, >> >> Where can I find information about the current state of the project? > > What kind of information are you looking for? I would like to know if I can learn and use some basic FMAC features by using the fmac-gate. Is it ready for basic usage? I have never used SELinux/SEBSD. > I gave a talk on Sep 25th about the project; you can find the slides and > video over on the SVOSUG page, > http://www.opensolaris.org/os/project/svosug/ Thanks, I will watch the video. > Since then we've addressed some issues with the integration into ZFS and > added labeled tmpfs support. > > Two Alpha release have been made thus far, and an Alpha 3 release should be available soon. > http://www.opensolaris.org/os/project/fmac/downloads/ Anyway I prefer to play with the latest fmac-gate :) -- Regards, Piotr Jasiukajtis | estibi | SCA OS0072 http://estseg.blogspot.com From sds at tycho.nsa.gov Wed Oct 15 13:43:34 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 15 Oct 2008 16:43:34 -0400 Subject: [fmac-discuss] Current state of the project In-Reply-To: <48F64F51.4060901@opensolaris.com.pl> References: <48F64432.1040103@opensolaris.com.pl> <1224099688.2628.71.camel@moss-spartans.epoch.ncsc.mil> <48F64F51.4060901@opensolaris.com.pl> Message-ID: <1224103414.2628.96.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-10-15 at 22:15 +0200, Piotr Jasiukajtis wrote: > Stephen Smalley pisze: > > On Wed, 2008-10-15 at 21:27 +0200, Piotr Jasiukajtis wrote: > >> Hi, > >> > >> Where can I find information about the current state of the project? > > > > What kind of information are you looking for? > I would like to know if I can learn and use some basic FMAC features by using > the fmac-gate. Is it ready for basic usage? > I have never used SELinux/SEBSD. You can boot it and experiment with the set of access controls that are presently implemented, but I wouldn't call it end user ready ;) Some (sketchy) instructions to get it up and running were posted in: http://mail.opensolaris.org/pipermail/fmac-discuss/2008-September/000270.html Note that you need a ZFS root, as we only presently support security labeling of ZFS (and more recently tmpfs). Better instructions and a more functional policy should be forthcoming with the alpha 3 release, so you may want to just wait a bit. -- Stephen Smalley National Security Agency From john.weeks at sun.com Wed Oct 15 14:08:05 2008 From: john.weeks at sun.com (John Weeks) Date: Wed, 15 Oct 2008 14:08:05 -0700 Subject: [fmac-discuss] [PATCH] Rework the AVC interface and locking In-Reply-To: <1224083931.15903.64.camel@moss-spartans.epoch.ncsc.mil> References: <1224083931.15903.64.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F65BB5.4090905@sun.com> On 10/15/08 08:18, Stephen Smalley wrote: > Rework the AVC interface and locking. Introduce an avc_compute_av() > interface for getting complete access vectors from the AVC. Reduce down > to a single avc_has_perm() interface rather than supporting multiple > variants with different arguments. Drop AVC entry references from the > interface. Take more of the AVC definitions and functions private to > avc.c. Convert the AVC lock from a mutex to a read-write lock. > Introduce a separate lock for the AVC audit buffer. > > The avc_compute_av() interface should be helpful in e.g. computing > privilege sets where we want to do more than get a success/fail for a > set of requested permissions. The locking changes should improve > scalability although finer-grained locking may be necessary, e.g. taking > the locks to the individual avc hash buckets and nodes. > > Webrev at: http://cr.opensolaris.org/~sds/avc/ Acked-by: John Weeks > > diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c > --- a/usr/src/uts/common/fmac/avc.c > +++ b/usr/src/uts/common/fmac/avc.c > @@ -58,7 +58,19 @@ > #include > #include > > -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; > @@ -101,23 +113,18 @@ > 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]); > - > - 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]); > + printf("%s avc: %d lookups == %d hits + %d misses\n", > + tag, avc_cache_stats[AVC_LOOKUPS], > + avc_cache_stats[AVC_HITS], avc_cache_stats[AVC_MISSES]); > > printf("%s avc: cav: %d/%d probe/hit ratio\n", > - tag, avc_cache_stats[AVC_CAV_PROBES], > - avc_cache_stats[AVC_CAV_HITS]); > + tag, avc_cache_stats[AVC_PROBES], > + avc_cache_stats[AVC_HITS]); > } > > static void avc_audit_start(void) > { > + mutex_enter(&avc_audit_lock); > (void) memset(avc_audit_buffer, 0, PAGESIZE); > } > > @@ -136,6 +143,7 @@ > static void avc_audit_end(void) > { > (void) printf("%s\n", avc_audit_buffer); > + mutex_exit(&avc_audit_lock); > } > > /* > @@ -234,6 +242,9 @@ > if (!fmac_enabled) > return; > > + rw_init(&avc_lock, NULL, RW_DEFAULT, NULL); > + mutex_init(&avc_audit_lock, NULL, MUTEX_DEFAULT, NULL); > + > for (i = 0; i < AVC_NSTATS; i++) > avc_cache_stats[i] = 0; > > @@ -271,7 +282,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 +300,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", > @@ -463,32 +474,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(AVC_LOOKUPS); > + > + 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; > + avc_cache_stats_incr(AVC_HITS); > + avc_cache_stats_add(AVC_PROBES, probes); > + (void) memcpy(avd, &node->ae.avd, sizeof (*avd)); > + rw_exit(&avc_lock); > return (0); > } > + rw_exit(&avc_lock); > > - avc_cache_stats_incr(AVC_CAV_MISSES); > + avc_cache_stats_incr(AVC_MISSES); > return (ENOENT); > } > > @@ -504,53 +514,42 @@ > * `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; > @@ -664,17 +663,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 +691,7 @@ > } > } > > - mutex_exit(&avc_lock); > + rw_exit(&avc_lock); > > return (0); > } > @@ -754,10 +749,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 +818,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,7 +838,7 @@ > } > avc_cache.lru_hint = 0; > > - mutex_exit(&avc_lock); > + rw_exit(&avc_lock); > > for (i = 0; i < AVC_NSTATS; i++) > avc_cache_stats[i] = 0; > @@ -857,10 +852,10 @@ > } > } > > - 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); > } > @@ -902,100 +897,62 @@ > } > > /* > - * 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); > +} > > - denied = requested & ~(ae->avd.allowed); > +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; > > - if (!requested || denied) { > - if (!requested || (denied & ae->avd.auditdeny)) > - avc_audit(ssid, tsid, tclass, denied, ae, AVC_AUDITDENY, > + ASSERT(requested); > + > + rc = avc_compute_av(ssid, tsid, tclass, requested, &avd); > + if (rc) > + return (rc); > + > + 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)); > -} > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -216,6 +216,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); > @@ -236,18 +237,20 @@ > */ > 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); > @@ -328,12 +331,12 @@ > 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); > > @@ -411,13 +414,13 @@ > 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, > + return (avc_has_perm(cr_secid, svp->v_secid, sclass, > FILE__LINK, &ad)); > } > > @@ -442,7 +445,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); > @@ -452,7 +455,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 > @@ -477,19 +480,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); > @@ -505,7 +508,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); > @@ -532,7 +535,7 @@ > > AVC_AUDIT_DATA_INIT(&ad, FS); > ad.u.fs.vp = vp; > - return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, > FILE__SETATTR, &ad)); > } > > @@ -556,10 +559,11 @@ > 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); > @@ -569,19 +573,17 @@ > } > > 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 > @@ -670,7 +672,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 > @@ -681,7 +683,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 > @@ -709,5 +711,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)); > } > diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h > --- a/usr/src/uts/common/sys/fmac/avc.h > +++ b/usr/src/uts/common/sys/fmac/avc.h > @@ -45,32 +45,6 @@ > #include > #include > > -/* > - * 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 { > @@ -98,15 +72,11 @@ > /* > * 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 > +#define AVC_LOOKUPS 1 > +#define AVC_HITS 2 > +#define AVC_PROBES 3 > +#define AVC_MISSES 4 > +#define AVC_NSTATS 5 > extern unsigned avc_cache_stats[AVC_NSTATS]; > void avc_dump_stats(char *tag); > > @@ -133,84 +103,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 */ > +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); > > -/* > - * 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 */ > - > - > -/* 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 > diff --git a/usr/src/uts/common/syscall/fmacsys.c b/usr/src/uts/common/syscall/fmacsys.c > --- a/usr/src/uts/common/syscall/fmacsys.c > +++ b/usr/src/uts/common/syscall/fmacsys.c > @@ -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) { > > From john.weeks at sun.com Wed Oct 15 16:25:07 2008 From: john.weeks at sun.com (John Weeks) Date: Wed, 15 Oct 2008 16:25:07 -0700 Subject: [fmac-discuss] [PATCH] Export AVC stats via kstat In-Reply-To: <1224096303.2628.38.camel@moss-spartans.epoch.ncsc.mil> References: <1224096303.2628.38.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F67BD3.30303@sun.com> On 10/15/08 11:45, Stephen Smalley wrote: > Export basic AVC statistics using kstat, along with a few other minor > cleanups of the AVC. Relative to the prior AVC interface/locking patch. > > Still to-do: Export avc_hash_stats in some manner upon request by > userspace, and either export avc_dump_cache in some manner or drop it. > > Example output after this patch: > $ kstat -m avc > module: avc instance: 0 > name: avcstats class: misc > avchits 498329 > avclookups 498582 > avcmisses 253 > avcprobes 879284 > crtime 17.180095603 > snaptime 366.184087142 > > Interpretation of the above output: For permission checks that have > occurred thus far while the system is running, we found the desired > entry in the AVC 498,329 out of 498,582 times (99.95%), only having to > call the security server 253 times. When we found the entry in the AVC, > we had to look at an average of 879,284 / 498,329 == 1.76 entries before > finding the right one in the hash chain. Now we can easily track AVC stats. Thank you :-) Acked-by: John Weeks > > Webrev at: http://cr.opensolaris.org/~sds/avckstat/ > > diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c > --- a/usr/src/uts/common/fmac/avc.c > +++ b/usr/src/uts/common/fmac/avc.c > @@ -49,6 +49,8 @@ > #include > #include > #include > +#include > +#include > #include > #include > #include > @@ -97,30 +99,26 @@ > > static char *avc_audit_buffer = NULL; > > -unsigned avc_cache_stats[AVC_NSTATS]; > +/* > + * AVC statistics > + */ > +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 } > +}; > > -#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 */ > +kstat_named_t *avcstats_ptr = (kstat_named_t *)&avcstats; > +uint_t avcstats_ndata = sizeof (avcstats) / sizeof (kstat_named_t); > > -/* > - * Display the cache statistics > - */ > -void > -avc_dump_stats(char *tag) > -{ > - printf("%s avc: %d lookups == %d hits + %d misses\n", > - tag, avc_cache_stats[AVC_LOOKUPS], > - avc_cache_stats[AVC_HITS], avc_cache_stats[AVC_MISSES]); > - > - printf("%s avc: cav: %d/%d probe/hit ratio\n", > - tag, avc_cache_stats[AVC_PROBES], > - avc_cache_stats[AVC_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) > { > @@ -149,7 +147,7 @@ > /* > * 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; > @@ -202,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 */ > @@ -236,6 +234,7 @@ > void > avc_init(void) > { > + kstat_t *ksp; > avc_node_t *new; > int i; > > @@ -245,8 +244,13 @@ > rw_init(&avc_lock, NULL, RW_DEFAULT, NULL); > mutex_init(&avc_audit_lock, NULL, MUTEX_DEFAULT, NULL); > > - for (i = 0; i < AVC_NSTATS; i++) > - avc_cache_stats[i] = 0; > + 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; > @@ -322,8 +326,6 @@ > int max_chain_len; > int slots_used; > avc_node_t *node; > - > - avc_dump_stats(tag); > > slots_used = 0; > max_chain_len = 0; > @@ -485,20 +487,20 @@ > avc_node_t *node; > int probes; > > - avc_cache_stats_incr(AVC_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_HITS); > - avc_cache_stats_add(AVC_PROBES, probes); > (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_MISSES); > + avc_cache_stats_incr(avcmisses); > return (ENOENT); > } > > @@ -840,9 +842,6 @@ > > rw_exit(&avc_lock); > > - for (i = 0; i < AVC_NSTATS; i++) > - avc_cache_stats[i] = 0; > - > for (c = avc_callbacks; c; c = c->next) { > if (c->events & AVC_CALLBACK_RESET) { > rc = c->callback(AVC_CALLBACK_RESET, > diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h > --- a/usr/src/uts/common/sys/fmac/avc.h > +++ b/usr/src/uts/common/sys/fmac/avc.h > @@ -70,32 +70,6 @@ > } > > /* > - * AVC statistics > - */ > -#define AVC_LOOKUPS 1 > -#define AVC_HITS 2 > -#define AVC_PROBES 3 > -#define AVC_MISSES 4 > -#define AVC_NSTATS 5 > -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 > */ > > @@ -142,6 +116,9 @@ > security_class_t tclass, > access_vector_t perms); > > +/* Dump cache contents. */ > +extern void avc_dump_cache(char *tag); > + > #ifdef __cplusplus > } > #endif > > From sds at tycho.nsa.gov Thu Oct 16 07:48:28 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 16 Oct 2008 10:48:28 -0400 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code Message-ID: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> Move the remaining FMAC permission checking hooks (link, setattr) from the fop layer into the filesystem code for consistency with the other permission checking hooks. This also allows fmac_vnode_link() to occur after the VOP_REALVP call by the filesystem code and thus not need to separately invoke it. The fmac_vnode_link() hook is required in order to check link permission to the target file. The fmac_vnode_setattr() hook is required in order to ensure that setattr permission to the target file is always checked, as the existing zfs access checks can be overridden by the various secpolicy hooks called by zfs_setattr(). This might be later obsoleted by the integration of FMAC and privileges. Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -409,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) @@ -424,9 +422,6 @@ sclass = fmac_vtype_to_sclass(svp->v_type); if (!sclass) return (0); - - if (VOP_REALVP(svp, &realvp, ct) == 0) - svp = realvp; cr_secid = crgetsecid(cr); diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c @@ -748,6 +748,10 @@ return (EINVAL); } + error = fmac_vnode_setattr(vp, cred); + if (error) + return (error); + mutex_enter(&tp->tn_tlock); get = &tp->tn_attr; @@ -1150,6 +1154,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); diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -3287,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); @@ -3452,10 +3448,6 @@ return (EINVAL); 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); @@ -4071,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); diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -2518,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) { @@ -3474,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); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -93,8 +93,7 @@ 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); -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Oct 16 14:27:21 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 16 Oct 2008 15:27:21 -0600 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F7B1B9.1040909@Sun.COM> Stephen Smalley wrote: > Move the remaining FMAC permission checking hooks (link, setattr) from > the fop layer into the filesystem code for consistency with the other > permission checking hooks. This also allows fmac_vnode_link() to occur > after the VOP_REALVP call by the filesystem code and thus not need to > separately invoke it. The fmac_vnode_link() hook is required in order > to check link permission to the target file. The fmac_vnode_setattr() > hook is required in order to ensure that setattr permission to the > target file is always checked, as the existing zfs access checks can be > overridden by the various secpolicy hooks called by zfs_setattr(). This > might be later obsoleted by the integration of FMAC and privileges. > > Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ > This looks ok, but you do have a cstyle issue on line 553 of fmac.c -Mark From john.weeks at sun.com Thu Oct 16 23:18:54 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 16 Oct 2008 23:18:54 -0700 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F82E4E.9040305@sun.com> On 10/16/08 07:48, Stephen Smalley wrote: > Move the remaining FMAC permission checking hooks (link, setattr) from > the fop layer into the filesystem code for consistency with the other > permission checking hooks. This also allows fmac_vnode_link() to occur > after the VOP_REALVP call by the filesystem code and thus not need to > separately invoke it. The fmac_vnode_link() hook is required in order > to check link permission to the target file. The fmac_vnode_setattr() > hook is required in order to ensure that setattr permission to the > target file is always checked, as the existing zfs access checks can be > overridden by the various secpolicy hooks called by zfs_setattr(). This > might be later obsoleted by the integration of FMAC and privileges. > > Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ Acked-by: John Weeks Please resolve cstyle issue before pushing. > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -409,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) > @@ -424,9 +422,6 @@ > sclass = fmac_vtype_to_sclass(svp->v_type); > if (!sclass) > return (0); > - > - if (VOP_REALVP(svp, &realvp, ct) == 0) > - svp = realvp; > > cr_secid = crgetsecid(cr); > > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > @@ -748,6 +748,10 @@ > return (EINVAL); > } > > + error = fmac_vnode_setattr(vp, cred); > + if (error) > + return (error); > + > mutex_enter(&tp->tn_tlock); > > get = &tp->tn_attr; > @@ -1150,6 +1154,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); > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -3287,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); > @@ -3452,10 +3448,6 @@ > return (EINVAL); > > 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); > @@ -4071,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); > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -2518,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) { > @@ -3474,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); > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -93,8 +93,7 @@ > 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); > > > From sds at tycho.nsa.gov Fri Oct 17 04:49:24 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 17 Oct 2008 07:49:24 -0400 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <48F7B1B9.1040909@Sun.COM> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> <48F7B1B9.1040909@Sun.COM> Message-ID: <1224244164.18694.6.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-16 at 15:27 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Move the remaining FMAC permission checking hooks (link, setattr) from > > the fop layer into the filesystem code for consistency with the other > > permission checking hooks. This also allows fmac_vnode_link() to occur > > after the VOP_REALVP call by the filesystem code and thus not need to > > separately invoke it. The fmac_vnode_link() hook is required in order > > to check link permission to the target file. The fmac_vnode_setattr() > > hook is required in order to ensure that setattr permission to the > > target file is always checked, as the existing zfs access checks can be > > overridden by the various secpolicy hooks called by zfs_setattr(). This > > might be later obsoleted by the integration of FMAC and privileges. > > > > Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ > > > > This looks ok, but you do have a cstyle issue on line 553 of fmac.c Sorry, how do you run cstyle? I get no output from cstyle fmac.c. Should I be running cstyle -p? -- Stephen Smalley National Security Agency From Darren.Moffat at Sun.COM Fri Oct 17 05:04:23 2008 From: Darren.Moffat at Sun.COM (Darren J Moffat) Date: Fri, 17 Oct 2008 13:04:23 +0100 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <1224244164.18694.6.camel@moss-spartans.epoch.ncsc.mil> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> <48F7B1B9.1040909@Sun.COM> <1224244164.18694.6.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F87F47.90407@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-10-16 at 15:27 -0600, Mark Shellenbaum wrote: >> Stephen Smalley wrote: >>> Move the remaining FMAC permission checking hooks (link, setattr) from >>> the fop layer into the filesystem code for consistency with the other >>> permission checking hooks. This also allows fmac_vnode_link() to occur >>> after the VOP_REALVP call by the filesystem code and thus not need to >>> separately invoke it. The fmac_vnode_link() hook is required in order >>> to check link permission to the target file. The fmac_vnode_setattr() >>> hook is required in order to ensure that setattr permission to the >>> target file is always checked, as the existing zfs access checks can be >>> overridden by the various secpolicy hooks called by zfs_setattr(). This >>> might be later obsoleted by the integration of FMAC and privileges. >>> >>> Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ >>> >> This looks ok, but you do have a cstyle issue on line 553 of fmac.c > > Sorry, how do you run cstyle? I get no output from cstyle fmac.c. > Should I be running cstyle -p? Easiest way if you have the Mercurial cdm extension enabled is to run: $ hg pbchk To enable cdm if you don't already have it add the following to ~/.hgrc [extensions] hgext.cdm=/opt/onbld/lib/python/onbld/hgext/cdm.py I find the following useful (assuming you use vi or vim): cstyle -p -P fmac.c | error -v -- Darren J Moffat From sds at tycho.nsa.gov Fri Oct 17 05:44:09 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 17 Oct 2008 08:44:09 -0400 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <48F87F47.90407@Sun.COM> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> <48F7B1B9.1040909@Sun.COM> <1224244164.18694.6.camel@moss-spartans.epoch.ncsc.mil> <48F87F47.90407@Sun.COM> Message-ID: <1224247449.18694.50.camel@moss-spartans.epoch.ncsc.mil> On Fri, 2008-10-17 at 13:04 +0100, Darren J Moffat wrote: > Stephen Smalley wrote: > > On Thu, 2008-10-16 at 15:27 -0600, Mark Shellenbaum wrote: > >> Stephen Smalley wrote: > >>> Move the remaining FMAC permission checking hooks (link, setattr) from > >>> the fop layer into the filesystem code for consistency with the other > >>> permission checking hooks. This also allows fmac_vnode_link() to occur > >>> after the VOP_REALVP call by the filesystem code and thus not need to > >>> separately invoke it. The fmac_vnode_link() hook is required in order > >>> to check link permission to the target file. The fmac_vnode_setattr() > >>> hook is required in order to ensure that setattr permission to the > >>> target file is always checked, as the existing zfs access checks can be > >>> overridden by the various secpolicy hooks called by zfs_setattr(). This > >>> might be later obsoleted by the integration of FMAC and privileges. > >>> > >>> Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ > >>> > >> This looks ok, but you do have a cstyle issue on line 553 of fmac.c > > > > Sorry, how do you run cstyle? I get no output from cstyle fmac.c. > > Should I be running cstyle -p? > > Easiest way if you have the Mercurial cdm extension enabled is to run: > > $ hg pbchk > > To enable cdm if you don't already have it add the following to ~/.hgrc > > [extensions] > hgext.cdm=/opt/onbld/lib/python/onbld/hgext/cdm.py Thanks - didn't know about that. > I find the following useful (assuming you use vi or vim): > > cstyle -p -P fmac.c | error -v That set of options to cstyle still didn't report the particular issue pointed out by Mark. Looking more closely at cstyle's options, I see I have to specify -c as well to pick up continuation line issues. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Oct 17 06:04:06 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 17 Oct 2008 09:04:06 -0400 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <48F82E4E.9040305@sun.com> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> <48F82E4E.9040305@sun.com> Message-ID: <1224248646.18694.60.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-10-16 at 23:18 -0700, John Weeks wrote: > On 10/16/08 07:48, Stephen Smalley wrote: > > Move the remaining FMAC permission checking hooks (link, setattr) from > > the fop layer into the filesystem code for consistency with the other > > permission checking hooks. This also allows fmac_vnode_link() to occur > > after the VOP_REALVP call by the filesystem code and thus not need to > > separately invoke it. The fmac_vnode_link() hook is required in order > > to check link permission to the target file. The fmac_vnode_setattr() > > hook is required in order to ensure that setattr permission to the > > target file is always checked, as the existing zfs access checks can be > > overridden by the various secpolicy hooks called by zfs_setattr(). This > > might be later obsoleted by the integration of FMAC and privileges. > > > > Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ > > Acked-by: John Weeks > > Please resolve cstyle issue before pushing. Revised patch to fix all cstyle issues reported by cstyle -cpP on all files modified by this patch. diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -189,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 { @@ -377,7 +377,7 @@ xva_from_va(xvap, vap); *vapp = &xvap->xva_vattr; } else { - xvap = (xvattr_t *) vap; + xvap = (xvattr_t *)vap; } error = security_sid_to_context(secid, &scontext, &scontext_len); @@ -409,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) @@ -424,9 +422,6 @@ sclass = fmac_vtype_to_sclass(svp->v_type); if (!sclass) return (0); - - if (VOP_REALVP(svp, &realvp, ct) == 0) - svp = realvp; cr_secid = crgetsecid(cr); @@ -440,7 +435,7 @@ ad.u.fs.vp = svp; return (avc_has_perm(cr_secid, svp->v_secid, sclass, - FILE__LINK, &ad)); + FILE__LINK, &ad)); } int @@ -555,7 +550,7 @@ AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = vp; return (avc_has_perm(cr_secid, vp->v_secid, sclass, - FILE__SETATTR, &ad)); + FILE__SETATTR, &ad)); } int @@ -702,7 +697,7 @@ if (!fmac_enabled) return (0); return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), - SECCLASS_PROCESS, PROCESS__PTRACE, NULL)); + SECCLASS_PROCESS, PROCESS__PTRACE, NULL)); } access_vector_t diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c @@ -748,6 +748,10 @@ return (EINVAL); } + error = fmac_vnode_setattr(vp, cred); + if (error) + return (error); + mutex_enter(&tp->tn_tlock); get = &tp->tn_attr; @@ -1150,6 +1154,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); diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -3287,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); @@ -3452,10 +3448,6 @@ return (EINVAL); 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); @@ -4071,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); diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -2518,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) { @@ -3474,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); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -93,8 +93,7 @@ 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); -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Oct 17 06:10:33 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 17 Oct 2008 09:10:33 -0400 Subject: [fmac-discuss] [PATCH] Fix cstyle issues in avc.c Message-ID: <1224249033.19562.1.camel@moss-spartans.epoch.ncsc.mil> Fix cstyle issues in avc.c reported by cstyle -cpP. diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c --- a/usr/src/uts/common/fmac/avc.c +++ b/usr/src/uts/common/fmac/avc.c @@ -188,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; @@ -259,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); @@ -609,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; @@ -845,7 +845,7 @@ 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); } @@ -871,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 */ @@ -889,10 +889,10 @@ { 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); } /* -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Oct 17 06:44:24 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 17 Oct 2008 09:44:24 -0400 Subject: [fmac-discuss] [PATCH] Fix more cstyle issues Message-ID: <1224251064.19562.9.camel@moss-spartans.epoch.ncsc.mil> Fix more cstyle issues introduced by prior patches, in particular the hasprocperm patch and the secctx patch. uts/common/syscall/lgrpsys.c is still not clean with regard to continuation indentation but the remaining warnings were not introduced by our patches. diff --git a/usr/src/uts/common/contract/process.c b/usr/src/uts/common/contract/process.c --- a/usr/src/uts/common/contract/process.c +++ b/usr/src/uts/common/contract/process.c @@ -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); diff --git a/usr/src/uts/common/disp/class.c b/usr/src/uts/common/disp/class.c --- a/usr/src/uts/common/disp/class.c +++ b/usr/src/uts/common/disp/class.c @@ -261,7 +261,7 @@ * Check basic permissions. */ if (!prochasprocperm(targpp, reqpp, reqpcredp, - PROCESS__SETSCHED)) { + PROCESS__SETSCHED)) { crfree(reqpcredp); return (EPERM); } diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c --- a/usr/src/uts/common/fs/xattr.c +++ b/usr/src/uts/common/fs/xattr.c @@ -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; diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c --- a/usr/src/uts/common/os/cpu.c +++ b/usr/src/uts/common/os/cpu.c @@ -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); diff --git a/usr/src/uts/common/os/klpd.c b/usr/src/uts/common/os/klpd.c --- a/usr/src/uts/common/os/klpd.c +++ b/usr/src/uts/common/os/klpd.c @@ -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)); diff --git a/usr/src/uts/common/syscall/corectl.c b/usr/src/uts/common/syscall/corectl.c --- a/usr/src/uts/common/syscall/corectl.c +++ b/usr/src/uts/common/syscall/corectl.c @@ -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) { diff --git a/usr/src/uts/common/syscall/lgrpsys.c b/usr/src/uts/common/syscall/lgrpsys.c --- a/usr/src/uts/common/syscall/lgrpsys.c +++ b/usr/src/uts/common/syscall/lgrpsys.c @@ -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)); } -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Oct 17 08:12:06 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 17 Oct 2008 11:12:06 -0400 Subject: [fmac-discuss] [PATCH] Fix setting of prev_secid Message-ID: <1224256326.19562.50.camel@moss-spartans.epoch.ncsc.mil> prev_secid is supposed to track the security context prior to the last exec so that applications can get the context of their caller using getprevcon(). This requires the prev_secid to be updated at times other than when the secid is changing. This patch changes the fmac_exec() and gexec() logic accordingly to ensure that the prev_secid is updated as needed. In the case where the prior exec was a secid transition and the current exec is not changing credentials, this requires a new cred in order to update the prev_secid. We may migrate the prev_secid out of the cred and into a per-process structure (as in Linux) in the future. Webrev at: http://cr.opensolaris.org/~sds/prevsecid/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -583,6 +583,7 @@ return (error); *execsetid = B_FALSE; *setsecid = B_FALSE; + *prev_secidp = *secidp = secid; return (0); } diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -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 */ -- Stephen Smalley National Security Agency From john.weeks at sun.com Fri Oct 17 10:35:57 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 17 Oct 2008 10:35:57 -0700 Subject: [fmac-discuss] [PATCH] Move link/setattr hooks into filesystem code In-Reply-To: <1224248646.18694.60.camel@moss-spartans.epoch.ncsc.mil> References: <1224168508.9247.66.camel@moss-spartans.epoch.ncsc.mil> <48F82E4E.9040305@sun.com> <1224248646.18694.60.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F8CCFD.5030007@sun.com> On 10/17/08 06:04, Stephen Smalley wrote: > On Thu, 2008-10-16 at 23:18 -0700, John Weeks wrote: >> On 10/16/08 07:48, Stephen Smalley wrote: >>> Move the remaining FMAC permission checking hooks (link, setattr) from >>> the fop layer into the filesystem code for consistency with the other >>> permission checking hooks. This also allows fmac_vnode_link() to occur >>> after the VOP_REALVP call by the filesystem code and thus not need to >>> separately invoke it. The fmac_vnode_link() hook is required in order >>> to check link permission to the target file. The fmac_vnode_setattr() >>> hook is required in order to ensure that setattr permission to the >>> target file is always checked, as the existing zfs access checks can be >>> overridden by the various secpolicy hooks called by zfs_setattr(). This >>> might be later obsoleted by the integration of FMAC and privileges. >>> >>> Webrev at: http://cr.opensolaris.org/~sds/linksetattr/ >> Acked-by: John Weeks >> >> Please resolve cstyle issue before pushing. > > Revised patch to fix all cstyle issues reported by cstyle -cpP on all > files modified by this patch. Acked-by: John Weeks Thank you. > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -189,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 { > @@ -377,7 +377,7 @@ > xva_from_va(xvap, vap); > *vapp = &xvap->xva_vattr; > } else { > - xvap = (xvattr_t *) vap; > + xvap = (xvattr_t *)vap; > } > > error = security_sid_to_context(secid, &scontext, &scontext_len); > @@ -409,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) > @@ -424,9 +422,6 @@ > sclass = fmac_vtype_to_sclass(svp->v_type); > if (!sclass) > return (0); > - > - if (VOP_REALVP(svp, &realvp, ct) == 0) > - svp = realvp; > > cr_secid = crgetsecid(cr); > > @@ -440,7 +435,7 @@ > > ad.u.fs.vp = svp; > return (avc_has_perm(cr_secid, svp->v_secid, sclass, > - FILE__LINK, &ad)); > + FILE__LINK, &ad)); > } > > int > @@ -555,7 +550,7 @@ > AVC_AUDIT_DATA_INIT(&ad, FS); > ad.u.fs.vp = vp; > return (avc_has_perm(cr_secid, vp->v_secid, sclass, > - FILE__SETATTR, &ad)); > + FILE__SETATTR, &ad)); > } > > int > @@ -702,7 +697,7 @@ > if (!fmac_enabled) > return (0); > return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), > - SECCLASS_PROCESS, PROCESS__PTRACE, NULL)); > + SECCLASS_PROCESS, PROCESS__PTRACE, NULL)); > } > > access_vector_t > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c > @@ -748,6 +748,10 @@ > return (EINVAL); > } > > + error = fmac_vnode_setattr(vp, cred); > + if (error) > + return (error); > + > mutex_enter(&tp->tn_tlock); > > get = &tp->tn_attr; > @@ -1150,6 +1154,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); > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -3287,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); > @@ -3452,10 +3448,6 @@ > return (EINVAL); > > 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); > @@ -4071,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); > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -2518,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) { > @@ -3474,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); > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -93,8 +93,7 @@ > 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); > From john.weeks at sun.com Fri Oct 17 10:37:17 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 17 Oct 2008 10:37:17 -0700 Subject: [fmac-discuss] [PATCH] Fix cstyle issues in avc.c In-Reply-To: <1224249033.19562.1.camel@moss-spartans.epoch.ncsc.mil> References: <1224249033.19562.1.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F8CD4D.7000208@sun.com> On 10/17/08 06:10, Stephen Smalley wrote: > Fix cstyle issues in avc.c reported by cstyle -cpP. > Acked-by: John Weeks Thank you for taking care of these :-) > diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c > --- a/usr/src/uts/common/fmac/avc.c > +++ b/usr/src/uts/common/fmac/avc.c > @@ -188,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; > @@ -259,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); > @@ -609,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; > @@ -845,7 +845,7 @@ > 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); > } > @@ -871,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 */ > @@ -889,10 +889,10 @@ > { > 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); > } > > /* > From john.weeks at sun.com Fri Oct 17 10:38:00 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 17 Oct 2008 10:38:00 -0700 Subject: [fmac-discuss] [PATCH] Fix more cstyle issues In-Reply-To: <1224251064.19562.9.camel@moss-spartans.epoch.ncsc.mil> References: <1224251064.19562.9.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F8CD78.9000502@sun.com> On 10/17/08 06:44, Stephen Smalley wrote: > Fix more cstyle issues introduced by prior patches, in particular the > hasprocperm patch and the secctx patch. > > uts/common/syscall/lgrpsys.c is still not clean with regard to > continuation indentation but the remaining warnings were not introduced > by our patches. Acked-by: John Weeks > > diff --git a/usr/src/uts/common/contract/process.c b/usr/src/uts/common/contract/process.c > --- a/usr/src/uts/common/contract/process.c > +++ b/usr/src/uts/common/contract/process.c > @@ -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); > diff --git a/usr/src/uts/common/disp/class.c b/usr/src/uts/common/disp/class.c > --- a/usr/src/uts/common/disp/class.c > +++ b/usr/src/uts/common/disp/class.c > @@ -261,7 +261,7 @@ > * Check basic permissions. > */ > if (!prochasprocperm(targpp, reqpp, reqpcredp, > - PROCESS__SETSCHED)) { > + PROCESS__SETSCHED)) { > crfree(reqpcredp); > return (EPERM); > } > diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c > --- a/usr/src/uts/common/fs/xattr.c > +++ b/usr/src/uts/common/fs/xattr.c > @@ -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; > diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c > --- a/usr/src/uts/common/os/cpu.c > +++ b/usr/src/uts/common/os/cpu.c > @@ -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); > diff --git a/usr/src/uts/common/os/klpd.c b/usr/src/uts/common/os/klpd.c > --- a/usr/src/uts/common/os/klpd.c > +++ b/usr/src/uts/common/os/klpd.c > @@ -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)); > diff --git a/usr/src/uts/common/syscall/corectl.c b/usr/src/uts/common/syscall/corectl.c > --- a/usr/src/uts/common/syscall/corectl.c > +++ b/usr/src/uts/common/syscall/corectl.c > @@ -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) { > diff --git a/usr/src/uts/common/syscall/lgrpsys.c b/usr/src/uts/common/syscall/lgrpsys.c > --- a/usr/src/uts/common/syscall/lgrpsys.c > +++ b/usr/src/uts/common/syscall/lgrpsys.c > @@ -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)); > } > > From john.weeks at sun.com Fri Oct 17 10:39:44 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 17 Oct 2008 10:39:44 -0700 Subject: [fmac-discuss] [PATCH] Fix setting of prev_secid In-Reply-To: <1224256326.19562.50.camel@moss-spartans.epoch.ncsc.mil> References: <1224256326.19562.50.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48F8CDE0.2080309@sun.com> On 10/17/08 08:12, Stephen Smalley wrote: > prev_secid is supposed to track the security context prior to the last > exec so that applications can get the context of their caller using > getprevcon(). This requires the prev_secid to be updated at times other > than when the secid is changing. This patch changes the fmac_exec() and > gexec() logic accordingly to ensure that the prev_secid is updated as > needed. In the case where the prior exec was a secid transition and the > current exec is not changing credentials, this requires a new cred in > order to update the prev_secid. We may migrate the prev_secid out of > the cred and into a per-process structure (as in Linux) in the future. > > Webrev at: http://cr.opensolaris.org/~sds/prevsecid/ Acked-by: John Weeks > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -583,6 +583,7 @@ > return (error); > *execsetid = B_FALSE; > *setsecid = B_FALSE; > + *prev_secidp = *secidp = secid; > return (0); > } > > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > --- a/usr/src/uts/common/os/exec.c > +++ b/usr/src/uts/common/os/exec.c > @@ -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 */ > > From john.weeks at sun.com Tue Oct 28 11:19:06 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 28 Oct 2008 11:19:06 -0700 Subject: [fmac-discuss] [PATCH] newrole, fmacsetup and policy updates Message-ID: <4907579A.7050308@sun.com> This patch represents the final set of changes for our Alpha 3 release. New Commands: ------------- NAME newrole - Run a shell in a new Flexible Mandatory Access Control context SYNOPSIS /usr/bin/newrole [-r ROLE ] [-t TYPE] [-l LEVEL ] [-- [ARGS]...] DESCRIPTION The newrole command will start a shell with the specified context. The command is modeled after the SELinux implementation http://linux.die.net/man/1/newrole with the following differences: -V not supported. If a role is specified, the type will default to the type of the process invoking the newrole command unless the -t option is specified. Note that this is a temporary gap until configuration information for default types for roles are introduced into FMAC policy. newrole doesn't re-authenticate the user since the policy governs all context transitions and newrole is not a suid program. Future versions of newrole may use some form of trusted path interface to force a user confirmation to prevent role changing without user consent. EXAMPLES Example 1 Starting a shell in the sysadm_r role and sysadm_t context newrole -r sysadm_r -t sysadm_t Example 2 Running the pcon command with the user_r role and user_t context newrole -r user_r -t user_t -- -c pcon CAVEATS Please note that this implementation of newrole does not change the UID/GID that has been discussed on the fmac-discuss list to support real users for roles. Future versions of newrole may be enhanced to include this functionality, or other utilities such as su may be modified to include type transitions. Until this is sorted out, we can use newrole as an example of how to start a shell in a different context. NAME fmacsetup - Prepare a BFU'd system to run Flexible Mandatory Access Control SYNOPSIS /sbin/fmacsetup DESCRIPTION The fmacsetup script will perform several steps to prepare a system that has been BFU'd to run Flexible Mandatory Access Control: Unmount shared object (libraries) so that the underlying object can be labeled. Label files in the root (/) file system. Labels /export/home if not already labeled. fmacsetup is a temporary solution until a package-based method (pkg tools, IPS) to label files is implemented. Policy Updates: --------------- This patch also includes a number of policy changes allowing a system to be booted into multi-user with a minimum of policy denials. Other: ------ The setfiles utility has been moved to /sbin since it may need to be run early in the system boot process. The fs-root milestone has been modified to label tmpfs mount points before they are mounted. This modification will be removed when package-based labeling is implemented. The sysadm_u has been added to support system administration. The sysadm_u user is allowed access to the user_r & sysadm_r roles. Webrev: http://cr.opensolaris.org/~jweeks/newrole-policy/ -John diff --git a/usr/src/cmd/fmac/Makefile b/usr/src/cmd/fmac/Makefile --- a/usr/src/cmd/fmac/Makefile +++ b/usr/src/cmd/fmac/Makefile @@ -34,7 +34,9 @@ getenforce \ pcon \ getfilecon \ - setfilecon + setfilecon \ + newrole \ + fmacsetup SUBDIR_POLICY = \ policy diff --git a/usr/src/cmd/fmac/fmacsetup/Makefile b/usr/src/cmd/fmac/fmacsetup/Makefile new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/fmacsetup/Makefile @@ -0,0 +1,41 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +PROG= fmacsetup + +include ../../Makefile.cmd + +SRCS = fmacsetup.sh + +all: $(PROG) + +install: all $(ROOTSBINPROG) + +lint: + +clean: + +include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/fmacsetup/fmacsetup.sh b/usr/src/cmd/fmac/fmacsetup/fmacsetup.sh new file mode 100755 --- /dev/null +++ b/usr/src/cmd/fmac/fmacsetup/fmacsetup.sh @@ -0,0 +1,121 @@ +#!/usr/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Use full pathnames so that we can run from the environment +# BFU leaves us in. +# +GETFILECON="/usr/bin/getfilecon" +SETFILES="/sbin/setfiles" +FILE_CONTEXTS="/etc/security/fmac/file_contexts" +LOADPOLICY="/sbin/loadpolicy" +SS_POLICY="/etc/security/fmac/ss_policy" + +# +# Test if mount point is on a ZFS file system +# +is_zfs() { + mtype=`mount -p | nawk '$3=='\""$1"\"' && $4=="zfs" {print $4}'` + [ "${mtype}" = "zfs" ] && return 0 + return 1; +} + +# +# Only set /export/home context if its on a ZFS file system and is +# not already labeled. This prevents the relabeling of existing home +# directories. +# +label_home() { + if is_zfs /export/home ; then + HCONTEXT=`${GETFILECON} /export/home | \ + nawk '{print $2}' ` 2>&1 >/dev/null + if [ "${HCONTEXT}" != "system_u:object_r:user_home_t" ]; then + echo "Labeling files in /export/home" + ${SETFILES} ${FILE_CONTEXTS} /export/home + else + echo "/export/home already labeled" + fi + return 0 + else + echo "/export/home is not a ZFS file system" + return 1 + fi +} + +# +# Label root if it's on a ZFS file system. +# +label_root() { + if is_zfs / ; then + echo "Labeling files in /" + ${SETFILES} ${FILE_CONTEXTS} / + return 0 + else + echo "/ is not a ZFS file system" + return 1 + fi +} + +# +# Unmount libraries so that the underlying object can be labeled +# +unmount_libs () { + for lib in `mount | egrep '^*\.so.*' | nawk '{ print $1 }'`; do + umount ${lib} + done + return 0; +} + +# +# Load the current and/or updated policy +# +reload_policy() { + + if ${LOADPOLICY} ${SS_POLICY}; then + echo "Policy reloaded" + return 0 + else + echo "Policy load failed" + return 1 + fi +} + +# +# Perform post-BFU labeling and boot setup +# +# Normal sequence is: +# bfu +# acr +# /sbin/fmacsetup +# reboot +# +/usr/sbin/zfs mount -a # Make sure all ZFS file systems are mounted +unmount_libs # Unmount platform specific libraries +reload_policy # Load the new BFU'd policy before labeling +label_root # Relabel /export/home if necessary +label_home # Relabel /export/home if necessary +echo "System labeling complete, please reboot now" diff --git a/usr/src/cmd/fmac/newrole/Makefile b/usr/src/cmd/fmac/newrole/Makefile new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/newrole/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +PROG= newrole + +include ../../Makefile.cmd + +.KEEP_STATE: + +all: $(PROG) + +install: all $(ROOTPROG) + +clean: + +lint: lint_PROG + +include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/newrole/newrole.c b/usr/src/cmd/fmac/newrole/newrole.c new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/newrole/newrole.c @@ -0,0 +1,196 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Start a shell in the requested context + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + int i; + int c; + char *prog = argv[0]; + int errflg = 0; + struct passwd *pw; + security_context_t pcontext; + char ncontext[FMAC_MAX_CONTEXT_LEN]; + char *p_user; + char *p_role; + char *p_type; + char *p_level; + char *n_role = NULL; + char *n_type = NULL; + char *n_level = NULL; + char *shell; + char **nargv; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + (void) textdomain(TEXT_DOMAIN); + + while ((c = getopt(argc, argv, "r:t:l:")) != -1) { + switch (c) { + case 'r': + n_role = optarg; + break; + case 't': + n_type = optarg; + break; + case 'l': + n_level = optarg; + break; + case ':': + (void) fprintf(stderr, + gettext("%s: option -%c requires an operand\n"), + prog, optopt); + errflg++; + break; + case '?': + (void) fprintf(stderr, + gettext("%s: unrecognized option: -%c\n"), + prog, optopt); + errflg++; + break; + } + } + + if (!n_role && !n_type && !n_level) + errflg++; + + if (errflg) { + (void) fprintf(stderr, + gettext("usage: %s [-r role] [-t type] [-l level] " + "command...\n"), prog); + exit(1); + } + + argc -= optind; + argv += optind; + + if ((pw = getpwuid(getuid())) == NULL) { + (void) fprintf(stderr, + gettext("%s: can't get user shell entry: %s\n"), + prog, strerror(errno)); + exit(1); + } + + if ((shell = strdup(pw->pw_shell)) == NULL) { + (void) fprintf(stderr, + gettext("%s: allocation for passwd shell failed: %s\n"), + prog, strerror(errno)); + exit(1); + + } + + /* Get and parse previous process context */ + if (getprevcon(&pcontext)) { + (void) fprintf(stderr, + gettext("%s: can't get pervious context: %s\n"), + prog, strerror(errno)); + exit(1); + } + + p_user = strtok(pcontext, ":"); + p_role = strtok(NULL, ":"); + p_type = strtok(NULL, ":"); + p_level = strtok(NULL, ""); + + /* Merge process and requested context fields */ + if (n_role == NULL) + n_role = p_role; + if (n_type == NULL) + n_type = p_type; + if (n_level == NULL && p_level != NULL) + n_level = p_level; + + /* Build new context string */ + if (snprintf(ncontext, FMAC_MAX_CONTEXT_LEN, "%s:%s:%s", p_user, + n_role, n_type) >= sizeof (ncontext)) { + (void) fprintf(stderr, + gettext("%s: maximum size of context exceeded\n"), prog); + exit(1); + } + + if (n_level) + if (strlcat(ncontext, ":", + FMAC_MAX_CONTEXT_LEN) >= FMAC_MAX_CONTEXT_LEN || + strlcat(ncontext, n_level, + FMAC_MAX_CONTEXT_LEN) >= FMAC_MAX_CONTEXT_LEN) { + (void) fprintf(stderr, + gettext("%s: maximum size of context exceeded\n"), + prog); + exit(1); + } + + if (security_check_context(ncontext) != 0) { + (void) fprintf(stderr, + gettext("%s: invalid context %s failed: %s\n"), + prog, ncontext, strerror(errno)); + exit(1); + } + + if ((nargv = calloc(argc+2, sizeof (char **))) == NULL) { + (void) fprintf(stderr, + gettext("%s: allocation of argument array failed: %s\n"), + prog, strerror(errno)); + exit(1); + + } + + nargv[0] = shell; + + for (i = 1; i <= argc; i++) + nargv[i] = argv[i-1]; + + nargv[i] = NULL; + + if (setexeccon(ncontext)) { + (void) fprintf(stderr, + gettext("%s: secexeccon of %s failed: %s\n"), + prog, ncontext, strerror(errno)); + exit(1); + } + + (void) execvp(nargv[0], nargv); + + (void) fprintf(stderr, gettext("%s: execvp failed: %s\n"), prog, + strerror(errno)); + + return (1); +} diff --git a/usr/src/cmd/fmac/policy/Makefile b/usr/src/cmd/fmac/policy/Makefile --- a/usr/src/cmd/fmac/policy/Makefile +++ b/usr/src/cmd/fmac/policy/Makefile @@ -72,7 +72,7 @@ domains/program/lpr.te \ domains/program/mail.te \ domains/program/modutil.te \ - domains/program/netscape.te \ + domains/program/mozilla.te \ domains/program/newrole.te \ domains/program/passwd.te \ domains/program/su.te \ diff --git a/usr/src/cmd/fmac/policy/domains/admin/sysadm.te b/usr/src/cmd/fmac/policy/domains/admin/sysadm.te --- a/usr/src/cmd/fmac/policy/domains/admin/sysadm.te +++ b/usr/src/cmd/fmac/policy/domains/admin/sysadm.te @@ -161,15 +161,15 @@ allow $1_su_t user_home_t:file create_file_perms; # Allow searching of /tmp/.X11-unix. -allow $1_netscape_t user_xserver_tmp_t:dir r_dir_perms; +allow $1_mozilla_t user_xserver_tmp_t:dir r_dir_perms; -# Allow our netscape domain to write to .netscape. -allow $1_netscape_t user_netscape_rw_t:dir create_dir_perms; -allow $1_netscape_t user_netscape_rw_t:{ file lnk_file } create_file_perms; +# Allow our mozilla domain to write to .mozilla. +allow $1_mozilla_t user_mozilla_rw_t:dir create_dir_perms; +allow $1_mozilla_t user_mozilla_rw_t:{ file lnk_file } create_file_perms; # Allow our domain to relabel downloaded files to its home type. -allow $1_t user_netscape_rw_t:{ dir file lnk_file } relabelfrom; -allow user_netscape_rw_t $1_home_t:{ dir file lnk_file } transition; +allow $1_t user_mozilla_rw_t:{ dir file lnk_file } relabelfrom; +allow user_mozilla_rw_t $1_home_t:{ dir file lnk_file } transition; # Allow our crontab domain to unlink a user cron spool file. allow $1_crontab_t user_cron_spool_t:file unlink; diff --git a/usr/src/cmd/fmac/policy/domains/every.te b/usr/src/cmd/fmac/policy/domains/every.te --- a/usr/src/cmd/fmac/policy/domains/every.te +++ b/usr/src/cmd/fmac/policy/domains/every.te @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -46,10 +51,10 @@ allow domain default_t:dir r_dir_perms; allow domain default_t:file r_file_perms; -# Create/access files that do not yet support labeling. -# This shows up for e.g. tmpfs mounts on /tmp, /var/run, ... -allow domain file_t:dir create_dir_perms; -allow domain file_t:file create_file_perms; +# Read/search directories/files that have no secctx. +# This shows up for e.g. mount points and unlabeled filesystems. +allow domain file_t:dir r_dir_perms; +allow domain file_t:file r_file_perms; # Get attributes of file systems. allow domain fs_type:filesystem getattr; diff --git a/usr/src/cmd/fmac/policy/domains/program/gnome-pty-helper.te b/usr/src/cmd/fmac/policy/domains/program/gnome-pty-helper.te --- a/usr/src/cmd/fmac/policy/domains/program/gnome-pty-helper.te +++ b/usr/src/cmd/fmac/policy/domains/program/gnome-pty-helper.te @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -56,6 +61,7 @@ # Allow gnome-pty-helper to update /var/run/utmp and /var/log/wtmp. allow $1_gph_t initrc_var_run_t:file rw_file_perms; +allow $1_gph_t var_log_t:file rw_file_perms; allow $1_gph_t wtmp_t:file rw_file_perms; # Allow gph to rw to stream sockets of appropriate user type. diff --git a/usr/src/cmd/fmac/policy/domains/program/ifconfig.te b/usr/src/cmd/fmac/policy/domains/program/ifconfig.te --- a/usr/src/cmd/fmac/policy/domains/program/ifconfig.te +++ b/usr/src/cmd/fmac/policy/domains/program/ifconfig.te @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -48,3 +53,20 @@ # Use a pipe created by initrc_t. allow ifconfig_t initrc_t:pipe rw_file_perms; + +# Run dhcpagent in the dhcp_t domain. +domain_auto_trans(ifconfig_t, dhcp_exec_t, dhcp_t) + +################################# +# +# Rules for the dhcp_t domain. +# +type dhcp_t, domain, privlog; +type dhcp_exec_t, file_type, sysadmfile, exec_type; +type etc_dhcp_t, file_type, sysadmfile; + +allow dhcp_t etc_dhcp_t:dir rw_dir_perms; +allow dhcp_t etc_dhcp_t:file create_file_perms; + +# Use the network +can_network(dhcp_t) diff --git a/usr/src/cmd/fmac/policy/domains/program/netscape.te b/usr/src/cmd/fmac/policy/domains/program/mozilla.te rename from usr/src/cmd/fmac/policy/domains/program/netscape.te rename to usr/src/cmd/fmac/policy/domains/program/mozilla.te --- a/usr/src/cmd/fmac/policy/domains/program/netscape.te +++ b/usr/src/cmd/fmac/policy/domains/program/mozilla.te @@ -25,96 +25,96 @@ # # -# netscape_exec_t is the type of the netscape executable. +# mozilla_exec_t is the type of the mozilla executable. # -type netscape_exec_t, file_type, sysadmfile, exec_type; +type mozilla_exec_t, file_type, sysadmfile, exec_type; ################################# # -# netscape_domain(user_domain) +# mozilla_domain(user_domain) # -# Define a netscape domain for a user domain. +# Define a mozilla domain for a user domain. # -define(`netscape_domain',` +define(`mozilla_domain',` -type $1_netscape_t, domain, privlog; -type $1_netscape_rw_t, file_type, sysadmfile, tmpfile; -type $1_netscape_noread_t, file_type, sysadmfile; +type $1_mozilla_t, domain, privlog; +type $1_mozilla_rw_t, file_type, sysadmfile, tmpfile; +type $1_mozilla_noread_t, file_type, sysadmfile; -# Enter by the netscape executable. -domain_auto_trans($1_t, netscape_exec_t, $1_netscape_t) +# Enter by the mozilla executable. +domain_auto_trans($1_t, mozilla_exec_t, $1_mozilla_t) -# Allow the user domain to send any signal to the netscape process. -allow $1_t $1_netscape_t:process signal_perms; +# Allow the user domain to send any signal to the mozilla process. +allow $1_t $1_mozilla_t:process signal_perms; # Allow the user domain to read the /proc/PID directory for -# the netscape process. -allow $1_t $1_netscape_t:dir r_dir_perms; -allow $1_t $1_netscape_t:notdevfile_class_set r_file_perms; +# the mozilla process. +allow $1_t $1_mozilla_t:dir r_dir_perms; +allow $1_t $1_mozilla_t:notdevfile_class_set r_file_perms; # Allow use of /dev/zero by ld.so. -allow $1_netscape_t zero_device_t:chr_file rw_file_perms; +allow $1_mozilla_t zero_device_t:chr_file rw_file_perms; # Create temporary files -file_type_auto_trans($1_netscape_t, tmp_t, $1_netscape_rw_t) +file_type_auto_trans($1_mozilla_t, tmp_t, $1_mozilla_rw_t) # Execute system programs. -can_exec_any($1_netscape_t) +can_exec_any($1_mozilla_t) # Execute downloaded programs. -can_exec($1_netscape_t, $1_netscape_rw_t) +can_exec($1_mozilla_t, $1_mozilla_rw_t) # Use capabilities. -allow $1_netscape_t self:capability { setuid setgid dac_override }; +allow $1_mozilla_t self:capability { setuid setgid dac_override }; # Inherit and use descriptors from login. -allow $1_netscape_t local_login_t:fd inherit_fd_perms; -allow $1_netscape_t remote_login_t:fd inherit_fd_perms; +allow $1_mozilla_t local_login_t:fd inherit_fd_perms; +allow $1_mozilla_t remote_login_t:fd inherit_fd_perms; # Inherit and use descriptors from gnome-pty-helper. -allow $1_netscape_t $1_gph_t:fd inherit_fd_perms; +allow $1_mozilla_t $1_gph_t:fd inherit_fd_perms; # Use the network. -can_network($1_netscape_t) +can_network($1_mozilla_t) # Allow connections to X server. -allow $1_netscape_t $1_xserver_tmp_t:dir r_dir_perms; -allow $1_netscape_t $1_xserver_tmp_t:sock_file rw_file_perms; -can_unix_connect($1_netscape_t, $1_xserver_t) +allow $1_mozilla_t $1_xserver_tmp_t:dir r_dir_perms; +allow $1_mozilla_t $1_xserver_tmp_t:sock_file rw_file_perms; +can_unix_connect($1_mozilla_t, $1_xserver_t) # Allow probing of network interfaces. -allow $1_netscape_t kernel_t:system net_io_control; -allow $1_netscape_t netif_type:netif getattr; +allow $1_mozilla_t kernel_t:system net_io_control; +allow $1_mozilla_t netif_type:netif getattr; # Write to the user domain tty. -allow $1_netscape_t $1_tty_device_t:chr_file rw_file_perms; -allow $1_netscape_t $1_devpts_t:chr_file rw_file_perms; +allow $1_mozilla_t $1_tty_device_t:chr_file rw_file_perms; +allow $1_mozilla_t $1_devpts_t:chr_file rw_file_perms; -# Read and write netscape_rw_t. -allow $1_netscape_t $1_netscape_rw_t:dir create_dir_perms; -allow $1_netscape_t $1_netscape_rw_t:{ file lnk_file } create_file_perms; +# Read and write mozilla_rw_t. +allow $1_mozilla_t $1_mozilla_rw_t:dir create_dir_perms; +allow $1_mozilla_t $1_mozilla_rw_t:{ file lnk_file } create_file_perms; # Allow the user domain to relabel home directory files. allow $1_t $1_home_t:{ dir file lnk_file } relabelfrom; # Allow the user domain to create/relabel files that can be written by -# the netscape domain. -allow $1_t $1_netscape_rw_t:dir create_dir_perms; -allow $1_t $1_netscape_rw_t:{ file lnk_file } create_file_perms; -allow $1_t $1_netscape_rw_t:{ dir file lnk_file } relabelto; -allow $1_home_t $1_netscape_rw_t:{ dir file lnk_file } transition; +# the mozilla domain. +allow $1_t $1_mozilla_rw_t:dir create_dir_perms; +allow $1_t $1_mozilla_rw_t:{ file lnk_file } create_file_perms; +allow $1_t $1_mozilla_rw_t:{ dir file lnk_file } relabelto; +allow $1_home_t $1_mozilla_rw_t:{ dir file lnk_file } transition; # Allow the user domain to create/relabel files that cannot be read by -# by the netscape domain. -allow $1_t $1_netscape_noread_t:dir create_dir_perms; -allow $1_t $1_netscape_noread_t:notdevfile_class_set create_file_perms; -allow $1_t $1_netscape_noread_t:{ dir file lnk_file } relabelto; -allow $1_home_t $1_netscape_noread_t:{ dir file lnk_file } transition; +# by the mozilla domain. +allow $1_t $1_mozilla_noread_t:dir create_dir_perms; +allow $1_t $1_mozilla_noread_t:notdevfile_class_set create_file_perms; +allow $1_t $1_mozilla_noread_t:{ dir file lnk_file } relabelto; +allow $1_home_t $1_mozilla_noread_t:{ dir file lnk_file } transition; # Allow the user domain to relabel downloaded files to its home type. -allow $1_t $1_netscape_rw_t:{ dir file lnk_file } relabelfrom; +allow $1_t $1_mozilla_rw_t:{ dir file lnk_file } relabelfrom; allow $1_t $1_home_t:{ dir file lnk_file } relabelto; -allow $1_netscape_rw_t $1_home_t:{ dir file lnk_file } transition; +allow $1_mozilla_rw_t $1_home_t:{ dir file lnk_file } transition; ') diff --git a/usr/src/cmd/fmac/policy/domains/program/newrole.te b/usr/src/cmd/fmac/policy/domains/program/newrole.te --- a/usr/src/cmd/fmac/policy/domains/program/newrole.te +++ b/usr/src/cmd/fmac/policy/domains/program/newrole.te @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -46,6 +51,9 @@ # Allow newrole_t to transition to user domains. domain_trans(newrole_t, shell_exec_t, userdomain) + +# No need for linker security flag setting on newrole -> user shell transition. +allow newrole_t { user_t sysadm_t }:process execsetid; # Use capabilities. allow newrole_t self:capability { setuid setgid net_bind_service dac_override }; @@ -94,3 +102,7 @@ # allow newrole_t sysadm_t:fd create; allow newrole_t user_t:fd create; + +# Check the validity of security contexts. +# Used by pam unix_cred. +allow newrole_t security_t:security check_context; diff --git a/usr/src/cmd/fmac/policy/domains/system/portmap.te b/usr/src/cmd/fmac/policy/domains/system/portmap.te --- a/usr/src/cmd/fmac/policy/domains/system/portmap.te +++ b/usr/src/cmd/fmac/policy/domains/system/portmap.te @@ -20,6 +20,11 @@ # # +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# # Original files contributed to OpenSolaris.org under license by the # United States Government (NSA) to Sun Microsystems, Inc. # @@ -33,6 +38,9 @@ type portmap_tmp_t, file_type, sysadmfile, tmpfile; file_type_auto_trans(portmap_t, tmp_t, portmap_tmp_t) + +type portmap_var_run_t, file_type, sysadmfile; +file_type_auto_trans(portmap_t, var_run_t, portmap_var_run_t) # Inherit and use descriptors from init. allow portmap_t init_t:fd inherit_fd_perms; diff --git a/usr/src/cmd/fmac/policy/domains/system/syslogd.te b/usr/src/cmd/fmac/policy/domains/system/syslogd.te --- a/usr/src/cmd/fmac/policy/domains/system/syslogd.te +++ b/usr/src/cmd/fmac/policy/domains/system/syslogd.te @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -45,6 +50,9 @@ # Use the net_bind_service capability. allow syslogd_t syslogd_t:capability { net_bind_service }; +# Create symlink to syslogd door. +allow syslogd_t etc_t:dir add_name; + # Inherit and use descriptors from init. allow syslogd_t init_t:fd inherit_fd_perms; diff --git a/usr/src/cmd/fmac/policy/domains/user/user.te b/usr/src/cmd/fmac/policy/domains/user/user.te --- a/usr/src/cmd/fmac/policy/domains/user/user.te +++ b/usr/src/cmd/fmac/policy/domains/user/user.te @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -148,11 +153,14 @@ # Run gnome-pty-helper in a separate domain corresponding to this user domain. gph_domain($1) +# Allow transition from gnome-pty-helper to utempter_t +domain_auto_trans($1_gph_t, utempter_exec_t, utempter_t) + # Run su in a separate domain. su_domain($1) -# Run netscape in a separate domain. -netscape_domain($1) +# Run mozilla in a separate domain. +mozilla_domain($1) # Run the X server, lpr/lpq/lprm, and sendmail in appropriate domains. xserver_domain($1) @@ -184,6 +192,9 @@ # Create temporary files. file_type_auto_trans($1_t, tmp_t, $1_tmp_t) +# Allow relabeling from /tmp to /export/home +allow $1_t $1_tmp_t:file relabelto; + # When the user domain runs ps, there will be a number of access # denials when ps tries to search /proc. Do not audit these denials. auditdeny $1_t domain:dir ~r_dir_perms; diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts --- a/usr/src/cmd/fmac/policy/file_contexts +++ b/usr/src/cmd/fmac/policy/file_contexts @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -78,7 +83,7 @@ # Other user home directories. # /home(/.*)? system_u:object_r:user_home_t -/export/home(/.*)? system_u:object_r:user_home_t +/export/home(/.*)? system_u:object_r:user_home_t # # /boot @@ -127,8 +132,17 @@ /etc/mail/aliases system_u:object_r:etc_aliases_t /etc/mail/aliases.db system_u:object_r:etc_aliases_t /etc/cron.d(/.*)? system_u:object_r:system_crond_script_t +/etc/dhcp(/.*)? system_u:object_r:etc_dhcp_t /etc/ssh/ssh_host_dsa_key system_u:object_r:sshd_key_t /etc/ssh/ssh_host_rsa_key system_u:object_r:sshd_key_t +/etc/fs/dev/mount system_u:object_r:bin_t +/etc/fs/hsfs/mount system_u:object_r:bin_t +/etc/fs/nfs/mount system_u:object_r:bin_t +/etc/fs/ufs/mount system_u:object_r:bin_t +/etc/fs/zfs/mount system_u:object_r:bin_t +/etc/fs/zfs/umount system_u:object_r:bin_t +/etc/lib/lu.*\.so.* system_u:object_r:lib_t +/etc/lib/lu(/.*)? system_u:object_r:bin_t # # /lib @@ -143,7 +157,10 @@ # /sbin(/.*)? system_u:object_r:bin_t /sbin/sh system_u:object_r:shell_exec_t +/sbin/jsh system_u:object_r:shell_exec_t +/sbin/pfsh system_u:object_r:shell_exec_t /sbin/ifconfig system_u:object_r:ifconfig_exec_t +/sbin/dhcpagent system_u:object_r:dhcp_exec_t /sbin/init system_u:object_r:init_exec_t /sbin/sulogin system_u:object_r:sulogin_exec_t @@ -163,7 +180,16 @@ /usr(/.*)? system_u:object_r:usr_t /usr/src(/.*)? system_u:object_r:src_t /usr/tmp(/.*)? system_u:object_r:tmp_t -/usr/share/man(/.*)? system_u:object_r:man_t +/usr/share/man(/.*)? system_u:object_r:man_t +/usr/apache/bin(/.*)? system_u:object_r:bin_t +/usr/apache/libexec(/.*)? system_u:object_r:lib_t +/usr/ast/bin(/.*)? system_u:object_r:bin_t +/usr/mysql/bin(/.*)? system_u:object_r:bin_t +/usr/mysql/lib(/.*)? system_u:object_r:lib_t +/usr/ruby/1.8/bin(/.*)? system_u:object_r:bin_t +/usr/ruby/1.8/lib(/.*)? system_u:object_r:lib_t +/usr/snadm/bin(/.*)? system_u:object_r:bin_t +/usr/snadm/lib(/.*)? system_u:object_r:lib_t # # /usr/bin @@ -171,10 +197,15 @@ /usr/bin(/.*)? system_u:object_r:bin_t /usr/bin/login system_u:object_r:login_exec_t /usr/bin/csh system_u:object_r:shell_exec_t +/usr/bin/pfcsh system_u:object_r:shell_exec_t /usr/bin/tcsh system_u:object_r:shell_exec_t /usr/bin/bash system_u:object_r:shell_exec_t /usr/bin/ksh system_u:object_r:shell_exec_t +/usr/bin/(amd|sparcv).*/.*ksh93 system_u:object_r:shell_exec_t +/usr/bin/pfksh system_u:object_r:shell_exec_t +/usr/bin/rksh system_u:object_r:shell_exec_t /usr/bin/zsh system_u:object_r:shell_exec_t +/usr/bin/zsh-4.3.4 system_u:object_r:shell_exec_t /usr/bin/su system_u:object_r:su_exec_t /usr/bin/ls system_u:object_r:ls_exec_t /usr/bin/lpr system_u:object_r:lpr_exec_t @@ -182,6 +213,13 @@ /usr/bin/lprm system_u:object_r:lpr_exec_t /usr/bin/crontab system_u:object_r:crontab_exec_t /usr/bin/passwd system_u:object_r:passwd_exec_t +/usr/bin/newrole system_u:object_r:newrole_exec_t + +# +# /usr/ccs +# +/usr/ccs/bin(/.*)? system_u:object_r:bin_t +/usr/ccs/lib(/.*)? system_u:object_r:lib_t # @@ -191,8 +229,114 @@ /usr/lib/ssh/sshd system_u:object_r:sshd_exec_t /usr/lib/inet/inetd system_u:object_r:inetd_exec_t /usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t +/usr/lib/gss/gssd system_u:object_r:inetd_child_exec_t /usr/lib/sendmail system_u:object_r:sendmail_exec_t /usr/lib/utmp_update system_u:object_r:utempter_exec_t +/usr/lib/gnome-pty-helper system_u:object_r:gph_exec_t +/usr/lib/fs/autofs/automount system_u:object_r:bin_t +/usr/lib/fs/autofs/dfshares system_u:object_r:bin_t +/usr/lib/fs/autofs/mount system_u:object_r:bin_t +/usr/lib/fs/autofs/share system_u:object_r:bin_t +/usr/lib/fs/autofs/unshare system_u:object_r:bin_t +/usr/lib/fs/cachefs(/.*)? system_u:object_r:bin_t +/usr/lib/fs/ctfs/mount system_u:object_r:bin_t +/usr/lib/fs/dev/mount system_u:object_r:bin_t +/usr/lib/fs/fd/mount system_u:object_r:bin_t +/usr/lib/fs/hsfs/fstyp system_u:object_r:bin_t +/usr/lib/fs/hsfs/labelit system_u:object_r:bin_t +/usr/lib/fs/hsfs/mount system_u:object_r:bin_t +/usr/lib/fs/lofs/mount system_u:object_r:bin_t +/usr/lib/fs/mntfs/mount system_u:object_r:bin_t +/usr/lib/fs/nfs/dfmounts system_u:object_r:bin_t +/usr/lib/fs/nfs/dfshares system_u:object_r:bin_t +/usr/lib/fs/nfs/mount system_u:object_r:bin_t +/usr/lib/fs/nfs/nfsfind system_u:object_r:bin_t +/usr/lib/fs/nfs/showmount system_u:object_r:bin_t +/usr/lib/fs/nfs/umount system_u:object_r:bin_t +/usr/lib/fs/objfs/mount system_u:object_r:bin_t +/usr/lib/fs/pcfs/fsck system_u:object_r:bin_t +/usr/lib/fs/pcfs/fstyp system_u:object_r:bin_t +/usr/lib/fs/pcfs/mkfs system_u:object_r:bin_t +/usr/lib/fs/pcfs/mount system_u:object_r:bin_t +/usr/lib/fs/proc/mount system_u:object_r:bin_t +/usr/lib/fs/sharefs/mount system_u:object_r:bin_t +/usr/lib/fs/smbfs/mount system_u:object_r:bin_t +/usr/lib/fs/smbfs/umount system_u:object_r:bin_t +/usr/lib/fs/tmpfs/mount system_u:object_r:bin_t +/usr/lib/fs/udfs/fsck system_u:object_r:bin_t +/usr/lib/fs/udfs/fsdb system_u:object_r:bin_t +/usr/lib/fs/udfs/fstyp system_u:object_r:bin_t +/usr/lib/fs/udfs/labelit system_u:object_r:bin_t +/usr/lib/fs/udfs/mkfs system_u:object_r:bin_t +/usr/lib/fs/udfs/mount system_u:object_r:bin_t +/usr/lib/fs/ufs/clri system_u:object_r:bin_t +/usr/lib/fs/ufs/dcopy system_u:object_r:bin_t +/usr/lib/fs/ufs/df system_u:object_r:bin_t +/usr/lib/fs/ufs/edquota system_u:object_r:bin_t +/usr/lib/fs/ufs/ff system_u:object_r:bin_t +/usr/lib/fs/ufs/fsck system_u:object_r:bin_t +/usr/lib/fs/ufs/fsckall system_u:object_r:bin_t +/usr/lib/fs/ufs/fsdb system_u:object_r:bin_t +/usr/lib/fs/ufs/fsirand system_u:object_r:bin_t +/usr/lib/fs/ufs/fssnap system_u:object_r:bin_t +/usr/lib/fs/ufs/fstyp system_u:object_r:bin_t +/usr/lib/fs/ufs/labelit system_u:object_r:bin_t +/usr/lib/fs/ufs/lockfs system_u:object_r:bin_t +/usr/lib/fs/ufs/mboot system_u:object_r:bin_t +/usr/lib/fs/ufs/mkfs system_u:object_r:bin_t +/usr/lib/fs/ufs/mount system_u:object_r:bin_t +/usr/lib/fs/ufs/ncheck system_u:object_r:bin_t +/usr/lib/fs/ufs/newfs system_u:object_r:bin_t +/usr/lib/fs/ufs/quot system_u:object_r:bin_t +/usr/lib/fs/ufs/quota system_u:object_r:bin_t +/usr/lib/fs/ufs/quotacheck system_u:object_r:bin_t +/usr/lib/fs/ufs/quotaoff system_u:object_r:bin_t +/usr/lib/fs/ufs/quotaon system_u:object_r:bin_t +/usr/lib/fs/ufs/repquota system_u:object_r:bin_t +/usr/lib/fs/ufs/tunefs system_u:object_r:bin_t +/usr/lib/fs/ufs/ufsdump system_u:object_r:bin_t +/usr/lib/fs/ufs/ufsrestore system_u:object_r:bin_t +/usr/lib/fs/ufs/volcopy system_u:object_r:bin_t +/usr/lib/fs/zfs/fstyp system_u:object_r:bin_t +/usr/lib/fs/zfs/mount system_u:object_r:bin_t +/usr/lib/fs/zfs/umount system_u:object_r:bin_t +/usr/lib/lp/bin(/.*)? system_u:object_r:bin_t +/usr/lib/zones(/.*)? system_u:object_r:bin_t +/usr/lib/xend system_u:object_r:bin_t +/usr/lib/xenstored system_u:object_r:bin_t +/usr/lib/xenbaked system_u:object_r:bin_t +/usr/lib/xenconsoled system_u:object_r:bin_t +/usr/lib/xen/bin(/.*)? system_u:object_r:bin_t +/usr/lib/xen/boot(/.*)? system_u:object_r:bin_t +/usr/lib/xen/scripts(/.*)? system_u:object_r:bin_t +/usr/lib/vscan/vscand system_u:object_r:bin_t +/usr/lib/cacao/bin(/.*)? system_u:object_r:bin_t +/usr/lib/cpp system_u:object_r:bin_t +/usr/lib/ldap(/.*)? system_u:object_r:bin_t +/usr/lib/ipf(/.*)? system_u:object_r:bin_t +/usr/lib/rcap(/.*)? system_u:object_r:bin_t +/usr/lib/libvirtd system_u:object_r:bin_t +/usr/lib/platexec system_u:object_r:bin_t +/usr/lib/power/powerd system_u:object_r:bin_t +/usr/lib/mail.local system_u:object_r:bin_t + +/usr/lib/firefox/firefox system_u:object_r:bin_t +/usr/lib/firefox/firefox-bin system_u:object_r:bin_t +/usr/lib/firefox/mozilla-xremote-client system_u:object_r:bin_t +/usr/lib/firefox/run-mozilla.sh system_u:object_r:bin_t +/usr/lib/firefox/xpidl system_u:object_r:bin_t +/usr/lib/firefox/xpt_dump system_u:object_r:bin_t +/usr/lib/firefox/xpt_link system_u:object_r:bin_t + +/usr/lib/thunderbird/thunderbird system_u:object_r:bin_t +/usr/lib/thunderbird/thunderbird-bin system_u:object_r:bin_t +/usr/lib/thunderbird/mozilla-xremote-client system_u:object_r:bin_t +/usr/lib/thunderbird/mozilla-installer-bin system_u:object_r:bin_t +/usr/lib/thunderbird/run-mozilla.sh system_u:object_r:bin_t +/usr/lib/thunderbird/xpcshell system_u:object_r:bin_t +/usr/lib/thunderbird/xpidl system_u:object_r:bin_t +/usr/lib/thunderbird/xpt_dump system_u:object_r:bin_t +/usr/lib/thunderbird/xpt_link system_u:object_r:bin_t # # /usr/sbin @@ -218,6 +362,12 @@ /usr/sadm/bin(/.*)? system_u:object_r:bin_t /usr/sadm/admin/bin(/.*)? system_u:object_r:bin_t /usr/sadm/lib(/.*)? system_u:object_r:lib_t +/usr/sadm/lib/wbem/rds system_u:object_r:bin_t +/usr/sadm/lib/wbem/cimonboot system_u:object_r:bin_t +/usr/sadm/lib/wbem/ddo system_u:object_r:bin_t +/usr/sadm/lib/wbem/remotedprovider system_u:object_r:bin_t +/usr/sadm/lib/wbem/smosscmd system_u:object_r:bin_t +/usr/sadm/lib/wbem/snmpXwbemd system_u:object_r:bin_t # # /usr/sfw @@ -238,16 +388,73 @@ /usr/openwin/sfw(/.*)? system_u:object_r:lib_t /usr/openwin/server(/.*)? system_u:object_r:lib_t -/usr/snadm/bin(/.*)? system_u:object_r:bin_t -/usr/snadm/lib(/.*)? system_u:object_r:lib_t - # # /usr/X11 # /usr/X11/bin(/.*)? system_u:object_r:bin_t -/usr/X11/bin/amd64/Xorg system_u:object_r:xserver_exec_t +/usr/X11/bin/Xserver system_u:object_r:xserver_exec_t +/usr/X11/bin/(amd|i386|sparcv).*/Xorg system_u:object_r:xserver_exec_t /usr/X11/lib(/.*)? system_u:object_r:lib_t -/usr/X11/share/man(/.*)? system_u:object_r:man_t +/usr/X11/share/man(/.*)? system_u:object_r:man_t + +# +# /usr/perl5 +# +/usr/perl5(/.*)? system_u:object_r:bin_t +/usr/perl5/man(/.*)? system_u:object_r:man_t + +# +# /usr/[java,jdk] +# +/usr/java(/.*)? system_u:object_r:bin_t +/usr/jdk(/.*)? system_u:object_r:bin_t + +# +# /usr/bsd +# +/usr/ucb(/.*)? system_u:object_r:bin_t + +# +# /usr/xpg[4-5] +# +/usr/xpg4/bin(/.*)? system_u:object_r:bin_t +/usr/xpg5/bin(/.*)? system_u:object_r:bin_t + +# +# StarOffice +# +/opt/staroffice8/program/lib.*\.so.* system_u:object_r:lib_t +/opt/staroffice8/program/.*\.so system_u:object_r:lib_t +/opt/staroffice8/program/pagin system_u:object_r:bin_t +/opt/staroffice8/program/soffice system_u:object_r:bin_t +/opt/staroffice8/program/soffice.bin system_u:object_r:bin_t +/opt/staroffice8/program/spadmin system_u:object_r:bin_t +/opt/staroffice8/program/spadmin.bin system_u:object_r:bin_t +/opt/staroffice8/program/stclient_wrapper system_u:object_r:bin_t +/opt/staroffice8/program/pkgchk.bin system_u:object_r:bin_t +/opt/staroffice8/program/pluginapp.bin system_u:object_r:bin_t + +# +# SUNWspro +# +/opt/SUNWspro/prod/bin(/.*)? system_u:object_r:bin_t +/opt/SUNWspro/prod/lib(/.*)? system_u:object_r:lib_t + +# +# SUNWonbld +# +/opt/onbld/bin(/.*)? system_u:object_r:bin_t +/opt/onbld/lib(/.*)? system_u:object_r:lib_t + +# +# /usr/gnu +# +/usr/gnu/bin(/.*)? system_u:object_r:bin_t + +# +# /usr/benchmarks +# +/usr/benchmarks(/.*)? system_u:object_r:bin_t # # /var @@ -257,14 +464,15 @@ /var/lib(/.*)? system_u:object_r:var_lib_t /var/tmp(/.*)? system_u:object_r:tmp_t /var/dt/tmp(/.*)? system_u:object_r:tmp_t -/var/dt/appconfig/appmanager(/.*)? system_u:object_r:tmp_t +/var/dt/appconfig/appmanager(/.*)? system_u:object_r:tmp_t /var/cron(/.*)? system_u:object_r:cron_log_t # -# /var/run +# /var/run & /etc/svc/volatile # /var/run(/.*)? system_u:object_r:var_run_t /var/run/.*\.*pid <> +/etc/svc/volatile system_u:object_r:var_run_t # # /var/spool @@ -285,3 +493,10 @@ # Wrapper for architecture-specific executables. /usr/lib/isaexec system_u:object_r:bin_t + +# +# Solaris platform specific files +# +/platform(/.*)?*\.so\.[1-9]? system_u:object_r:lib_t +/usr/platform(/.*)?*\.so.* system_u:object_r:lib_t +/usr/platform(/.*)?\/sbin\/.* system_u:object_r:bin_t diff --git a/usr/src/cmd/fmac/policy/rbac b/usr/src/cmd/fmac/policy/rbac --- a/usr/src/cmd/fmac/policy/rbac +++ b/usr/src/cmd/fmac/policy/rbac @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -83,6 +88,7 @@ rmmod_t fsadm_t ifconfig_t + dhcp_t logrotate_t user_mail_t # mail sent by crond }; @@ -100,7 +106,7 @@ user_xserver_t user_gph_t user_su_t - user_netscape_t + user_mozilla_t user_crontab_t user_crond_t user_ftpd_t @@ -126,7 +132,7 @@ sysadm_xserver_t sysadm_gph_t sysadm_su_t - sysadm_netscape_t + sysadm_mozilla_t sysadm_crontab_t sysadm_crond_t sysadm_ftpd_t diff --git a/usr/src/cmd/fmac/policy/users b/usr/src/cmd/fmac/policy/users --- a/usr/src/cmd/fmac/policy/users +++ b/usr/src/cmd/fmac/policy/users @@ -17,6 +17,11 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -54,6 +59,12 @@ user user_u roles { user_r }; # +# sysadm_u is the user identity for system administration. +# + +user sysadm_u roles { user_r sysadm_r }; + +# # The following users correspond to Unix identities. # These identities are typically assigned as the user attribute # when login starts the user shell. diff --git a/usr/src/cmd/fmac/setfiles/Makefile b/usr/src/cmd/fmac/setfiles/Makefile --- a/usr/src/cmd/fmac/setfiles/Makefile +++ b/usr/src/cmd/fmac/setfiles/Makefile @@ -37,7 +37,7 @@ all: $(PROG) -install: all $(ROOTPROG) +install: all $(ROOTSBINPROG) clean: diff --git a/usr/src/cmd/svc/milestone/fs-root b/usr/src/cmd/svc/milestone/fs-root --- a/usr/src/cmd/svc/milestone/fs-root +++ b/usr/src/cmd/svc/milestone/fs-root @@ -31,6 +31,20 @@ # Make sure that the libraries essential to this stage of booting can be found. LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH + + +# Set directory and library labels before mounting. +set_labels() +{ + if [ `/sbin/getenforce` != "disabled" ] ; then + /sbin/setfiles /etc/security/fmac/file_contexts \ + /lib/libc.so.1 \ + /tmp \ + /var/run \ + /etc/svc/volatile + fi +} + libc_mount() { # @@ -158,6 +172,7 @@ # it needs to currently exist for all zones. # if smf_is_nonglobalzone; then + set_labels libc_mount libc_psr_mount exit $SMF_EXIT_OK @@ -282,6 +297,7 @@ # /usr/sbin/devfsadm -I -P +set_labels libc_mount libc_psr_mount diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -403,6 +403,7 @@ f none sbin/dhcpagent 555 root bin f none sbin/dhcpinfo 555 root bin f none sbin/fdisk 555 root bin +f none sbin/fmacsetup 555 root bin f none sbin/hostconfig 555 root bin f none sbin/ifconfig 555 root bin f none sbin/ifparse 555 root bin diff --git a/usr/src/pkgdefs/SUNWesu/prototype_com b/usr/src/pkgdefs/SUNWesu/prototype_com --- a/usr/src/pkgdefs/SUNWesu/prototype_com +++ b/usr/src/pkgdefs/SUNWesu/prototype_com @@ -77,6 +77,7 @@ f none usr/bin/mkfifo 555 root bin f none usr/bin/nawk 555 root bin f none usr/bin/newform 555 root bin +f none usr/bin/newrole 555 root bin f none usr/bin/news 555 root bin f none usr/bin/nl 555 root bin l none usr/bin/oawk=../../usr/bin/awk @@ -105,7 +106,6 @@ l none usr/bin/pwdx=../../usr/lib/isaexec f none usr/bin/sdiff 555 root bin f none usr/bin/setfilecon 555 root bin -f none usr/bin/setfiles 555 root bin l none usr/bin/sort=../../usr/lib/isaexec f none usr/bin/spell 555 root bin f none usr/bin/spline 555 root bin From sds at tycho.nsa.gov Tue Oct 28 13:11:36 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 28 Oct 2008 16:11:36 -0400 Subject: [fmac-discuss] [PATCH] newrole, fmacsetup and policy updates In-Reply-To: <4907579A.7050308@sun.com> References: <4907579A.7050308@sun.com> Message-ID: <1225224696.5266.77.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-10-28 at 11:19 -0700, John Weeks wrote: > This patch represents the final set of changes for our Alpha 3 release. Acked-by: Stephen Smalley > > New Commands: > ------------- > > NAME > newrole - Run a shell in a new Flexible Mandatory Access Control context > > SYNOPSIS > /usr/bin/newrole [-r ROLE ] [-t TYPE] [-l LEVEL ] [-- [ARGS]...] > > DESCRIPTION > The newrole command will start a shell with the specified context. > The command is modeled after the SELinux implementation > http://linux.die.net/man/1/newrole with the following differences: > > -V not supported. > > If a role is specified, the type will default to the type of the > process invoking the newrole command unless the -t option is > specified. Note that this is a temporary gap until configuration > information for default types for roles are introduced into FMAC > policy. > > newrole doesn't re-authenticate the user since the policy governs > all context transitions and newrole is not a suid program. Future > versions of newrole may use some form of trusted path interface to > force a user confirmation to prevent role changing without user > consent. > > EXAMPLES > Example 1 Starting a shell in the sysadm_r role and sysadm_t context > > newrole -r sysadm_r -t sysadm_t > > Example 2 Running the pcon command with the user_r role and user_t context > > newrole -r user_r -t user_t -- -c pcon > > CAVEATS > Please note that this implementation of newrole does not change the UID/GID > that has been discussed on the fmac-discuss list to support real users for > roles. Future versions of newrole may be enhanced to include this functionality, > or other utilities such as su may be modified to include type transitions. Until > this is sorted out, we can use newrole as an example of how to start a shell in > a different context. > > > NAME > fmacsetup - Prepare a BFU'd system to run Flexible Mandatory Access Control > > SYNOPSIS > /sbin/fmacsetup > > DESCRIPTION > The fmacsetup script will perform several steps to prepare a system that has > been BFU'd to run Flexible Mandatory Access Control: > > Unmount shared object (libraries) so that the underlying object can be labeled. > > Label files in the root (/) file system. > > Labels /export/home if not already labeled. > > fmacsetup is a temporary solution until a package-based method (pkg tools, IPS) > to label files is implemented. > > Policy Updates: > --------------- > > This patch also includes a number of policy changes allowing a system to be booted > into multi-user with a minimum of policy denials. > > Other: > ------ > > The setfiles utility has been moved to /sbin since it may need to be run early in > the system boot process. > > The fs-root milestone has been modified to label tmpfs mount points before they are > mounted. This modification will be removed when package-based labeling is implemented. > > The sysadm_u has been added to support system administration. The sysadm_u user is allowed > access to the user_r & sysadm_r roles. > > Webrev: http://cr.opensolaris.org/~jweeks/newrole-policy/ -- Stephen Smalley National Security Agency From john.weeks at sun.com Thu Oct 30 13:55:30 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 30 Oct 2008 13:55:30 -0700 Subject: [fmac-discuss] [ANNOUNCE] FMAC Alpha 3 Available Message-ID: <490A1F42.5020804@sun.com> It is with great pleasure that we announce the availability of FMAC Alpha 3: New FMAC kernel functionality: o File security labeling and access controls for ZFS and TMPFS o Basic process context transition support on exec mmap PROT_EXEC restrictions Setting of linker security flag o Basic proc vnode protection o Basic process access controls (hasprocperm) o Extended AVC auditing to include pid, comm, and path information o Improved AVC interface and locking o Exported AVC stats via kstat kstat -m avc o Fixed getprevcon() and setting of prev_secid New FMAC system calls to libc: int getfilecon(const char *path, char **secctxp); int setfilecon(const char *path, char *secctx); New FMAC utilities: o The getfilecon command lets you view the security context on a file o The setfilecon command lets you set the security context on a file o The newrole command lets you start a shell with a different context o The fmacsetup command labels files after a BFU o The setfiles command is now functional and labels file objects, see the setfiles(1M) man page Enhanced FMAC policy: o The file_contexts file has been adapted to the Solaris[tm] Operating System o The FMAC user, sysadm_u, has been added Assignment of Solaris users to FMAC users: o A new context attribute has been added to user_attr that maps the Solaris user to a FMAC user. For example: jack::::context=user_u\:user_r\:user_t jill::::context=sysadm_u\:user_r\:user_t root::::context=root\:sysadm_r\:sysadm_t o The unix_cred PAM module has been modified to set the initial user context based on the user_attr context attribute. If a context attribute is not specified in user_attr for a user, the unix_cred module will default to the following: root: root:sysadm_r:sysadm_t non-root: user_u:user_r:user_t Please visit the FMAC Alpha 3 project page for complete details: http://opensolaris.org/os/project/fmac/downloads/Alpha3/ Thanks again to all of you that helped make the Alpha 3 milestone a reality :-) Regards, John, Stephen & the FMAC community From sds at tycho.nsa.gov Fri Oct 31 05:48:53 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 31 Oct 2008 08:48:53 -0400 Subject: [fmac-discuss] Rebase to onnv_101 and tmpfs labeling Message-ID: <1225457333.19610.20.camel@moss-spartans.epoch.ncsc.mil> I've successfully merged onnv_101 into a copy of the fmac gate. The merged tree builds, boots, and operates as expected in terms of FMAC functionality with the exception of the tmpfs security labeling functionality, which as expected, is broken by the fact that tmpfs no longer registers support for VFSFT_XVATTR. I applied the following patch locally in order to restore the tmpfs security labeling functionality, but I understand we need to resolve how to make this work cleanly with CIFS. The options for fixing this issue appear to be: 1) Implement full support for system attributes in tmpfs so that we can in fact register support for VFSFT_XVATTR without causing confusion for CIFS or others. I'm not sure that this approach is justified though as I don't see a legitimate use case for running CIFS over tmpfs or otherwise providing such support in tmpfs. 2) Introduce a separate VFSFT_XVATTR_SECCTX feature flag and have tmpfs register it. This doesn't seem very scalable to me (in the sense of generalizing to deal with other attributes that might only be selectively supported by a given filesystem), and it also requires changing many cases that presently test VFSFT_XVATTR to instead test for either VFSFT_XVATTR or VFSFT_XVATTR_SECCTX, e.g. fop_getattr and fop_setattr will clear AT_XVATTR from the va_mask if the filesystem doesn't support VFSFT_XVATTR, and xattr_file_write() will return EINVAL if it doesn't support VFSFT_XVATTR. 3) Teach CIFS to not assume that just because a filesystem has VFSFT_XVATTR set, it does not necessarily mean that the filesystem supports setting _all_ system attributes, and have them instead test for and handle setting of the individual system attributes of interest by checking return flags on VOP_GETATTR() or _SETATTR() and gracefully falling back as needed. This makes the most sense to me, and is consistent with Linux, where a filesystem may register handlers for ->getxattr() and ->setxattr() methods without necessarily supporting getting or setting _all_ attributes. Thoughts? (trivial patch to restore VFSFT_XVATTR for tmpfs is below, but this does not try to implement any of the approaches above for resolving the CIFS issue). diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c @@ -370,8 +370,10 @@ error = 0; out: - if (error == 0) + if (error == 0) { vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); + vfs_set_feature(vfsp, VFSFT_XVATTR); + } return (error); } -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Oct 31 06:33:54 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 31 Oct 2008 09:33:54 -0400 Subject: [fmac-discuss] [RFC][PATCH] Mediate file DAC privilege checks Message-ID: <1225460034.19610.58.camel@moss-spartans.epoch.ncsc.mil> Contrary to my earlier comments, I think we can provide privilege checks based on both subject and object security contexts in FMAC while still protecting privileged subjects from subversion by their caller. This is due to the fact that new permissions can only be obtained by transitioning into a new security context, and the same safeguards applied upon privilege increases can be applied on security context transitions when the new security context is more privileged than the old one. We already provide at least some of those safeguards on security context transitions in FMAC; in particular, setting of the linker security flag unless the "execsetid" permission is allowed between the calling context and the new context and invalidating proc vnodes (by virtue of setting PRIV_SETUGID) in addition to the new controls we introduce on entrypoint and execution of code. We will need further processing on security context transitions to fully provide the same guarantees as setuid/forced-privs execution, like setting of the suid flags on the process, but as with execsetid, these will need to be conditional on some permission check as we will not want them applied on every domain transition, only when escalating privileges. This patch demonstrates how we might introduce FMAC controls on the file DAC privilege checks. It defines new FMAC priv_read, priv_write, priv_execute, and priv_search permissions and adds a fmac_vnode_priv_access() hook called by secpolicy_vnode_access() to apply these permission checks. The fmac_vnode_priv_access() hook will fall back to the legacy policy decision if FMAC is disabled, although ultimately our goal is to make FMAC always enabled as previously discussed. If the process is privilege-aware, then FMAC will also honor any legacy policy denial so that it will not unwittingly escalate privileges for a program that is using privilege bracketing. We may also want to apply other constraints here, like checking against the limit set. Otherwise, FMAC will consult its policy to determine whether the privilege is granted, and this is done authoritatively, i.e. it can override a denial by the legacy policy logic. A new avc_has_perm_strict() interface is introduced to support checking a permission without considering permissive mode (or in the future, permissive domains) so that FMAC will always only grant privileges explicitly authorized by the policy even if permissive. Thus, permissive mode has no impact on privilege granting by FMAC. The patch also includes cred_impl.h into fmac.c for the first time and therefore replaces all references to crget*secid with direct references to the secid fields. This was done to access the privilege awareness flag but was already planned in order to avoid the overhead of calling a function from fmac.c every time we want to extract a secid from a cred. With this patch applied, in order to e.g. read /etc/shadow without being setuid, passwd would need: allow passwd_t shadow_t:file { read priv_read }; in order to pass both the FMAC priv_read permission check (May passwd_t override DAC read restrictions on shadow_t?) and the FMAC read permission check (May passwd_t read shadow_t?). An implication of making FMAC authoritative wrt privileges is that we cannot leave any fully "unconfined" domains in the policy for production use (except where we actually do want to allow all privileges to all processes running in that domain). A more limited "unconfined" domain definition is possible though where the domain is allowed all permissions except for the privilege permissions. Also, we will not able to share a single domain in any case where we want different privilege sets (aside from privilege bracketing) under this approach. This is rather different than the current situation in SELinux. Example of the result of this change: $ id uid=123(sds) gid=1(other) $ pcon $$ 101438: sysadm_u:sysadm_r:sysadm_t:unclassified $ ppriv $$ 101438: /bin/bash flags = E: basic I: basic P: basic L: all $ sum /etc/shadow 34860 1 /etc/shadow (A non-root user with only basic privs in its effective privilege set was allowed to read /etc/shadow because the current example FMAC policy allows sysadm_t all file permissions, including the priv_* ones.) Webrev available at: http://cr.opensolaris.org/~sds/filedacpriv/ diff --git a/usr/src/common/fmac/policy/flask/access_vectors b/usr/src/common/fmac/policy/flask/access_vectors --- a/usr/src/common/fmac/policy/flask/access_vectors +++ b/usr/src/common/fmac/policy/flask/access_vectors @@ -40,6 +40,9 @@ write read append + priv_execute + priv_write + priv_read open create link @@ -130,6 +133,7 @@ remove_name reparent search + priv_search rmdir mounton mountassociate diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c --- a/usr/src/uts/common/fmac/avc.c +++ b/usr/src/uts/common/fmac/avc.c @@ -920,9 +920,10 @@ 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) +static int +avc_has_perm_common(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + avc_audit_data_t *auditdata, boolean_t strict) { struct av_decision avd; access_vector_t denied; @@ -940,7 +941,7 @@ if (denied & avd.auditdeny) avc_audit(ssid, tsid, tclass, denied, AVC_AUDITDENY, auditdata); - if (fmac_enforcing) { + if (strict || fmac_enforcing) { return (EACCES); } else { (void) avc_update_cache(AVC_CALLBACK_GRANT, ssid, tsid, @@ -955,3 +956,20 @@ 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) +{ + return avc_has_perm_common(ssid, tsid, tclass, requested, auditdata, + B_FALSE); +} + +int +avc_has_perm_strict(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + avc_audit_data_t *auditdata) +{ + return avc_has_perm_common(ssid, tsid, tclass, requested, auditdata, + B_TRUE); +} diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -39,6 +39,7 @@ #include #include #include +#include #include /* Tunables */ @@ -240,7 +241,7 @@ if (!fmac_enabled) return (EINVAL); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; sclass = fmac_vtype_to_sclass(vtype); if (!sclass) @@ -339,7 +340,7 @@ if (!sclass) return (0); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; error = security_transition_sid(cr_secid, dvp->v_secid, sclass, &secid); @@ -423,7 +424,7 @@ if (!sclass) return (0); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = tdvp; @@ -454,7 +455,7 @@ if (!sclass) return (0); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = dvp; @@ -489,7 +490,7 @@ if (!sclass) return (0); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; AVC_AUDIT_DATA_INIT(&ad, FS); @@ -545,7 +546,7 @@ if (!sclass) return (0); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = vp; @@ -564,8 +565,8 @@ if (!fmac_enabled) return (0); - prev_secid = crgetsecid(cr); - secid = crgetexecsecid(cr); + prev_secid = cr->cr_secid; + secid = cr->cr_exec_secid; if (!secid) { error = security_transition_sid(prev_secid, vp->v_secid, SECCLASS_PROCESS, &secid); @@ -633,7 +634,7 @@ if (!fmac_enabled) return (0); - cr_secid = crgetsecid(cr); + cr_secid = cr->cr_secid; sclass = fmac_vtype_to_sclass(vp->v_type); if (!sclass) @@ -697,7 +698,7 @@ if (!fmac_enabled) return (0); - return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), + return (avc_has_perm(scr->cr_secid, tcr->cr_secid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL)); } @@ -724,7 +725,52 @@ if (!fmac_enabled) return (0); - tsecid = crgetsecid((cred_t *)tcrp); - ssecid = crgetsecid((cred_t *)scrp); + tsecid = tcrp->cr_secid; + ssecid = scrp->cr_secid; return (avc_has_perm(ssecid, tsecid, SECCLASS_PROCESS, perms, NULL)); } + +int +fmac_vnode_priv_access(const cred_t *cr, vnode_t *vp, int mode, int err) +{ + security_id_t cr_secid; + security_class_t sclass; + access_vector_t av; + avc_audit_data_t ad; + + /* If not enabled, just return the legacy policy decision. */ + if (!fmac_enabled) + return (err); + + /* + * If privilege aware, then honor any legacy policy denial + * since the program may have reduced its own privileges. + */ + if ((CR_FLAGS(cr) & PRIV_AWARE) && err) + return (err); + + cr_secid = cr->cr_secid; + + sclass = fmac_vtype_to_sclass(vp->v_type); + if (!sclass) + return (err); + + av = 0; + if (mode & VREAD) + av |= FILE__PRIV_READ; + if (mode & VWRITE) + av |= FILE__PRIV_WRITE; + if (mode & VEXEC) { + if (sclass == SECCLASS_DIR) + av |= DIR__PRIV_SEARCH; + else + av |= FILE__PRIV_EXECUTE; + } + + if (!av) + return (err); + + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; + return (avc_has_perm_strict(cr_secid, vp->v_secid, sclass, av, &ad)); +} diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -834,13 +834,15 @@ int secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) { + int err = 0; + if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { - return (EACCES); + err = EACCES; } - if (mode & VWRITE) { + if (!err && (mode & VWRITE)) { boolean_t allzone; if (owner == 0 && cr->cr_uid != 0) @@ -850,21 +852,22 @@ if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { - return (EACCES); + err = EACCES; } } - if (mode & VEXEC) { + if (!err && (mode & VEXEC)) { /* * Directories use file_dac_search to override the execute bit. */ int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : PRIV_FILE_DAC_EXECUTE; - return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, - KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); + err = priv_policy_va(cr, p, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE); } - return (0); + + return (fmac_vnode_priv_access(cr, vp, mode, err)); } /* diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h --- a/usr/src/uts/common/sys/fmac/avc.h +++ b/usr/src/uts/common/sys/fmac/avc.h @@ -88,6 +88,11 @@ security_class_t tclass, access_vector_t requested, avc_audit_data_t *auditdata); +/* Check requested permissions without considering permissive mode/domains. */ +extern int avc_has_perm_strict(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 #define AVC_CALLBACK_REVOKE 4 diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -105,6 +105,7 @@ access_vector_t fmac_sigtoav(int sig); int fmac_hasprocperm(const cred_t *tcrp, const cred_t *scrp, access_vector_t perms); +int fmac_vnode_priv_access(const cred_t *, vnode_t *, int, int); #endif /* _KERNEL */ #ifdef __cplusplus -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Fri Oct 31 07:34:52 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Fri, 31 Oct 2008 08:34:52 -0600 Subject: [fmac-discuss] Rebase to onnv_101 and tmpfs labeling In-Reply-To: <1225457333.19610.20.camel@moss-spartans.epoch.ncsc.mil> References: <1225457333.19610.20.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <490B178C.5000101@Sun.COM> Stephen Smalley wrote: > I've successfully merged onnv_101 into a copy of the fmac gate. The > merged tree builds, boots, and operates as expected in terms of FMAC > functionality with the exception of the tmpfs security labeling > functionality, which as expected, is broken by the fact that tmpfs no > longer registers support for VFSFT_XVATTR. I applied the following > patch locally in order to restore the tmpfs security labeling > functionality, but I understand we need to resolve how to make this work > cleanly with CIFS. > > The options for fixing this issue appear to be: > 1) Implement full support for system attributes in tmpfs so that we can > in fact register support for VFSFT_XVATTR without causing confusion for > CIFS or others. I'm not sure that this approach is justified though as > I don't see a legitimate use case for running CIFS over tmpfs or > otherwise providing such support in tmpfs. > The CIFS server isn't officially supported on tmpfs. I don't believe there is anything in the code to prevent you from using tmpfs, though. They have this bug to prevent sharing of non-disk file system. 6599469 Prevent CIFS share enabling for virtual file system or non-nodev file system > 2) Introduce a separate VFSFT_XVATTR_SECCTX feature flag and have tmpfs > register it. This doesn't seem very scalable to me (in the sense of > generalizing to deal with other attributes that might only be > selectively supported by a given filesystem), and it also requires > changing many cases that presently test VFSFT_XVATTR to instead test for > either VFSFT_XVATTR or VFSFT_XVATTR_SECCTX, e.g. fop_getattr and > fop_setattr will clear AT_XVATTR from the va_mask if the filesystem > doesn't support VFSFT_XVATTR, and xattr_file_write() will return EINVAL > if it doesn't support VFSFT_XVATTR. > > 3) Teach CIFS to not assume that just because a filesystem has > VFSFT_XVATTR set, it does not necessarily mean that the filesystem > supports setting _all_ system attributes, and have them instead test for > and handle setting of the individual system attributes of interest by > checking return flags on VOP_GETATTR() or _SETATTR() and gracefully > falling back as needed. This makes the most sense to me, and is > consistent with Linux, where a filesystem may register handlers for > ->getxattr() and ->setxattr() methods without necessarily supporting > getting or setting _all_ attributes. > I believe the CIFS server already does test the returns from VOP_GETATTR/VOP_SETATTR() to see which attributes were returned/set. Unfortunately, the person most familiar with this part of the CIFS server recently went on maternity leave. I can discuss it with some other people on the CIFS team and report back what I find out. > Thoughts? > > (trivial patch to restore VFSFT_XVATTR for tmpfs is below, but this does > not try to implement any of the approaches above for resolving the CIFS > issue). > This seems reasonable for now, until we can figure out what to do with the CIFS server issue. > diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > --- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > +++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c > @@ -370,8 +370,10 @@ > error = 0; > > out: > - if (error == 0) > + if (error == 0) { > vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); > + vfs_set_feature(vfsp, VFSFT_XVATTR); > + } > > return (error); > } > > From Glenn.Faden at Sun.COM Fri Oct 31 11:36:41 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Fri, 31 Oct 2008 11:36:41 -0700 Subject: [fmac-discuss] [RFC][PATCH] Mediate file DAC privilege checks In-Reply-To: <1225460034.19610.58.camel@moss-spartans.epoch.ncsc.mil> References: <1225460034.19610.58.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <490B5039.5080006@sun.com> Stephen Smalley wrote: > Contrary to my earlier comments, I think we can provide privilege checks > based on both subject and object security contexts in FMAC while still > protecting privileged subjects from subversion by their caller. This is > due to the fact that new permissions can only be obtained by > transitioning into a new security context, and the same safeguards > applied upon privilege increases can be applied on security context > transitions when the new security context is more privileged than the > old one. We already provide at least some of those safeguards on > security context transitions in FMAC; in particular, setting of the > linker security flag unless the "execsetid" permission is allowed > between the calling context and the new context and invalidating proc > vnodes (by virtue of setting PRIV_SETUGID) in addition to the new > controls we introduce on entrypoint and execution of code. We will need > further processing on security context transitions to fully provide the > same guarantees as setuid/forced-privs execution, like setting of the > suid flags on the process, but as with execsetid, these will need to be > conditional on some permission check as we will not want them applied on > every domain transition, only when escalating privileges. > > This patch demonstrates how we might introduce FMAC controls on the file > DAC privilege checks. It defines new FMAC priv_read, priv_write, > priv_execute, and priv_search permissions and adds a > fmac_vnode_priv_access() hook called by secpolicy_vnode_access() to > apply these permission checks. The fmac_vnode_priv_access() hook will > fall back to the legacy policy decision if FMAC is disabled, although > ultimately our goal is to make FMAC always enabled as previously > discussed. If the process is privilege-aware, then FMAC will also honor > any legacy policy denial so that it will not unwittingly escalate > privileges for a program that is using privilege bracketing. We may > also want to apply other constraints here, like checking against the > limit set. Otherwise, FMAC will consult its policy to determine whether > the privilege is granted, and this is done authoritatively, i.e. it can > override a denial by the legacy policy logic. A new > avc_has_perm_strict() interface is introduced to support checking a > permission without considering permissive mode (or in the future, > permissive domains) so that FMAC will always only grant privileges > explicitly authorized by the policy even if permissive. Thus, > permissive mode has no impact on privilege granting by FMAC. > > The patch also includes cred_impl.h into fmac.c for the first time and > therefore replaces all references to crget*secid with direct references > to the secid fields. This was done to access the privilege awareness > flag but was already planned in order to avoid the overhead of calling a > function from fmac.c every time we want to extract a secid from a cred. > > With this patch applied, in order to e.g. read /etc/shadow without being > setuid, passwd would need: > allow passwd_t shadow_t:file { read priv_read }; > in order to pass both the FMAC priv_read permission check (May passwd_t > override DAC read restrictions on shadow_t?) and the FMAC read > permission check (May passwd_t read shadow_t?). > > An implication of making FMAC authoritative wrt privileges is that we > cannot leave any fully "unconfined" domains in the policy for production > use (except where we actually do want to allow all privileges to all > processes running in that domain). A more limited "unconfined" domain > definition is possible though where the domain is allowed all > permissions except for the privilege permissions. Also, we will not > able to share a single domain in any case where we want different > privilege sets (aside from privilege bracketing) under this approach. > This is rather different than the current situation in SELinux. > > > This looks good to me. It seems to meet the goals we've discussed, while preserving backward compatibility. Will you need to define a new FMAC permission corresponding to every Solaris privilege for which FMAC is authoritative? Since FMAC permissions are associated with object managers, I assume you can use the same FMAC permission name, e.g. priv_read, to correspond to PRIV_FILE_DAC_READ for the filesystem object manager, and to PRIV_IPC_DAC_READ for the IPC object manager. Similarly, a new FMAC permission, like priv_setid, might apply to either the PRIV_FILE_SETID or PRIV_PROC_SETID privileges, depending on the object. I'm not yet clear on how the semantics of the privilege limit set should be applied. My initial thought is that a process must have the privilege corresponding to the FMAC permission in it's limit in order for the FMAC policy to be authoritative over it. --Glenn From sds at tycho.nsa.gov Fri Oct 31 12:52:08 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 31 Oct 2008 15:52:08 -0400 Subject: [fmac-discuss] [RFC][PATCH] Mediate file DAC privilege checks In-Reply-To: <490B5039.5080006@sun.com> References: <1225460034.19610.58.camel@moss-spartans.epoch.ncsc.mil> <490B5039.5080006@sun.com> Message-ID: <1225482728.19610.111.camel@moss-spartans.epoch.ncsc.mil> On Fri, 2008-10-31 at 11:36 -0700, Glenn Faden wrote: > This looks good to me. It seems to meet the goals we've discussed, while > preserving backward compatibility. > > Will you need to define a new FMAC permission corresponding to every > Solaris privilege for which FMAC is authoritative? Since FMAC > permissions are associated with object managers, I assume you can use > the same FMAC permission name, e.g. priv_read, to correspond to > PRIV_FILE_DAC_READ for the filesystem object manager, and to > PRIV_IPC_DAC_READ for the IPC object manager. Similarly, a new FMAC > permission, like priv_setid, might apply to either the PRIV_FILE_SETID > or PRIV_PROC_SETID privileges, depending on the object. Right, the permissions are defined per-object-class in FMAC/Flask, and you can use the same permission name in multiple object classes, although they don't necessarily have to map to the same value (bit index). So from a policy writing point of view, we can have priv_read defined and used for files, ipc, and other objects, but in the kernel's code, we'll be passing different symbolic constants, e.g. avc_has_perm(ssid, tsid, tclass, FILE__PRIV_READ, ...) in fmac_vnode_priv_access() vs. avc_has_perm(ssid, tsid, tclass, IPC__PRIV_READ, ...) in a new fmac_ipc_priv_access() hook. > I'm not yet clear on how the semantics of the privilege limit set should > be applied. My initial thought is that a process must have the privilege > corresponding to the FMAC permission in it's limit in order for the FMAC > policy to be authoritative over it. Yes, that makes sense, and would seem simple enough to implement such a restriction within the fmac_vnode_priv_access() logic. -- Stephen Smalley National Security Agency