These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / security / selinux / ss / services.c
index 9e2d820..ebb5eb3 100644 (file)
@@ -93,9 +93,10 @@ static int context_struct_to_string(struct context *context, char **scontext,
                                    u32 *scontext_len);
 
 static void context_struct_compute_av(struct context *scontext,
-                                     struct context *tcontext,
-                                     u16 tclass,
-                                     struct av_decision *avd);
+                                       struct context *tcontext,
+                                       u16 tclass,
+                                       struct av_decision *avd,
+                                       struct extended_perms *xperms);
 
 struct selinux_mapping {
        u16 value; /* policy value */
@@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext,
                context_struct_compute_av(&lo_scontext,
                                          tcontext,
                                          tclass,
-                                         &lo_avd);
+                                         &lo_avd,
+                                         NULL);
                if ((lo_avd.allowed & avd->allowed) == avd->allowed)
                        return;         /* no masked permission */
                masked = ~lo_avd.allowed & avd->allowed;
@@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext,
                context_struct_compute_av(scontext,
                                          &lo_tcontext,
                                          tclass,
-                                         &lo_avd);
+                                         &lo_avd,
+                                         NULL);
                if ((lo_avd.allowed & avd->allowed) == avd->allowed)
                        return;         /* no masked permission */
                masked = ~lo_avd.allowed & avd->allowed;
@@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext,
                context_struct_compute_av(&lo_scontext,
                                          &lo_tcontext,
                                          tclass,
-                                         &lo_avd);
+                                         &lo_avd,
+                                         NULL);
                if ((lo_avd.allowed & avd->allowed) == avd->allowed)
                        return;         /* no masked permission */
                masked = ~lo_avd.allowed & avd->allowed;
@@ -613,13 +617,39 @@ static void type_attribute_bounds_av(struct context *scontext,
 }
 
 /*
- * Compute access vectors based on a context structure pair for
- * the permissions in a particular class.
+ * flag which drivers have permissions
+ * only looking for ioctl based extended permssions
+ */
+void services_compute_xperms_drivers(
+               struct extended_perms *xperms,
+               struct avtab_node *node)
+{
+       unsigned int i;
+
+       if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
+               /* if one or more driver has all permissions allowed */
+               for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
+                       xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
+       } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
+               /* if allowing permissions within a driver */
+               security_xperm_set(xperms->drivers.p,
+                                       node->datum.u.xperms->driver);
+       }
+
+       /* If no ioctl commands are allowed, ignore auditallow and auditdeny */
+       if (node->key.specified & AVTAB_XPERMS_ALLOWED)
+               xperms->len = 1;
+}
+
+/*
+ * Compute access vectors and extended permissions based on a context
+ * structure pair for the permissions in a particular class.
  */
 static void context_struct_compute_av(struct context *scontext,
-                                     struct context *tcontext,
-                                     u16 tclass,
-                                     struct av_decision *avd)
+                                       struct context *tcontext,
+                                       u16 tclass,
+                                       struct av_decision *avd,
+                                       struct extended_perms *xperms)
 {
        struct constraint_node *constraint;
        struct role_allow *ra;
@@ -633,6 +663,10 @@ static void context_struct_compute_av(struct context *scontext,
        avd->allowed = 0;
        avd->auditallow = 0;
        avd->auditdeny = 0xffffffff;
+       if (xperms) {
+               memset(&xperms->drivers, 0, sizeof(xperms->drivers));
+               xperms->len = 0;
+       }
 
        if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
                if (printk_ratelimit())
@@ -647,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext,
         * this permission check, then use it.
         */
        avkey.target_class = tclass;
-       avkey.specified = AVTAB_AV;
+       avkey.specified = AVTAB_AV | AVTAB_XPERMS;
        sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
        BUG_ON(!sattr);
        tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
@@ -660,15 +694,18 @@ static void context_struct_compute_av(struct context *scontext,
                             node;
                             node = avtab_search_node_next(node, avkey.specified)) {
                                if (node->key.specified == AVTAB_ALLOWED)
-                                       avd->allowed |= node->datum.data;
+                                       avd->allowed |= node->datum.u.data;
                                else if (node->key.specified == AVTAB_AUDITALLOW)
-                                       avd->auditallow |= node->datum.data;
+                                       avd->auditallow |= node->datum.u.data;
                                else if (node->key.specified == AVTAB_AUDITDENY)
-                                       avd->auditdeny &= node->datum.data;
+                                       avd->auditdeny &= node->datum.u.data;
+                               else if (xperms && (node->key.specified & AVTAB_XPERMS))
+                                       services_compute_xperms_drivers(xperms, node);
                        }
 
                        /* Check conditional av table for additional permissions */
-                       cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+                       cond_compute_av(&policydb.te_cond_avtab, &avkey,
+                                       avd, xperms);
 
                }
        }
