|
@@ -70,11 +70,6 @@ unsigned int policydb_loaded_version;
|
|
|
int selinux_policycap_netpeer;
|
|
|
int selinux_policycap_openperm;
|
|
|
|
|
|
-/*
|
|
|
- * This is declared in avc.c
|
|
|
- */
|
|
|
-extern const struct selinux_class_perm selinux_class_perm;
|
|
|
-
|
|
|
static DEFINE_RWLOCK(policy_rwlock);
|
|
|
|
|
|
static struct sidtab sidtab;
|
|
@@ -98,6 +93,158 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
u16 tclass,
|
|
|
u32 requested,
|
|
|
struct av_decision *avd);
|
|
|
+
|
|
|
+struct selinux_mapping {
|
|
|
+ u16 value; /* policy value */
|
|
|
+ unsigned num_perms;
|
|
|
+ u32 perms[sizeof(u32) * 8];
|
|
|
+};
|
|
|
+
|
|
|
+static struct selinux_mapping *current_mapping;
|
|
|
+static u16 current_mapping_size;
|
|
|
+
|
|
|
+static int selinux_set_mapping(struct policydb *pol,
|
|
|
+ struct security_class_mapping *map,
|
|
|
+ struct selinux_mapping **out_map_p,
|
|
|
+ u16 *out_map_size)
|
|
|
+{
|
|
|
+ struct selinux_mapping *out_map = NULL;
|
|
|
+ size_t size = sizeof(struct selinux_mapping);
|
|
|
+ u16 i, j;
|
|
|
+ unsigned k;
|
|
|
+ bool print_unknown_handle = false;
|
|
|
+
|
|
|
+ /* Find number of classes in the input mapping */
|
|
|
+ if (!map)
|
|
|
+ return -EINVAL;
|
|
|
+ i = 0;
|
|
|
+ while (map[i].name)
|
|
|
+ i++;
|
|
|
+
|
|
|
+ /* Allocate space for the class records, plus one for class zero */
|
|
|
+ out_map = kcalloc(++i, size, GFP_ATOMIC);
|
|
|
+ if (!out_map)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ /* Store the raw class and permission values */
|
|
|
+ j = 0;
|
|
|
+ while (map[j].name) {
|
|
|
+ struct security_class_mapping *p_in = map + (j++);
|
|
|
+ struct selinux_mapping *p_out = out_map + j;
|
|
|
+
|
|
|
+ /* An empty class string skips ahead */
|
|
|
+ if (!strcmp(p_in->name, "")) {
|
|
|
+ p_out->num_perms = 0;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ p_out->value = string_to_security_class(pol, p_in->name);
|
|
|
+ if (!p_out->value) {
|
|
|
+ printk(KERN_INFO
|
|
|
+ "SELinux: Class %s not defined in policy.\n",
|
|
|
+ p_in->name);
|
|
|
+ if (pol->reject_unknown)
|
|
|
+ goto err;
|
|
|
+ p_out->num_perms = 0;
|
|
|
+ print_unknown_handle = true;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ k = 0;
|
|
|
+ while (p_in->perms && p_in->perms[k]) {
|
|
|
+ /* An empty permission string skips ahead */
|
|
|
+ if (!*p_in->perms[k]) {
|
|
|
+ k++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ p_out->perms[k] = string_to_av_perm(pol, p_out->value,
|
|
|
+ p_in->perms[k]);
|
|
|
+ if (!p_out->perms[k]) {
|
|
|
+ printk(KERN_INFO
|
|
|
+ "SELinux: Permission %s in class %s not defined in policy.\n",
|
|
|
+ p_in->perms[k], p_in->name);
|
|
|
+ if (pol->reject_unknown)
|
|
|
+ goto err;
|
|
|
+ print_unknown_handle = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ k++;
|
|
|
+ }
|
|
|
+ p_out->num_perms = k;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (print_unknown_handle)
|
|
|
+ printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
|
|
|
+ pol->allow_unknown ? "allowed" : "denied");
|
|
|
+
|
|
|
+ *out_map_p = out_map;
|
|
|
+ *out_map_size = i;
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ kfree(out_map);
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Get real, policy values from mapped values
|
|
|
+ */
|
|
|
+
|
|
|
+static u16 unmap_class(u16 tclass)
|
|
|
+{
|
|
|
+ if (tclass < current_mapping_size)
|
|
|
+ return current_mapping[tclass].value;
|
|
|
+
|
|
|
+ return tclass;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 unmap_perm(u16 tclass, u32 tperm)
|
|
|
+{
|
|
|
+ if (tclass < current_mapping_size) {
|
|
|
+ unsigned i;
|
|
|
+ u32 kperm = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < current_mapping[tclass].num_perms; i++)
|
|
|
+ if (tperm & (1<<i)) {
|
|
|
+ kperm |= current_mapping[tclass].perms[i];
|
|
|
+ tperm &= ~(1<<i);
|
|
|
+ }
|
|
|
+ return kperm;
|
|
|
+ }
|
|
|
+
|
|
|
+ return tperm;
|
|
|
+}
|
|
|
+
|
|
|
+static void map_decision(u16 tclass, struct av_decision *avd,
|
|
|
+ int allow_unknown)
|
|
|
+{
|
|
|
+ if (tclass < current_mapping_size) {
|
|
|
+ unsigned i, n = current_mapping[tclass].num_perms;
|
|
|
+ u32 result;
|
|
|
+
|
|
|
+ for (i = 0, result = 0; i < n; i++) {
|
|
|
+ if (avd->allowed & current_mapping[tclass].perms[i])
|
|
|
+ result |= 1<<i;
|
|
|
+ if (allow_unknown && !current_mapping[tclass].perms[i])
|
|
|
+ result |= 1<<i;
|
|
|
+ }
|
|
|
+ avd->allowed = result;
|
|
|
+
|
|
|
+ for (i = 0, result = 0; i < n; i++)
|
|
|
+ if (avd->auditallow & current_mapping[tclass].perms[i])
|
|
|
+ result |= 1<<i;
|
|
|
+ avd->auditallow = result;
|
|
|
+
|
|
|
+ for (i = 0, result = 0; i < n; i++) {
|
|
|
+ if (avd->auditdeny & current_mapping[tclass].perms[i])
|
|
|
+ result |= 1<<i;
|
|
|
+ if (!allow_unknown && !current_mapping[tclass].perms[i])
|
|
|
+ result |= 1<<i;
|
|
|
+ }
|
|
|
+ avd->auditdeny = result;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Return the boolean value of a constraint expression
|
|
|
* when it is applied to the specified source and target
|
|
@@ -467,7 +614,6 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
struct class_datum *tclass_datum;
|
|
|
struct ebitmap *sattr, *tattr;
|
|
|
struct ebitmap_node *snode, *tnode;
|
|
|
- const struct selinux_class_perm *kdefs = &selinux_class_perm;
|
|
|
unsigned int i, j;
|
|
|
|
|
|
/*
|
|
@@ -477,9 +623,9 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
* to remain in the correct class.
|
|
|
*/
|
|
|
if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
|
|
|
- if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
|
|
|
- tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
|
|
|
- tclass = SECCLASS_NETLINK_SOCKET;
|
|
|
+ if (tclass >= unmap_class(SECCLASS_NETLINK_ROUTE_SOCKET) &&
|
|
|
+ tclass <= unmap_class(SECCLASS_NETLINK_DNRT_SOCKET))
|
|
|
+ tclass = unmap_class(SECCLASS_NETLINK_SOCKET);
|
|
|
|
|
|
/*
|
|
|
* Initialize the access vectors to the default values.
|
|
@@ -490,33 +636,11 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
avd->seqno = latest_granting;
|
|
|
avd->flags = 0;
|
|
|
|
|
|
- /*
|
|
|
- * Check for all the invalid cases.
|
|
|
- * - tclass 0
|
|
|
- * - tclass > policy and > kernel
|
|
|
- * - tclass > policy but is a userspace class
|
|
|
- * - tclass > policy but we do not allow unknowns
|
|
|
- */
|
|
|
- if (unlikely(!tclass))
|
|
|
- goto inval_class;
|
|
|
- if (unlikely(tclass > policydb.p_classes.nprim))
|
|
|
- if (tclass > kdefs->cts_len ||
|
|
|
- !kdefs->class_to_string[tclass] ||
|
|
|
- !policydb.allow_unknown)
|
|
|
- goto inval_class;
|
|
|
-
|
|
|
- /*
|
|
|
- * Kernel class and we allow unknown so pad the allow decision
|
|
|
- * the pad will be all 1 for unknown classes.
|
|
|
- */
|
|
|
- if (tclass <= kdefs->cts_len && policydb.allow_unknown)
|
|
|
- avd->allowed = policydb.undefined_perms[tclass - 1];
|
|
|
-
|
|
|
- /*
|
|
|
- * Not in policy. Since decision is completed (all 1 or all 0) return.
|
|
|
- */
|
|
|
- if (unlikely(tclass > policydb.p_classes.nprim))
|
|
|
- return 0;
|
|
|
+ if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
|
|
|
+ if (printk_ratelimit())
|
|
|
+ printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
tclass_datum = policydb.class_val_to_struct[tclass - 1];
|
|
|
|
|
@@ -568,8 +692,8 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
* role is changing, then check the (current_role, new_role)
|
|
|
* pair.
|
|
|
*/
|
|
|
- if (tclass == SECCLASS_PROCESS &&
|
|
|
- (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
|
|
|
+ if (tclass == policydb.process_class &&
|
|
|
+ (avd->allowed & policydb.process_trans_perms) &&
|
|
|
scontext->role != tcontext->role) {
|
|
|
for (ra = policydb.role_allow; ra; ra = ra->next) {
|
|
|
if (scontext->role == ra->role &&
|
|
@@ -577,8 +701,7 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
break;
|
|
|
}
|
|
|
if (!ra)
|
|
|
- avd->allowed &= ~(PROCESS__TRANSITION |
|
|
|
- PROCESS__DYNTRANSITION);
|
|
|
+ avd->allowed &= ~policydb.process_trans_perms;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -590,21 +713,6 @@ static int context_struct_compute_av(struct context *scontext,
|
|
|
tclass, requested, avd);
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-inval_class:
|
|
|
- if (!tclass || tclass > kdefs->cts_len ||
|
|
|
- !kdefs->class_to_string[tclass]) {
|
|
|
- if (printk_ratelimit())
|
|
|
- printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
|
|
|
- __func__, tclass);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Known to the kernel, but not to the policy.
|
|
|
- * Handle as a denial (allowed is 0).
|
|
|
- */
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
static int security_validtrans_handle_fail(struct context *ocontext,
|
|
@@ -636,13 +744,14 @@ out:
|
|
|
}
|
|
|
|
|
|
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
- u16 tclass)
|
|
|
+ u16 orig_tclass)
|
|
|
{
|
|
|
struct context *ocontext;
|
|
|
struct context *ncontext;
|
|
|
struct context *tcontext;
|
|
|
struct class_datum *tclass_datum;
|
|
|
struct constraint_node *constraint;
|
|
|
+ u16 tclass;
|
|
|
int rc = 0;
|
|
|
|
|
|
if (!ss_initialized)
|
|
@@ -650,6 +759,8 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
|
|
|
read_lock(&policy_rwlock);
|
|
|
|
|
|
+ tclass = unmap_class(orig_tclass);
|
|
|
+
|
|
|
/*
|
|
|
* Remap extended Netlink classes for old policy versions.
|
|
|
* Do this here rather than socket_type_to_security_class()
|
|
@@ -657,9 +768,9 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
* to remain in the correct class.
|
|
|
*/
|
|
|
if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
|
|
|
- if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
|
|
|
- tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
|
|
|
- tclass = SECCLASS_NETLINK_SOCKET;
|
|
|
+ if (tclass >= unmap_class(SECCLASS_NETLINK_ROUTE_SOCKET) &&
|
|
|
+ tclass <= unmap_class(SECCLASS_NETLINK_DNRT_SOCKET))
|
|
|
+ tclass = unmap_class(SECCLASS_NETLINK_SOCKET);
|
|
|
|
|
|
if (!tclass || tclass > policydb.p_classes.nprim) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
|
|
@@ -792,6 +903,38 @@ out:
|
|
|
}
|
|
|
|
|
|
|
|
|
+static int security_compute_av_core(u32 ssid,
|
|
|
+ u32 tsid,
|
|
|
+ u16 tclass,
|
|
|
+ u32 requested,
|
|
|
+ struct av_decision *avd)
|
|
|
+{
|
|
|
+ struct context *scontext = NULL, *tcontext = NULL;
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ scontext = sidtab_search(&sidtab, ssid);
|
|
|
+ if (!scontext) {
|
|
|
+ printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
+ __func__, ssid);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ tcontext = sidtab_search(&sidtab, tsid);
|
|
|
+ if (!tcontext) {
|
|
|
+ printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
+ __func__, tsid);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = context_struct_compute_av(scontext, tcontext, tclass,
|
|
|
+ requested, avd);
|
|
|
+
|
|
|
+ /* permissive domain? */
|
|
|
+ if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
|
|
+ avd->flags |= AVD_FLAGS_PERMISSIVE;
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* security_compute_av - Compute access vector decisions.
|
|
|
* @ssid: source security identifier
|
|
@@ -807,12 +950,45 @@ out:
|
|
|
*/
|
|
|
int security_compute_av(u32 ssid,
|
|
|
u32 tsid,
|
|
|
- u16 tclass,
|
|
|
- u32 requested,
|
|
|
+ u16 orig_tclass,
|
|
|
+ u32 orig_requested,
|
|
|
struct av_decision *avd)
|
|
|
{
|
|
|
- struct context *scontext = NULL, *tcontext = NULL;
|
|
|
- int rc = 0;
|
|
|
+ u16 tclass;
|
|
|
+ u32 requested;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ if (!ss_initialized)
|
|
|
+ goto allow;
|
|
|
+
|
|
|
+ read_lock(&policy_rwlock);
|
|
|
+ requested = unmap_perm(orig_tclass, orig_requested);
|
|
|
+ tclass = unmap_class(orig_tclass);
|
|
|
+ if (unlikely(orig_tclass && !tclass)) {
|
|
|
+ if (policydb.allow_unknown)
|
|
|
+ goto allow;
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ rc = security_compute_av_core(ssid, tsid, tclass, requested, avd);
|
|
|
+ map_decision(orig_tclass, avd, policydb.allow_unknown);
|
|
|
+ read_unlock(&policy_rwlock);
|
|
|
+ return rc;
|
|
|
+allow:
|
|
|
+ avd->allowed = 0xffffffff;
|
|
|
+ avd->auditallow = 0;
|
|
|
+ avd->auditdeny = 0xffffffff;
|
|
|
+ avd->seqno = latest_granting;
|
|
|
+ avd->flags = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int security_compute_av_user(u32 ssid,
|
|
|
+ u32 tsid,
|
|
|
+ u16 tclass,
|
|
|
+ u32 requested,
|
|
|
+ struct av_decision *avd)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
|
|
|
if (!ss_initialized) {
|
|
|
avd->allowed = 0xffffffff;
|
|
@@ -823,29 +999,7 @@ int security_compute_av(u32 ssid,
|
|
|
}
|
|
|
|
|
|
read_lock(&policy_rwlock);
|
|
|
-
|
|
|
- scontext = sidtab_search(&sidtab, ssid);
|
|
|
- if (!scontext) {
|
|
|
- printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
- __func__, ssid);
|
|
|
- rc = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- tcontext = sidtab_search(&sidtab, tsid);
|
|
|
- if (!tcontext) {
|
|
|
- printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
- __func__, tsid);
|
|
|
- rc = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- rc = context_struct_compute_av(scontext, tcontext, tclass,
|
|
|
- requested, avd);
|
|
|
-
|
|
|
- /* permissive domain? */
|
|
|
- if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
|
|
- avd->flags |= AVD_FLAGS_PERMISSIVE;
|
|
|
-out:
|
|
|
+ rc = security_compute_av_core(ssid, tsid, tclass, requested, avd);
|
|
|
read_unlock(&policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
@@ -1204,20 +1358,22 @@ out:
|
|
|
|
|
|
static int security_compute_sid(u32 ssid,
|
|
|
u32 tsid,
|
|
|
- u16 tclass,
|
|
|
+ u16 orig_tclass,
|
|
|
u32 specified,
|
|
|
- u32 *out_sid)
|
|
|
+ u32 *out_sid,
|
|
|
+ bool kern)
|
|
|
{
|
|
|
struct context *scontext = NULL, *tcontext = NULL, newcontext;
|
|
|
struct role_trans *roletr = NULL;
|
|
|
struct avtab_key avkey;
|
|
|
struct avtab_datum *avdatum;
|
|
|
struct avtab_node *node;
|
|
|
+ u16 tclass;
|
|
|
int rc = 0;
|
|
|
|
|
|
if (!ss_initialized) {
|
|
|
- switch (tclass) {
|
|
|
- case SECCLASS_PROCESS:
|
|
|
+ switch (orig_tclass) {
|
|
|
+ case SECCLASS_PROCESS: /* kernel value */
|
|
|
*out_sid = ssid;
|
|
|
break;
|
|
|
default:
|
|
@@ -1231,6 +1387,11 @@ static int security_compute_sid(u32 ssid,
|
|
|
|
|
|
read_lock(&policy_rwlock);
|
|
|
|
|
|
+ if (kern)
|
|
|
+ tclass = unmap_class(orig_tclass);
|
|
|
+ else
|
|
|
+ tclass = orig_tclass;
|
|
|
+
|
|
|
scontext = sidtab_search(&sidtab, ssid);
|
|
|
if (!scontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
@@ -1260,13 +1421,11 @@ static int security_compute_sid(u32 ssid,
|
|
|
}
|
|
|
|
|
|
/* Set the role and type to default values. */
|
|
|
- switch (tclass) {
|
|
|
- case SECCLASS_PROCESS:
|
|
|
+ if (tclass == policydb.process_class) {
|
|
|
/* Use the current role and type of process. */
|
|
|
newcontext.role = scontext->role;
|
|
|
newcontext.type = scontext->type;
|
|
|
- break;
|
|
|
- default:
|
|
|
+ } else {
|
|
|
/* Use the well-defined object role. */
|
|
|
newcontext.role = OBJECT_R_VAL;
|
|
|
/* Use the type of the related object. */
|
|
@@ -1297,8 +1456,7 @@ static int security_compute_sid(u32 ssid,
|
|
|
}
|
|
|
|
|
|
/* Check for class-specific changes. */
|
|
|
- switch (tclass) {
|
|
|
- case SECCLASS_PROCESS:
|
|
|
+ if (tclass == policydb.process_class) {
|
|
|
if (specified & AVTAB_TRANSITION) {
|
|
|
/* Look for a role transition rule. */
|
|
|
for (roletr = policydb.role_tr; roletr;
|
|
@@ -1311,9 +1469,6 @@ static int security_compute_sid(u32 ssid,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
}
|
|
|
|
|
|
/* Set the MLS attributes.
|
|
@@ -1358,7 +1513,17 @@ int security_transition_sid(u32 ssid,
|
|
|
u16 tclass,
|
|
|
u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
|
|
|
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
|
|
|
+ out_sid, true);
|
|
|
+}
|
|
|
+
|
|
|
+int security_transition_sid_user(u32 ssid,
|
|
|
+ u32 tsid,
|
|
|
+ u16 tclass,
|
|
|
+ u32 *out_sid)
|
|
|
+{
|
|
|
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
|
|
|
+ out_sid, false);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1379,7 +1544,8 @@ int security_member_sid(u32 ssid,
|
|
|
u16 tclass,
|
|
|
u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
|
|
|
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid,
|
|
|
+ false);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1400,144 +1566,8 @@ int security_change_sid(u32 ssid,
|
|
|
u16 tclass,
|
|
|
u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Verify that each kernel class that is defined in the
|
|
|
- * policy is correct
|
|
|
- */
|
|
|
-static int validate_classes(struct policydb *p)
|
|
|
-{
|
|
|
- int i, j;
|
|
|
- struct class_datum *cladatum;
|
|
|
- struct perm_datum *perdatum;
|
|
|
- u32 nprim, tmp, common_pts_len, perm_val, pol_val;
|
|
|
- u16 class_val;
|
|
|
- const struct selinux_class_perm *kdefs = &selinux_class_perm;
|
|
|
- const char *def_class, *def_perm, *pol_class;
|
|
|
- struct symtab *perms;
|
|
|
- bool print_unknown_handle = 0;
|
|
|
-
|
|
|
- if (p->allow_unknown) {
|
|
|
- u32 num_classes = kdefs->cts_len;
|
|
|
- p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL);
|
|
|
- if (!p->undefined_perms)
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 1; i < kdefs->cts_len; i++) {
|
|
|
- def_class = kdefs->class_to_string[i];
|
|
|
- if (!def_class)
|
|
|
- continue;
|
|
|
- if (i > p->p_classes.nprim) {
|
|
|
- printk(KERN_INFO
|
|
|
- "SELinux: class %s not defined in policy\n",
|
|
|
- def_class);
|
|
|
- if (p->reject_unknown)
|
|
|
- return -EINVAL;
|
|
|
- if (p->allow_unknown)
|
|
|
- p->undefined_perms[i-1] = ~0U;
|
|
|
- print_unknown_handle = 1;
|
|
|
- continue;
|
|
|
- }
|
|
|
- pol_class = p->p_class_val_to_name[i-1];
|
|
|
- if (strcmp(pol_class, def_class)) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: class %d is incorrect, found %s but should be %s\n",
|
|
|
- i, pol_class, def_class);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
- for (i = 0; i < kdefs->av_pts_len; i++) {
|
|
|
- class_val = kdefs->av_perm_to_string[i].tclass;
|
|
|
- perm_val = kdefs->av_perm_to_string[i].value;
|
|
|
- def_perm = kdefs->av_perm_to_string[i].name;
|
|
|
- if (class_val > p->p_classes.nprim)
|
|
|
- continue;
|
|
|
- pol_class = p->p_class_val_to_name[class_val-1];
|
|
|
- cladatum = hashtab_search(p->p_classes.table, pol_class);
|
|
|
- BUG_ON(!cladatum);
|
|
|
- perms = &cladatum->permissions;
|
|
|
- nprim = 1 << (perms->nprim - 1);
|
|
|
- if (perm_val > nprim) {
|
|
|
- printk(KERN_INFO
|
|
|
- "SELinux: permission %s in class %s not defined in policy\n",
|
|
|
- def_perm, pol_class);
|
|
|
- if (p->reject_unknown)
|
|
|
- return -EINVAL;
|
|
|
- if (p->allow_unknown)
|
|
|
- p->undefined_perms[class_val-1] |= perm_val;
|
|
|
- print_unknown_handle = 1;
|
|
|
- continue;
|
|
|
- }
|
|
|
- perdatum = hashtab_search(perms->table, def_perm);
|
|
|
- if (perdatum == NULL) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: permission %s in class %s not found in policy, bad policy\n",
|
|
|
- def_perm, pol_class);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- pol_val = 1 << (perdatum->value - 1);
|
|
|
- if (pol_val != perm_val) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: permission %s in class %s has incorrect value\n",
|
|
|
- def_perm, pol_class);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
- for (i = 0; i < kdefs->av_inherit_len; i++) {
|
|
|
- class_val = kdefs->av_inherit[i].tclass;
|
|
|
- if (class_val > p->p_classes.nprim)
|
|
|
- continue;
|
|
|
- pol_class = p->p_class_val_to_name[class_val-1];
|
|
|
- cladatum = hashtab_search(p->p_classes.table, pol_class);
|
|
|
- BUG_ON(!cladatum);
|
|
|
- if (!cladatum->comdatum) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: class %s should have an inherits clause but does not\n",
|
|
|
- pol_class);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- tmp = kdefs->av_inherit[i].common_base;
|
|
|
- common_pts_len = 0;
|
|
|
- while (!(tmp & 0x01)) {
|
|
|
- common_pts_len++;
|
|
|
- tmp >>= 1;
|
|
|
- }
|
|
|
- perms = &cladatum->comdatum->permissions;
|
|
|
- for (j = 0; j < common_pts_len; j++) {
|
|
|
- def_perm = kdefs->av_inherit[i].common_pts[j];
|
|
|
- if (j >= perms->nprim) {
|
|
|
- printk(KERN_INFO
|
|
|
- "SELinux: permission %s in class %s not defined in policy\n",
|
|
|
- def_perm, pol_class);
|
|
|
- if (p->reject_unknown)
|
|
|
- return -EINVAL;
|
|
|
- if (p->allow_unknown)
|
|
|
- p->undefined_perms[class_val-1] |= (1 << j);
|
|
|
- print_unknown_handle = 1;
|
|
|
- continue;
|
|
|
- }
|
|
|
- perdatum = hashtab_search(perms->table, def_perm);
|
|
|
- if (perdatum == NULL) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: permission %s in class %s not found in policy, bad policy\n",
|
|
|
- def_perm, pol_class);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- if (perdatum->value != j + 1) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: permission %s in class %s has incorrect value\n",
|
|
|
- def_perm, pol_class);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (print_unknown_handle)
|
|
|
- printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
|
|
|
- (security_get_allow_unknown() ? "allowed" : "denied"));
|
|
|
- return 0;
|
|
|
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid,
|
|
|
+ false);
|
|
|
}
|
|
|
|
|
|
/* Clone the SID into the new SID table. */
|
|
@@ -1710,8 +1740,10 @@ int security_load_policy(void *data, size_t len)
|
|
|
{
|
|
|
struct policydb oldpolicydb, newpolicydb;
|
|
|
struct sidtab oldsidtab, newsidtab;
|
|
|
+ struct selinux_mapping *oldmap, *map = NULL;
|
|
|
struct convert_context_args args;
|
|
|
u32 seqno;
|
|
|
+ u16 map_size;
|
|
|
int rc = 0;
|
|
|
struct policy_file file = { data, len }, *fp = &file;
|
|
|
|
|
@@ -1721,16 +1753,14 @@ int security_load_policy(void *data, size_t len)
|
|
|
avtab_cache_destroy();
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- if (policydb_load_isids(&policydb, &sidtab)) {
|
|
|
+ if (selinux_set_mapping(&policydb, secclass_map,
|
|
|
+ ¤t_mapping,
|
|
|
+ ¤t_mapping_size)) {
|
|
|
policydb_destroy(&policydb);
|
|
|
avtab_cache_destroy();
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- /* Verify that the kernel defined classes are correct. */
|
|
|
- if (validate_classes(&policydb)) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: the definition of a class is incorrect\n");
|
|
|
- sidtab_destroy(&sidtab);
|
|
|
+ if (policydb_load_isids(&policydb, &sidtab)) {
|
|
|
policydb_destroy(&policydb);
|
|
|
avtab_cache_destroy();
|
|
|
return -EINVAL;
|
|
@@ -1759,13 +1789,9 @@ int security_load_policy(void *data, size_t len)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- /* Verify that the kernel defined classes are correct. */
|
|
|
- if (validate_classes(&newpolicydb)) {
|
|
|
- printk(KERN_ERR
|
|
|
- "SELinux: the definition of a class is incorrect\n");
|
|
|
- rc = -EINVAL;
|
|
|
+ if (selinux_set_mapping(&newpolicydb, secclass_map,
|
|
|
+ &map, &map_size))
|
|
|
goto err;
|
|
|
- }
|
|
|
|
|
|
rc = security_preserve_bools(&newpolicydb);
|
|
|
if (rc) {
|
|
@@ -1799,6 +1825,9 @@ int security_load_policy(void *data, size_t len)
|
|
|
memcpy(&policydb, &newpolicydb, sizeof policydb);
|
|
|
sidtab_set(&sidtab, &newsidtab);
|
|
|
security_load_policycaps();
|
|
|
+ oldmap = current_mapping;
|
|
|
+ current_mapping = map;
|
|
|
+ current_mapping_size = map_size;
|
|
|
seqno = ++latest_granting;
|
|
|
policydb_loaded_version = policydb.policyvers;
|
|
|
write_unlock_irq(&policy_rwlock);
|
|
@@ -1806,6 +1835,7 @@ int security_load_policy(void *data, size_t len)
|
|
|
/* Free the old policydb and SID table. */
|
|
|
policydb_destroy(&oldpolicydb);
|
|
|
sidtab_destroy(&oldsidtab);
|
|
|
+ kfree(oldmap);
|
|
|
|
|
|
avc_ss_reset(seqno);
|
|
|
selnl_notify_policyload(seqno);
|
|
@@ -1815,6 +1845,7 @@ int security_load_policy(void *data, size_t len)
|
|
|
return 0;
|
|
|
|
|
|
err:
|
|
|
+ kfree(map);
|
|
|
sidtab_destroy(&newsidtab);
|
|
|
policydb_destroy(&newpolicydb);
|
|
|
return rc;
|
|
@@ -2091,7 +2122,7 @@ out_unlock:
|
|
|
}
|
|
|
for (i = 0, j = 0; i < mynel; i++) {
|
|
|
rc = avc_has_perm_noaudit(fromsid, mysids[i],
|
|
|
- SECCLASS_PROCESS,
|
|
|
+ SECCLASS_PROCESS, /* kernel value */
|
|
|
PROCESS__TRANSITION, AVC_STRICT,
|
|
|
NULL);
|
|
|
if (!rc)
|
|
@@ -2119,10 +2150,11 @@ out:
|
|
|
*/
|
|
|
int security_genfs_sid(const char *fstype,
|
|
|
char *path,
|
|
|
- u16 sclass,
|
|
|
+ u16 orig_sclass,
|
|
|
u32 *sid)
|
|
|
{
|
|
|
int len;
|
|
|
+ u16 sclass;
|
|
|
struct genfs *genfs;
|
|
|
struct ocontext *c;
|
|
|
int rc = 0, cmp = 0;
|
|
@@ -2132,6 +2164,8 @@ int security_genfs_sid(const char *fstype,
|
|
|
|
|
|
read_lock(&policy_rwlock);
|
|
|
|
|
|
+ sclass = unmap_class(orig_sclass);
|
|
|
+
|
|
|
for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
|
|
|
cmp = strcmp(fstype, genfs->fstype);
|
|
|
if (cmp <= 0)
|