|
@@ -80,53 +80,32 @@ char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
|
|
|
"nnp_nosuid_transition"
|
|
|
};
|
|
|
|
|
|
-int selinux_policycap_netpeer;
|
|
|
-int selinux_policycap_openperm;
|
|
|
-int selinux_policycap_extsockclass;
|
|
|
-int selinux_policycap_alwaysnetwork;
|
|
|
-int selinux_policycap_cgroupseclabel;
|
|
|
-int selinux_policycap_nnp_nosuid_transition;
|
|
|
+static struct selinux_ss selinux_ss;
|
|
|
|
|
|
-static DEFINE_RWLOCK(policy_rwlock);
|
|
|
-
|
|
|
-static struct sidtab sidtab;
|
|
|
-struct policydb policydb;
|
|
|
-int ss_initialized;
|
|
|
-
|
|
|
-/*
|
|
|
- * The largest sequence number that has been used when
|
|
|
- * providing an access decision to the access vector cache.
|
|
|
- * The sequence number only changes when a policy change
|
|
|
- * occurs.
|
|
|
- */
|
|
|
-static u32 latest_granting;
|
|
|
+void selinux_ss_init(struct selinux_ss **ss)
|
|
|
+{
|
|
|
+ rwlock_init(&selinux_ss.policy_rwlock);
|
|
|
+ mutex_init(&selinux_ss.status_lock);
|
|
|
+ *ss = &selinux_ss;
|
|
|
+}
|
|
|
|
|
|
/* Forward declaration. */
|
|
|
-static int context_struct_to_string(struct context *context, char **scontext,
|
|
|
+static int context_struct_to_string(struct policydb *policydb,
|
|
|
+ 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 extended_perms *xperms);
|
|
|
-
|
|
|
-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 void context_struct_compute_av(struct policydb *policydb,
|
|
|
+ struct context *scontext,
|
|
|
+ struct context *tcontext,
|
|
|
+ u16 tclass,
|
|
|
+ struct av_decision *avd,
|
|
|
+ struct extended_perms *xperms);
|
|
|
|
|
|
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_map *out_map)
|
|
|
{
|
|
|
- struct selinux_mapping *out_map = NULL;
|
|
|
- size_t size = sizeof(struct selinux_mapping);
|
|
|
u16 i, j;
|
|
|
unsigned k;
|
|
|
bool print_unknown_handle = false;
|
|
@@ -139,15 +118,15 @@ static int selinux_set_mapping(struct policydb *pol,
|
|
|
i++;
|
|
|
|
|
|
/* Allocate space for the class records, plus one for class zero */
|
|
|
- out_map = kcalloc(++i, size, GFP_ATOMIC);
|
|
|
- if (!out_map)
|
|
|
+ out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
|
|
|
+ if (!out_map->mapping)
|
|
|
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;
|
|
|
+ struct selinux_mapping *p_out = out_map->mapping + j;
|
|
|
|
|
|
/* An empty class string skips ahead */
|
|
|
if (!strcmp(p_in->name, "")) {
|
|
@@ -194,11 +173,11 @@ static int selinux_set_mapping(struct policydb *pol,
|
|
|
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;
|
|
|
+ out_map->size = i;
|
|
|
return 0;
|
|
|
err:
|
|
|
- kfree(out_map);
|
|
|
+ kfree(out_map->mapping);
|
|
|
+ out_map->mapping = NULL;
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -206,10 +185,10 @@ err:
|
|
|
* Get real, policy values from mapped values
|
|
|
*/
|
|
|
|
|
|
-static u16 unmap_class(u16 tclass)
|
|
|
+static u16 unmap_class(struct selinux_map *map, u16 tclass)
|
|
|
{
|
|
|
- if (tclass < current_mapping_size)
|
|
|
- return current_mapping[tclass].value;
|
|
|
+ if (tclass < map->size)
|
|
|
+ return map->mapping[tclass].value;
|
|
|
|
|
|
return tclass;
|
|
|
}
|
|
@@ -217,42 +196,44 @@ static u16 unmap_class(u16 tclass)
|
|
|
/*
|
|
|
* Get kernel value for class from its policy value
|
|
|
*/
|
|
|
-static u16 map_class(u16 pol_value)
|
|
|
+static u16 map_class(struct selinux_map *map, u16 pol_value)
|
|
|
{
|
|
|
u16 i;
|
|
|
|
|
|
- for (i = 1; i < current_mapping_size; i++) {
|
|
|
- if (current_mapping[i].value == pol_value)
|
|
|
+ for (i = 1; i < map->size; i++) {
|
|
|
+ if (map->mapping[i].value == pol_value)
|
|
|
return i;
|
|
|
}
|
|
|
|
|
|
return SECCLASS_NULL;
|
|
|
}
|
|
|
|
|
|
-static void map_decision(u16 tclass, struct av_decision *avd,
|
|
|
+static void map_decision(struct selinux_map *map,
|
|
|
+ u16 tclass, struct av_decision *avd,
|
|
|
int allow_unknown)
|
|
|
{
|
|
|
- if (tclass < current_mapping_size) {
|
|
|
- unsigned i, n = current_mapping[tclass].num_perms;
|
|
|
+ if (tclass < map->size) {
|
|
|
+ struct selinux_mapping *mapping = &map->mapping[tclass];
|
|
|
+ unsigned int i, n = mapping->num_perms;
|
|
|
u32 result;
|
|
|
|
|
|
for (i = 0, result = 0; i < n; i++) {
|
|
|
- if (avd->allowed & current_mapping[tclass].perms[i])
|
|
|
+ if (avd->allowed & mapping->perms[i])
|
|
|
result |= 1<<i;
|
|
|
- if (allow_unknown && !current_mapping[tclass].perms[i])
|
|
|
+ if (allow_unknown && !mapping->perms[i])
|
|
|
result |= 1<<i;
|
|
|
}
|
|
|
avd->allowed = result;
|
|
|
|
|
|
for (i = 0, result = 0; i < n; i++)
|
|
|
- if (avd->auditallow & current_mapping[tclass].perms[i])
|
|
|
+ if (avd->auditallow & mapping->perms[i])
|
|
|
result |= 1<<i;
|
|
|
avd->auditallow = result;
|
|
|
|
|
|
for (i = 0, result = 0; i < n; i++) {
|
|
|
- if (avd->auditdeny & current_mapping[tclass].perms[i])
|
|
|
+ if (avd->auditdeny & mapping->perms[i])
|
|
|
result |= 1<<i;
|
|
|
- if (!allow_unknown && !current_mapping[tclass].perms[i])
|
|
|
+ if (!allow_unknown && !mapping->perms[i])
|
|
|
result |= 1<<i;
|
|
|
}
|
|
|
/*
|
|
@@ -266,9 +247,11 @@ static void map_decision(u16 tclass, struct av_decision *avd,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-int security_mls_enabled(void)
|
|
|
+int security_mls_enabled(struct selinux_state *state)
|
|
|
{
|
|
|
- return policydb.mls_enabled;
|
|
|
+ struct policydb *p = &state->ss->policydb;
|
|
|
+
|
|
|
+ return p->mls_enabled;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -282,7 +265,8 @@ int security_mls_enabled(void)
|
|
|
* of the process performing the transition. All other callers of
|
|
|
* constraint_expr_eval should pass in NULL for xcontext.
|
|
|
*/
|
|
|
-static int constraint_expr_eval(struct context *scontext,
|
|
|
+static int constraint_expr_eval(struct policydb *policydb,
|
|
|
+ struct context *scontext,
|
|
|
struct context *tcontext,
|
|
|
struct context *xcontext,
|
|
|
struct constraint_expr *cexpr)
|
|
@@ -326,8 +310,8 @@ static int constraint_expr_eval(struct context *scontext,
|
|
|
case CEXPR_ROLE:
|
|
|
val1 = scontext->role;
|
|
|
val2 = tcontext->role;
|
|
|
- r1 = policydb.role_val_to_struct[val1 - 1];
|
|
|
- r2 = policydb.role_val_to_struct[val2 - 1];
|
|
|
+ r1 = policydb->role_val_to_struct[val1 - 1];
|
|
|
+ r2 = policydb->role_val_to_struct[val2 - 1];
|
|
|
switch (e->op) {
|
|
|
case CEXPR_DOM:
|
|
|
s[++sp] = ebitmap_get_bit(&r1->dominates,
|
|
@@ -472,7 +456,8 @@ static int dump_masked_av_helper(void *k, void *d, void *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void security_dump_masked_av(struct context *scontext,
|
|
|
+static void security_dump_masked_av(struct policydb *policydb,
|
|
|
+ struct context *scontext,
|
|
|
struct context *tcontext,
|
|
|
u16 tclass,
|
|
|
u32 permissions,
|
|
@@ -492,8 +477,8 @@ static void security_dump_masked_av(struct context *scontext,
|
|
|
if (!permissions)
|
|
|
return;
|
|
|
|
|
|
- tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);
|
|
|
- tclass_dat = policydb.class_val_to_struct[tclass - 1];
|
|
|
+ tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
|
|
|
+ tclass_dat = policydb->class_val_to_struct[tclass - 1];
|
|
|
common_dat = tclass_dat->comdatum;
|
|
|
|
|
|
/* init permission_names */
|
|
@@ -507,11 +492,11 @@ static void security_dump_masked_av(struct context *scontext,
|
|
|
goto out;
|
|
|
|
|
|
/* get scontext/tcontext in text form */
|
|
|
- if (context_struct_to_string(scontext,
|
|
|
+ if (context_struct_to_string(policydb, scontext,
|
|
|
&scontext_name, &length) < 0)
|
|
|
goto out;
|
|
|
|
|
|
- if (context_struct_to_string(tcontext,
|
|
|
+ if (context_struct_to_string(policydb, tcontext,
|
|
|
&tcontext_name, &length) < 0)
|
|
|
goto out;
|
|
|
|
|
@@ -550,7 +535,8 @@ out:
|
|
|
* security_boundary_permission - drops violated permissions
|
|
|
* on boundary constraint.
|
|
|
*/
|
|
|
-static void type_attribute_bounds_av(struct context *scontext,
|
|
|
+static void type_attribute_bounds_av(struct policydb *policydb,
|
|
|
+ struct context *scontext,
|
|
|
struct context *tcontext,
|
|
|
u16 tclass,
|
|
|
struct av_decision *avd)
|
|
@@ -562,14 +548,14 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|
|
struct type_datum *target;
|
|
|
u32 masked = 0;
|
|
|
|
|
|
- source = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
|
|
+ source = flex_array_get_ptr(policydb->type_val_to_struct_array,
|
|
|
scontext->type - 1);
|
|
|
BUG_ON(!source);
|
|
|
|
|
|
if (!source->bounds)
|
|
|
return;
|
|
|
|
|
|
- target = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
|
|
+ target = flex_array_get_ptr(policydb->type_val_to_struct_array,
|
|
|
tcontext->type - 1);
|
|
|
BUG_ON(!target);
|
|
|
|
|
@@ -584,7 +570,7 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|
|
tcontextp = &lo_tcontext;
|
|
|
}
|
|
|
|
|
|
- context_struct_compute_av(&lo_scontext,
|
|
|
+ context_struct_compute_av(policydb, &lo_scontext,
|
|
|
tcontextp,
|
|
|
tclass,
|
|
|
&lo_avd,
|
|
@@ -599,7 +585,7 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|
|
avd->allowed &= ~masked;
|
|
|
|
|
|
/* audit masked permissions */
|
|
|
- security_dump_masked_av(scontext, tcontext,
|
|
|
+ security_dump_masked_av(policydb, scontext, tcontext,
|
|
|
tclass, masked, "bounds");
|
|
|
}
|
|
|
|
|
@@ -632,11 +618,12 @@ void services_compute_xperms_drivers(
|
|
|
* 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 extended_perms *xperms)
|
|
|
+static void context_struct_compute_av(struct policydb *policydb,
|
|
|
+ struct context *scontext,
|
|
|
+ struct context *tcontext,
|
|
|
+ u16 tclass,
|
|
|
+ struct av_decision *avd,
|
|
|
+ struct extended_perms *xperms)
|
|
|
{
|
|
|
struct constraint_node *constraint;
|
|
|
struct role_allow *ra;
|
|
@@ -655,13 +642,13 @@ static void context_struct_compute_av(struct context *scontext,
|
|
|
xperms->len = 0;
|
|
|
}
|
|
|
|
|
|
- if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
|
|
|
+ if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
|
|
|
if (printk_ratelimit())
|
|
|
printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- tclass_datum = policydb.class_val_to_struct[tclass - 1];
|
|
|
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
|
|
|
|
|
|
/*
|
|
|
* If a specific type enforcement rule was defined for
|
|
@@ -669,15 +656,18 @@ static void context_struct_compute_av(struct context *scontext,
|
|
|
*/
|
|
|
avkey.target_class = tclass;
|
|
|
avkey.specified = AVTAB_AV | AVTAB_XPERMS;
|
|
|
- sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
|
|
|
+ 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);
|
|
|
+ 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);
|
|
|
+ for (node = avtab_search_node(&policydb->te_avtab,
|
|
|
+ &avkey);
|
|
|
node;
|
|
|
node = avtab_search_node_next(node, avkey.specified)) {
|
|
|
if (node->key.specified == AVTAB_ALLOWED)
|
|
@@ -691,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext,
|
|
|
}
|
|
|
|
|
|
/* Check conditional av table for additional permissions */
|
|
|
- cond_compute_av(&policydb.te_cond_avtab, &avkey,
|
|
|
+ cond_compute_av(&policydb->te_cond_avtab, &avkey,
|
|
|
avd, xperms);
|
|
|
|
|
|
}
|
|
@@ -704,7 +694,7 @@ static void context_struct_compute_av(struct context *scontext,
|
|
|
constraint = tclass_datum->constraints;
|
|
|
while (constraint) {
|
|
|
if ((constraint->permissions & (avd->allowed)) &&
|
|
|
- !constraint_expr_eval(scontext, tcontext, NULL,
|
|
|
+ !constraint_expr_eval(policydb, scontext, tcontext, NULL,
|
|
|
constraint->expr)) {
|
|
|
avd->allowed &= ~(constraint->permissions);
|
|
|
}
|
|
@@ -716,16 +706,16 @@ static void context_struct_compute_av(struct context *scontext,
|
|
|
* role is changing, then check the (current_role, new_role)
|
|
|
* pair.
|
|
|
*/
|
|
|
- if (tclass == policydb.process_class &&
|
|
|
- (avd->allowed & policydb.process_trans_perms) &&
|
|
|
+ if (tclass == policydb->process_class &&
|
|
|
+ (avd->allowed & policydb->process_trans_perms) &&
|
|
|
scontext->role != tcontext->role) {
|
|
|
- for (ra = policydb.role_allow; ra; ra = ra->next) {
|
|
|
+ for (ra = policydb->role_allow; ra; ra = ra->next) {
|
|
|
if (scontext->role == ra->role &&
|
|
|
tcontext->role == ra->new_role)
|
|
|
break;
|
|
|
}
|
|
|
if (!ra)
|
|
|
- avd->allowed &= ~policydb.process_trans_perms;
|
|
|
+ avd->allowed &= ~policydb->process_trans_perms;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -733,41 +723,46 @@ static void context_struct_compute_av(struct context *scontext,
|
|
|
* constraint, lazy checks have to mask any violated
|
|
|
* permission and notice it to userspace via audit.
|
|
|
*/
|
|
|
- type_attribute_bounds_av(scontext, tcontext,
|
|
|
+ type_attribute_bounds_av(policydb, scontext, tcontext,
|
|
|
tclass, avd);
|
|
|
}
|
|
|
|
|
|
-static int security_validtrans_handle_fail(struct context *ocontext,
|
|
|
+static int security_validtrans_handle_fail(struct selinux_state *state,
|
|
|
+ struct context *ocontext,
|
|
|
struct context *ncontext,
|
|
|
struct context *tcontext,
|
|
|
u16 tclass)
|
|
|
{
|
|
|
+ struct policydb *p = &state->ss->policydb;
|
|
|
char *o = NULL, *n = NULL, *t = NULL;
|
|
|
u32 olen, nlen, tlen;
|
|
|
|
|
|
- if (context_struct_to_string(ocontext, &o, &olen))
|
|
|
+ if (context_struct_to_string(p, ocontext, &o, &olen))
|
|
|
goto out;
|
|
|
- if (context_struct_to_string(ncontext, &n, &nlen))
|
|
|
+ if (context_struct_to_string(p, ncontext, &n, &nlen))
|
|
|
goto out;
|
|
|
- if (context_struct_to_string(tcontext, &t, &tlen))
|
|
|
+ if (context_struct_to_string(p, tcontext, &t, &tlen))
|
|
|
goto out;
|
|
|
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
|
|
"op=security_validate_transition seresult=denied"
|
|
|
" oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
|
|
|
- o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
|
|
|
+ o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
|
|
|
out:
|
|
|
kfree(o);
|
|
|
kfree(n);
|
|
|
kfree(t);
|
|
|
|
|
|
- if (!selinux_enforcing)
|
|
|
+ if (!enforcing_enabled(state))
|
|
|
return 0;
|
|
|
return -EPERM;
|
|
|
}
|
|
|
|
|
|
-static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
+static int security_compute_validatetrans(struct selinux_state *state,
|
|
|
+ u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
u16 orig_tclass, bool user)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct context *ocontext;
|
|
|
struct context *ncontext;
|
|
|
struct context *tcontext;
|
|
@@ -776,23 +771,27 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
u16 tclass;
|
|
|
int rc = 0;
|
|
|
|
|
|
- if (!ss_initialized)
|
|
|
+
|
|
|
+ if (!state->initialized)
|
|
|
return 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
|
|
|
if (!user)
|
|
|
- tclass = unmap_class(orig_tclass);
|
|
|
+ tclass = unmap_class(&state->ss->map, orig_tclass);
|
|
|
else
|
|
|
tclass = orig_tclass;
|
|
|
|
|
|
- if (!tclass || tclass > policydb.p_classes.nprim) {
|
|
|
+ if (!tclass || tclass > policydb->p_classes.nprim) {
|
|
|
rc = -EINVAL;
|
|
|
goto out;
|
|
|
}
|
|
|
- tclass_datum = policydb.class_val_to_struct[tclass - 1];
|
|
|
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
|
|
|
|
|
|
- ocontext = sidtab_search(&sidtab, oldsid);
|
|
|
+ ocontext = sidtab_search(sidtab, oldsid);
|
|
|
if (!ocontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, oldsid);
|
|
@@ -800,7 +799,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ncontext = sidtab_search(&sidtab, newsid);
|
|
|
+ ncontext = sidtab_search(sidtab, newsid);
|
|
|
if (!ncontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, newsid);
|
|
@@ -808,7 +807,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- tcontext = sidtab_search(&sidtab, tasksid);
|
|
|
+ tcontext = sidtab_search(sidtab, tasksid);
|
|
|
if (!tcontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, tasksid);
|
|
@@ -818,12 +817,13 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
|
|
|
constraint = tclass_datum->validatetrans;
|
|
|
while (constraint) {
|
|
|
- if (!constraint_expr_eval(ocontext, ncontext, tcontext,
|
|
|
- constraint->expr)) {
|
|
|
+ if (!constraint_expr_eval(policydb, ocontext, ncontext,
|
|
|
+ tcontext, constraint->expr)) {
|
|
|
if (user)
|
|
|
rc = -EPERM;
|
|
|
else
|
|
|
- rc = security_validtrans_handle_fail(ocontext,
|
|
|
+ rc = security_validtrans_handle_fail(state,
|
|
|
+ ocontext,
|
|
|
ncontext,
|
|
|
tcontext,
|
|
|
tclass);
|
|
@@ -833,22 +833,24 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
- u16 tclass)
|
|
|
+int security_validate_transition_user(struct selinux_state *state,
|
|
|
+ u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
+ u16 tclass)
|
|
|
{
|
|
|
- return security_compute_validatetrans(oldsid, newsid, tasksid,
|
|
|
- tclass, true);
|
|
|
+ return security_compute_validatetrans(state, oldsid, newsid, tasksid,
|
|
|
+ tclass, true);
|
|
|
}
|
|
|
|
|
|
-int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
+int security_validate_transition(struct selinux_state *state,
|
|
|
+ u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
u16 orig_tclass)
|
|
|
{
|
|
|
- return security_compute_validatetrans(oldsid, newsid, tasksid,
|
|
|
- orig_tclass, false);
|
|
|
+ return security_compute_validatetrans(state, oldsid, newsid, tasksid,
|
|
|
+ orig_tclass, false);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -860,20 +862,26 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
* @oldsid : current security identifier
|
|
|
* @newsid : destinated security identifier
|
|
|
*/
|
|
|
-int security_bounded_transition(u32 old_sid, u32 new_sid)
|
|
|
+int security_bounded_transition(struct selinux_state *state,
|
|
|
+ u32 old_sid, u32 new_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct context *old_context, *new_context;
|
|
|
struct type_datum *type;
|
|
|
int index;
|
|
|
int rc;
|
|
|
|
|
|
- if (!ss_initialized)
|
|
|
+ if (!state->initialized)
|
|
|
return 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- old_context = sidtab_search(&sidtab, old_sid);
|
|
|
+ old_context = sidtab_search(sidtab, old_sid);
|
|
|
if (!old_context) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
|
|
|
__func__, old_sid);
|
|
@@ -881,7 +889,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
|
|
}
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- new_context = sidtab_search(&sidtab, new_sid);
|
|
|
+ new_context = sidtab_search(sidtab, new_sid);
|
|
|
if (!new_context) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
|
|
|
__func__, new_sid);
|
|
@@ -895,7 +903,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
|
|
|
|
|
index = new_context->type;
|
|
|
while (true) {
|
|
|
- type = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
|
|
+ type = flex_array_get_ptr(policydb->type_val_to_struct_array,
|
|
|
index - 1);
|
|
|
BUG_ON(!type);
|
|
|
|
|
@@ -917,9 +925,9 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
|
|
char *new_name = NULL;
|
|
|
u32 length;
|
|
|
|
|
|
- if (!context_struct_to_string(old_context,
|
|
|
+ if (!context_struct_to_string(policydb, old_context,
|
|
|
&old_name, &length) &&
|
|
|
- !context_struct_to_string(new_context,
|
|
|
+ !context_struct_to_string(policydb, new_context,
|
|
|
&new_name, &length)) {
|
|
|
audit_log(current->audit_context,
|
|
|
GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
|
@@ -932,17 +940,17 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
|
|
kfree(old_name);
|
|
|
}
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static void avd_init(struct av_decision *avd)
|
|
|
+static void avd_init(struct selinux_state *state, struct av_decision *avd)
|
|
|
{
|
|
|
avd->allowed = 0;
|
|
|
avd->auditallow = 0;
|
|
|
avd->auditdeny = 0xffffffff;
|
|
|
- avd->seqno = latest_granting;
|
|
|
+ avd->seqno = state->ss->latest_granting;
|
|
|
avd->flags = 0;
|
|
|
}
|
|
|
|
|
@@ -1000,12 +1008,15 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void security_compute_xperms_decision(u32 ssid,
|
|
|
- u32 tsid,
|
|
|
- u16 orig_tclass,
|
|
|
- u8 driver,
|
|
|
- struct extended_perms_decision *xpermd)
|
|
|
+void security_compute_xperms_decision(struct selinux_state *state,
|
|
|
+ u32 ssid,
|
|
|
+ u32 tsid,
|
|
|
+ u16 orig_tclass,
|
|
|
+ u8 driver,
|
|
|
+ struct extended_perms_decision *xpermd)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
u16 tclass;
|
|
|
struct context *scontext, *tcontext;
|
|
|
struct avtab_key avkey;
|
|
@@ -1020,60 +1031,64 @@ void security_compute_xperms_decision(u32 ssid,
|
|
|
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)
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ if (!state->initialized)
|
|
|
goto allow;
|
|
|
|
|
|
- scontext = sidtab_search(&sidtab, ssid);
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ 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);
|
|
|
+ tclass = unmap_class(&state->ss->map, orig_tclass);
|
|
|
if (unlikely(orig_tclass && !tclass)) {
|
|
|
- if (policydb.allow_unknown)
|
|
|
+ if (policydb->allow_unknown)
|
|
|
goto allow;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
|
|
|
- if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
|
|
|
+ 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,
|
|
|
+ sattr = flex_array_get(policydb->type_attr_map_array,
|
|
|
scontext->type - 1);
|
|
|
BUG_ON(!sattr);
|
|
|
- tattr = flex_array_get(policydb.type_attr_map_array,
|
|
|
+ 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);
|
|
|
+ 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,
|
|
|
+ cond_compute_xperms(&policydb->te_cond_avtab,
|
|
|
&avkey, xpermd);
|
|
|
}
|
|
|
}
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return;
|
|
|
allow:
|
|
|
memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
|
|
@@ -1091,22 +1106,28 @@ allow:
|
|
|
* Compute a set of access vector decisions based on the
|
|
|
* SID pair (@ssid, @tsid) for the permissions in @tclass.
|
|
|
*/
|
|
|
-void security_compute_av(u32 ssid,
|
|
|
+void security_compute_av(struct selinux_state *state,
|
|
|
+ u32 ssid,
|
|
|
u32 tsid,
|
|
|
u16 orig_tclass,
|
|
|
struct av_decision *avd,
|
|
|
struct extended_perms *xperms)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
u16 tclass;
|
|
|
struct context *scontext = NULL, *tcontext = NULL;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- avd_init(avd);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ avd_init(state, avd);
|
|
|
xperms->len = 0;
|
|
|
- if (!ss_initialized)
|
|
|
+ if (!state->initialized)
|
|
|
goto allow;
|
|
|
|
|
|
- scontext = sidtab_search(&sidtab, ssid);
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ scontext = sidtab_search(sidtab, ssid);
|
|
|
if (!scontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, ssid);
|
|
@@ -1114,45 +1135,53 @@ void security_compute_av(u32 ssid,
|
|
|
}
|
|
|
|
|
|
/* permissive domain? */
|
|
|
- if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
|
|
+ if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
|
|
|
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
|
|
|
|
|
- tcontext = sidtab_search(&sidtab, tsid);
|
|
|
+ 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);
|
|
|
+ tclass = unmap_class(&state->ss->map, orig_tclass);
|
|
|
if (unlikely(orig_tclass && !tclass)) {
|
|
|
- if (policydb.allow_unknown)
|
|
|
+ if (policydb->allow_unknown)
|
|
|
goto allow;
|
|
|
goto out;
|
|
|
}
|
|
|
- context_struct_compute_av(scontext, tcontext, tclass, avd, xperms);
|
|
|
- map_decision(orig_tclass, avd, policydb.allow_unknown);
|
|
|
+ context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
|
|
|
+ xperms);
|
|
|
+ map_decision(&state->ss->map, orig_tclass, avd,
|
|
|
+ policydb->allow_unknown);
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return;
|
|
|
allow:
|
|
|
avd->allowed = 0xffffffff;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
-void security_compute_av_user(u32 ssid,
|
|
|
+void security_compute_av_user(struct selinux_state *state,
|
|
|
+ u32 ssid,
|
|
|
u32 tsid,
|
|
|
u16 tclass,
|
|
|
struct av_decision *avd)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct context *scontext = NULL, *tcontext = NULL;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- avd_init(avd);
|
|
|
- if (!ss_initialized)
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ avd_init(state, avd);
|
|
|
+ if (!state->initialized)
|
|
|
goto allow;
|
|
|
|
|
|
- scontext = sidtab_search(&sidtab, ssid);
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ scontext = sidtab_search(sidtab, ssid);
|
|
|
if (!scontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, ssid);
|
|
@@ -1160,10 +1189,10 @@ void security_compute_av_user(u32 ssid,
|
|
|
}
|
|
|
|
|
|
/* permissive domain? */
|
|
|
- if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
|
|
+ if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
|
|
|
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
|
|
|
|
|
- tcontext = sidtab_search(&sidtab, tsid);
|
|
|
+ tcontext = sidtab_search(sidtab, tsid);
|
|
|
if (!tcontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, tsid);
|
|
@@ -1171,14 +1200,15 @@ void security_compute_av_user(u32 ssid,
|
|
|
}
|
|
|
|
|
|
if (unlikely(!tclass)) {
|
|
|
- if (policydb.allow_unknown)
|
|
|
+ if (policydb->allow_unknown)
|
|
|
goto allow;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- context_struct_compute_av(scontext, tcontext, tclass, avd, NULL);
|
|
|
+ context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
|
|
|
+ NULL);
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return;
|
|
|
allow:
|
|
|
avd->allowed = 0xffffffff;
|
|
@@ -1192,7 +1222,9 @@ allow:
|
|
|
* to point to this string and set `*scontext_len' to
|
|
|
* the length of the string.
|
|
|
*/
|
|
|
-static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
|
|
|
+static int context_struct_to_string(struct policydb *p,
|
|
|
+ struct context *context,
|
|
|
+ char **scontext, u32 *scontext_len)
|
|
|
{
|
|
|
char *scontextp;
|
|
|
|
|
@@ -1211,10 +1243,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
|
|
|
}
|
|
|
|
|
|
/* Compute the size of the context. */
|
|
|
- *scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1;
|
|
|
- *scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1;
|
|
|
- *scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;
|
|
|
- *scontext_len += mls_compute_context_len(context);
|
|
|
+ *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
|
|
|
+ *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
|
|
|
+ *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
|
|
|
+ *scontext_len += mls_compute_context_len(p, context);
|
|
|
|
|
|
if (!scontext)
|
|
|
return 0;
|
|
@@ -1229,11 +1261,11 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
|
|
|
* Copy the user name, role name and type name into the context.
|
|
|
*/
|
|
|
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));
|
|
|
+ sym_name(p, SYM_USERS, context->user - 1),
|
|
|
+ sym_name(p, SYM_ROLES, context->role - 1),
|
|
|
+ sym_name(p, SYM_TYPES, context->type - 1));
|
|
|
|
|
|
- mls_sid_to_context(context, &scontextp);
|
|
|
+ mls_sid_to_context(p, context, &scontextp);
|
|
|
|
|
|
*scontextp = 0;
|
|
|
|
|
@@ -1249,9 +1281,12 @@ const char *security_get_initial_sid_context(u32 sid)
|
|
|
return initial_sid_to_string[sid];
|
|
|
}
|
|
|
|
|
|
-static int security_sid_to_context_core(u32 sid, char **scontext,
|
|
|
+static int security_sid_to_context_core(struct selinux_state *state,
|
|
|
+ u32 sid, char **scontext,
|
|
|
u32 *scontext_len, int force)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct context *context;
|
|
|
int rc = 0;
|
|
|
|
|
@@ -1259,7 +1294,7 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
|
|
|
*scontext = NULL;
|
|
|
*scontext_len = 0;
|
|
|
|
|
|
- if (!ss_initialized) {
|
|
|
+ if (!state->initialized) {
|
|
|
if (sid <= SECINITSID_NUM) {
|
|
|
char *scontextp;
|
|
|
|
|
@@ -1280,20 +1315,23 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
|
|
|
rc = -EINVAL;
|
|
|
goto out;
|
|
|
}
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
if (force)
|
|
|
- context = sidtab_search_force(&sidtab, sid);
|
|
|
+ context = sidtab_search_force(sidtab, sid);
|
|
|
else
|
|
|
- context = sidtab_search(&sidtab, sid);
|
|
|
+ context = sidtab_search(sidtab, sid);
|
|
|
if (!context) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, sid);
|
|
|
rc = -EINVAL;
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
- rc = context_struct_to_string(context, scontext, scontext_len);
|
|
|
+ rc = context_struct_to_string(policydb, context, scontext,
|
|
|
+ scontext_len);
|
|
|
out_unlock:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
out:
|
|
|
return rc;
|
|
|
|
|
@@ -1309,14 +1347,18 @@ out:
|
|
|
* into a dynamically allocated string of the correct size. Set @scontext
|
|
|
* to point to this string and set @scontext_len to the length of the string.
|
|
|
*/
|
|
|
-int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
|
|
|
+int security_sid_to_context(struct selinux_state *state,
|
|
|
+ u32 sid, char **scontext, u32 *scontext_len)
|
|
|
{
|
|
|
- return security_sid_to_context_core(sid, scontext, scontext_len, 0);
|
|
|
+ return security_sid_to_context_core(state, sid, scontext,
|
|
|
+ scontext_len, 0);
|
|
|
}
|
|
|
|
|
|
-int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
|
|
|
+int security_sid_to_context_force(struct selinux_state *state, u32 sid,
|
|
|
+ char **scontext, u32 *scontext_len)
|
|
|
{
|
|
|
- return security_sid_to_context_core(sid, scontext, scontext_len, 1);
|
|
|
+ return security_sid_to_context_core(state, sid, scontext,
|
|
|
+ scontext_len, 1);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1404,10 +1446,13 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
|
|
|
+static int security_context_to_sid_core(struct selinux_state *state,
|
|
|
+ const char *scontext, u32 scontext_len,
|
|
|
u32 *sid, u32 def_sid, gfp_t gfp_flags,
|
|
|
int force)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
char *scontext2, *str = NULL;
|
|
|
struct context context;
|
|
|
int rc = 0;
|
|
@@ -1421,7 +1466,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
|
|
|
if (!scontext2)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- if (!ss_initialized) {
|
|
|
+ if (!state->initialized) {
|
|
|
int i;
|
|
|
|
|
|
for (i = 1; i < SECINITSID_NUM; i++) {
|
|
@@ -1442,9 +1487,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
|
|
|
if (!str)
|
|
|
goto out;
|
|
|
}
|
|
|
-
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- rc = string_to_context_struct(&policydb, &sidtab, scontext2,
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+ rc = string_to_context_struct(policydb, sidtab, scontext2,
|
|
|
scontext_len, &context, def_sid);
|
|
|
if (rc == -EINVAL && force) {
|
|
|
context.str = str;
|
|
@@ -1452,10 +1498,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
|
|
|
str = NULL;
|
|
|
} else if (rc)
|
|
|
goto out_unlock;
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &context, sid);
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &context, sid);
|
|
|
context_destroy(&context);
|
|
|
out_unlock:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
out:
|
|
|
kfree(scontext2);
|
|
|
kfree(str);
|
|
@@ -1474,16 +1520,19 @@ out:
|
|
|
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
|
|
|
* memory is available, or 0 on success.
|
|
|
*/
|
|
|
-int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
|
|
|
+int security_context_to_sid(struct selinux_state *state,
|
|
|
+ const char *scontext, u32 scontext_len, u32 *sid,
|
|
|
gfp_t gfp)
|
|
|
{
|
|
|
- return security_context_to_sid_core(scontext, scontext_len,
|
|
|
+ return security_context_to_sid_core(state, scontext, scontext_len,
|
|
|
sid, SECSID_NULL, gfp, 0);
|
|
|
}
|
|
|
|
|
|
-int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
|
|
|
+int security_context_str_to_sid(struct selinux_state *state,
|
|
|
+ const char *scontext, u32 *sid, gfp_t gfp)
|
|
|
{
|
|
|
- return security_context_to_sid(scontext, strlen(scontext), sid, gfp);
|
|
|
+ return security_context_to_sid(state, scontext, strlen(scontext),
|
|
|
+ sid, gfp);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1504,51 +1553,56 @@ int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
|
|
|
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
|
|
|
* memory is available, or 0 on success.
|
|
|
*/
|
|
|
-int security_context_to_sid_default(const char *scontext, u32 scontext_len,
|
|
|
+int security_context_to_sid_default(struct selinux_state *state,
|
|
|
+ const char *scontext, u32 scontext_len,
|
|
|
u32 *sid, u32 def_sid, gfp_t gfp_flags)
|
|
|
{
|
|
|
- return security_context_to_sid_core(scontext, scontext_len,
|
|
|
+ return security_context_to_sid_core(state, scontext, scontext_len,
|
|
|
sid, def_sid, gfp_flags, 1);
|
|
|
}
|
|
|
|
|
|
-int security_context_to_sid_force(const char *scontext, u32 scontext_len,
|
|
|
+int security_context_to_sid_force(struct selinux_state *state,
|
|
|
+ const char *scontext, u32 scontext_len,
|
|
|
u32 *sid)
|
|
|
{
|
|
|
- return security_context_to_sid_core(scontext, scontext_len,
|
|
|
+ return security_context_to_sid_core(state, scontext, scontext_len,
|
|
|
sid, SECSID_NULL, GFP_KERNEL, 1);
|
|
|
}
|
|
|
|
|
|
static int compute_sid_handle_invalid_context(
|
|
|
+ struct selinux_state *state,
|
|
|
struct context *scontext,
|
|
|
struct context *tcontext,
|
|
|
u16 tclass,
|
|
|
struct context *newcontext)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
char *s = NULL, *t = NULL, *n = NULL;
|
|
|
u32 slen, tlen, nlen;
|
|
|
|
|
|
- if (context_struct_to_string(scontext, &s, &slen))
|
|
|
+ if (context_struct_to_string(policydb, scontext, &s, &slen))
|
|
|
goto out;
|
|
|
- if (context_struct_to_string(tcontext, &t, &tlen))
|
|
|
+ if (context_struct_to_string(policydb, tcontext, &t, &tlen))
|
|
|
goto out;
|
|
|
- if (context_struct_to_string(newcontext, &n, &nlen))
|
|
|
+ if (context_struct_to_string(policydb, newcontext, &n, &nlen))
|
|
|
goto out;
|
|
|
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
|
|
"op=security_compute_sid invalid_context=%s"
|
|
|
" scontext=%s"
|
|
|
" tcontext=%s"
|
|
|
" tclass=%s",
|
|
|
- n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
|
|
|
+ n, s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
|
|
|
out:
|
|
|
kfree(s);
|
|
|
kfree(t);
|
|
|
kfree(n);
|
|
|
- if (!selinux_enforcing)
|
|
|
+ if (!enforcing_enabled(state))
|
|
|
return 0;
|
|
|
return -EACCES;
|
|
|
}
|
|
|
|
|
|
-static void filename_compute_type(struct policydb *p, struct context *newcontext,
|
|
|
+static void filename_compute_type(struct policydb *policydb,
|
|
|
+ struct context *newcontext,
|
|
|
u32 stype, u32 ttype, u16 tclass,
|
|
|
const char *objname)
|
|
|
{
|
|
@@ -1560,7 +1614,7 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
|
|
|
* like /dev or /var/run. This bitmap will quickly skip rule searches
|
|
|
* if the ttype does not contain any rules.
|
|
|
*/
|
|
|
- if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
|
|
|
+ if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
|
|
|
return;
|
|
|
|
|
|
ft.stype = stype;
|
|
@@ -1568,12 +1622,13 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
|
|
|
ft.tclass = tclass;
|
|
|
ft.name = objname;
|
|
|
|
|
|
- otype = hashtab_search(p->filename_trans, &ft);
|
|
|
+ otype = hashtab_search(policydb->filename_trans, &ft);
|
|
|
if (otype)
|
|
|
newcontext->type = otype->otype;
|
|
|
}
|
|
|
|
|
|
-static int security_compute_sid(u32 ssid,
|
|
|
+static int security_compute_sid(struct selinux_state *state,
|
|
|
+ u32 ssid,
|
|
|
u32 tsid,
|
|
|
u16 orig_tclass,
|
|
|
u32 specified,
|
|
@@ -1581,6 +1636,8 @@ static int security_compute_sid(u32 ssid,
|
|
|
u32 *out_sid,
|
|
|
bool kern)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct class_datum *cladatum = NULL;
|
|
|
struct context *scontext = NULL, *tcontext = NULL, newcontext;
|
|
|
struct role_trans *roletr = NULL;
|
|
@@ -1591,7 +1648,7 @@ static int security_compute_sid(u32 ssid,
|
|
|
int rc = 0;
|
|
|
bool sock;
|
|
|
|
|
|
- if (!ss_initialized) {
|
|
|
+ if (!state->initialized) {
|
|
|
switch (orig_tclass) {
|
|
|
case SECCLASS_PROCESS: /* kernel value */
|
|
|
*out_sid = ssid;
|
|
@@ -1605,24 +1662,28 @@ static int security_compute_sid(u32 ssid,
|
|
|
|
|
|
context_init(&newcontext);
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
if (kern) {
|
|
|
- tclass = unmap_class(orig_tclass);
|
|
|
+ tclass = unmap_class(&state->ss->map, orig_tclass);
|
|
|
sock = security_is_socket_class(orig_tclass);
|
|
|
} else {
|
|
|
tclass = orig_tclass;
|
|
|
- sock = security_is_socket_class(map_class(tclass));
|
|
|
+ sock = security_is_socket_class(map_class(&state->ss->map,
|
|
|
+ tclass));
|
|
|
}
|
|
|
|
|
|
- scontext = sidtab_search(&sidtab, ssid);
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ scontext = sidtab_search(sidtab, ssid);
|
|
|
if (!scontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, ssid);
|
|
|
rc = -EINVAL;
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
- tcontext = sidtab_search(&sidtab, tsid);
|
|
|
+ tcontext = sidtab_search(sidtab, tsid);
|
|
|
if (!tcontext) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, tsid);
|
|
@@ -1630,8 +1691,8 @@ static int security_compute_sid(u32 ssid,
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
|
|
|
- if (tclass && tclass <= policydb.p_classes.nprim)
|
|
|
- cladatum = policydb.class_val_to_struct[tclass - 1];
|
|
|
+ if (tclass && tclass <= policydb->p_classes.nprim)
|
|
|
+ cladatum = policydb->class_val_to_struct[tclass - 1];
|
|
|
|
|
|
/* Set the user identity. */
|
|
|
switch (specified) {
|
|
@@ -1657,7 +1718,7 @@ static int security_compute_sid(u32 ssid,
|
|
|
} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
|
|
|
newcontext.role = tcontext->role;
|
|
|
} else {
|
|
|
- if ((tclass == policydb.process_class) || (sock == true))
|
|
|
+ if ((tclass == policydb->process_class) || (sock == true))
|
|
|
newcontext.role = scontext->role;
|
|
|
else
|
|
|
newcontext.role = OBJECT_R_VAL;
|
|
@@ -1669,7 +1730,7 @@ static int security_compute_sid(u32 ssid,
|
|
|
} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
|
|
|
newcontext.type = tcontext->type;
|
|
|
} else {
|
|
|
- if ((tclass == policydb.process_class) || (sock == true)) {
|
|
|
+ if ((tclass == policydb->process_class) || (sock == true)) {
|
|
|
/* Use the type of process. */
|
|
|
newcontext.type = scontext->type;
|
|
|
} else {
|
|
@@ -1683,11 +1744,11 @@ static int security_compute_sid(u32 ssid,
|
|
|
avkey.target_type = tcontext->type;
|
|
|
avkey.target_class = tclass;
|
|
|
avkey.specified = specified;
|
|
|
- avdatum = avtab_search(&policydb.te_avtab, &avkey);
|
|
|
+ avdatum = avtab_search(&policydb->te_avtab, &avkey);
|
|
|
|
|
|
/* If no permanent rule, also check for enabled conditional rules */
|
|
|
if (!avdatum) {
|
|
|
- node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
|
|
|
+ node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
|
|
|
for (; node; node = avtab_search_node_next(node, specified)) {
|
|
|
if (node->key.specified & AVTAB_ENABLED) {
|
|
|
avdatum = &node->datum;
|
|
@@ -1703,13 +1764,14 @@ static int security_compute_sid(u32 ssid,
|
|
|
|
|
|
/* if we have a objname this is a file trans check so check those rules */
|
|
|
if (objname)
|
|
|
- filename_compute_type(&policydb, &newcontext, scontext->type,
|
|
|
+ filename_compute_type(policydb, &newcontext, scontext->type,
|
|
|
tcontext->type, tclass, objname);
|
|
|
|
|
|
/* Check for class-specific changes. */
|
|
|
if (specified & AVTAB_TRANSITION) {
|
|
|
/* Look for a role transition rule. */
|
|
|
- for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
|
|
|
+ for (roletr = policydb->role_tr; roletr;
|
|
|
+ roletr = roletr->next) {
|
|
|
if ((roletr->role == scontext->role) &&
|
|
|
(roletr->type == tcontext->type) &&
|
|
|
(roletr->tclass == tclass)) {
|
|
@@ -1722,14 +1784,14 @@ static int security_compute_sid(u32 ssid,
|
|
|
|
|
|
/* Set the MLS attributes.
|
|
|
This is done last because it may allocate memory. */
|
|
|
- rc = mls_compute_sid(scontext, tcontext, tclass, specified,
|
|
|
+ rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
|
|
|
&newcontext, sock);
|
|
|
if (rc)
|
|
|
goto out_unlock;
|
|
|
|
|
|
/* Check the validity of the context. */
|
|
|
- if (!policydb_context_isvalid(&policydb, &newcontext)) {
|
|
|
- rc = compute_sid_handle_invalid_context(scontext,
|
|
|
+ if (!policydb_context_isvalid(policydb, &newcontext)) {
|
|
|
+ rc = compute_sid_handle_invalid_context(state, scontext,
|
|
|
tcontext,
|
|
|
tclass,
|
|
|
&newcontext);
|
|
@@ -1737,9 +1799,9 @@ static int security_compute_sid(u32 ssid,
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
/* Obtain the sid for the context. */
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
|
|
|
out_unlock:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
context_destroy(&newcontext);
|
|
|
out:
|
|
|
return rc;
|
|
@@ -1758,17 +1820,21 @@ out:
|
|
|
* if insufficient memory is available, or %0 if the new SID was
|
|
|
* computed successfully.
|
|
|
*/
|
|
|
-int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
|
|
|
+int security_transition_sid(struct selinux_state *state,
|
|
|
+ u32 ssid, u32 tsid, u16 tclass,
|
|
|
const struct qstr *qstr, u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
|
|
|
+ return security_compute_sid(state, ssid, tsid, tclass,
|
|
|
+ AVTAB_TRANSITION,
|
|
|
qstr ? qstr->name : NULL, out_sid, true);
|
|
|
}
|
|
|
|
|
|
-int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
|
|
|
+int security_transition_sid_user(struct selinux_state *state,
|
|
|
+ u32 ssid, u32 tsid, u16 tclass,
|
|
|
const char *objname, u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
|
|
|
+ return security_compute_sid(state, ssid, tsid, tclass,
|
|
|
+ AVTAB_TRANSITION,
|
|
|
objname, out_sid, false);
|
|
|
}
|
|
|
|
|
@@ -1785,12 +1851,14 @@ int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
|
|
|
* if insufficient memory is available, or %0 if the SID was
|
|
|
* computed successfully.
|
|
|
*/
|
|
|
-int security_member_sid(u32 ssid,
|
|
|
+int security_member_sid(struct selinux_state *state,
|
|
|
+ u32 ssid,
|
|
|
u32 tsid,
|
|
|
u16 tclass,
|
|
|
u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL,
|
|
|
+ return security_compute_sid(state, ssid, tsid, tclass,
|
|
|
+ AVTAB_MEMBER, NULL,
|
|
|
out_sid, false);
|
|
|
}
|
|
|
|
|
@@ -1807,12 +1875,14 @@ int security_member_sid(u32 ssid,
|
|
|
* if insufficient memory is available, or %0 if the SID was
|
|
|
* computed successfully.
|
|
|
*/
|
|
|
-int security_change_sid(u32 ssid,
|
|
|
+int security_change_sid(struct selinux_state *state,
|
|
|
+ u32 ssid,
|
|
|
u32 tsid,
|
|
|
u16 tclass,
|
|
|
u32 *out_sid)
|
|
|
{
|
|
|
- return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
|
|
|
+ return security_compute_sid(state,
|
|
|
+ ssid, tsid, tclass, AVTAB_CHANGE, NULL,
|
|
|
out_sid, false);
|
|
|
}
|
|
|
|
|
@@ -1829,15 +1899,18 @@ static int clone_sid(u32 sid,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static inline int convert_context_handle_invalid_context(struct context *context)
|
|
|
+static inline int convert_context_handle_invalid_context(
|
|
|
+ struct selinux_state *state,
|
|
|
+ struct context *context)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
char *s;
|
|
|
u32 len;
|
|
|
|
|
|
- if (selinux_enforcing)
|
|
|
+ if (enforcing_enabled(state))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (!context_struct_to_string(context, &s, &len)) {
|
|
|
+ if (!context_struct_to_string(policydb, context, &s, &len)) {
|
|
|
printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s);
|
|
|
kfree(s);
|
|
|
}
|
|
@@ -1845,6 +1918,7 @@ static inline int convert_context_handle_invalid_context(struct context *context
|
|
|
}
|
|
|
|
|
|
struct convert_context_args {
|
|
|
+ struct selinux_state *state;
|
|
|
struct policydb *oldp;
|
|
|
struct policydb *newp;
|
|
|
};
|
|
@@ -1971,7 +2045,8 @@ static int convert_context(u32 key,
|
|
|
|
|
|
/* Check the validity of the new context. */
|
|
|
if (!policydb_context_isvalid(args->newp, c)) {
|
|
|
- rc = convert_context_handle_invalid_context(&oldc);
|
|
|
+ rc = convert_context_handle_invalid_context(args->state,
|
|
|
+ &oldc);
|
|
|
if (rc)
|
|
|
goto bad;
|
|
|
}
|
|
@@ -1983,7 +2058,7 @@ out:
|
|
|
return rc;
|
|
|
bad:
|
|
|
/* Map old representation to string and save it. */
|
|
|
- rc = context_struct_to_string(&oldc, &s, &len);
|
|
|
+ rc = context_struct_to_string(args->oldp, &oldc, &s, &len);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
context_destroy(&oldc);
|
|
@@ -1996,39 +2071,29 @@ bad:
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
-static void security_load_policycaps(void)
|
|
|
+static void security_load_policycaps(struct selinux_state *state)
|
|
|
{
|
|
|
+ struct policydb *p = &state->ss->policydb;
|
|
|
unsigned int i;
|
|
|
struct ebitmap_node *node;
|
|
|
|
|
|
- selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
|
|
|
- POLICYDB_CAPABILITY_NETPEER);
|
|
|
- selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
|
|
|
- POLICYDB_CAPABILITY_OPENPERM);
|
|
|
- selinux_policycap_extsockclass = ebitmap_get_bit(&policydb.policycaps,
|
|
|
- POLICYDB_CAPABILITY_EXTSOCKCLASS);
|
|
|
- selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
|
|
|
- POLICYDB_CAPABILITY_ALWAYSNETWORK);
|
|
|
- selinux_policycap_cgroupseclabel =
|
|
|
- ebitmap_get_bit(&policydb.policycaps,
|
|
|
- POLICYDB_CAPABILITY_CGROUPSECLABEL);
|
|
|
- selinux_policycap_nnp_nosuid_transition =
|
|
|
- ebitmap_get_bit(&policydb.policycaps,
|
|
|
- POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
|
|
|
+ state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
|
|
|
pr_info("SELinux: policy capability %s=%d\n",
|
|
|
selinux_policycap_names[i],
|
|
|
- ebitmap_get_bit(&policydb.policycaps, i));
|
|
|
+ ebitmap_get_bit(&p->policycaps, i));
|
|
|
|
|
|
- ebitmap_for_each_positive_bit(&policydb.policycaps, node, i) {
|
|
|
+ ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
|
|
|
if (i >= ARRAY_SIZE(selinux_policycap_names))
|
|
|
pr_info("SELinux: unknown policy capability %u\n",
|
|
|
i);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int security_preserve_bools(struct policydb *p);
|
|
|
+static int security_preserve_bools(struct selinux_state *state,
|
|
|
+ struct policydb *newpolicydb);
|
|
|
|
|
|
/**
|
|
|
* security_load_policy - Load a security policy configuration.
|
|
@@ -2040,14 +2105,16 @@ static int security_preserve_bools(struct policydb *p);
|
|
|
* This function will flush the access vector cache after
|
|
|
* loading the new policy.
|
|
|
*/
|
|
|
-int security_load_policy(void *data, size_t len)
|
|
|
+int security_load_policy(struct selinux_state *state, void *data, size_t len)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct policydb *oldpolicydb, *newpolicydb;
|
|
|
struct sidtab oldsidtab, newsidtab;
|
|
|
- struct selinux_mapping *oldmap, *map = NULL;
|
|
|
+ struct selinux_mapping *oldmapping;
|
|
|
+ struct selinux_map newmap;
|
|
|
struct convert_context_args args;
|
|
|
u32 seqno;
|
|
|
- u16 map_size;
|
|
|
int rc = 0;
|
|
|
struct policy_file file = { data, len }, *fp = &file;
|
|
|
|
|
@@ -2058,53 +2125,42 @@ int security_load_policy(void *data, size_t len)
|
|
|
}
|
|
|
newpolicydb = oldpolicydb + 1;
|
|
|
|
|
|
- if (!ss_initialized) {
|
|
|
- avtab_cache_init();
|
|
|
- ebitmap_cache_init();
|
|
|
- hashtab_cache_init();
|
|
|
- rc = policydb_read(&policydb, fp);
|
|
|
- if (rc) {
|
|
|
- avtab_cache_destroy();
|
|
|
- ebitmap_cache_destroy();
|
|
|
- hashtab_cache_destroy();
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ if (!state->initialized) {
|
|
|
+ rc = policydb_read(policydb, fp);
|
|
|
+ if (rc)
|
|
|
goto out;
|
|
|
- }
|
|
|
|
|
|
- policydb.len = len;
|
|
|
- rc = selinux_set_mapping(&policydb, secclass_map,
|
|
|
- ¤t_mapping,
|
|
|
- ¤t_mapping_size);
|
|
|
+ policydb->len = len;
|
|
|
+ rc = selinux_set_mapping(policydb, secclass_map,
|
|
|
+ &state->ss->map);
|
|
|
if (rc) {
|
|
|
- policydb_destroy(&policydb);
|
|
|
- avtab_cache_destroy();
|
|
|
- ebitmap_cache_destroy();
|
|
|
- hashtab_cache_destroy();
|
|
|
+ policydb_destroy(policydb);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- rc = policydb_load_isids(&policydb, &sidtab);
|
|
|
+ rc = policydb_load_isids(policydb, sidtab);
|
|
|
if (rc) {
|
|
|
- policydb_destroy(&policydb);
|
|
|
- avtab_cache_destroy();
|
|
|
- ebitmap_cache_destroy();
|
|
|
- hashtab_cache_destroy();
|
|
|
+ policydb_destroy(policydb);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- security_load_policycaps();
|
|
|
- ss_initialized = 1;
|
|
|
- seqno = ++latest_granting;
|
|
|
+ security_load_policycaps(state);
|
|
|
+ state->initialized = 1;
|
|
|
+ seqno = ++state->ss->latest_granting;
|
|
|
selinux_complete_init();
|
|
|
- avc_ss_reset(seqno);
|
|
|
+ avc_ss_reset(state->avc, seqno);
|
|
|
selnl_notify_policyload(seqno);
|
|
|
- selinux_status_update_policyload(seqno);
|
|
|
+ selinux_status_update_policyload(state, seqno);
|
|
|
selinux_netlbl_cache_invalidate();
|
|
|
selinux_xfrm_notify_policyload();
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
- sidtab_hash_eval(&sidtab, "sids");
|
|
|
+ sidtab_hash_eval(sidtab, "sids");
|
|
|
#endif
|
|
|
|
|
|
rc = policydb_read(newpolicydb, fp);
|
|
@@ -2113,9 +2169,9 @@ int security_load_policy(void *data, size_t len)
|
|
|
|
|
|
newpolicydb->len = len;
|
|
|
/* If switching between different policy types, log MLS status */
|
|
|
- if (policydb.mls_enabled && !newpolicydb->mls_enabled)
|
|
|
+ if (policydb->mls_enabled && !newpolicydb->mls_enabled)
|
|
|
printk(KERN_INFO "SELinux: Disabling MLS support...\n");
|
|
|
- else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
|
|
|
+ else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
|
|
|
printk(KERN_INFO "SELinux: Enabling MLS support...\n");
|
|
|
|
|
|
rc = policydb_load_isids(newpolicydb, &newsidtab);
|
|
@@ -2125,20 +2181,20 @@ int security_load_policy(void *data, size_t len)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
|
|
|
+ rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap);
|
|
|
if (rc)
|
|
|
goto err;
|
|
|
|
|
|
- rc = security_preserve_bools(newpolicydb);
|
|
|
+ rc = security_preserve_bools(state, newpolicydb);
|
|
|
if (rc) {
|
|
|
printk(KERN_ERR "SELinux: unable to preserve booleans\n");
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
/* Clone the SID table. */
|
|
|
- sidtab_shutdown(&sidtab);
|
|
|
+ sidtab_shutdown(sidtab);
|
|
|
|
|
|
- rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
|
|
|
+ rc = sidtab_map(sidtab, clone_sid, &newsidtab);
|
|
|
if (rc)
|
|
|
goto err;
|
|
|
|
|
@@ -2146,7 +2202,8 @@ int security_load_policy(void *data, size_t len)
|
|
|
* Convert the internal representations of contexts
|
|
|
* in the new SID table.
|
|
|
*/
|
|
|
- args.oldp = &policydb;
|
|
|
+ args.state = state;
|
|
|
+ args.oldp = policydb;
|
|
|
args.newp = newpolicydb;
|
|
|
rc = sidtab_map(&newsidtab, convert_context, &args);
|
|
|
if (rc) {
|
|
@@ -2157,28 +2214,28 @@ int security_load_policy(void *data, size_t len)
|
|
|
}
|
|
|
|
|
|
/* Save the old policydb and SID table to free later. */
|
|
|
- memcpy(oldpolicydb, &policydb, sizeof(policydb));
|
|
|
- sidtab_set(&oldsidtab, &sidtab);
|
|
|
+ memcpy(oldpolicydb, policydb, sizeof(*policydb));
|
|
|
+ sidtab_set(&oldsidtab, sidtab);
|
|
|
|
|
|
/* Install the new policydb and SID table. */
|
|
|
- write_lock_irq(&policy_rwlock);
|
|
|
- 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;
|
|
|
- write_unlock_irq(&policy_rwlock);
|
|
|
+ write_lock_irq(&state->ss->policy_rwlock);
|
|
|
+ memcpy(policydb, newpolicydb, sizeof(*policydb));
|
|
|
+ sidtab_set(sidtab, &newsidtab);
|
|
|
+ security_load_policycaps(state);
|
|
|
+ oldmapping = state->ss->map.mapping;
|
|
|
+ state->ss->map.mapping = newmap.mapping;
|
|
|
+ state->ss->map.size = newmap.size;
|
|
|
+ seqno = ++state->ss->latest_granting;
|
|
|
+ write_unlock_irq(&state->ss->policy_rwlock);
|
|
|
|
|
|
/* Free the old policydb and SID table. */
|
|
|
policydb_destroy(oldpolicydb);
|
|
|
sidtab_destroy(&oldsidtab);
|
|
|
- kfree(oldmap);
|
|
|
+ kfree(oldmapping);
|
|
|
|
|
|
- avc_ss_reset(seqno);
|
|
|
+ avc_ss_reset(state->avc, seqno);
|
|
|
selnl_notify_policyload(seqno);
|
|
|
- selinux_status_update_policyload(seqno);
|
|
|
+ selinux_status_update_policyload(state, seqno);
|
|
|
selinux_netlbl_cache_invalidate();
|
|
|
selinux_xfrm_notify_policyload();
|
|
|
|
|
@@ -2186,7 +2243,7 @@ int security_load_policy(void *data, size_t len)
|
|
|
goto out;
|
|
|
|
|
|
err:
|
|
|
- kfree(map);
|
|
|
+ kfree(newmap.mapping);
|
|
|
sidtab_destroy(&newsidtab);
|
|
|
policydb_destroy(newpolicydb);
|
|
|
|
|
@@ -2195,13 +2252,14 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-size_t security_policydb_len(void)
|
|
|
+size_t security_policydb_len(struct selinux_state *state)
|
|
|
{
|
|
|
+ struct policydb *p = &state->ss->policydb;
|
|
|
size_t len;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- len = policydb.len;
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ len = p->len;
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
|
|
|
return len;
|
|
|
}
|
|
@@ -2212,14 +2270,20 @@ size_t security_policydb_len(void)
|
|
|
* @port: port number
|
|
|
* @out_sid: security identifier
|
|
|
*/
|
|
|
-int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
|
|
|
+int security_port_sid(struct selinux_state *state,
|
|
|
+ u8 protocol, u16 port, u32 *out_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct ocontext *c;
|
|
|
int rc = 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
- c = policydb.ocontexts[OCON_PORT];
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ c = policydb->ocontexts[OCON_PORT];
|
|
|
while (c) {
|
|
|
if (c->u.port.protocol == protocol &&
|
|
|
c->u.port.low_port <= port &&
|
|
@@ -2230,7 +2294,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
|
|
|
|
|
|
if (c) {
|
|
|
if (!c->sid[0]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab,
|
|
|
+ rc = sidtab_context_to_sid(sidtab,
|
|
|
&c->context[0],
|
|
|
&c->sid[0]);
|
|
|
if (rc)
|
|
@@ -2242,7 +2306,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2252,14 +2316,20 @@ out:
|
|
|
* @pkey_num: pkey number
|
|
|
* @out_sid: security identifier
|
|
|
*/
|
|
|
-int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
|
|
|
+int security_ib_pkey_sid(struct selinux_state *state,
|
|
|
+ u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct ocontext *c;
|
|
|
int rc = 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
|
|
|
- c = policydb.ocontexts[OCON_IBPKEY];
|
|
|
+ c = policydb->ocontexts[OCON_IBPKEY];
|
|
|
while (c) {
|
|
|
if (c->u.ibpkey.low_pkey <= pkey_num &&
|
|
|
c->u.ibpkey.high_pkey >= pkey_num &&
|
|
@@ -2271,7 +2341,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
|
|
|
|
|
|
if (c) {
|
|
|
if (!c->sid[0]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab,
|
|
|
+ rc = sidtab_context_to_sid(sidtab,
|
|
|
&c->context[0],
|
|
|
&c->sid[0]);
|
|
|
if (rc)
|
|
@@ -2282,7 +2352,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
|
|
|
*out_sid = SECINITSID_UNLABELED;
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2292,14 +2362,20 @@ out:
|
|
|
* @port: port number
|
|
|
* @out_sid: security identifier
|
|
|
*/
|
|
|
-int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
|
|
|
+int security_ib_endport_sid(struct selinux_state *state,
|
|
|
+ const char *dev_name, u8 port_num, u32 *out_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct ocontext *c;
|
|
|
int rc = 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
|
|
|
- c = policydb.ocontexts[OCON_IBENDPORT];
|
|
|
+ c = policydb->ocontexts[OCON_IBENDPORT];
|
|
|
while (c) {
|
|
|
if (c->u.ibendport.port == port_num &&
|
|
|
!strncmp(c->u.ibendport.dev_name,
|
|
@@ -2312,7 +2388,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
|
|
|
|
|
|
if (c) {
|
|
|
if (!c->sid[0]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab,
|
|
|
+ rc = sidtab_context_to_sid(sidtab,
|
|
|
&c->context[0],
|
|
|
&c->sid[0]);
|
|
|
if (rc)
|
|
@@ -2323,7 +2399,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
|
|
|
*out_sid = SECINITSID_UNLABELED;
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2332,14 +2408,20 @@ out:
|
|
|
* @name: interface name
|
|
|
* @if_sid: interface SID
|
|
|
*/
|
|
|
-int security_netif_sid(char *name, u32 *if_sid)
|
|
|
+int security_netif_sid(struct selinux_state *state,
|
|
|
+ char *name, u32 *if_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
int rc = 0;
|
|
|
struct ocontext *c;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
- c = policydb.ocontexts[OCON_NETIF];
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ c = policydb->ocontexts[OCON_NETIF];
|
|
|
while (c) {
|
|
|
if (strcmp(name, c->u.name) == 0)
|
|
|
break;
|
|
@@ -2348,12 +2430,12 @@ int security_netif_sid(char *name, u32 *if_sid)
|
|
|
|
|
|
if (c) {
|
|
|
if (!c->sid[0] || !c->sid[1]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab,
|
|
|
+ rc = sidtab_context_to_sid(sidtab,
|
|
|
&c->context[0],
|
|
|
&c->sid[0]);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
- rc = sidtab_context_to_sid(&sidtab,
|
|
|
+ rc = sidtab_context_to_sid(sidtab,
|
|
|
&c->context[1],
|
|
|
&c->sid[1]);
|
|
|
if (rc)
|
|
@@ -2364,7 +2446,7 @@ int security_netif_sid(char *name, u32 *if_sid)
|
|
|
*if_sid = SECINITSID_NETIF;
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2388,15 +2470,21 @@ static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
|
|
|
* @addrlen: address length in bytes
|
|
|
* @out_sid: security identifier
|
|
|
*/
|
|
|
-int security_node_sid(u16 domain,
|
|
|
+int security_node_sid(struct selinux_state *state,
|
|
|
+ u16 domain,
|
|
|
void *addrp,
|
|
|
u32 addrlen,
|
|
|
u32 *out_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
int rc;
|
|
|
struct ocontext *c;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
|
|
|
switch (domain) {
|
|
|
case AF_INET: {
|
|
@@ -2408,7 +2496,7 @@ int security_node_sid(u16 domain,
|
|
|
|
|
|
addr = *((u32 *)addrp);
|
|
|
|
|
|
- c = policydb.ocontexts[OCON_NODE];
|
|
|
+ c = policydb->ocontexts[OCON_NODE];
|
|
|
while (c) {
|
|
|
if (c->u.node.addr == (addr & c->u.node.mask))
|
|
|
break;
|
|
@@ -2421,7 +2509,7 @@ int security_node_sid(u16 domain,
|
|
|
rc = -EINVAL;
|
|
|
if (addrlen != sizeof(u64) * 2)
|
|
|
goto out;
|
|
|
- c = policydb.ocontexts[OCON_NODE6];
|
|
|
+ c = policydb->ocontexts[OCON_NODE6];
|
|
|
while (c) {
|
|
|
if (match_ipv6_addrmask(addrp, c->u.node6.addr,
|
|
|
c->u.node6.mask))
|
|
@@ -2438,7 +2526,7 @@ int security_node_sid(u16 domain,
|
|
|
|
|
|
if (c) {
|
|
|
if (!c->sid[0]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab,
|
|
|
+ rc = sidtab_context_to_sid(sidtab,
|
|
|
&c->context[0],
|
|
|
&c->sid[0]);
|
|
|
if (rc)
|
|
@@ -2451,7 +2539,7 @@ int security_node_sid(u16 domain,
|
|
|
|
|
|
rc = 0;
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2471,11 +2559,14 @@ out:
|
|
|
* number of elements in the array.
|
|
|
*/
|
|
|
|
|
|
-int security_get_user_sids(u32 fromsid,
|
|
|
+int security_get_user_sids(struct selinux_state *state,
|
|
|
+ u32 fromsid,
|
|
|
char *username,
|
|
|
u32 **sids,
|
|
|
u32 *nel)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
struct context *fromcon, usercon;
|
|
|
u32 *mysids = NULL, *mysids2, sid;
|
|
|
u32 mynel = 0, maxnel = SIDS_NEL;
|
|
@@ -2487,20 +2578,23 @@ int security_get_user_sids(u32 fromsid,
|
|
|
*sids = NULL;
|
|
|
*nel = 0;
|
|
|
|
|
|
- if (!ss_initialized)
|
|
|
+ if (!state->initialized)
|
|
|
goto out;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
|
|
|
context_init(&usercon);
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- fromcon = sidtab_search(&sidtab, fromsid);
|
|
|
+ fromcon = sidtab_search(sidtab, fromsid);
|
|
|
if (!fromcon)
|
|
|
goto out_unlock;
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- user = hashtab_search(policydb.p_users.table, username);
|
|
|
+ user = hashtab_search(policydb->p_users.table, username);
|
|
|
if (!user)
|
|
|
goto out_unlock;
|
|
|
|
|
@@ -2512,15 +2606,16 @@ int security_get_user_sids(u32 fromsid,
|
|
|
goto out_unlock;
|
|
|
|
|
|
ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
|
|
|
- role = policydb.role_val_to_struct[i];
|
|
|
+ role = policydb->role_val_to_struct[i];
|
|
|
usercon.role = i + 1;
|
|
|
ebitmap_for_each_positive_bit(&role->types, tnode, j) {
|
|
|
usercon.type = j + 1;
|
|
|
|
|
|
- if (mls_setup_user_range(fromcon, user, &usercon))
|
|
|
+ if (mls_setup_user_range(policydb, fromcon, user,
|
|
|
+ &usercon))
|
|
|
continue;
|
|
|
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
|
|
|
if (rc)
|
|
|
goto out_unlock;
|
|
|
if (mynel < maxnel) {
|
|
@@ -2540,7 +2635,7 @@ int security_get_user_sids(u32 fromsid,
|
|
|
}
|
|
|
rc = 0;
|
|
|
out_unlock:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
if (rc || !mynel) {
|
|
|
kfree(mysids);
|
|
|
goto out;
|
|
@@ -2554,7 +2649,8 @@ out_unlock:
|
|
|
}
|
|
|
for (i = 0, j = 0; i < mynel; i++) {
|
|
|
struct av_decision dummy_avd;
|
|
|
- rc = avc_has_perm_noaudit(fromsid, mysids[i],
|
|
|
+ rc = avc_has_perm_noaudit(state,
|
|
|
+ fromsid, mysids[i],
|
|
|
SECCLASS_PROCESS, /* kernel value */
|
|
|
PROCESS__TRANSITION, AVC_STRICT,
|
|
|
&dummy_avd);
|
|
@@ -2583,11 +2679,14 @@ out:
|
|
|
*
|
|
|
* The caller must acquire the policy_rwlock before calling this function.
|
|
|
*/
|
|
|
-static inline int __security_genfs_sid(const char *fstype,
|
|
|
+static inline int __security_genfs_sid(struct selinux_state *state,
|
|
|
+ const char *fstype,
|
|
|
char *path,
|
|
|
u16 orig_sclass,
|
|
|
u32 *sid)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
+ struct sidtab *sidtab = &state->ss->sidtab;
|
|
|
int len;
|
|
|
u16 sclass;
|
|
|
struct genfs *genfs;
|
|
@@ -2597,10 +2696,10 @@ static inline int __security_genfs_sid(const char *fstype,
|
|
|
while (path[0] == '/' && path[1] == '/')
|
|
|
path++;
|
|
|
|
|
|
- sclass = unmap_class(orig_sclass);
|
|
|
+ sclass = unmap_class(&state->ss->map, orig_sclass);
|
|
|
*sid = SECINITSID_UNLABELED;
|
|
|
|
|
|
- for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
|
|
|
+ for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
|
|
|
cmp = strcmp(fstype, genfs->fstype);
|
|
|
if (cmp <= 0)
|
|
|
break;
|
|
@@ -2622,7 +2721,7 @@ static inline int __security_genfs_sid(const char *fstype,
|
|
|
goto out;
|
|
|
|
|
|
if (!c->sid[0]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
}
|
|
@@ -2643,16 +2742,17 @@ out:
|
|
|
* Acquire policy_rwlock before calling __security_genfs_sid() and release
|
|
|
* it afterward.
|
|
|
*/
|
|
|
-int security_genfs_sid(const char *fstype,
|
|
|
+int security_genfs_sid(struct selinux_state *state,
|
|
|
+ const char *fstype,
|
|
|
char *path,
|
|
|
u16 orig_sclass,
|
|
|
u32 *sid)
|
|
|
{
|
|
|
int retval;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- retval = __security_genfs_sid(fstype, path, orig_sclass, sid);
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
@@ -2660,16 +2760,21 @@ int security_genfs_sid(const char *fstype,
|
|
|
* security_fs_use - Determine how to handle labeling for a filesystem.
|
|
|
* @sb: superblock in question
|
|
|
*/
|
|
|
-int security_fs_use(struct super_block *sb)
|
|
|
+int security_fs_use(struct selinux_state *state, struct super_block *sb)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
+ struct sidtab *sidtab;
|
|
|
int rc = 0;
|
|
|
struct ocontext *c;
|
|
|
struct superblock_security_struct *sbsec = sb->s_security;
|
|
|
const char *fstype = sb->s_type->name;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
- c = policydb.ocontexts[OCON_FSUSE];
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+ sidtab = &state->ss->sidtab;
|
|
|
+
|
|
|
+ c = policydb->ocontexts[OCON_FSUSE];
|
|
|
while (c) {
|
|
|
if (strcmp(fstype, c->u.name) == 0)
|
|
|
break;
|
|
@@ -2679,14 +2784,14 @@ int security_fs_use(struct super_block *sb)
|
|
|
if (c) {
|
|
|
sbsec->behavior = c->v.behavior;
|
|
|
if (!c->sid[0]) {
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &c->context[0],
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
|
|
&c->sid[0]);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
}
|
|
|
sbsec->sid = c->sid[0];
|
|
|
} else {
|
|
|
- rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR,
|
|
|
+ rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
|
|
|
&sbsec->sid);
|
|
|
if (rc) {
|
|
|
sbsec->behavior = SECURITY_FS_USE_NONE;
|
|
@@ -2697,20 +2802,32 @@ int security_fs_use(struct super_block *sb)
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-int security_get_bools(int *len, char ***names, int **values)
|
|
|
+int security_get_bools(struct selinux_state *state,
|
|
|
+ int *len, char ***names, int **values)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
int i, rc;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ if (!state->initialized) {
|
|
|
+ *len = 0;
|
|
|
+ *names = NULL;
|
|
|
+ *values = NULL;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
+
|
|
|
*names = NULL;
|
|
|
*values = NULL;
|
|
|
|
|
|
rc = 0;
|
|
|
- *len = policydb.p_bools.nprim;
|
|
|
+ *len = policydb->p_bools.nprim;
|
|
|
if (!*len)
|
|
|
goto out;
|
|
|
|
|
@@ -2725,16 +2842,17 @@ int security_get_bools(int *len, char ***names, int **values)
|
|
|
goto err;
|
|
|
|
|
|
for (i = 0; i < *len; i++) {
|
|
|
- (*values)[i] = policydb.bool_val_to_struct[i]->state;
|
|
|
+ (*values)[i] = policydb->bool_val_to_struct[i]->state;
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
- (*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC);
|
|
|
+ (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
|
|
|
+ GFP_ATOMIC);
|
|
|
if (!(*names)[i])
|
|
|
goto err;
|
|
|
}
|
|
|
rc = 0;
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
err:
|
|
|
if (*names) {
|
|
@@ -2746,90 +2864,98 @@ err:
|
|
|
}
|
|
|
|
|
|
|
|
|
-int security_set_bools(int len, int *values)
|
|
|
+int security_set_bools(struct selinux_state *state, int len, int *values)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
int i, rc;
|
|
|
int lenp, seqno = 0;
|
|
|
struct cond_node *cur;
|
|
|
|
|
|
- write_lock_irq(&policy_rwlock);
|
|
|
+ write_lock_irq(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
|
|
|
rc = -EFAULT;
|
|
|
- lenp = policydb.p_bools.nprim;
|
|
|
+ lenp = policydb->p_bools.nprim;
|
|
|
if (len != lenp)
|
|
|
goto out;
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
- if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
|
|
|
+ if (!!values[i] != policydb->bool_val_to_struct[i]->state) {
|
|
|
audit_log(current->audit_context, GFP_ATOMIC,
|
|
|
AUDIT_MAC_CONFIG_CHANGE,
|
|
|
"bool=%s val=%d old_val=%d auid=%u ses=%u",
|
|
|
- sym_name(&policydb, SYM_BOOLS, i),
|
|
|
+ sym_name(policydb, SYM_BOOLS, i),
|
|
|
!!values[i],
|
|
|
- policydb.bool_val_to_struct[i]->state,
|
|
|
+ policydb->bool_val_to_struct[i]->state,
|
|
|
from_kuid(&init_user_ns, audit_get_loginuid(current)),
|
|
|
audit_get_sessionid(current));
|
|
|
}
|
|
|
if (values[i])
|
|
|
- policydb.bool_val_to_struct[i]->state = 1;
|
|
|
+ policydb->bool_val_to_struct[i]->state = 1;
|
|
|
else
|
|
|
- policydb.bool_val_to_struct[i]->state = 0;
|
|
|
+ policydb->bool_val_to_struct[i]->state = 0;
|
|
|
}
|
|
|
|
|
|
- for (cur = policydb.cond_list; cur; cur = cur->next) {
|
|
|
- rc = evaluate_cond_node(&policydb, cur);
|
|
|
+ for (cur = policydb->cond_list; cur; cur = cur->next) {
|
|
|
+ rc = evaluate_cond_node(policydb, cur);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- seqno = ++latest_granting;
|
|
|
+ seqno = ++state->ss->latest_granting;
|
|
|
rc = 0;
|
|
|
out:
|
|
|
- write_unlock_irq(&policy_rwlock);
|
|
|
+ write_unlock_irq(&state->ss->policy_rwlock);
|
|
|
if (!rc) {
|
|
|
- avc_ss_reset(seqno);
|
|
|
+ avc_ss_reset(state->avc, seqno);
|
|
|
selnl_notify_policyload(seqno);
|
|
|
- selinux_status_update_policyload(seqno);
|
|
|
+ selinux_status_update_policyload(state, seqno);
|
|
|
selinux_xfrm_notify_policyload();
|
|
|
}
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-int security_get_bool_value(int index)
|
|
|
+int security_get_bool_value(struct selinux_state *state,
|
|
|
+ int index)
|
|
|
{
|
|
|
+ struct policydb *policydb;
|
|
|
int rc;
|
|
|
int len;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+
|
|
|
+ policydb = &state->ss->policydb;
|
|
|
|
|
|
rc = -EFAULT;
|
|
|
- len = policydb.p_bools.nprim;
|
|
|
+ len = policydb->p_bools.nprim;
|
|
|
if (index >= len)
|
|
|
goto out;
|
|
|
|
|
|
- rc = policydb.bool_val_to_struct[index]->state;
|
|
|
+ rc = policydb->bool_val_to_struct[index]->state;
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static int security_preserve_bools(struct policydb *p)
|
|
|
+static int security_preserve_bools(struct selinux_state *state,
|
|
|
+ struct policydb *policydb)
|
|
|
{
|
|
|
int rc, nbools = 0, *bvalues = NULL, i;
|
|
|
char **bnames = NULL;
|
|
|
struct cond_bool_datum *booldatum;
|
|
|
struct cond_node *cur;
|
|
|
|
|
|
- rc = security_get_bools(&nbools, &bnames, &bvalues);
|
|
|
+ rc = security_get_bools(state, &nbools, &bnames, &bvalues);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
for (i = 0; i < nbools; i++) {
|
|
|
- booldatum = hashtab_search(p->p_bools.table, bnames[i]);
|
|
|
+ booldatum = hashtab_search(policydb->p_bools.table, bnames[i]);
|
|
|
if (booldatum)
|
|
|
booldatum->state = bvalues[i];
|
|
|
}
|
|
|
- for (cur = p->cond_list; cur; cur = cur->next) {
|
|
|
- rc = evaluate_cond_node(p, cur);
|
|
|
+ for (cur = policydb->cond_list; cur; cur = cur->next) {
|
|
|
+ rc = evaluate_cond_node(policydb, cur);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
}
|
|
@@ -2848,8 +2974,11 @@ out:
|
|
|
* security_sid_mls_copy() - computes a new sid based on the given
|
|
|
* sid and the mls portion of mls_sid.
|
|
|
*/
|
|
|
-int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
|
|
+int security_sid_mls_copy(struct selinux_state *state,
|
|
|
+ u32 sid, u32 mls_sid, u32 *new_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
+ struct sidtab *sidtab = &state->ss->sidtab;
|
|
|
struct context *context1;
|
|
|
struct context *context2;
|
|
|
struct context newcon;
|
|
@@ -2858,17 +2987,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
|
|
int rc;
|
|
|
|
|
|
rc = 0;
|
|
|
- if (!ss_initialized || !policydb.mls_enabled) {
|
|
|
+ if (!state->initialized || !policydb->mls_enabled) {
|
|
|
*new_sid = sid;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
context_init(&newcon);
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- context1 = sidtab_search(&sidtab, sid);
|
|
|
+ context1 = sidtab_search(sidtab, sid);
|
|
|
if (!context1) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, sid);
|
|
@@ -2876,7 +3005,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
|
|
}
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- context2 = sidtab_search(&sidtab, mls_sid);
|
|
|
+ context2 = sidtab_search(sidtab, mls_sid);
|
|
|
if (!context2) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, mls_sid);
|
|
@@ -2891,10 +3020,11 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
|
|
goto out_unlock;
|
|
|
|
|
|
/* Check the validity of the new context. */
|
|
|
- if (!policydb_context_isvalid(&policydb, &newcon)) {
|
|
|
- rc = convert_context_handle_invalid_context(&newcon);
|
|
|
+ if (!policydb_context_isvalid(policydb, &newcon)) {
|
|
|
+ rc = convert_context_handle_invalid_context(state, &newcon);
|
|
|
if (rc) {
|
|
|
- if (!context_struct_to_string(&newcon, &s, &len)) {
|
|
|
+ if (!context_struct_to_string(policydb, &newcon, &s,
|
|
|
+ &len)) {
|
|
|
audit_log(current->audit_context,
|
|
|
GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
|
|
"op=security_sid_mls_copy "
|
|
@@ -2905,9 +3035,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
|
|
|
out_unlock:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
context_destroy(&newcon);
|
|
|
out:
|
|
|
return rc;
|
|
@@ -2933,10 +3063,13 @@ out:
|
|
|
* multiple, inconsistent labels | -<errno> | SECSID_NULL
|
|
|
*
|
|
|
*/
|
|
|
-int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
|
|
|
+int security_net_peersid_resolve(struct selinux_state *state,
|
|
|
+ u32 nlbl_sid, u32 nlbl_type,
|
|
|
u32 xfrm_sid,
|
|
|
u32 *peer_sid)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
+ struct sidtab *sidtab = &state->ss->sidtab;
|
|
|
int rc;
|
|
|
struct context *nlbl_ctx;
|
|
|
struct context *xfrm_ctx;
|
|
@@ -2958,23 +3091,25 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- /* we don't need to check ss_initialized here since the only way both
|
|
|
+ /*
|
|
|
+ * We don't need to check initialized here since the only way both
|
|
|
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
|
|
|
- * security server was initialized and ss_initialized was true */
|
|
|
- if (!policydb.mls_enabled)
|
|
|
+ * security server was initialized and state->initialized was true.
|
|
|
+ */
|
|
|
+ if (!policydb->mls_enabled)
|
|
|
return 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
|
|
|
+ nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
|
|
|
if (!nlbl_ctx) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, nlbl_sid);
|
|
|
goto out;
|
|
|
}
|
|
|
rc = -EINVAL;
|
|
|
- xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
|
|
|
+ xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
|
|
|
if (!xfrm_ctx) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
|
|
__func__, xfrm_sid);
|
|
@@ -2991,7 +3126,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
|
|
|
* expressive */
|
|
|
*peer_sid = xfrm_sid;
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -3008,19 +3143,27 @@ static int get_classes_callback(void *k, void *d, void *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int security_get_classes(char ***classes, int *nclasses)
|
|
|
+int security_get_classes(struct selinux_state *state,
|
|
|
+ char ***classes, int *nclasses)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
int rc;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ if (!state->initialized) {
|
|
|
+ *nclasses = 0;
|
|
|
+ *classes = NULL;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
- *nclasses = policydb.p_classes.nprim;
|
|
|
+ *nclasses = policydb->p_classes.nprim;
|
|
|
*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
|
|
|
if (!*classes)
|
|
|
goto out;
|
|
|
|
|
|
- rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
|
|
|
+ rc = hashtab_map(policydb->p_classes.table, get_classes_callback,
|
|
|
*classes);
|
|
|
if (rc) {
|
|
|
int i;
|
|
@@ -3030,7 +3173,7 @@ int security_get_classes(char ***classes, int *nclasses)
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -3047,15 +3190,17 @@ static int get_permissions_callback(void *k, void *d, void *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int security_get_permissions(char *class, char ***perms, int *nperms)
|
|
|
+int security_get_permissions(struct selinux_state *state,
|
|
|
+ char *class, char ***perms, int *nperms)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
int rc, i;
|
|
|
struct class_datum *match;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
- match = hashtab_search(policydb.p_classes.table, class);
|
|
|
+ match = hashtab_search(policydb->p_classes.table, class);
|
|
|
if (!match) {
|
|
|
printk(KERN_ERR "SELinux: %s: unrecognized class %s\n",
|
|
|
__func__, class);
|
|
@@ -3081,25 +3226,25 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
|
|
|
goto err;
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
|
|
|
err:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
for (i = 0; i < *nperms; i++)
|
|
|
kfree((*perms)[i]);
|
|
|
kfree(*perms);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-int security_get_reject_unknown(void)
|
|
|
+int security_get_reject_unknown(struct selinux_state *state)
|
|
|
{
|
|
|
- return policydb.reject_unknown;
|
|
|
+ return state->ss->policydb.reject_unknown;
|
|
|
}
|
|
|
|
|
|
-int security_get_allow_unknown(void)
|
|
|
+int security_get_allow_unknown(struct selinux_state *state)
|
|
|
{
|
|
|
- return policydb.allow_unknown;
|
|
|
+ return state->ss->policydb.allow_unknown;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -3112,13 +3257,15 @@ int security_get_allow_unknown(void)
|
|
|
* supported, false (0) if it isn't supported.
|
|
|
*
|
|
|
*/
|
|
|
-int security_policycap_supported(unsigned int req_cap)
|
|
|
+int security_policycap_supported(struct selinux_state *state,
|
|
|
+ unsigned int req_cap)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
int rc;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ rc = ebitmap_get_bit(&policydb->policycaps, req_cap);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
@@ -3140,6 +3287,8 @@ void selinux_audit_rule_free(void *vrule)
|
|
|
|
|
|
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
|
|
{
|
|
|
+ struct selinux_state *state = &selinux_state;
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
struct selinux_audit_rule *tmprule;
|
|
|
struct role_datum *roledatum;
|
|
|
struct type_datum *typedatum;
|
|
@@ -3149,7 +3298,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
|
|
|
|
|
*rule = NULL;
|
|
|
|
|
|
- if (!ss_initialized)
|
|
|
+ if (!state->initialized)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
switch (field) {
|
|
@@ -3182,15 +3331,15 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
|
|
|
|
|
context_init(&tmprule->au_ctxt);
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
- tmprule->au_seqno = latest_granting;
|
|
|
+ tmprule->au_seqno = state->ss->latest_granting;
|
|
|
|
|
|
switch (field) {
|
|
|
case AUDIT_SUBJ_USER:
|
|
|
case AUDIT_OBJ_USER:
|
|
|
rc = -EINVAL;
|
|
|
- userdatum = hashtab_search(policydb.p_users.table, rulestr);
|
|
|
+ userdatum = hashtab_search(policydb->p_users.table, rulestr);
|
|
|
if (!userdatum)
|
|
|
goto out;
|
|
|
tmprule->au_ctxt.user = userdatum->value;
|
|
@@ -3198,7 +3347,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
|
|
case AUDIT_SUBJ_ROLE:
|
|
|
case AUDIT_OBJ_ROLE:
|
|
|
rc = -EINVAL;
|
|
|
- roledatum = hashtab_search(policydb.p_roles.table, rulestr);
|
|
|
+ roledatum = hashtab_search(policydb->p_roles.table, rulestr);
|
|
|
if (!roledatum)
|
|
|
goto out;
|
|
|
tmprule->au_ctxt.role = roledatum->value;
|
|
@@ -3206,7 +3355,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
|
|
case AUDIT_SUBJ_TYPE:
|
|
|
case AUDIT_OBJ_TYPE:
|
|
|
rc = -EINVAL;
|
|
|
- typedatum = hashtab_search(policydb.p_types.table, rulestr);
|
|
|
+ typedatum = hashtab_search(policydb->p_types.table, rulestr);
|
|
|
if (!typedatum)
|
|
|
goto out;
|
|
|
tmprule->au_ctxt.type = typedatum->value;
|
|
@@ -3215,14 +3364,15 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
|
|
case AUDIT_SUBJ_CLR:
|
|
|
case AUDIT_OBJ_LEV_LOW:
|
|
|
case AUDIT_OBJ_LEV_HIGH:
|
|
|
- rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
|
|
|
+ rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
|
|
|
+ GFP_ATOMIC);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
break;
|
|
|
}
|
|
|
rc = 0;
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
|
|
|
if (rc) {
|
|
|
selinux_audit_rule_free(tmprule);
|
|
@@ -3262,6 +3412,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
|
|
|
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
|
|
struct audit_context *actx)
|
|
|
{
|
|
|
+ struct selinux_state *state = &selinux_state;
|
|
|
struct context *ctxt;
|
|
|
struct mls_level *level;
|
|
|
struct selinux_audit_rule *rule = vrule;
|
|
@@ -3272,14 +3423,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
|
|
return -ENOENT;
|
|
|
}
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
- if (rule->au_seqno < latest_granting) {
|
|
|
+ if (rule->au_seqno < state->ss->latest_granting) {
|
|
|
match = -ESTALE;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ctxt = sidtab_search(&sidtab, sid);
|
|
|
+ ctxt = sidtab_search(&state->ss->sidtab, sid);
|
|
|
if (unlikely(!ctxt)) {
|
|
|
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
|
|
|
sid);
|
|
@@ -3363,7 +3514,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return match;
|
|
|
}
|
|
|
|
|
@@ -3437,19 +3588,22 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
|
|
|
* failure.
|
|
|
*
|
|
|
*/
|
|
|
-int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
|
|
+int security_netlbl_secattr_to_sid(struct selinux_state *state,
|
|
|
+ struct netlbl_lsm_secattr *secattr,
|
|
|
u32 *sid)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
+ struct sidtab *sidtab = &state->ss->sidtab;
|
|
|
int rc;
|
|
|
struct context *ctx;
|
|
|
struct context ctx_new;
|
|
|
|
|
|
- if (!ss_initialized) {
|
|
|
+ if (!state->initialized) {
|
|
|
*sid = SECSID_NULL;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
if (secattr->flags & NETLBL_SECATTR_CACHE)
|
|
|
*sid = *(u32 *)secattr->cache->data;
|
|
@@ -3457,7 +3611,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
|
|
*sid = secattr->attr.secid;
|
|
|
else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
|
|
|
rc = -EIDRM;
|
|
|
- ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
|
|
|
+ ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
|
|
|
if (ctx == NULL)
|
|
|
goto out;
|
|
|
|
|
@@ -3465,17 +3619,17 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
|
|
ctx_new.user = ctx->user;
|
|
|
ctx_new.role = ctx->role;
|
|
|
ctx_new.type = ctx->type;
|
|
|
- mls_import_netlbl_lvl(&ctx_new, secattr);
|
|
|
+ mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
|
|
|
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
|
|
|
- rc = mls_import_netlbl_cat(&ctx_new, secattr);
|
|
|
+ rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
|
|
|
if (rc)
|
|
|
goto out;
|
|
|
}
|
|
|
rc = -EIDRM;
|
|
|
- if (!mls_context_isvalid(&policydb, &ctx_new))
|
|
|
+ if (!mls_context_isvalid(policydb, &ctx_new))
|
|
|
goto out_free;
|
|
|
|
|
|
- rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
|
|
|
+ rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
|
|
|
if (rc)
|
|
|
goto out_free;
|
|
|
|
|
@@ -3485,12 +3639,12 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
|
|
} else
|
|
|
*sid = SECSID_NULL;
|
|
|
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return 0;
|
|
|
out_free:
|
|
|
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -3504,33 +3658,35 @@ out:
|
|
|
* Returns zero on success, negative values on failure.
|
|
|
*
|
|
|
*/
|
|
|
-int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
|
|
|
+int security_netlbl_sid_to_secattr(struct selinux_state *state,
|
|
|
+ u32 sid, struct netlbl_lsm_secattr *secattr)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
int rc;
|
|
|
struct context *ctx;
|
|
|
|
|
|
- if (!ss_initialized)
|
|
|
+ if (!state->initialized)
|
|
|
return 0;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
|
|
|
rc = -ENOENT;
|
|
|
- ctx = sidtab_search(&sidtab, sid);
|
|
|
+ ctx = sidtab_search(&state->ss->sidtab, sid);
|
|
|
if (ctx == NULL)
|
|
|
goto out;
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
- secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),
|
|
|
+ secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
|
|
|
GFP_ATOMIC);
|
|
|
if (secattr->domain == NULL)
|
|
|
goto out;
|
|
|
|
|
|
secattr->attr.secid = sid;
|
|
|
secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
|
|
|
- mls_export_netlbl_lvl(ctx, secattr);
|
|
|
- rc = mls_export_netlbl_cat(ctx, secattr);
|
|
|
+ mls_export_netlbl_lvl(policydb, ctx, secattr);
|
|
|
+ rc = mls_export_netlbl_cat(policydb, ctx, secattr);
|
|
|
out:
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
return rc;
|
|
|
}
|
|
|
#endif /* CONFIG_NETLABEL */
|
|
@@ -3541,15 +3697,17 @@ out:
|
|
|
* @len: length of data in bytes
|
|
|
*
|
|
|
*/
|
|
|
-int security_read_policy(void **data, size_t *len)
|
|
|
+int security_read_policy(struct selinux_state *state,
|
|
|
+ void **data, size_t *len)
|
|
|
{
|
|
|
+ struct policydb *policydb = &state->ss->policydb;
|
|
|
int rc;
|
|
|
struct policy_file fp;
|
|
|
|
|
|
- if (!ss_initialized)
|
|
|
+ if (!state->initialized)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- *len = security_policydb_len();
|
|
|
+ *len = security_policydb_len(state);
|
|
|
|
|
|
*data = vmalloc_user(*len);
|
|
|
if (!*data)
|
|
@@ -3558,9 +3716,9 @@ int security_read_policy(void **data, size_t *len)
|
|
|
fp.data = *data;
|
|
|
fp.len = *len;
|
|
|
|
|
|
- read_lock(&policy_rwlock);
|
|
|
- rc = policydb_write(&policydb, &fp);
|
|
|
- read_unlock(&policy_rwlock);
|
|
|
+ read_lock(&state->ss->policy_rwlock);
|
|
|
+ rc = policydb_write(policydb, &fp);
|
|
|
+ read_unlock(&state->ss->policy_rwlock);
|
|
|
|
|
|
if (rc)
|
|
|
return rc;
|