@@ -899,6 +936,139 @@ static void avd_init(struct av_decision *avd)
        avd->flags = 0;
 }
 
+void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
+                                       struct avtab_node *node)
+{
+       unsigned int i;
+
+       if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
+               if (xpermd->driver != node->datum.u.xperms->driver)
+                       return;
+       } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
+               if (!security_xperm_test(node->datum.u.xperms->perms.p,
+                                       xpermd->driver))
+                       return;
+       } else {
+               BUG();
+       }
+
+       if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
+               xpermd->used |= XPERMS_ALLOWED;
+               if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
+                       memset(xpermd->allowed->p, 0xff,
+                                       sizeof(xpermd->allowed->p));
+               }
+               if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
+                       for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
+                               xpermd->allowed->p[i] |=
+                                       node->datum.u.xperms->perms.p[i];
+               }
+       } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
+               xpermd->used |= XPERMS_AUDITALLOW;
+               if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
+                       memset(xpermd->auditallow->p, 0xff,
+                                       sizeof(xpermd->auditallow->p));
+               }
+               if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
+                       for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
+                               xpermd->auditallow->p[i] |=
+                                       node->datum.u.xperms->perms.p[i];
+               }
+       } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
+               xpermd->used |= XPERMS_DONTAUDIT;
+               if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
+                       memset(xpermd->dontaudit->p, 0xff,
+                                       sizeof(xpermd->dontaudit->p));
+               }
+               if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
+                       for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
+                               xpermd->dontaudit->p[i] |=
+                                       node->datum.u.xperms->perms.p[i];
+               }
+       } else {
+               BUG();
+       }
+}
+
+void security_compute_xperms_decision(u32 ssid,
+                               u32 tsid,
+                               u16 orig_tclass,
+                               u8 driver,
+                               struct extended_perms_decision *xpermd)
+{
+       u16 tclass;
+       struct context *scontext, *tcontext;
+       struct avtab_key avkey;
+       struct avtab_node *node;
+       struct ebitmap *sattr, *tattr;
+       struct ebitmap_node *snode, *tnode;
+       unsigned int i, j;
+
+       xpermd->driver = driver;
+       xpermd->used = 0;
+       memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
+       memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
+       memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
+
+       read_lock(&policy_rwlock);
+       if (!ss_initialized)
+               goto allow;
+
+       scontext = sidtab_search(&sidtab, ssid);
+       if (!scontext) {
+               printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
+                      __func__, ssid);
+               goto out;
+       }
+
+       tcontext = sidtab_search(&sidtab, tsid);
+       if (!tcontext) {
+               printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
+                      __func__, tsid);
+               goto out;
+       }
+
+       tclass = unmap_class(orig_tclass);
+       if (unlikely(orig_tclass && !tclass)) {
+               if (policydb.allow_unknown)
+                       goto allow;
+               goto out;
+       }
+
+
+       if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
+               pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
+               goto out;
+       }
+
+       avkey.target_class = tclass;
+       avkey.specified = AVTAB_XPERMS;
+       sattr = flex_array_get(policydb.type_attr_map_array,
+                               scontext->type - 1);
+       BUG_ON(!sattr);
+       tattr = flex_array_get(policydb.type_attr_map_array,
+                               tcontext->type - 1);
+       BUG_ON(!tattr);
+       ebitmap_for_each_positive_bit(sattr, snode, i) {
+               ebitmap_for_each_positive_bit(tattr, tnode, j) {
+                       avkey.source_type = i + 1;
+                       avkey.target_type = j + 1;
+                       for (node = avtab_search_node(&policydb.te_avtab, &avkey);
+                            node;
+                            node = avtab_search_node_next(node, avkey.specified))
+                               services_compute_xperms_decision(xpermd, node);
+
+                       cond_compute_xperms(&policydb.te_cond_avtab,
+                                               &avkey, xpermd);
+               }
+       }
+out:
+       read_unlock(&policy_rwlock);
+       return;
+allow:
+       memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
+       goto out;
+}
 
 /**
  * security_compute_av - Compute access vector decisions.
@@ -906,6 +1076,7 @@ static void avd_init(struct av_decision *avd)
  * @tsid: target security identifier
  * @tclass: target security class
  * @avd: access vector decisions
+ * @xperms: extended permissions
  *
  * Compute a set of access vector decisions based on the
  * SID pair (@ssid, @tsid) for the permissions in @tclass.
@@ -913,13 +1084,15 @@ static void avd_init(struct av_decision *avd)
 void security_compute_av(u32 ssid,
                         u32 tsid,
                         u16 orig_tclass,
-                        struct av_decision *avd)
+                        struct av_decision *avd,
+                        struct extended_perms *xperms)
 {
        u16 tclass;
        struct context *scontext = NULL, *tcontext = NULL;
 
        read_lock(&policy_rwlock);
        avd_init(avd);
+       xperms->len = 0;
        if (!ss_initialized)
                goto allow;
 
@@ -947,7 +1120,7 @@ void security_compute_av(u32 ssid,
                        goto allow;
                goto out;
        }
-       context_struct_compute_av(scontext, tcontext, tclass, avd);
+       context_struct_compute_av(scontext, tcontext, tclass, avd, xperms);
        map_decision(orig_tclass, avd, policydb.allow_unknown);
 out:
        read_unlock(&policy_rwlock);
@@ -993,7 +1166,7 @@ void security_compute_av_user(u32 ssid,
                goto out;
        }
 
-       context_struct_compute_av(scontext, tcontext, tclass, avd);
+       context_struct_compute_av(scontext, tcontext, tclass, avd, NULL);
  out:
        read_unlock(&policy_rwlock);
        return;
@@ -1045,13 +1218,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
        /*
         * Copy the user name, role name and type name into the context.
         */
