aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/services.c
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2018-03-01 18:48:02 -0500
committerPaul Moore <paul@paul-moore.com>2018-03-01 18:48:02 -0500
commitaa8e712cee93d520e96a2ca8e3a20f807c937e3f (patch)
tree5e2bdce92022ebb334bfa68b6a731b71ef86974d /security/selinux/ss/services.c
parentselinux: fix typo in selinux_netlbl_sctp_sk_clone declaration (diff)
downloadlinux-dev-aa8e712cee93d520e96a2ca8e3a20f807c937e3f.tar.xz
linux-dev-aa8e712cee93d520e96a2ca8e3a20f807c937e3f.zip
selinux: wrap global selinux state
Define a selinux state structure (struct selinux_state) for global SELinux state and pass it explicitly to all security server functions. The public portion of the structure contains state that is used throughout the SELinux code, such as the enforcing mode. The structure also contains a pointer to a selinux_ss structure whose definition is private to the security server and contains security server specific state such as the policy database and SID table. This change should have no effect on SELinux behavior or APIs (userspace or LSM). It merely wraps SELinux state and passes it explicitly as needed. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> [PM: minor fixups needed due to collisions with the SCTP patches] Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r--security/selinux/ss/services.c1078
1 files changed, 611 insertions, 467 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 8900ea5cbabf..3698352213d7 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -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 (!is_enforcing(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 (!is_enforcing(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 (is_enforcing(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,
- &current_mapping,
- &current_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);
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);
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);
+
+ policydb = &state->ss->policydb;
+ sidtab = &state->ss->sidtab;
- c = policydb.ocontexts[OCON_PORT];
+ 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);
- c = policydb.ocontexts[OCON_IBENDPORT];
+ policydb = &state->ss->policydb;
+ sidtab = &state->ss->sidtab;
+
+ 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);
+
+ policydb = &state->ss->policydb;
+ sidtab = &state->ss->sidtab;
- c = policydb.ocontexts[OCON_NETIF];
+ 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;
@@ -2583,11 +2678,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 +2695,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 +2720,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 +2741,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 +2759,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);
+
+ policydb = &state->ss->policydb;
+ sidtab = &state->ss->sidtab;
- c = policydb.ocontexts[OCON_FSUSE];
+ c = policydb->ocontexts[OCON_FSUSE];
while (c) {
if (strcmp(fstype, c->u.name) == 0)
break;
@@ -2679,14 +2783,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 +2801,25 @@ 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);
+ 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 +2834,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 +2856,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);
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 +2966,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 +2979,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 +2997,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 +3012,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 +3027,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 +3055,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 +3083,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 +3118,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 +3135,21 @@ 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);
+ 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 +3159,7 @@ int security_get_classes(char ***classes, int *nclasses)
}
out:
- read_unlock(&policy_rwlock);
+ read_unlock(&state->ss->policy_rwlock);
return rc;
}
@@ -3047,15 +3176,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 +3212,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 +3243,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 +3273,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 +3284,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 +3317,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 +3333,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 +3341,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 +3350,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 +3398,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 +3409,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 +3500,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 +3574,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 +3597,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 +3605,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 +3625,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 +3644,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 +3683,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 +3702,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;