From sds at tycho.nsa.gov Mon Dec 15 10:16:56 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 15 Dec 2008 13:16:56 -0500 Subject: [fmac-discuss] [RFC][PATCH] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, handle secpolicy_require_set Message-ID: <1229365016.14137.14.camel@localhost.localdomain> This patch replaces PRIV_ALL and PRIV_FULLSET checks with specific privilege checks and introduces FMAC mediation of secpolicy_require_set(). These changes complete the support for further restricting the use of privileges via FMAC. The particular choices of privilege names and how operations are mapped to privileges is entirely open to discussion. Webrev available at: http://cr.opensolaris.org/~sds/privall/ diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c --- a/usr/src/uts/common/dtrace/dtrace.c +++ b/usr/src/uts/common/dtrace/dtrace.c @@ -6370,7 +6370,7 @@ { uint32_t priv; - if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { + if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_ALL, B_FALSE)) { /* * For DTRACE_PRIV_ALL, the uid and zoneid don't matter. */ @@ -10033,7 +10033,7 @@ ASSERT(MUTEX_HELD(&dtrace_lock)); if (size > dtrace_nonroot_maxsize && - !PRIV_POLICY_CHOICE(CRED(), PRIV_ALL, B_FALSE)) + !PRIV_POLICY_CHOICE(CRED(), PRIV_DTRACE_ALL, B_FALSE)) return (EFBIG); cp = cpu_list; @@ -12104,7 +12104,7 @@ * actual anonymous tracing, or the possession of all privileges, all of * the normal checks are bypassed. */ - if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { + if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_ALL, B_FALSE)) { state->dts_cred.dcr_visible = DTRACE_CRV_ALL; state->dts_cred.dcr_action = DTRACE_CRA_ALL; } else { diff --git a/usr/src/uts/common/dtrace/fasttrap.c b/usr/src/uts/common/dtrace/fasttrap.c --- a/usr/src/uts/common/dtrace/fasttrap.c +++ b/usr/src/uts/common/dtrace/fasttrap.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1968,7 +1969,7 @@ } } - if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { + if (!PRIV_POLICY_CHOICE(cr, PRIV_DTRACE_ALL, B_FALSE)) { proc_t *p; pid_t pid = probe->ftps_pid; @@ -2008,7 +2009,7 @@ if (copyin((void *)arg, &instr, sizeof (instr)) != 0) return (EFAULT); - if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { + if (!PRIV_POLICY_CHOICE(cr, PRIV_DTRACE_ALL, B_FALSE)) { proc_t *p; pid_t pid = instr.ftiq_pid; 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 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -883,3 +884,15 @@ ad.u.priv.priv = priv; return (avc_has_perm(cr_secid, cr_secid, sclass, av, &ad)); } + +int +fmac_priv_require_set(const cred_t *cr, const priv_set_t *req) +{ + int priv; + + for (priv = 0; priv < nprivs; priv++) + if (priv_ismember(req, priv)) + if (fmac_priv_restrict(cr, priv)) + return (EACCES); + return (0); +} 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 @@ -475,11 +475,11 @@ if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, &CR_OEPRIV(cr))) { - return (0); + return (fmac_priv_require_set(cr, req)); } if (priv_policy_override_set(cr, req, KLPDARG_NOMORE) == 0) - return (0); + return (fmac_priv_require_set(cr, req)); if (req == PRIV_FULLSET || priv_isfullset(req)) { priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); @@ -1321,7 +1321,7 @@ int secpolicy_pcfs_modify_bootpartition(const cred_t *cred) { - return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, + return (PRIV_POLICY(cred, PRIV_BOOTPART_MODIFY, B_FALSE, EACCES, "modify pcfs boot partition")); } @@ -1514,13 +1514,13 @@ int secpolicy_kmdb(const cred_t *scr) { - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); + return (PRIV_POLICY(scr, PRIV_SYS_DESTROY, B_FALSE, EPERM, NULL)); } int secpolicy_error_inject(const cred_t *scr) { - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); + return (PRIV_POLICY(scr, PRIV_SYS_DESTROY, B_FALSE, EPERM, NULL)); } /* @@ -1585,11 +1585,7 @@ int secpolicy_zone_config(const cred_t *cr) { - /* - * Require all privileges to avoid possibility of privilege - * escalation. - */ - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_ZONE_CONFIG, B_FALSE, EPERM, NULL)); } /* @@ -1979,7 +1975,8 @@ return (0); case MODLOAD: case MODSETDEVPOLICY: - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_MODULE_LOAD, B_FALSE, EPERM, + NULL)); default: return (secpolicy_sys_config(cr, B_FALSE)); } @@ -2004,7 +2001,7 @@ int secpolicy_sti(const cred_t *cr) { - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_STI, B_FALSE, EPERM, NULL)); } boolean_t @@ -2125,7 +2122,7 @@ int secpolicy_zinject(const cred_t *cr) { - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_ZFS_CONTROL, B_FALSE, EPERM, NULL)); } /* @@ -2160,7 +2157,7 @@ int secpolicy_ucode_update(const cred_t *scr) { - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); + return (PRIV_POLICY(scr, PRIV_UCODE_UPDATE, B_FALSE, EPERM, NULL)); } /* diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs --- a/usr/src/uts/common/os/priv_defs +++ b/usr/src/uts/common/os/priv_defs @@ -31,6 +31,10 @@ # add the new privilege at the end; for ordinary releases privileges # should be ordered alphabetically. # + +privilege PRIV_BOOTPART_MODIFY + + Allows a process to modify a pcfs boot partition. privilege PRIV_CONTRACT_EVENT @@ -71,6 +75,10 @@ Allows DTrace user-level tracing. Allows use of the syscall and profile DTrace providers to examine processes to which the user has permissions. + +privilege PRIV_DTRACE_ALL + + Allows DTrace tracing of all credentials. privilege PRIV_FILE_CHOWN @@ -162,6 +170,10 @@ Allows a process to set immutable, nounlink or appendonly file attributes. +privilege PRIV_FIRMWARE_UPDATE + + Allows a process to update firmware. + privilege PRIV_GRAPHICS_ACCESS Allows a process to make privileged ioctls to graphics devices. @@ -200,6 +212,10 @@ Message Queue, Semaphore Set, or Shared Memory Segment. Additional restrictions apply if the owner of the object has uid 0 and the effective uid of the current process is not 0. + +privilege PRIV_MODULE_LOAD + + Allows a process to load a module or set device policy. privilege PRIV_NET_BINDMLP @@ -309,6 +325,10 @@ Allows a process to trace or send signals to processes in other zones. +privilege PRIV_STI + + Allows a process to simulate terminal input. + privilege PRIV_SYS_ACCT Allows a process to enable and disable and manage accounting through @@ -335,6 +355,10 @@ Allows a process to add and remove swap devices; when adding a swap device, a process must also have sufficient privileges to read from and write to the swap device. + +privilege PRIV_SYS_DESTROY + + Allows a process to destroy the system (kmdb, error_inject). privilege PRIV_SYS_DEVICES @@ -446,6 +470,10 @@ string form. This privilege is interpreted only if the system is configured with Trusted Extensions. + +privilege PRIV_UCODE_UPDATE + + Allows a process to update the microcode of the platform. privilege PRIV_VIRT_MANAGE @@ -560,6 +588,14 @@ managing guest domains and the hypervisor. This privilege is used only if booted into xVM on x86 platforms. +privilege PRIV_ZFS_CONTROL + + Allows a process to inject faults in the ZFS fault injection framework. + +privilege PRIV_ZONE_CONFIG + + Allows a process to configure zones (create, halt, enter). + set PRIV_EFFECTIVE Set of privileges currently in effect. 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 @@ -35,6 +35,7 @@ #include #include #include +#include #else #include #endif /* _KERNEL */ @@ -107,6 +108,7 @@ access_vector_t perms); int fmac_vnode_priv_access(const cred_t *, vnode_t *, int, int); int fmac_priv_restrict(const cred_t *cr, int priv); +int fmac_priv_require_set(const cred_t *cr, const priv_set_t *req); int fmac_xvattr(cred_t *cr, vnode_t *vp, int priv, int err); #endif /* _KERNEL */ diff --git a/usr/src/uts/intel/io/dktp/dcdev/dadk.c b/usr/src/uts/intel/io/dktp/dcdev/dadk.c --- a/usr/src/uts/intel/io/dktp/dcdev/dadk.c +++ b/usr/src/uts/intel/io/dktp/dcdev/dadk.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -813,7 +814,8 @@ * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW * to protect the firmware update from malicious use */ - if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) + if (PRIV_POLICY(cred_p, PRIV_FIRMWARE_UPDATE, B_FALSE, + EPERM, NULL) != 0) return (EPERM); else return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); -- Stephen Smalley National Security Agency From William.Young at Sun.COM Mon Dec 15 10:54:00 2008 From: William.Young at Sun.COM (Will Young) Date: Mon, 15 Dec 2008 13:54:00 -0500 Subject: [fmac-discuss] [RFC][PATCH] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, handle secpolicy_require_set In-Reply-To: <1229365016.14137.14.camel@localhost.localdomain> References: <1229365016.14137.14.camel@localhost.localdomain> Message-ID: <4946A7C8.5050601@sun.com> Stephen Smalley wrote: > This patch replaces PRIV_ALL and PRIV_FULLSET checks with specific > privilege checks and introduces FMAC mediation of > secpolicy_require_set(). These changes complete the support for further > restricting the use of privileges via FMAC. > I think the changes make sense to me. The change in forced relationships between all privileges and capabilities that can achieve all privileges seems a little odd to me. I.e. I think the intention is that a user could have all the privileges allowed on the system and still not have PRIV_DTRACE_ALL, but inverting the usage a user could now have PRIV_DTRACE_ALL but not all the privileges allowed on the system. This appears lesser but I think it would be easily escalated. In some respects it seems to me like a set of privileges may need to emerge that can only be used when one both has all privileges allowed by FMAC and still have the specific privilege. > The particular choices of privilege names and how operations are mapped > to privileges is entirely open to discussion. > I have no issues with the choice of names. I do have one comment nit: > diff --git a/usr/src/uts/intel/io/dktp/dcdev/dadk.c b/usr/src/uts/intel/io/dktp/dcdev/dadk.c > --- a/usr/src/uts/intel/io/dktp/dcdev/dadk.c > +++ b/usr/src/uts/intel/io/dktp/dcdev/dadk.c > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > #include > > #include > @@ -813,7 +814,8 @@ > * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW > PRIV_ALL needs to be replaced with PRIV_FIRMWARE_UPDATE > * to protect the firmware update from malicious use > */ > - if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) > + if (PRIV_POLICY(cred_p, PRIV_FIRMWARE_UPDATE, B_FALSE, > + EPERM, NULL) != 0) > return (EPERM); > else > return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); > > > > Thanks, -Will From sds at tycho.nsa.gov Tue Dec 16 08:04:26 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 16 Dec 2008 11:04:26 -0500 Subject: [fmac-discuss] [RFC][PATCH] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, handle secpolicy_require_set In-Reply-To: <4946A7C8.5050601@sun.com> References: <1229365016.14137.14.camel@localhost.localdomain> <4946A7C8.5050601@sun.com> Message-ID: <1229443466.23604.90.camel@localhost.localdomain> On Mon, 2008-12-15 at 13:54 -0500, Will Young wrote: > Stephen Smalley wrote: > > This patch replaces PRIV_ALL and PRIV_FULLSET checks with specific > > privilege checks and introduces FMAC mediation of > > secpolicy_require_set(). These changes complete the support for further > > restricting the use of privileges via FMAC. > > > I think the changes make sense to me. The change in forced > relationships between all privileges and capabilities that can achieve > all privileges seems a little odd to me. I.e. I think the intention is > that a user could have all the privileges allowed on the system and > still not have PRIV_DTRACE_ALL, but inverting the usage a user could now > have PRIV_DTRACE_ALL but not all the privileges allowed on the system. > This appears lesser but I think it would be easily escalated. > > In some respects it seems to me like a set of privileges may need to > emerge that can only be used when one both has all privileges allowed by > FMAC and still have the specific privilege. We want to be able to enforce full least privilege (i.e. it should be possible to configure the mechanism such that no single subject in the system is allowed all privileges), and to maintain a clean separation between policy and mechanism. The situation prior to this patch is that we have to be overly permissive in allowing privileges to appease the privilege escalation prevention model, granting more privileges to subjects than they require for their purpose. While this may accurately reflect what those subjects can potentially achieve via escalation, it limits our ability to protect those subjects from being tricked into misusing privileges and may in fact ease exploitation of flaws in the privileged subjects. Using separate privileges and requiring people to understand the implications of granting a particular privilege (which seems necessary regardless) gives us greater control and flexibility. > > > The particular choices of privilege names and how operations are mapped > > to privileges is entirely open to discussion. > > > I have no issues with the choice of names. > > I do have one comment nit: > > diff --git a/usr/src/uts/intel/io/dktp/dcdev/dadk.c b/usr/src/uts/intel/io/dktp/dcdev/dadk.c > > --- a/usr/src/uts/intel/io/dktp/dcdev/dadk.c > > +++ b/usr/src/uts/intel/io/dktp/dcdev/dadk.c > > @@ -36,6 +36,7 @@ > > #include > > #include > > #include > > +#include > > #include > > > > #include > > @@ -813,7 +814,8 @@ > > * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW > > > PRIV_ALL needs to be replaced with PRIV_FIRMWARE_UPDATE Or perhaps drop the comment altogether, as it no longer provides much value when we are using a separate privilege that reflects the operation. > > * to protect the firmware update from malicious use > > */ > > - if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) > > + if (PRIV_POLICY(cred_p, PRIV_FIRMWARE_UPDATE, B_FALSE, > > + EPERM, NULL) != 0) > > return (EPERM); > > else > > return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); > > > > > > > > -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Tue Dec 16 11:17:09 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Tue, 16 Dec 2008 11:17:09 -0800 Subject: [fmac-discuss] [RFC][PATCH] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, handle secpolicy_require_set In-Reply-To: <1229443466.23604.90.camel@localhost.localdomain> References: <1229365016.14137.14.camel@localhost.localdomain> <4946A7C8.5050601@sun.com> <1229443466.23604.90.camel@localhost.localdomain> Message-ID: <4947FEB5.1030704@sun.com> Stephen Smalley wrote: > On Mon, 2008-12-15 at 13:54 -0500, Will Young wrote: > >> Stephen Smalley wrote: >> >>> This patch replaces PRIV_ALL and PRIV_FULLSET checks with specific >>> privilege checks and introduces FMAC mediation of >>> secpolicy_require_set(). These changes complete the support for further >>> restricting the use of privileges via FMAC. >>> >>> >> I think the changes make sense to me. The change in forced >> relationships between all privileges and capabilities that can achieve >> all privileges seems a little odd to me. I.e. I think the intention is >> that a user could have all the privileges allowed on the system and >> still not have PRIV_DTRACE_ALL, but inverting the usage a user could now >> have PRIV_DTRACE_ALL but not all the privileges allowed on the system. >> This appears lesser but I think it would be easily escalated. >> >> In some respects it seems to me like a set of privileges may need to >> emerge that can only be used when one both has all privileges allowed by >> FMAC and still have the specific privilege. >> > > We want to be able to enforce full least privilege (i.e. it should be > possible to configure the mechanism such that no single subject in the > system is allowed all privileges), and to maintain a clean separation > between policy and mechanism. > > The situation prior to this patch is that we have to be overly > permissive in allowing privileges to appease the privilege escalation > prevention model, granting more privileges to subjects than they require > for their purpose. While this may accurately reflect what those > subjects can potentially achieve via escalation, it limits our ability > to protect those subjects from being tricked into misusing privileges > and may in fact ease exploitation of flaws in the privileged subjects. > > Using separate privileges and requiring people to understand the > implications of granting a particular privilege (which seems necessary > regardless) gives us greater control and flexibility. > > You make an interesting point about the current requirement for PRIV_FULLSET. There are clearly cases where we have required all privileges for operations that don't present privilege escalation risks (such as editing /etc/motd). Type Enforcement is one way to indicate the security risk associated with modifying individual objects. In some cases, just changing the ownership of files like /etc/motd so that they are no longer owned by root should be done, which would enable a process with just PRIV_FILE_DAC_WRITE to make such modifications. The distinction between trusting a subject not to abuse it current privileges to make some configuration change which would result in escalation, vs. preventing the user from being tricked into using its privileges is rather subtle. It is almost a religious issue. --Glenn From sds at tycho.nsa.gov Tue Dec 16 11:39:31 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 16 Dec 2008 14:39:31 -0500 Subject: [fmac-discuss] [RFC][PATCH] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, handle secpolicy_require_set In-Reply-To: <4947FEB5.1030704@sun.com> References: <1229365016.14137.14.camel@localhost.localdomain> <4946A7C8.5050601@sun.com> <1229443466.23604.90.camel@localhost.localdomain> <4947FEB5.1030704@sun.com> Message-ID: <1229456371.23604.123.camel@localhost.localdomain> On Tue, 2008-12-16 at 11:17 -0800, Glenn Faden wrote: > Stephen Smalley wrote: > > On Mon, 2008-12-15 at 13:54 -0500, Will Young wrote: > > > >> Stephen Smalley wrote: > >> > >>> This patch replaces PRIV_ALL and PRIV_FULLSET checks with specific > >>> privilege checks and introduces FMAC mediation of > >>> secpolicy_require_set(). These changes complete the support for further > >>> restricting the use of privileges via FMAC. > >>> > >>> > >> I think the changes make sense to me. The change in forced > >> relationships between all privileges and capabilities that can achieve > >> all privileges seems a little odd to me. I.e. I think the intention is > >> that a user could have all the privileges allowed on the system and > >> still not have PRIV_DTRACE_ALL, but inverting the usage a user could now > >> have PRIV_DTRACE_ALL but not all the privileges allowed on the system. > >> This appears lesser but I think it would be easily escalated. > >> > >> In some respects it seems to me like a set of privileges may need to > >> emerge that can only be used when one both has all privileges allowed by > >> FMAC and still have the specific privilege. > >> > > > > We want to be able to enforce full least privilege (i.e. it should be > > possible to configure the mechanism such that no single subject in the > > system is allowed all privileges), and to maintain a clean separation > > between policy and mechanism. > > > > The situation prior to this patch is that we have to be overly > > permissive in allowing privileges to appease the privilege escalation > > prevention model, granting more privileges to subjects than they require > > for their purpose. While this may accurately reflect what those > > subjects can potentially achieve via escalation, it limits our ability > > to protect those subjects from being tricked into misusing privileges > > and may in fact ease exploitation of flaws in the privileged subjects. > > > > Using separate privileges and requiring people to understand the > > implications of granting a particular privilege (which seems necessary > > regardless) gives us greater control and flexibility. > > > > > You make an interesting point about the current requirement for > PRIV_FULLSET. There are clearly cases where we have required all > privileges for operations that don't present privilege escalation risks > (such as editing /etc/motd). Type Enforcement is one way to indicate the > security risk associated with modifying individual objects. In some > cases, just changing the ownership of files like /etc/motd so that they > are no longer owned by root should be done, which would enable a process > with just PRIV_FILE_DAC_WRITE to make such modifications. > > The distinction between trusting a subject not to abuse it current > privileges to make some configuration change which would result in > escalation, vs. preventing the user from being tricked into using its > privileges is rather subtle. It is almost a religious issue. Consider a case where the operation does in fact convey total control of the system, like loading a kernel module. Before this patch, that operation requires PRIV_FULLSET. With this patch, a separate privilege, PRIV_MODULE_LOAD, is required for it. Clearly having PRIV_MODULE_LOAD enables the subject to gain full privileges if it so chooses. Yet requiring that subject to have all privileges is counter-productive - the module loader has no legitimate reason to open arbitrary files, execute arbitrary programs, perform raw network access, etc, and allowing all privileges to that subject only opens more opportunities for it to be tricked into consuming untrustworthy inputs, executing evil code, loading the wrong module, etc. Protecting the kernel module loading process was in fact one of the examples in the original SELinux policy configuration. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Dec 17 10:10:26 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 17 Dec 2008 13:10:26 -0500 Subject: [fmac-discuss] [PATCH v2] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, mediate secpolicy_require_set Message-ID: <1229537426.31499.32.camel@localhost.localdomain> Second version of a patch that replaces PRIV_ALL and PRIV_FULLSET checks with specific privilege checks and introduces FMAC mediation of secpolicy_require_set(). These changes complete the support for further restricting the use of privileges via FMAC. Changes since the prior version: - Fixed firmware update comment. - Introduce separate privileges for kmdb vs error_inject (I don't see any callers of the latter, btw). - Rename a couple of the new privileges for clarity. In running the resulting system, I noticed that the initial ifconfig invocation triggers a require_set check on all privileges when opening the udp pseudo device. If I understand correctly, this is because it accesses the device before device policy has been loaded and the initial default policy requires all privs for any device access. Hopefully we can alleviate that problem in some manner so that we don't have to allow the ifconfig_t domain all privileges in policy, possibly by moving up the loading of device policy. (updated) Webrev available at: http://cr.opensolaris.org/~sds/privall/ diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c --- a/usr/src/uts/common/dtrace/dtrace.c +++ b/usr/src/uts/common/dtrace/dtrace.c @@ -6370,7 +6370,7 @@ { uint32_t priv; - if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { + if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_ALL, B_FALSE)) { /* * For DTRACE_PRIV_ALL, the uid and zoneid don't matter. */ @@ -10033,7 +10033,7 @@ ASSERT(MUTEX_HELD(&dtrace_lock)); if (size > dtrace_nonroot_maxsize && - !PRIV_POLICY_CHOICE(CRED(), PRIV_ALL, B_FALSE)) + !PRIV_POLICY_CHOICE(CRED(), PRIV_DTRACE_ALL, B_FALSE)) return (EFBIG); cp = cpu_list; @@ -12104,7 +12104,7 @@ * actual anonymous tracing, or the possession of all privileges, all of * the normal checks are bypassed. */ - if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { + if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_ALL, B_FALSE)) { state->dts_cred.dcr_visible = DTRACE_CRV_ALL; state->dts_cred.dcr_action = DTRACE_CRA_ALL; } else { diff --git a/usr/src/uts/common/dtrace/fasttrap.c b/usr/src/uts/common/dtrace/fasttrap.c --- a/usr/src/uts/common/dtrace/fasttrap.c +++ b/usr/src/uts/common/dtrace/fasttrap.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1968,7 +1969,7 @@ } } - if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { + if (!PRIV_POLICY_CHOICE(cr, PRIV_DTRACE_ALL, B_FALSE)) { proc_t *p; pid_t pid = probe->ftps_pid; @@ -2008,7 +2009,7 @@ if (copyin((void *)arg, &instr, sizeof (instr)) != 0) return (EFAULT); - if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { + if (!PRIV_POLICY_CHOICE(cr, PRIV_DTRACE_ALL, B_FALSE)) { proc_t *p; pid_t pid = instr.ftiq_pid; 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 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -883,3 +884,15 @@ ad.u.priv.priv = priv; return (avc_has_perm(cr_secid, cr_secid, sclass, av, &ad)); } + +int +fmac_priv_require_set(const cred_t *cr, const priv_set_t *req) +{ + int priv; + + for (priv = 0; priv < nprivs; priv++) + if (priv_ismember(req, priv)) + if (fmac_priv_restrict(cr, priv)) + return (EACCES); + return (0); +} 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 @@ -475,11 +475,11 @@ if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, &CR_OEPRIV(cr))) { - return (0); + return (fmac_priv_require_set(cr, req)); } if (priv_policy_override_set(cr, req, KLPDARG_NOMORE) == 0) - return (0); + return (fmac_priv_require_set(cr, req)); if (req == PRIV_FULLSET || priv_isfullset(req)) { priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); @@ -1321,7 +1321,7 @@ int secpolicy_pcfs_modify_bootpartition(const cred_t *cred) { - return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, + return (PRIV_POLICY(cred, PRIV_BOOTPART_MODIFY, B_FALSE, EACCES, "modify pcfs boot partition")); } @@ -1514,13 +1514,13 @@ int secpolicy_kmdb(const cred_t *scr) { - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); + return (PRIV_POLICY(scr, PRIV_KMDB, B_FALSE, EPERM, NULL)); } int secpolicy_error_inject(const cred_t *scr) { - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); + return (PRIV_POLICY(scr, PRIV_ERROR_INJECT, B_FALSE, EPERM, NULL)); } /* @@ -1585,11 +1585,7 @@ int secpolicy_zone_config(const cred_t *cr) { - /* - * Require all privileges to avoid possibility of privilege - * escalation. - */ - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_ZONE_CONFIG, B_FALSE, EPERM, NULL)); } /* @@ -1979,7 +1975,8 @@ return (0); case MODLOAD: case MODSETDEVPOLICY: - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_MODULE_LOAD, B_FALSE, EPERM, + NULL)); default: return (secpolicy_sys_config(cr, B_FALSE)); } @@ -2004,7 +2001,7 @@ int secpolicy_sti(const cred_t *cr) { - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_TTY_INPUT, B_FALSE, EPERM, NULL)); } boolean_t @@ -2125,7 +2122,7 @@ int secpolicy_zinject(const cred_t *cr) { - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (PRIV_POLICY(cr, PRIV_ZFS_INJECT, B_FALSE, EPERM, NULL)); } /* @@ -2160,7 +2157,7 @@ int secpolicy_ucode_update(const cred_t *scr) { - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); + return (PRIV_POLICY(scr, PRIV_UCODE_UPDATE, B_FALSE, EPERM, NULL)); } /* diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs --- a/usr/src/uts/common/os/priv_defs +++ b/usr/src/uts/common/os/priv_defs @@ -31,6 +31,10 @@ # add the new privilege at the end; for ordinary releases privileges # should be ordered alphabetically. # + +privilege PRIV_BOOTPART_MODIFY + + Allows a process to modify a pcfs boot partition. privilege PRIV_CONTRACT_EVENT @@ -71,6 +75,14 @@ Allows DTrace user-level tracing. Allows use of the syscall and profile DTrace providers to examine processes to which the user has permissions. + +privilege PRIV_DTRACE_ALL + + Allows DTrace tracing of all credentials. + +privilege PRIV_ERROR_INJECT + + Allows error injection. privilege PRIV_FILE_CHOWN @@ -162,6 +174,10 @@ Allows a process to set immutable, nounlink or appendonly file attributes. +privilege PRIV_FIRMWARE_UPDATE + + Allows a process to update firmware. + privilege PRIV_GRAPHICS_ACCESS Allows a process to make privileged ioctls to graphics devices. @@ -200,6 +216,14 @@ Message Queue, Semaphore Set, or Shared Memory Segment. Additional restrictions apply if the owner of the object has uid 0 and the effective uid of the current process is not 0. + +privilege PRIV_KMDB + + Allows access to /dev/kmdb. + +privilege PRIV_MODULE_LOAD + + Allows a process to load a module or set device policy. privilege PRIV_NET_BINDMLP @@ -447,6 +471,14 @@ This privilege is interpreted only if the system is configured with Trusted Extensions. +privilege PRIV_TTY_INPUT + + Allows a process to simulate terminal input. + +privilege PRIV_UCODE_UPDATE + + Allows a process to update the microcode of the platform. + privilege PRIV_VIRT_MANAGE Allows a process to manage virtualized environments such as @@ -560,6 +592,14 @@ managing guest domains and the hypervisor. This privilege is used only if booted into xVM on x86 platforms. +privilege PRIV_ZFS_INJECT + + Allows a process to inject faults in the ZFS fault injection framework. + +privilege PRIV_ZONE_CONFIG + + Allows a process to configure zones (create, halt, enter). + set PRIV_EFFECTIVE Set of privileges currently in effect. 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 @@ -35,6 +35,7 @@ #include #include #include +#include #else #include #endif /* _KERNEL */ @@ -107,6 +108,7 @@ access_vector_t perms); int fmac_vnode_priv_access(const cred_t *, vnode_t *, int, int); int fmac_priv_restrict(const cred_t *cr, int priv); +int fmac_priv_require_set(const cred_t *cr, const priv_set_t *req); int fmac_xvattr(cred_t *cr, vnode_t *vp, int priv, int err); #endif /* _KERNEL */ diff --git a/usr/src/uts/intel/io/dktp/dcdev/dadk.c b/usr/src/uts/intel/io/dktp/dcdev/dadk.c --- a/usr/src/uts/intel/io/dktp/dcdev/dadk.c +++ b/usr/src/uts/intel/io/dktp/dcdev/dadk.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -810,10 +811,10 @@ case DKIOC_UPDATEFW: /* - * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW - * to protect the firmware update from malicious use + * Protect the firmware update from malicious use */ - if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) + if (PRIV_POLICY(cred_p, PRIV_FIRMWARE_UPDATE, B_FALSE, + EPERM, NULL) != 0) return (EPERM); else return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); -- Stephen Smalley National Security Agency From john.weeks at sun.com Thu Dec 18 08:26:26 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 18 Dec 2008 08:26:26 -0800 Subject: [fmac-discuss] [PATCH v2] Replace PRIV_ALL/PRIV_FULLSET tests with specific privileges, mediate secpolicy_require_set In-Reply-To: <1229537426.31499.32.camel@localhost.localdomain> References: <1229537426.31499.32.camel@localhost.localdomain> Message-ID: <494A79B2.3080506@sun.com> On 12/17/08 10:10, Stephen Smalley wrote: > Second version of a patch that replaces PRIV_ALL and PRIV_FULLSET checks > with specific privilege checks and introduces FMAC mediation of > secpolicy_require_set(). These changes complete the support for further > restricting the use of privileges via FMAC. > > Changes since the prior version: > - Fixed firmware update comment. > - Introduce separate privileges for kmdb vs error_inject (I don't see > any callers of the latter, btw). > - Rename a couple of the new privileges for clarity. > > In running the resulting system, I noticed that the initial ifconfig > invocation triggers a require_set check on all privileges when opening > the udp pseudo device. If I understand correctly, this is because it > accesses the device before device policy has been loaded and the initial > default policy requires all privs for any device access. Hopefully we > can alleviate that problem in some manner so that we don't have to allow > the ifconfig_t domain all privileges in policy, possibly by moving up > the loading of device policy. > > (updated) Webrev available at: http://cr.opensolaris.org/~sds/privall/ Acked-by: John Weeks > > diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c > --- a/usr/src/uts/common/dtrace/dtrace.c > +++ b/usr/src/uts/common/dtrace/dtrace.c > @@ -6370,7 +6370,7 @@ > { > uint32_t priv; > > - if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { > + if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_ALL, B_FALSE)) { > /* > * For DTRACE_PRIV_ALL, the uid and zoneid don't matter. > */ > @@ -10033,7 +10033,7 @@ > ASSERT(MUTEX_HELD(&dtrace_lock)); > > if (size > dtrace_nonroot_maxsize && > - !PRIV_POLICY_CHOICE(CRED(), PRIV_ALL, B_FALSE)) > + !PRIV_POLICY_CHOICE(CRED(), PRIV_DTRACE_ALL, B_FALSE)) > return (EFBIG); > > cp = cpu_list; > @@ -12104,7 +12104,7 @@ > * actual anonymous tracing, or the possession of all privileges, all of > * the normal checks are bypassed. > */ > - if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { > + if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_ALL, B_FALSE)) { > state->dts_cred.dcr_visible = DTRACE_CRV_ALL; > state->dts_cred.dcr_action = DTRACE_CRA_ALL; > } else { > diff --git a/usr/src/uts/common/dtrace/fasttrap.c b/usr/src/uts/common/dtrace/fasttrap.c > --- a/usr/src/uts/common/dtrace/fasttrap.c > +++ b/usr/src/uts/common/dtrace/fasttrap.c > @@ -43,6 +43,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -1968,7 +1969,7 @@ > } > } > > - if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { > + if (!PRIV_POLICY_CHOICE(cr, PRIV_DTRACE_ALL, B_FALSE)) { > proc_t *p; > pid_t pid = probe->ftps_pid; > > @@ -2008,7 +2009,7 @@ > if (copyin((void *)arg, &instr, sizeof (instr)) != 0) > return (EFAULT); > > - if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { > + if (!PRIV_POLICY_CHOICE(cr, PRIV_DTRACE_ALL, B_FALSE)) { > proc_t *p; > pid_t pid = instr.ftiq_pid; > > 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 > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -883,3 +884,15 @@ > ad.u.priv.priv = priv; > return (avc_has_perm(cr_secid, cr_secid, sclass, av, &ad)); > } > + > +int > +fmac_priv_require_set(const cred_t *cr, const priv_set_t *req) > +{ > + int priv; > + > + for (priv = 0; priv < nprivs; priv++) > + if (priv_ismember(req, priv)) > + if (fmac_priv_restrict(cr, priv)) > + return (EACCES); > + return (0); > +} > 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 > @@ -475,11 +475,11 @@ > > if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, > &CR_OEPRIV(cr))) { > - return (0); > + return (fmac_priv_require_set(cr, req)); > } > > if (priv_policy_override_set(cr, req, KLPDARG_NOMORE) == 0) > - return (0); > + return (fmac_priv_require_set(cr, req)); > > if (req == PRIV_FULLSET || priv_isfullset(req)) { > priv_policy_err(cr, PRIV_ALL, B_FALSE, msg); > @@ -1321,7 +1321,7 @@ > int > secpolicy_pcfs_modify_bootpartition(const cred_t *cred) > { > - return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, > + return (PRIV_POLICY(cred, PRIV_BOOTPART_MODIFY, B_FALSE, EACCES, > "modify pcfs boot partition")); > } > > @@ -1514,13 +1514,13 @@ > int > secpolicy_kmdb(const cred_t *scr) > { > - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); > + return (PRIV_POLICY(scr, PRIV_KMDB, B_FALSE, EPERM, NULL)); > } > > int > secpolicy_error_inject(const cred_t *scr) > { > - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); > + return (PRIV_POLICY(scr, PRIV_ERROR_INJECT, B_FALSE, EPERM, NULL)); > } > > /* > @@ -1585,11 +1585,7 @@ > int > secpolicy_zone_config(const cred_t *cr) > { > - /* > - * Require all privileges to avoid possibility of privilege > - * escalation. > - */ > - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); > + return (PRIV_POLICY(cr, PRIV_ZONE_CONFIG, B_FALSE, EPERM, NULL)); > } > > /* > @@ -1979,7 +1975,8 @@ > return (0); > case MODLOAD: > case MODSETDEVPOLICY: > - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); > + return (PRIV_POLICY(cr, PRIV_MODULE_LOAD, B_FALSE, EPERM, > + NULL)); > default: > return (secpolicy_sys_config(cr, B_FALSE)); > } > @@ -2004,7 +2001,7 @@ > int > secpolicy_sti(const cred_t *cr) > { > - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); > + return (PRIV_POLICY(cr, PRIV_TTY_INPUT, B_FALSE, EPERM, NULL)); > } > > boolean_t > @@ -2125,7 +2122,7 @@ > int > secpolicy_zinject(const cred_t *cr) > { > - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); > + return (PRIV_POLICY(cr, PRIV_ZFS_INJECT, B_FALSE, EPERM, NULL)); > } > > /* > @@ -2160,7 +2157,7 @@ > int > secpolicy_ucode_update(const cred_t *scr) > { > - return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); > + return (PRIV_POLICY(scr, PRIV_UCODE_UPDATE, B_FALSE, EPERM, NULL)); > } > > /* > diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs > --- a/usr/src/uts/common/os/priv_defs > +++ b/usr/src/uts/common/os/priv_defs > @@ -31,6 +31,10 @@ > # add the new privilege at the end; for ordinary releases privileges > # should be ordered alphabetically. > # > + > +privilege PRIV_BOOTPART_MODIFY > + > + Allows a process to modify a pcfs boot partition. > > privilege PRIV_CONTRACT_EVENT > > @@ -71,6 +75,14 @@ > Allows DTrace user-level tracing. > Allows use of the syscall and profile DTrace providers to > examine processes to which the user has permissions. > + > +privilege PRIV_DTRACE_ALL > + > + Allows DTrace tracing of all credentials. > + > +privilege PRIV_ERROR_INJECT > + > + Allows error injection. > > privilege PRIV_FILE_CHOWN > > @@ -162,6 +174,10 @@ > Allows a process to set immutable, nounlink or appendonly > file attributes. > > +privilege PRIV_FIRMWARE_UPDATE > + > + Allows a process to update firmware. > + > privilege PRIV_GRAPHICS_ACCESS > > Allows a process to make privileged ioctls to graphics devices. > @@ -200,6 +216,14 @@ > Message Queue, Semaphore Set, or Shared Memory Segment. > Additional restrictions apply if the owner of the object has uid 0 > and the effective uid of the current process is not 0. > + > +privilege PRIV_KMDB > + > + Allows access to /dev/kmdb. > + > +privilege PRIV_MODULE_LOAD > + > + Allows a process to load a module or set device policy. > > privilege PRIV_NET_BINDMLP > > @@ -447,6 +471,14 @@ > This privilege is interpreted only if the system is configured > with Trusted Extensions. > > +privilege PRIV_TTY_INPUT > + > + Allows a process to simulate terminal input. > + > +privilege PRIV_UCODE_UPDATE > + > + Allows a process to update the microcode of the platform. > + > privilege PRIV_VIRT_MANAGE > > Allows a process to manage virtualized environments such as > @@ -560,6 +592,14 @@ > managing guest domains and the hypervisor. This privilege is > used only if booted into xVM on x86 platforms. > > +privilege PRIV_ZFS_INJECT > + > + Allows a process to inject faults in the ZFS fault injection framework. > + > +privilege PRIV_ZONE_CONFIG > + > + Allows a process to configure zones (create, halt, enter). > + > set PRIV_EFFECTIVE > > Set of privileges currently in effect. > 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 > @@ -35,6 +35,7 @@ > #include > #include > #include > +#include > #else > #include > #endif /* _KERNEL */ > @@ -107,6 +108,7 @@ > access_vector_t perms); > int fmac_vnode_priv_access(const cred_t *, vnode_t *, int, int); > int fmac_priv_restrict(const cred_t *cr, int priv); > +int fmac_priv_require_set(const cred_t *cr, const priv_set_t *req); > int fmac_xvattr(cred_t *cr, vnode_t *vp, int priv, int err); > #endif /* _KERNEL */ > > diff --git a/usr/src/uts/intel/io/dktp/dcdev/dadk.c b/usr/src/uts/intel/io/dktp/dcdev/dadk.c > --- a/usr/src/uts/intel/io/dktp/dcdev/dadk.c > +++ b/usr/src/uts/intel/io/dktp/dcdev/dadk.c > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > #include > > #include > @@ -810,10 +811,10 @@ > case DKIOC_UPDATEFW: > > /* > - * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW > - * to protect the firmware update from malicious use > + * Protect the firmware update from malicious use > */ > - if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) > + if (PRIV_POLICY(cred_p, PRIV_FIRMWARE_UPDATE, B_FALSE, > + EPERM, NULL) != 0) > return (EPERM); > else > return (dadk_ctl_ioctl(dadkp, cmd, arg, flag)); > From john.weeks at sun.com Fri Dec 19 00:31:41 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 19 Dec 2008 00:31:41 -0800 Subject: [fmac-discuss] [PATCH] Add user space context routines Message-ID: <494B5BED.9060509@sun.com> This patch adds user space functionality for manipulating security contexts and includes the following new libc routines: #include fmac_context_t fmac_context_new(const char *); void fmac_context_free(fmac_context_t); char *fmac_context_str(fmac_context_t); const char *fmac_context_user_get(fmac_context_t); const char *fmac_context_role_get(fmac_context_t); const char *fmac_context_type_get(fmac_context_t); const char *fmac_context_range_get(fmac_context_t); int fmac_context_user_set(fmac_context_t, const char *); int fmac_context_type_set(fmac_context_t, const char *); int fmac_context_role_set(fmac_context_t, const char *); int fmac_context_range_set(fmac_context_t, const char *); Man pages for the SELinux counterparts are available at: http://linux.die.net/man/3/context_new Webrev: http://cr.opensolaris.org/~jweeks/fmac-context/ diff --git a/usr/src/head/Makefile b/usr/src/head/Makefile --- a/usr/src/head/Makefile +++ b/usr/src/head/Makefile @@ -279,7 +279,9 @@ LVMRPCHDRS = \ mhdx.h mdiox.h meta_basic.h metad.h metamed.h metamhd.h metacl.h -FMACHDRS = fmac.h +FMACHDRS = \ + fmac_context.h \ + fmac.h SYMHDRASSERT = $(ROOT)/usr/include/iso/assert_iso.h SYMHDRERRNO = $(ROOT)/usr/include/iso/errno_iso.h diff --git a/usr/src/head/fmac/fmac_context.h b/usr/src/head/fmac/fmac_context.h new file mode 100644 --- /dev/null +++ b/usr/src/head/fmac/fmac_context.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +/* + * This source code originated from + * http://www.nsa.gov/selinux/archives/libselinux-2.0.65.tgz + * with the following LICENSE file in the top-level of the tar archive: + * + * This library (libselinux) is public domain software, i.e. not copyrighted. + * + * Warranty Exclusion + * ------------------ + * You agree that this software is a + * non-commercially developed program that may contain "bugs" (as that + * term is used in the industry) and that it may not function as intended. + * The software is licensed "as is". NSA makes no, and hereby expressly + * disclaims all, warranties, express, implied, statutory, or otherwise + * with respect to the software, including noninfringement and the implied + * warranties of merchantability and fitness for a particular purpose. + * + * Limitation of Liability + * ----------------------- + * In no event will NSA be liable for any damages, including loss of data, + * lost profits, cost of cover, or other special, incidental, + * consequential, direct or indirect damages arising from the software or + * the use thereof, however caused and on any theory of liability. This + * limitation will apply even if NSA has been advised of the possibility + * of such damage. You acknowledge that this is a reasonable allocation of + * risk. + */ + +#ifndef _FMAC_FMAC_CONTEXT_H +#define _FMAC_FMAC_CONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Functions to deal with security contexts in user space. + */ + +typedef struct { + void *ptr; +} fmac_context_s_t; + +typedef fmac_context_s_t *fmac_context_t; + +/* + * Return a new context initialized to a context string. + */ +extern fmac_context_t fmac_context_new(const char *); + +/* + * Return a pointer to the string value of the fmac_context_t + * Valid until the next call to fmac_context_str or fmac_context_free + * for the same fmac_context_t* + */ +extern char *fmac_context_str(fmac_context_t); + +/* + * Free the storage used by a context. + */ +extern void fmac_context_free(fmac_context_t); + +/* + * Get a pointer to the string value of a context component. + */ +extern const char *fmac_context_type_get(fmac_context_t); +extern const char *fmac_context_range_get(fmac_context_t); +extern const char *fmac_context_role_get(fmac_context_t); +extern const char *fmac_context_user_get(fmac_context_t); + +/* + * Set a context component. Returns nonzero if unsuccessful. + */ +extern int fmac_context_type_set(fmac_context_t, const char *); +extern int fmac_context_range_set(fmac_context_t, const char *); +extern int fmac_context_role_set(fmac_context_t, const char *); +extern int fmac_context_user_set(fmac_context_t, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _FMAC_FMAC_CONTEXT_H */ diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -106,6 +106,7 @@ ecvt.o \ errlst.o \ filecon.o \ + fmac_context.o \ amd64_data.o \ ldivide.o \ lock.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -110,6 +110,7 @@ cuexit.o \ ecvt.o \ errlst.o \ + fmac_context.o \ i386_data.o \ ladd.o \ ldivide.o \ diff --git a/usr/src/lib/libc/port/gen/fmac_context.c b/usr/src/lib/libc/port/gen/fmac_context.c new file mode 100644 --- /dev/null +++ b/usr/src/lib/libc/port/gen/fmac_context.c @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/* + * This source code originated from + * http://www.nsa.gov/selinux/archives/libselinux-2.0.65.tgz + * with the following LICENSE file in the top-level of the tar archive: + * + * This library (libselinux) is public domain software, i.e. not copyrighted. + * + * Warranty Exclusion + * ------------------ + * You agree that this software is a + * non-commercially developed program that may contain "bugs" (as that + * term is used in the industry) and that it may not function as intended. + * The software is licensed "as is". NSA makes no, and hereby expressly + * disclaims all, warranties, express, implied, statutory, or otherwise + * with respect to the software, including noninfringement and the implied + * warranties of merchantability and fitness for a particular purpose. + * + * Limitation of Liability + * ----------------------- + * In no event will NSA be liable for any damages, including loss of data, + * lost profits, cost of cover, or other special, incidental, + * consequential, direct or indirect damages arising from the software or + * the use thereof, however caused and on any theory of liability. This + * limitation will apply even if NSA has been advised of the possibility + * of such damage. You acknowledge that this is a reasonable allocation of + * risk. + */ + +#include "lint.h" +#include +#include +#include +#include +#include + +#define COMP_USER 0 +#define COMP_ROLE 1 +#define COMP_TYPE 2 +#define COMP_RANGE 3 + +typedef struct { + char *current_str; /* This is made up-to-date only when needed */ + char *(component[4]); +} fmac_context_private_t; + +/* + * Allocate a new context, initialized from str. There must be 3 or + * 4 colon-separated components and no whitespace in any component other + * than the MLS component. + */ +fmac_context_t +fmac_context_new(const char *str) +{ + int i, count; + fmac_context_private_t *n = + (fmac_context_private_t *)malloc(sizeof (fmac_context_private_t)); + fmac_context_t result = + (fmac_context_t)malloc(sizeof (fmac_context_s_t)); + const char *p, *tok; + + if (result) + result->ptr = n; + else + free(n); + if (n == 0 || result == 0) { + goto err; + } + n->current_str = n->component[0] = n->component[1] = n->component[2] = + n->component[3] = 0; + for (i = count = 0, p = str; *p; p++) { + switch (*p) { + case ':': + count++; + break; + case '\n': + case '\t': + case '\r': + goto err; /* sanity check */ + case ' ': + if (count < 3) + goto err; /* sanity check */ + } + } + /* + * Could be anywhere from 2 - 5 + * e.g user:role:type to user:role:type:sens1:cata-sens2:catb + */ + if (count < 2 || count > 5) { /* might not have a range */ + goto err; + } + + n->component[3] = 0; + for (i = 0, tok = str; *tok; i++) { + if (i < 3) + for (p = tok; *p && *p != ':'; p++) { /* empty */ + } else { + /* MLS range is one component */ + for (p = tok; *p; p++) { /* empty */ + } + } + n->component[i] = (char *)malloc(p - tok + 1); + if (n->component[i] == 0) + goto err; + strncpy(n->component[i], tok, p - tok); + n->component[i][p - tok] = '\0'; + tok = *p ? p + 1 : p; + } + return (result); +err: + fmac_context_free(result); + return (0); +} + +static void +fmac_conditional_free(char **v) +{ + if (*v) { + free(*v); + } + *v = 0; +} + +/* + * free all storage used by a context. Safe to call with + * null pointer. + */ +void +fmac_context_free(fmac_context_t context) +{ + fmac_context_private_t *n; + int i; + if (context) { + n = context->ptr; + if (n) { + fmac_conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + fmac_conditional_free(&n->component[i]); + } + free(n); + } + free(context); + } +} + +/* + * Return a pointer to the string value of the context. + */ +char * +fmac_context_str(fmac_context_t context) +{ + fmac_context_private_t *n = context->ptr; + int i; + size_t total = 0; + fmac_conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + if (n->component[i]) { + total += strlen(n->component[i]) + 1; + } + } + n->current_str = malloc(total); + if (n->current_str != 0) { + char *cp = n->current_str; + + strcpy(cp, n->component[0]); + for (i = 1; i < 4; i++) { + if (n->component[i]) { + strcat(cp, ":"); + strcat(cp, n->component[i]); + } + } + } + return (n->current_str); +} + +/* + * Returns nonzero on failure. + */ +static int +fmac_set_comp(fmac_context_private_t *n, int idx, const char *str) +{ + char *t = NULL; + const char *p; + if (str) { + t = (char *)malloc(strlen(str) + 1); + if (!t) { + return (1); + } + for (p = str; *p; p++) { + if (*p == '\t' || *p == '\n' || *p == '\r' || + ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) { + free(t); + errno = EINVAL; + return (1); + } + } + strcpy(t, str); + } + fmac_conditional_free(&n->component[idx]); + n->component[idx] = t; + return (0); +} + +#define def_get(name, tag) \ +const char * \ +fmac_context_ ## name ## _get(fmac_context_t context) \ +{ \ + fmac_context_private_t *n = context->ptr; \ + return (n->component[tag]); \ +} + +def_get(type, COMP_TYPE) +def_get(user, COMP_USER) +def_get(range, COMP_RANGE) +def_get(role, COMP_ROLE) + +#define def_set(name, tag) \ +int \ +fmac_context_ ## name ## _set(fmac_context_t context, const char *str) \ +{ \ + return (fmac_set_comp(context->ptr, tag, str)); \ +} + +def_set(type, COMP_TYPE) +def_set(role, COMP_ROLE) +def_set(user, COMP_USER) +def_set(range, COMP_RANGE) diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc --- a/usr/src/lib/libc/port/llib-lc +++ b/usr/src/lib/libc/port/llib-lc @@ -161,6 +161,7 @@ #include #endif #include +#include /* * This really comes from the crt*.s startup modules. diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -73,6 +73,17 @@ errx; fdatasync; fgetattr; + fmac_context_free; + fmac_context_new; + fmac_context_range_get; + fmac_context_range_set; + fmac_context_role_get; + fmac_context_role_set; + fmac_context_str; + fmac_context_type_get; + fmac_context_type_set; + fmac_context_user_get; + fmac_context_user_set; forkallx; forkx; freecon; diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile --- a/usr/src/lib/libc/sparc/Makefile +++ b/usr/src/lib/libc/sparc/Makefile @@ -127,6 +127,7 @@ cuexit.o \ ecvt.o \ errlst.o \ + fmac_context.o \ getctxt.o \ ladd.o \ lmul.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile --- a/usr/src/lib/libc/sparcv9/Makefile +++ b/usr/src/lib/libc/sparcv9/Makefile @@ -127,6 +127,7 @@ byteorder.o \ cuexit.o \ ecvt.o \ + fmac_context.o \ getctxt.o \ lock.o \ makectxt.o \ diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -218,6 +218,7 @@ f none usr/include/float.h 644 root bin d none usr/include/fmac 755 root bin f none usr/include/fmac/fmac.h 644 root bin +f none usr/include/fmac/fmac_context.h 644 root bin f none usr/include/fmtmsg.h 644 root bin f none usr/include/fnmatch.h 644 root bin f none usr/include/form.h 644 root bin From sds at tycho.nsa.gov Fri Dec 19 05:37:41 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 19 Dec 2008 08:37:41 -0500 Subject: [fmac-discuss] [PATCH] Add user space context routines In-Reply-To: <494B5BED.9060509@sun.com> References: <494B5BED.9060509@sun.com> Message-ID: <1229693861.4948.10.camel@localhost.localdomain> On Fri, 2008-12-19 at 00:31 -0800, John Weeks wrote: > This patch adds user space functionality for manipulating security contexts and includes the following new libc routines: > > #include > > fmac_context_t fmac_context_new(const char *); > void fmac_context_free(fmac_context_t); > char *fmac_context_str(fmac_context_t); > const char *fmac_context_user_get(fmac_context_t); > const char *fmac_context_role_get(fmac_context_t); > const char *fmac_context_type_get(fmac_context_t); > const char *fmac_context_range_get(fmac_context_t); > int fmac_context_user_set(fmac_context_t, const char *); > int fmac_context_type_set(fmac_context_t, const char *); > int fmac_context_role_set(fmac_context_t, const char *); > int fmac_context_range_set(fmac_context_t, const char *); > > Man pages for the SELinux counterparts are available at: > > http://linux.die.net/man/3/context_new > > Webrev: > > http://cr.opensolaris.org/~jweeks/fmac-context/ Acked-by: Stephen Smalley > > diff --git a/usr/src/head/Makefile b/usr/src/head/Makefile > --- a/usr/src/head/Makefile > +++ b/usr/src/head/Makefile > @@ -279,7 +279,9 @@ > LVMRPCHDRS = \ > mhdx.h mdiox.h meta_basic.h metad.h metamed.h metamhd.h metacl.h > > -FMACHDRS = fmac.h > +FMACHDRS = \ > + fmac_context.h \ > + fmac.h > > SYMHDRASSERT = $(ROOT)/usr/include/iso/assert_iso.h > SYMHDRERRNO = $(ROOT)/usr/include/iso/errno_iso.h > diff --git a/usr/src/head/fmac/fmac_context.h b/usr/src/head/fmac/fmac_context.h > new file mode 100644 > --- /dev/null > +++ b/usr/src/head/fmac/fmac_context.h > @@ -0,0 +1,111 @@ > +/* > + * 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. > + */ > + > +/* > + * This source code originated from > + * http://www.nsa.gov/selinux/archives/libselinux-2.0.65.tgz > + * with the following LICENSE file in the top-level of the tar archive: > + * > + * This library (libselinux) is public domain software, i.e. not copyrighted. > + * > + * Warranty Exclusion > + * ------------------ > + * You agree that this software is a > + * non-commercially developed program that may contain "bugs" (as that > + * term is used in the industry) and that it may not function as intended. > + * The software is licensed "as is". NSA makes no, and hereby expressly > + * disclaims all, warranties, express, implied, statutory, or otherwise > + * with respect to the software, including noninfringement and the implied > + * warranties of merchantability and fitness for a particular purpose. > + * > + * Limitation of Liability > + * ----------------------- > + * In no event will NSA be liable for any damages, including loss of data, > + * lost profits, cost of cover, or other special, incidental, > + * consequential, direct or indirect damages arising from the software or > + * the use thereof, however caused and on any theory of liability. This > + * limitation will apply even if NSA has been advised of the possibility > + * of such damage. You acknowledge that this is a reasonable allocation of > + * risk. > + */ > + > +#ifndef _FMAC_FMAC_CONTEXT_H > +#define _FMAC_FMAC_CONTEXT_H > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include > + > +/* > + * Functions to deal with security contexts in user space. > + */ > + > +typedef struct { > + void *ptr; > +} fmac_context_s_t; > + > +typedef fmac_context_s_t *fmac_context_t; > + > +/* > + * Return a new context initialized to a context string. > + */ > +extern fmac_context_t fmac_context_new(const char *); > + > +/* > + * Return a pointer to the string value of the fmac_context_t > + * Valid until the next call to fmac_context_str or fmac_context_free > + * for the same fmac_context_t* > + */ > +extern char *fmac_context_str(fmac_context_t); > + > +/* > + * Free the storage used by a context. > + */ > +extern void fmac_context_free(fmac_context_t); > + > +/* > + * Get a pointer to the string value of a context component. > + */ > +extern const char *fmac_context_type_get(fmac_context_t); > +extern const char *fmac_context_range_get(fmac_context_t); > +extern const char *fmac_context_role_get(fmac_context_t); > +extern const char *fmac_context_user_get(fmac_context_t); > + > +/* > + * Set a context component. Returns nonzero if unsuccessful. > + */ > +extern int fmac_context_type_set(fmac_context_t, const char *); > +extern int fmac_context_range_set(fmac_context_t, const char *); > +extern int fmac_context_role_set(fmac_context_t, const char *); > +extern int fmac_context_user_set(fmac_context_t, const char *); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _FMAC_FMAC_CONTEXT_H */ > diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile > --- a/usr/src/lib/libc/amd64/Makefile > +++ b/usr/src/lib/libc/amd64/Makefile > @@ -106,6 +106,7 @@ > ecvt.o \ > errlst.o \ > filecon.o \ > + fmac_context.o \ > amd64_data.o \ > ldivide.o \ > lock.o \ > diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com > --- a/usr/src/lib/libc/i386/Makefile.com > +++ b/usr/src/lib/libc/i386/Makefile.com > @@ -110,6 +110,7 @@ > cuexit.o \ > ecvt.o \ > errlst.o \ > + fmac_context.o \ > i386_data.o \ > ladd.o \ > ldivide.o \ > diff --git a/usr/src/lib/libc/port/gen/fmac_context.c b/usr/src/lib/libc/port/gen/fmac_context.c > new file mode 100644 > --- /dev/null > +++ b/usr/src/lib/libc/port/gen/fmac_context.c > @@ -0,0 +1,252 @@ > +/* > + * 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. > + */ > + > +/* > + * This source code originated from > + * http://www.nsa.gov/selinux/archives/libselinux-2.0.65.tgz > + * with the following LICENSE file in the top-level of the tar archive: > + * > + * This library (libselinux) is public domain software, i.e. not copyrighted. > + * > + * Warranty Exclusion > + * ------------------ > + * You agree that this software is a > + * non-commercially developed program that may contain "bugs" (as that > + * term is used in the industry) and that it may not function as intended. > + * The software is licensed "as is". NSA makes no, and hereby expressly > + * disclaims all, warranties, express, implied, statutory, or otherwise > + * with respect to the software, including noninfringement and the implied > + * warranties of merchantability and fitness for a particular purpose. > + * > + * Limitation of Liability > + * ----------------------- > + * In no event will NSA be liable for any damages, including loss of data, > + * lost profits, cost of cover, or other special, incidental, > + * consequential, direct or indirect damages arising from the software or > + * the use thereof, however caused and on any theory of liability. This > + * limitation will apply even if NSA has been advised of the possibility > + * of such damage. You acknowledge that this is a reasonable allocation of > + * risk. > + */ > + > +#include "lint.h" > +#include > +#include > +#include > +#include > +#include > + > +#define COMP_USER 0 > +#define COMP_ROLE 1 > +#define COMP_TYPE 2 > +#define COMP_RANGE 3 > + > +typedef struct { > + char *current_str; /* This is made up-to-date only when needed */ > + char *(component[4]); > +} fmac_context_private_t; > + > +/* > + * Allocate a new context, initialized from str. There must be 3 or > + * 4 colon-separated components and no whitespace in any component other > + * than the MLS component. > + */ > +fmac_context_t > +fmac_context_new(const char *str) > +{ > + int i, count; > + fmac_context_private_t *n = > + (fmac_context_private_t *)malloc(sizeof (fmac_context_private_t)); > + fmac_context_t result = > + (fmac_context_t)malloc(sizeof (fmac_context_s_t)); > + const char *p, *tok; > + > + if (result) > + result->ptr = n; > + else > + free(n); > + if (n == 0 || result == 0) { > + goto err; > + } > + n->current_str = n->component[0] = n->component[1] = n->component[2] = > + n->component[3] = 0; > + for (i = count = 0, p = str; *p; p++) { > + switch (*p) { > + case ':': > + count++; > + break; > + case '\n': > + case '\t': > + case '\r': > + goto err; /* sanity check */ > + case ' ': > + if (count < 3) > + goto err; /* sanity check */ > + } > + } > + /* > + * Could be anywhere from 2 - 5 > + * e.g user:role:type to user:role:type:sens1:cata-sens2:catb > + */ > + if (count < 2 || count > 5) { /* might not have a range */ > + goto err; > + } > + > + n->component[3] = 0; > + for (i = 0, tok = str; *tok; i++) { > + if (i < 3) > + for (p = tok; *p && *p != ':'; p++) { /* empty */ > + } else { > + /* MLS range is one component */ > + for (p = tok; *p; p++) { /* empty */ > + } > + } > + n->component[i] = (char *)malloc(p - tok + 1); > + if (n->component[i] == 0) > + goto err; > + strncpy(n->component[i], tok, p - tok); > + n->component[i][p - tok] = '\0'; > + tok = *p ? p + 1 : p; > + } > + return (result); > +err: > + fmac_context_free(result); > + return (0); > +} > + > +static void > +fmac_conditional_free(char **v) > +{ > + if (*v) { > + free(*v); > + } > + *v = 0; > +} > + > +/* > + * free all storage used by a context. Safe to call with > + * null pointer. > + */ > +void > +fmac_context_free(fmac_context_t context) > +{ > + fmac_context_private_t *n; > + int i; > + if (context) { > + n = context->ptr; > + if (n) { > + fmac_conditional_free(&n->current_str); > + for (i = 0; i < 4; i++) { > + fmac_conditional_free(&n->component[i]); > + } > + free(n); > + } > + free(context); > + } > +} > + > +/* > + * Return a pointer to the string value of the context. > + */ > +char * > +fmac_context_str(fmac_context_t context) > +{ > + fmac_context_private_t *n = context->ptr; > + int i; > + size_t total = 0; > + fmac_conditional_free(&n->current_str); > + for (i = 0; i < 4; i++) { > + if (n->component[i]) { > + total += strlen(n->component[i]) + 1; > + } > + } > + n->current_str = malloc(total); > + if (n->current_str != 0) { > + char *cp = n->current_str; > + > + strcpy(cp, n->component[0]); > + for (i = 1; i < 4; i++) { > + if (n->component[i]) { > + strcat(cp, ":"); > + strcat(cp, n->component[i]); > + } > + } > + } > + return (n->current_str); > +} > + > +/* > + * Returns nonzero on failure. > + */ > +static int > +fmac_set_comp(fmac_context_private_t *n, int idx, const char *str) > +{ > + char *t = NULL; > + const char *p; > + if (str) { > + t = (char *)malloc(strlen(str) + 1); > + if (!t) { > + return (1); > + } > + for (p = str; *p; p++) { > + if (*p == '\t' || *p == '\n' || *p == '\r' || > + ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) { > + free(t); > + errno = EINVAL; > + return (1); > + } > + } > + strcpy(t, str); > + } > + fmac_conditional_free(&n->component[idx]); > + n->component[idx] = t; > + return (0); > +} > + > +#define def_get(name, tag) \ > +const char * \ > +fmac_context_ ## name ## _get(fmac_context_t context) \ > +{ \ > + fmac_context_private_t *n = context->ptr; \ > + return (n->component[tag]); \ > +} > + > +def_get(type, COMP_TYPE) > +def_get(user, COMP_USER) > +def_get(range, COMP_RANGE) > +def_get(role, COMP_ROLE) > + > +#define def_set(name, tag) \ > +int \ > +fmac_context_ ## name ## _set(fmac_context_t context, const char *str) \ > +{ \ > + return (fmac_set_comp(context->ptr, tag, str)); \ > +} > + > +def_set(type, COMP_TYPE) > +def_set(role, COMP_ROLE) > +def_set(user, COMP_USER) > +def_set(range, COMP_RANGE) > diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc > --- a/usr/src/lib/libc/port/llib-lc > +++ b/usr/src/lib/libc/port/llib-lc > @@ -161,6 +161,7 @@ > #include > #endif > #include > +#include > > /* > * This really comes from the crt*.s startup modules. > diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers > --- a/usr/src/lib/libc/port/mapfile-vers > +++ b/usr/src/lib/libc/port/mapfile-vers > @@ -73,6 +73,17 @@ > errx; > fdatasync; > fgetattr; > + fmac_context_free; > + fmac_context_new; > + fmac_context_range_get; > + fmac_context_range_set; > + fmac_context_role_get; > + fmac_context_role_set; > + fmac_context_str; > + fmac_context_type_get; > + fmac_context_type_set; > + fmac_context_user_get; > + fmac_context_user_set; > forkallx; > forkx; > freecon; > diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile > --- a/usr/src/lib/libc/sparc/Makefile > +++ b/usr/src/lib/libc/sparc/Makefile > @@ -127,6 +127,7 @@ > cuexit.o \ > ecvt.o \ > errlst.o \ > + fmac_context.o \ > getctxt.o \ > ladd.o \ > lmul.o \ > diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile > --- a/usr/src/lib/libc/sparcv9/Makefile > +++ b/usr/src/lib/libc/sparcv9/Makefile > @@ -127,6 +127,7 @@ > byteorder.o \ > cuexit.o \ > ecvt.o \ > + fmac_context.o \ > getctxt.o \ > lock.o \ > makectxt.o \ > diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com > --- a/usr/src/pkgdefs/SUNWhea/prototype_com > +++ b/usr/src/pkgdefs/SUNWhea/prototype_com > @@ -218,6 +218,7 @@ > f none usr/include/float.h 644 root bin > d none usr/include/fmac 755 root bin > f none usr/include/fmac/fmac.h 644 root bin > +f none usr/include/fmac/fmac_context.h 644 root bin > f none usr/include/fmtmsg.h 644 root bin > f none usr/include/fnmatch.h 644 root bin > f none usr/include/form.h 644 root bin > _______________________________________________ > 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 Fri Dec 19 05:38:56 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 19 Dec 2008 08:38:56 -0500 Subject: [fmac-discuss] [PATCH] Change newrole to use the fmac_context functions Message-ID: <1229693936.4948.12.camel@localhost.localdomain> Change newrole to use the fmac_context functions for manipulating the security context. diff --git a/usr/src/cmd/fmac/newrole/newrole.c b/usr/src/cmd/fmac/newrole/newrole.c --- a/usr/src/cmd/fmac/newrole/newrole.c +++ b/usr/src/cmd/fmac/newrole/newrole.c @@ -36,6 +36,7 @@ #include #include #include +#include #include int @@ -46,15 +47,14 @@ 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; + fmac_context_t fcon; + security_context_t pcontext, ncontext; + const char *p_role; + const char *p_type; + const char *p_level; + const char *n_role = NULL; + const char *n_type = NULL; + const char *n_level = NULL; char *shell; char **nargv; @@ -121,15 +121,22 @@ /* Get and parse previous process context */ if (getprevcon(&pcontext)) { (void) fprintf(stderr, - gettext("%s: can't get pervious context: %s\n"), + gettext("%s: can't get previous context: %s\n"), prog, strerror(errno)); exit(1); } - p_user = strtok(pcontext, ":"); - p_role = strtok(NULL, ":"); - p_type = strtok(NULL, ":"); - p_level = strtok(NULL, ""); + fcon = fmac_context_new(pcontext); + if (!fcon) { + (void) fprintf(stderr, + gettext("%s: can't split previous context: %s\n"), + prog, strerror(errno)); + exit(1); + } + + p_role = fmac_context_role_get(fcon); + p_type = fmac_context_type_get(fcon); + p_level = fmac_context_range_get(fcon); /* Merge process and requested context fields */ if (n_role == NULL) @@ -139,24 +146,28 @@ 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)) { + if (fmac_context_role_set(fcon, n_role)) { (void) fprintf(stderr, - gettext("%s: maximum size of context exceeded\n"), prog); + gettext("%s: unable to set role\n"), prog); + exit(1); + } + if (fmac_context_type_set(fcon, n_type)) { + (void) fprintf(stderr, + gettext("%s: unable to set type\n"), prog); + exit(1); + } + if (fmac_context_range_set(fcon, n_level)) { + (void) fprintf(stderr, + gettext("%s: unable to set level\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); + ncontext = fmac_context_str(fcon); + if (!ncontext) { + (void) fprintf(stderr, + gettext("%s: unable to set up new context\n"), prog); exit(1); - } + } if (security_check_context(ncontext) != 0) { (void) fprintf(stderr, -- Stephen Smalley National Security Agency From john.weeks at sun.com Fri Dec 19 08:38:40 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 19 Dec 2008 08:38:40 -0800 Subject: [fmac-discuss] [PATCH] Change newrole to use the fmac_context functions In-Reply-To: <1229693936.4948.12.camel@localhost.localdomain> References: <1229693936.4948.12.camel@localhost.localdomain> Message-ID: <494BCE10.7060506@sun.com> On 12/19/08 05:38, Stephen Smalley wrote: > Change newrole to use the fmac_context functions for manipulating the > security context. Thank you for updating newrole and fixing the typo I introduced in the original version. Acked-by: John Weeks > > diff --git a/usr/src/cmd/fmac/newrole/newrole.c b/usr/src/cmd/fmac/newrole/newrole.c > --- a/usr/src/cmd/fmac/newrole/newrole.c > +++ b/usr/src/cmd/fmac/newrole/newrole.c > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > #include > > int > @@ -46,15 +47,14 @@ > 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; > + fmac_context_t fcon; > + security_context_t pcontext, ncontext; > + const char *p_role; > + const char *p_type; > + const char *p_level; > + const char *n_role = NULL; > + const char *n_type = NULL; > + const char *n_level = NULL; > char *shell; > char **nargv; > > @@ -121,15 +121,22 @@ > /* Get and parse previous process context */ > if (getprevcon(&pcontext)) { > (void) fprintf(stderr, > - gettext("%s: can't get pervious context: %s\n"), > + gettext("%s: can't get previous context: %s\n"), > prog, strerror(errno)); > exit(1); > } > > - p_user = strtok(pcontext, ":"); > - p_role = strtok(NULL, ":"); > - p_type = strtok(NULL, ":"); > - p_level = strtok(NULL, ""); > + fcon = fmac_context_new(pcontext); > + if (!fcon) { > + (void) fprintf(stderr, > + gettext("%s: can't split previous context: %s\n"), > + prog, strerror(errno)); > + exit(1); > + } > + > + p_role = fmac_context_role_get(fcon); > + p_type = fmac_context_type_get(fcon); > + p_level = fmac_context_range_get(fcon); > > /* Merge process and requested context fields */ > if (n_role == NULL) > @@ -139,24 +146,28 @@ > 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)) { > + if (fmac_context_role_set(fcon, n_role)) { > (void) fprintf(stderr, > - gettext("%s: maximum size of context exceeded\n"), prog); > + gettext("%s: unable to set role\n"), prog); > + exit(1); > + } > + if (fmac_context_type_set(fcon, n_type)) { > + (void) fprintf(stderr, > + gettext("%s: unable to set type\n"), prog); > + exit(1); > + } > + if (fmac_context_range_set(fcon, n_level)) { > + (void) fprintf(stderr, > + gettext("%s: unable to set level\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); > + ncontext = fmac_context_str(fcon); > + if (!ncontext) { > + (void) fprintf(stderr, > + gettext("%s: unable to set up new context\n"), prog); > exit(1); > - } > + } > > if (security_check_context(ncontext) != 0) { > (void) fprintf(stderr, >