read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
if (!user)
tclass = unmap_class(&state->ss->map, orig_tclass);
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
rc = -EINVAL;
old_context = sidtab_search(sidtab, old_sid);
goto allow;
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
goto allow;
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
goto allow;
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
}
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
if (force)
context = sidtab_search_force(sidtab, sid);
else
}
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
rc = string_to_context_struct(policydb, sidtab, scontext2,
&context, def_sid);
if (rc == -EINVAL && force) {
}
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) {
struct user_datum *usrdatum;
char *s;
u32 len;
- int rc = 0;
-
- if (key <= SECINITSID_NUM)
- goto out;
+ int rc;
args = p;
int security_load_policy(struct selinux_state *state, void *data, size_t len)
{
struct policydb *policydb;
- struct sidtab *sidtab;
+ struct sidtab *oldsidtab, *newsidtab;
struct policydb *oldpolicydb, *newpolicydb;
- struct sidtab oldsidtab, newsidtab;
struct selinux_mapping *oldmapping;
struct selinux_map newmap;
struct convert_context_args args;
newpolicydb = oldpolicydb + 1;
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+
+ newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL);
+ if (!newsidtab) {
+ rc = -ENOMEM;
+ goto out;
+ }
if (!state->initialized) {
rc = policydb_read(policydb, fp);
- if (rc)
+ if (rc) {
+ kfree(newsidtab);
goto out;
+ }
policydb->len = len;
rc = selinux_set_mapping(policydb, secclass_map,
&state->ss->map);
if (rc) {
+ kfree(newsidtab);
policydb_destroy(policydb);
goto out;
}
- rc = policydb_load_isids(policydb, sidtab);
+ rc = policydb_load_isids(policydb, newsidtab);
if (rc) {
+ kfree(newsidtab);
policydb_destroy(policydb);
goto out;
}
+ state->ss->sidtab = newsidtab;
security_load_policycaps(state);
state->initialized = 1;
seqno = ++state->ss->latest_granting;
goto out;
}
+ oldsidtab = state->ss->sidtab;
+
#if 0
- sidtab_hash_eval(sidtab, "sids");
+ sidtab_hash_eval(oldsidtab, "sids");
#endif
rc = policydb_read(newpolicydb, fp);
- if (rc)
+ if (rc) {
+ kfree(newsidtab);
goto out;
+ }
newpolicydb->len = len;
/* If switching between different policy types, log MLS status */
else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
pr_info("SELinux: Enabling MLS support...\n");
- rc = policydb_load_isids(newpolicydb, &newsidtab);
+ rc = policydb_load_isids(newpolicydb, newsidtab);
if (rc) {
pr_err("SELinux: unable to load the initial SIDs\n");
policydb_destroy(newpolicydb);
+ kfree(newsidtab);
goto out;
}
args.state = state;
args.oldp = policydb;
args.newp = newpolicydb;
- rc = sidtab_convert(sidtab, &newsidtab, convert_context, &args);
+ rc = sidtab_convert(oldsidtab, newsidtab, convert_context, &args);
if (rc) {
pr_err("SELinux: unable to convert the internal"
" representation of contexts in the new SID"
/* Save the old policydb and SID table to free later. */
memcpy(oldpolicydb, policydb, sizeof(*policydb));
- sidtab_set(&oldsidtab, sidtab);
/* Install the new policydb and SID table. */
write_lock_irq(&state->ss->policy_rwlock);
memcpy(policydb, newpolicydb, sizeof(*policydb));
- sidtab_set(sidtab, &newsidtab);
+ state->ss->sidtab = newsidtab;
security_load_policycaps(state);
oldmapping = state->ss->map.mapping;
state->ss->map.mapping = newmap.mapping;
/* Free the old policydb and SID table. */
policydb_destroy(oldpolicydb);
- sidtab_destroy(&oldsidtab);
+ sidtab_destroy(oldsidtab);
+ kfree(oldsidtab);
kfree(oldmapping);
avc_ss_reset(state->avc, seqno);
err:
kfree(newmap.mapping);
- sidtab_destroy(&newsidtab);
+ sidtab_destroy(newsidtab);
+ kfree(newsidtab);
policydb_destroy(newpolicydb);
out:
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
c = policydb->ocontexts[OCON_PORT];
while (c) {
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
c = policydb->ocontexts[OCON_IBPKEY];
while (c) {
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
c = policydb->ocontexts[OCON_IBENDPORT];
while (c) {
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
c = policydb->ocontexts[OCON_NETIF];
while (c) {
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
switch (domain) {
case AF_INET: {
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
context_init(&usercon);
u32 *sid)
{
struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = &state->ss->sidtab;
+ struct sidtab *sidtab = state->ss->sidtab;
int len;
u16 sclass;
struct genfs *genfs;
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
- sidtab = &state->ss->sidtab;
+ sidtab = state->ss->sidtab;
c = policydb->ocontexts[OCON_FSUSE];
while (c) {
u32 sid, u32 mls_sid, u32 *new_sid)
{
struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = &state->ss->sidtab;
+ struct sidtab *sidtab = state->ss->sidtab;
struct context *context1;
struct context *context2;
struct context newcon;
u32 *peer_sid)
{
struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = &state->ss->sidtab;
+ struct sidtab *sidtab = state->ss->sidtab;
int rc;
struct context *nlbl_ctx;
struct context *xfrm_ctx;
goto out;
}
- ctxt = sidtab_search(&state->ss->sidtab, sid);
+ ctxt = sidtab_search(state->ss->sidtab, sid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
sid);
u32 *sid)
{
struct policydb *policydb = &state->ss->policydb;
- struct sidtab *sidtab = &state->ss->sidtab;
+ struct sidtab *sidtab = state->ss->sidtab;
int rc;
struct context *ctx;
struct context ctx_new;
read_lock(&state->ss->policy_rwlock);
rc = -ENOENT;
- ctx = sidtab_search(&state->ss->sidtab, sid);
+ ctx = sidtab_search(state->ss->sidtab, sid);
if (ctx == NULL)
goto out;
s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC);
if (!s->htable)
return -ENOMEM;
+
+ for (i = 0; i < SECINITSID_NUM; i++)
+ s->isids[i].set = 0;
+
for (i = 0; i < SIDTAB_SIZE; i++)
s->htable[i] = NULL;
+
+ for (i = 0; i < SIDTAB_CACHE_LEN; i++)
+ s->cache[i] = NULL;
+
s->nel = 0;
- s->next_sid = 1;
+ s->next_sid = 0;
s->shutdown = 0;
spin_lock_init(&s->lock);
return 0;
}
-int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
+static int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
{
int hvalue;
struct sidtab_node *prev, *cur, *newnode;
return 0;
}
-static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
+int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context)
+{
+ struct sidtab_isid_entry *entry;
+ int rc;
+
+ if (sid == 0 || sid > SECINITSID_NUM)
+ return -EINVAL;
+
+ entry = &s->isids[sid - 1];
+
+ rc = context_cpy(&entry->context, context);
+ if (rc)
+ return rc;
+
+ entry->set = 1;
+ return 0;
+}
+
+static struct context *sidtab_lookup(struct sidtab *s, u32 sid)
{
int hvalue;
struct sidtab_node *cur;
- if (!s)
- return NULL;
-
hvalue = SIDTAB_HASH(sid);
cur = s->htable[hvalue];
while (cur && sid > cur->sid)
cur = cur->next;
- if (force && cur && sid == cur->sid && cur->context.len)
- return &cur->context;
+ if (!cur || sid != cur->sid)
+ return NULL;
- if (!cur || sid != cur->sid || cur->context.len) {
- /* Remap invalid SIDs to the unlabeled SID. */
- sid = SECINITSID_UNLABELED;
- hvalue = SIDTAB_HASH(sid);
- cur = s->htable[hvalue];
- while (cur && sid > cur->sid)
- cur = cur->next;
- if (!cur || sid != cur->sid)
- return NULL;
+ return &cur->context;
+}
+
+static struct context *sidtab_lookup_initial(struct sidtab *s, u32 sid)
+{
+ return s->isids[sid - 1].set ? &s->isids[sid - 1].context : NULL;
+}
+
+static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
+{
+ struct context *context;
+
+ if (!s)
+ return NULL;
+
+ if (sid != 0) {
+ if (sid > SECINITSID_NUM)
+ context = sidtab_lookup(s, sid - (SECINITSID_NUM + 1));
+ else
+ context = sidtab_lookup_initial(s, sid);
+ if (context && (!context->len || force))
+ return context;
}
- return &cur->context;
+ return sidtab_lookup_initial(s, SECINITSID_UNLABELED);
}
struct context *sidtab_search(struct sidtab *s, u32 sid)
static int clone_sid(u32 sid, struct context *context, void *arg)
{
struct sidtab *s = arg;
-
- if (sid > SECINITSID_NUM)
- return sidtab_insert(s, sid, context);
- else
- return 0;
+ return sidtab_insert(s, sid, context);
}
int sidtab_convert(struct sidtab *s, struct sidtab *news,
s->cache[0] = n;
}
-static inline u32 sidtab_search_context(struct sidtab *s,
- struct context *context)
+static inline int sidtab_search_context(struct sidtab *s,
+ struct context *context, u32 *sid)
{
int i;
struct sidtab_node *cur;
while (cur) {
if (context_cmp(&cur->context, context)) {
sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);
- return cur->sid;
+ *sid = cur->sid;
+ return 0;
}
cur = cur->next;
}
}
- return 0;
+ return -ENOENT;
}
-static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context)
+static inline int sidtab_search_cache(struct sidtab *s, struct context *context,
+ u32 *sid)
{
int i;
struct sidtab_node *node;
for (i = 0; i < SIDTAB_CACHE_LEN; i++) {
node = s->cache[i];
if (unlikely(!node))
- return 0;
+ return -ENOENT;
if (context_cmp(&node->context, context)) {
sidtab_update_cache(s, node, i);
- return node->sid;
+ *sid = node->sid;
+ return 0;
}
}
- return 0;
+ return -ENOENT;
}
-int sidtab_context_to_sid(struct sidtab *s,
- struct context *context,
- u32 *out_sid)
+static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
+ u32 *sid)
{
- u32 sid;
- int ret = 0;
+ int ret;
unsigned long flags;
- *out_sid = SECSID_NULL;
-
- sid = sidtab_search_cache(s, context);
- if (!sid)
- sid = sidtab_search_context(s, context);
- if (!sid) {
+ ret = sidtab_search_cache(s, context, sid);
+ if (ret)
+ ret = sidtab_search_context(s, context, sid);
+ if (ret) {
spin_lock_irqsave(&s->lock, flags);
/* Rescan now that we hold the lock. */
- sid = sidtab_search_context(s, context);
- if (sid)
+ ret = sidtab_search_context(s, context, sid);
+ if (!ret)
goto unlock_out;
/* No SID exists for the context. Allocate a new one. */
- if (s->next_sid == UINT_MAX || s->shutdown) {
+ if (s->next_sid == (UINT_MAX - SECINITSID_NUM - 1) ||
+ s->shutdown) {
ret = -ENOMEM;
goto unlock_out;
}
- sid = s->next_sid++;
+ *sid = s->next_sid++;
if (context->len)
pr_info("SELinux: Context %s is not valid (left unmapped).\n",
context->str);
- ret = sidtab_insert(s, sid, context);
+ ret = sidtab_insert(s, *sid, context);
if (ret)
s->next_sid--;
unlock_out:
spin_unlock_irqrestore(&s->lock, flags);
}
- if (ret)
- return ret;
+ return ret;
+}
+
+int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
+{
+ int rc;
+ u32 i;
- *out_sid = sid;
+ for (i = 0; i < SECINITSID_NUM; i++) {
+ struct sidtab_isid_entry *entry = &s->isids[i];
+
+ if (entry->set && context_cmp(context, &entry->context)) {
+ *sid = i + 1;
+ return 0;
+ }
+ }
+
+ rc = sidtab_reverse_lookup(s, context, sid);
+ if (rc)
+ return rc;
+ *sid += SECINITSID_NUM + 1;
return 0;
}
if (!s)
return;
+ for (i = 0; i < SECINITSID_NUM; i++)
+ if (s->isids[i].set)
+ context_destroy(&s->isids[i].context);
+
for (i = 0; i < SIDTAB_SIZE; i++) {
cur = s->htable[i];
while (cur) {
s->nel = 0;
s->next_sid = 1;
}
-
-void sidtab_set(struct sidtab *dst, struct sidtab *src)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&src->lock, flags);
- dst->htable = src->htable;
- dst->nel = src->nel;
- dst->next_sid = src->next_sid;
- dst->shutdown = 0;
- for (i = 0; i < SIDTAB_CACHE_LEN; i++)
- dst->cache[i] = NULL;
- spin_unlock_irqrestore(&src->lock, flags);
-}