-       sprintf(scontextp, "%s:%s:%s",
+       scontextp += sprintf(scontextp, "%s:%s:%s",
                sym_name(&policydb, SYM_USERS, context->user - 1),
                sym_name(&policydb, SYM_ROLES, context->role - 1),
                sym_name(&policydb, SYM_TYPES, context->type - 1));
-       scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
-                    1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
-                    1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
 
        mls_sid_to_context(context, &scontextp);
 
@@ -1086,12 +1256,12 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
                        *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
                        if (!scontext)
                                goto out;
-                       scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
+                       scontextp = kmemdup(initial_sid_to_string[sid],
+                                           *scontext_len, GFP_ATOMIC);
                        if (!scontextp) {
                                rc = -ENOMEM;
                                goto out;
                        }
-                       strcpy(scontextp, initial_sid_to_string[sid]);
                        *scontext = scontextp;
                        goto out;
                }
@@ -1303,6 +1473,11 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
                                            sid, SECSID_NULL, gfp, 0);
 }
 
+int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
+{
+       return security_context_to_sid(scontext, strlen(scontext), sid, gfp);
+}
+
 /**
  * security_context_to_sid_default - Obtain a SID for a given security context,
  * falling back to specified default if needed.
@@ -1515,7 +1690,7 @@ static int security_compute_sid(u32 ssid,
 
        if (avdatum) {
                /* Use the type from the type transition/member/change rule. */
-               newcontext.type = avdatum->data;
+               newcontext.type = avdatum->u.data;
        }
 
        /* if we have a objname this is a file trans check so check those rules */
@@ -2431,18 +2606,12 @@ int security_get_bools(int *len, char ***names, int **values)
                goto err;
 
        for (i = 0; i < *len; i++) {
-               size_t name_len;
-
                (*values)[i] = policydb.bool_val_to_struct[i]->state;
-               name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
 
                rc = -ENOMEM;
-               (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
+               (*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC);
                if (!(*names)[i])
                        goto err;
-
-               strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
-               (*names)[i][name_len - 1] = 0;
        }
        rc = 0;
 out: