Re: [RFC PATCH v3 4/5] selinux: introduce kdbus names into the policy

Stephen Smalley
2015-10-09T16:38:54Z

On 10/07/2015 07:08 PM, Paul Moore wrote:
> SELinux treats kdbus service names as objects and therefore needs a
> mechanism to map service names to security labels. This patch adds
> support for loading kdbus name/label matches with the security policy.
>
> The patch supports service name prefix matching to lessen the burden
> on the policy developers and reduce the size of the resulting policy.
>
> Signed-off-by: Paul Moore <pmoore@redhat.com>
>
> ---
> ChangeLog:
> - v3
> * Ported to the 4.3-rc4 based kdbus tree, v2 hacks removed
> - v2
> * Porting needed to work with ioctl xperms
> - v1
> * Initial draft
> ---
> security/selinux/include/security.h | 5 ++
> security/selinux/ss/policydb.c | 88 +++++++++++++++++++++++++++++------
> security/selinux/ss/policydb.h | 3 +
> security/selinux/ss/services.c | 38 +++++++++++++++
> 4 files changed, 116 insertions(+), 18 deletions(-)
>

> diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
> index 992a315..9be2e6d 100644
> --- a/security/selinux/ss/policydb.c
> +++ b/security/selinux/ss/policydb.c
> @@ -2111,7 +2116,7 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
> int i, j, rc;
> u32 nel, len;
> __le32 buf[3];
> - struct ocontext *l, *c;
> + struct ocontext *l, *l2, *c;
> u32 nodebuf[8];
>
> for (i = 0; i < info->ocon_num; i++) {
> @@ -2130,6 +2135,7 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
> l->next = c;
> else
> p->ocontexts[i] = c;
> + l2 = l;
> l = c;
>
> switch (i) {
> @@ -2219,6 +2225,43 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
> goto out;
> break;
> }
> + case OCON_KDBUS: {
> + struct ocontext *iter, *last;
> + u32 len2;
> +
> + rc = next_entry(buf, fp, sizeof(u32));
> + if (rc)
> + goto out;
> + len = le32_to_cpu(buf[0]);
> + rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
> + if (rc)
> + goto out;
> + rc = context_read_and_validate(&c->context[0], p, fp);
> + if (rc) {
> + kfree(c->u.name);
> + goto out;
> + }
> +
> + /* sort by ->u.name length, longest first */
> + last = NULL;
> + iter = p->ocontexts[OCON_KDBUS];
> + while (iter != c) {
> + len2 = strlen(iter->u.name);
> + if (len > len2) {
> + if (l2)
> + l2->next = NULL;
> + c->next = iter;
> + if (last == NULL)
> + p->ocontexts[i] = c;
> + else
> + last->next = c;
> + break;
> + }
> + last = iter;
> + iter = iter->next;
> + }
> + break;

This seems complicated compared to genfs_read() due to the fact that
ocontext_read() pre-inserts node into the list. Maybe we should change
ocontext_read() to defer insertion until after the switch statement, and
then we don't have to un-link and re-link these entries?

> + }
> }
> }
> }
> @@ -3147,6 +3190,19 @@ static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
> if (rc)
> return rc;
> break;
> + case OCON_KDBUS:
> + len = strlen(c->u.name);
> + buf[0] = cpu_to_le32(len);
> + rc = put_entry(buf, sizeof(u32), 1, fp);
> + if (rc)
> + return rc;
> + rc = put_entry(c->u.name, len, 1, fp);
> + if (rc)
> + return rc;
> + rc = context_write(p, &c->context[0], fp);
> + if (rc)
> + return rc;
> + break;
> }
> }
> }
> diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
> index 725d594..ee9c120 100644
> --- a/security/selinux/ss/policydb.h
> +++ b/security/selinux/ss/policydb.h
> @@ -222,7 +222,8 @@ struct genfs {
> #define OCON_NODE 4 /* nodes */
> #define OCON_FSUSE 5 /* fs_use */
> #define OCON_NODE6 6 /* IPv6 nodes */
> -#define OCON_NUM 7
> +#define OCON_KDBUS 7 /* kdbus names */
> +#define OCON_NUM 8
>
> /* The policy database */
> struct policydb {
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index b7df12b..ada2d28 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -2536,6 +2536,44 @@ int security_genfs_sid(const char *fstype,
> }
>
> /**
> + * security_kdbus_sid - Obtain a SID for a kdbus name
> + * @name: kdbus name
> + * @sid: SID for the kdbus name
> + *
> + * Obtain a SID for the given kdbus service name. Returns zero on success,
> + * negative values on error.
> + */
> +int security_kdbus_sid(const char *name, u32 *sid)
> +{
> + int rc = 0;
> + struct ocontext *c;
> +
> + read_lock(&policy_rwlock);
> +
> + c = policydb.ocontexts[OCON_KDBUS];
> + while (c) {
> + if (strncmp(c->u.name, name, strlen(c->u.name)) == 0)
> + break;
> + c = c->next;
> + }
> +
> + if (c) {
> + if (!c->sid[0]) {
> + rc = sidtab_context_to_sid(&sidtab,
> + &c->context[0], &c->sid[0]);
> + if (rc)
> + goto out;
> + }
> + *sid = c->sid[0];
> + } else
> + *sid = SECINITSID_UNLABELED;
> +
> +out:
> + read_unlock(&policy_rwlock);
> + return rc;
> +}
> +
> +/**
> * security_fs_use - Determine how to handle labeling for a filesystem.
> * @sb: superblock in question
> */
>
> _______________________________________________
> Selinux mailing list
> Selinux@tycho.nsa.gov
> To unsubscribe, send email to Selinux-leave@tycho.nsa.gov.
> To get help, send an email containing "help" to Selinux-request@tycho.nsa.gov.
>