#define POLICYDB_VERSION_BOUNDARY      24
 #define POLICYDB_VERSION_FILENAME_TRANS        25
 #define POLICYDB_VERSION_ROLETRANS     26
+#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS   27
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX   CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_ROLETRANS
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_NEW_OBJECT_DEFAULTS
 #endif
 
 /* Mask for just the mount related flags */
 
        return rc;
 }
 
+/*
+ * Sets both levels in the MLS range of 'dst' to the high level of 'src'.
+ */
+static inline int mls_context_cpy_high(struct context *dst, struct context *src)
+{
+       int rc;
+
+       dst->range.level[0].sens = src->range.level[1].sens;
+       rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat);
+       if (rc)
+               goto out;
+
+       dst->range.level[1].sens = src->range.level[1].sens;
+       rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
+       if (rc)
+               ebitmap_destroy(&dst->range.level[0].cat);
+out:
+       return rc;
+}
+
 static inline int mls_context_cmp(struct context *c1, struct context *c2)
 {
        return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
 
 {
        struct range_trans rtr;
        struct mls_range *r;
+       struct class_datum *cladatum;
+       int default_range = 0;
 
        if (!policydb.mls_enabled)
                return 0;
                r = hashtab_search(policydb.range_tr, &rtr);
                if (r)
                        return mls_range_set(newcontext, r);
+
+               if (tclass && tclass <= policydb.p_classes.nprim) {
+                       cladatum = policydb.class_val_to_struct[tclass - 1];
+                       if (cladatum)
+                               default_range = cladatum->default_range;
+               }
+
+               switch (default_range) {
+               case DEFAULT_SOURCE_LOW:
+                       return mls_context_cpy_low(newcontext, scontext);
+               case DEFAULT_SOURCE_HIGH:
+                       return mls_context_cpy_high(newcontext, scontext);
+               case DEFAULT_SOURCE_LOW_HIGH:
+                       return mls_context_cpy(newcontext, scontext);
+               case DEFAULT_TARGET_LOW:
+                       return mls_context_cpy_low(newcontext, tcontext);
+               case DEFAULT_TARGET_HIGH:
+                       return mls_context_cpy_high(newcontext, tcontext);
+               case DEFAULT_TARGET_LOW_HIGH:
+                       return mls_context_cpy(newcontext, tcontext);
+               }
+
                /* Fallthrough */
        case AVTAB_CHANGE:
                if ((tclass == policydb.process_class) || (sock == true))
 
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
+       {
+               .version        = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       },
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
                        goto bad;
        }
 
+       if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
+               rc = next_entry(buf, fp, sizeof(u32) * 3);
+               if (rc)
+                       goto bad;
+
+               cladatum->default_user = le32_to_cpu(buf[0]);
+               cladatum->default_role = le32_to_cpu(buf[1]);
+               cladatum->default_range = le32_to_cpu(buf[2]);
+       }
+
        rc = hashtab_insert(h, key, cladatum);
        if (rc)
                goto bad;
        if (rc)
                return rc;
 
+       if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
+               buf[0] = cpu_to_le32(cladatum->default_user);
+               buf[1] = cpu_to_le32(cladatum->default_role);
+               buf[2] = cpu_to_le32(cladatum->default_range);
+
+               rc = put_entry(buf, sizeof(uint32_t), 3, fp);
+               if (rc)
+                       return rc;
+       }
+
        return 0;
 }
 
 
        struct symtab permissions;      /* class-specific permission symbol table */
        struct constraint_node *constraints;    /* constraints on class permissions */
        struct constraint_node *validatetrans;  /* special transition rules */
+       /* Options how a new object user and role should be decided */
+#define DEFAULT_SOURCE         1
+#define DEFAULT_TARGET         2
+       char default_user;
+       char default_role;
+/* Options how a new object range should be decided */
+#define DEFAULT_SOURCE_LOW     1
+#define DEFAULT_SOURCE_HIGH    2
+#define DEFAULT_SOURCE_LOW_HIGH        3
+#define DEFAULT_TARGET_LOW     4
+#define DEFAULT_TARGET_HIGH    5
+#define DEFAULT_TARGET_LOW_HIGH        6
+       char default_range;
 };
 
 /* Role attributes */
 
                                u32 *out_sid,
                                bool kern)
 {
+       struct class_datum *cladatum = NULL;
        struct context *scontext = NULL, *tcontext = NULL, newcontext;
        struct role_trans *roletr = NULL;
        struct avtab_key avkey;
                goto out_unlock;
        }
 
+       if (tclass && tclass <= policydb.p_classes.nprim)
+               cladatum = policydb.class_val_to_struct[tclass - 1];
+
        /* Set the user identity. */
        switch (specified) {
        case AVTAB_TRANSITION:
        case AVTAB_CHANGE:
-               /* Use the process user identity. */
-               newcontext.user = scontext->user;
+               if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
+                       newcontext.user = tcontext->user;
+               } else {
+                       /* notice this gets both DEFAULT_SOURCE and unset */
+                       /* Use the process user identity. */
+                       newcontext.user = scontext->user;
+               }
                break;
        case AVTAB_MEMBER:
                /* Use the related object owner. */
                break;
        }
 
-       /* Set the role and type to default values. */
-       if ((tclass == policydb.process_class) || (sock == true)) {
-               /* Use the current role and type of process. */
+       /* Set the role to default values. */
+       if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
                newcontext.role = scontext->role;
+       } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
+               newcontext.role = tcontext->role;
+       } else {
+               if ((tclass == policydb.process_class) || (sock == true))
+                       newcontext.role = scontext->role;
+               else
+                       newcontext.role = OBJECT_R_VAL;
+       }
+
+       /* Set the type to default values. */
+       if ((tclass == policydb.process_class) || (sock == true)) {
+               /* Use the type of process. */
                newcontext.type = scontext->type;
        } else {
-               /* Use the well-defined object role. */
-               newcontext.role = OBJECT_R_VAL;
                /* Use the type of the related object. */
                newcontext.type = tcontext->type;
        }