/* Find number of classes in the input mapping */ if (!map) return -EINVAL;
i = 0; while (map[i].name)
i++;
/* Allocate space for the class records, plus one for class zero */
out_map->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) { conststruct security_class_mapping *p_in = map + (j++); struct selinux_mapping *p_out = out_map->mapping + j;
u16 k;
/* An empty class string skips ahead */ if (!strcmp(p_in->name, "")) {
p_out->num_perms = 0; continue;
}
p_out->value = string_to_security_class(pol, p_in->name); if (!p_out->value) {
pr_info("SELinux: Class %s not defined in policy.\n",
p_in->name); if (pol->reject_unknown) goto err;
p_out->num_perms = 0;
print_unknown_handle = true; continue;
}
k = 0; while (p_in->perms[k]) { /* An empty permission string skips ahead */ if (!*p_in->perms[k]) {
k++; continue;
}
p_out->perms[k] = string_to_av_perm(pol, p_out->value,
p_in->perms[k]); if (!p_out->perms[k]) {
pr_info("SELinux: Permission %s in class %s not defined in policy.\n",
p_in->perms[k], p_in->name); if (pol->reject_unknown) goto err;
print_unknown_handle = true;
}
k++;
}
p_out->num_perms = k;
}
if (print_unknown_handle)
pr_info("SELinux: the above unknown classes and permissions will be %s\n",
pol->allow_unknown ? "allowed" : "denied");
/* * Get kernel value for class from its policy value
*/ static u16 map_class(struct selinux_map *map, u16 pol_value)
{
u16 i;
for (i = 1; i < map->size; i++) { if (map->mapping[i].value == pol_value) return i;
}
return SECCLASS_NULL;
}
staticvoid map_decision(struct selinux_map *map,
u16 tclass, struct av_decision *avd, int allow_unknown)
{ if (tclass < map->size) { struct selinux_mapping *mapping = &map->mapping[tclass]; unsignedint i, n = mapping->num_perms;
u32 result;
for (i = 0, result = 0; i < n; i++) { if (avd->allowed & mapping->perms[i])
result |= (u32)1<<i; if (allow_unknown && !mapping->perms[i])
result |= (u32)1<<i;
}
avd->allowed = result;
for (i = 0, result = 0; i < n; i++) if (avd->auditallow & mapping->perms[i])
result |= (u32)1<<i;
avd->auditallow = result;
for (i = 0, result = 0; i < n; i++) { if (avd->auditdeny & mapping->perms[i])
result |= (u32)1<<i; if (!allow_unknown && !mapping->perms[i])
result |= (u32)1<<i;
} /* * In case the kernel has a bug and requests a permission * between num_perms and the maximum permission number, we * should audit that denial
*/ for (; i < (sizeof(u32)*8); i++)
result |= (u32)1<<i;
avd->auditdeny = result;
}
}
int security_mls_enabled(void)
{ int mls_enabled; struct selinux_policy *policy;
/* * Return the boolean value of a constraint expression * when it is applied to the specified source and target * security contexts. * * xcontext is a special beast... It is used by the validatetrans rules * only. For these rules, scontext is the context before the transition, * tcontext is the context after the transition, and xcontext is the context * of the process performing the transition. All other callers of * constraint_expr_eval should pass in NULL for xcontext.
*/ staticint constraint_expr_eval(struct policydb *policydb, struct context *scontext, struct context *tcontext, struct context *xcontext, struct constraint_expr *cexpr)
{
u32 val1, val2; struct context *c; struct role_datum *r1, *r2; struct mls_level *l1, *l2; struct constraint_expr *e; int s[CEXPR_MAXDEPTH]; int sp = -1;
for (e = cexpr; e; e = e->next) { switch (e->expr_type) { case CEXPR_NOT:
BUG_ON(sp < 0);
s[sp] = !s[sp]; break; case CEXPR_AND:
BUG_ON(sp < 1);
sp--;
s[sp] &= s[sp + 1]; break; case CEXPR_OR:
BUG_ON(sp < 1);
sp--;
s[sp] |= s[sp + 1]; break; case CEXPR_ATTR: if (sp == (CEXPR_MAXDEPTH - 1)) return 0; switch (e->attr) { case CEXPR_USER:
val1 = scontext->user;
val2 = tcontext->user; break; case CEXPR_TYPE:
val1 = scontext->type;
val2 = tcontext->type; break; 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]; switch (e->op) { case CEXPR_DOM:
s[++sp] = ebitmap_get_bit(&r1->dominates,
val2 - 1); continue; case CEXPR_DOMBY:
s[++sp] = ebitmap_get_bit(&r2->dominates,
val1 - 1); continue; case CEXPR_INCOMP:
s[++sp] = (!ebitmap_get_bit(&r1->dominates,
val2 - 1) &&
!ebitmap_get_bit(&r2->dominates,
val1 - 1)); continue; default: break;
} break; case CEXPR_L1L2:
l1 = &(scontext->range.level[0]);
l2 = &(tcontext->range.level[0]); goto mls_ops; case CEXPR_L1H2:
l1 = &(scontext->range.level[0]);
l2 = &(tcontext->range.level[1]); goto mls_ops; case CEXPR_H1L2:
l1 = &(scontext->range.level[1]);
l2 = &(tcontext->range.level[0]); goto mls_ops; case CEXPR_H1H2:
l1 = &(scontext->range.level[1]);
l2 = &(tcontext->range.level[1]); goto mls_ops; case CEXPR_L1H1:
l1 = &(scontext->range.level[0]);
l2 = &(scontext->range.level[1]); goto mls_ops; case CEXPR_L2H2:
l1 = &(tcontext->range.level[0]);
l2 = &(tcontext->range.level[1]); goto mls_ops;
mls_ops: switch (e->op) { case CEXPR_EQ:
s[++sp] = mls_level_eq(l1, l2); continue; case CEXPR_NEQ:
s[++sp] = !mls_level_eq(l1, l2); continue; case CEXPR_DOM:
s[++sp] = mls_level_dom(l1, l2); continue; case CEXPR_DOMBY:
s[++sp] = mls_level_dom(l2, l1); continue; case CEXPR_INCOMP:
s[++sp] = mls_level_incomp(l2, l1); continue; default:
BUG(); return 0;
} break; default:
BUG(); return 0;
}
switch (e->op) { case CEXPR_EQ:
s[++sp] = (val1 == val2); break; case CEXPR_NEQ:
s[++sp] = (val1 != val2); break; default:
BUG(); return 0;
} break; case CEXPR_NAMES: if (sp == (CEXPR_MAXDEPTH-1)) return 0;
c = scontext; if (e->attr & CEXPR_TARGET)
c = tcontext; elseif (e->attr & CEXPR_XTARGET) {
c = xcontext; if (!c) {
BUG(); return 0;
}
} if (e->attr & CEXPR_USER)
val1 = c->user; elseif (e->attr & CEXPR_ROLE)
val1 = c->role; elseif (e->attr & CEXPR_TYPE)
val1 = c->type; else {
BUG(); return 0;
}
/* * Flag which drivers have permissions and which base permissions are covered.
*/ void services_compute_xperms_drivers( struct extended_perms *xperms, struct avtab_node *node)
{ unsignedint i;
switch (node->datum.u.xperms->specified) { case AVTAB_XPERMS_IOCTLDRIVER:
xperms->base_perms |= AVC_EXT_IOCTL; /* if one or more driver has all permissions allowed */ for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; break; case AVTAB_XPERMS_IOCTLFUNCTION:
xperms->base_perms |= AVC_EXT_IOCTL; /* if allowing permissions within a driver */
security_xperm_set(xperms->drivers.p,
node->datum.u.xperms->driver); break; case AVTAB_XPERMS_NLMSG:
xperms->base_perms |= AVC_EXT_NLMSG; /* if allowing permissions within a driver */
security_xperm_set(xperms->drivers.p,
node->datum.u.xperms->driver); break;
}
xperms->len = 1;
}
/* * Compute access vectors and extended permissions based on a context * structure pair for the permissions in a particular class.
*/ staticvoid 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; struct avtab_key avkey; struct avtab_node *node; struct class_datum *tclass_datum; struct ebitmap *sattr, *tattr; struct ebitmap_node *snode, *tnode; unsignedint i, j;
/* * If a specific type enforcement rule was defined for * this permission check, then use it.
*/
avkey.target_class = tclass;
avkey.specified = AVTAB_AV | AVTAB_XPERMS;
sattr = &policydb->type_attr_map_array[scontext->type - 1];
tattr = &policydb->type_attr_map_array[tcontext->type - 1];
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);
node;
node = avtab_search_node_next(node, avkey.specified)) { if (node->key.specified == AVTAB_ALLOWED)
avd->allowed |= node->datum.u.data; elseif (node->key.specified == AVTAB_AUDITALLOW)
avd->auditallow |= node->datum.u.data; elseif (node->key.specified == AVTAB_AUDITDENY)
avd->auditdeny &= node->datum.u.data; elseif (xperms && (node->key.specified & AVTAB_XPERMS))
services_compute_xperms_drivers(xperms, node);
}
/* Check conditional av table for additional permissions */
cond_compute_av(&policydb->te_cond_avtab, &avkey,
avd, xperms);
}
}
/* * Remove any permissions prohibited by a constraint (this includes * the MLS policy).
*/
constraint = tclass_datum->constraints; while (constraint) { if ((constraint->permissions & (avd->allowed)) &&
!constraint_expr_eval(policydb, scontext, tcontext, NULL,
constraint->expr)) {
avd->allowed &= ~(constraint->permissions);
}
constraint = constraint->next;
}
/* * If checking process transition permission and the * role is changing, then check the (current_role, new_role) * pair.
*/ if (tclass == policydb->process_class &&
(avd->allowed & policydb->process_trans_perms) &&
scontext->role != tcontext->role) { for (ra = policydb->role_allow; ra; ra = ra->next) { if (scontext->role == ra->role &&
tcontext->role == ra->new_role) break;
} if (!ra)
avd->allowed &= ~policydb->process_trans_perms;
}
/* * If the given source and target types have boundary * constraint, lazy checks have to mask any violated * permission and notice it to userspace via audit.
*/
type_attribute_bounds_av(policydb, scontext, tcontext,
tclass, avd);
}
switch (specified) { case AVTAB_XPERMS_IOCTLDRIVER:
memset(xp_data->p, 0xff, sizeof(xp_data->p)); break; case AVTAB_XPERMS_IOCTLFUNCTION: case AVTAB_XPERMS_NLMSG: for (i = 0; i < ARRAY_SIZE(xp_data->p); i++)
xp_data->p[i] |= from->p[i]; break;
}
/* * Write the security context string representation of * the context structure `context' 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.
*/ staticint context_struct_to_string(struct policydb *p, struct context *context, char **scontext, u32 *scontext_len)
{ char *scontextp;
if (scontext)
*scontext = NULL;
*scontext_len = 0;
if (context->len) {
*scontext_len = context->len; if (scontext) {
*scontext = kstrdup(context->str, GFP_ATOMIC); if (!(*scontext)) return -ENOMEM;
} return 0;
}
/* Allocate space for the context; caller must free this space. */
scontextp = kmalloc(*scontext_len, GFP_ATOMIC); if (!scontextp) return -ENOMEM;
*scontext = scontextp;
/* * Copy the user name, role name and type name into the context.
*/
scontextp += sprintf(scontextp, "%s:%s:%s",
sym_name(p, SYM_USERS, context->user - 1),
sym_name(p, SYM_ROLES, context->role - 1),
sym_name(p, SYM_TYPES, context->type - 1));
staticint security_sid_to_context_core(u32 sid, char **scontext,
u32 *scontext_len, int force, int only_invalid)
{ struct selinux_policy *policy; struct policydb *policydb; struct sidtab *sidtab; struct sidtab_entry *entry; int rc = 0;
if (scontext)
*scontext = NULL;
*scontext_len = 0;
if (!selinux_initialized()) { if (sid <= SECINITSID_NUM) { char *scontextp; constchar *s;
/* * Before the policy is loaded, translate * SECINITSID_INIT to "kernel", because systemd and * libselinux < 2.6 take a getcon_raw() result that is * both non-null and not "kernel" to mean that a policy * is already loaded.
*/ if (sid == SECINITSID_INIT)
sid = SECINITSID_KERNEL;
s = initial_sid_to_string[sid]; if (!s) return -EINVAL;
*scontext_len = strlen(s) + 1; if (!scontext) return 0;
scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC); if (!scontextp) return -ENOMEM;
*scontext = scontextp; return 0;
}
pr_err("SELinux: %s: called before initial " "load_policy on unknown SID %d\n", __func__, sid); return -EINVAL;
}
rcu_read_lock();
policy = rcu_dereference(selinux_state.policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
/** * security_sid_to_context - Obtain a context for a given SID. * @sid: security identifier, SID * @scontext: security context * @scontext_len: length in bytes * * Write the string representation of the context associated with @sid * 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)
{ return security_sid_to_context_core(sid, scontext,
scontext_len, 0, 0);
}
/** * security_sid_to_context_inval - Obtain a context for a given SID if it * is invalid. * @sid: security identifier, SID * @scontext: security context * @scontext_len: length in bytes * * Write the string representation of the context associated with @sid * into a dynamically allocated string of the correct size, but only if the * context is invalid in the current policy. Set @scontext to point to * this string (or NULL if the context is valid) and set @scontext_len to * the length of the string (or 0 if the context is valid).
*/ int security_sid_to_context_inval(u32 sid, char **scontext, u32 *scontext_len)
{ return security_sid_to_context_core(sid, scontext,
scontext_len, 1, 1);
}
/* Check the validity of the new context. */
rc = -EINVAL; if (!policydb_context_isvalid(pol, ctx)) goto out;
rc = 0;
out: if (rc)
context_destroy(ctx); return rc;
}
/* An empty security context is never valid. */ if (!scontext_len) return -EINVAL;
/* Copy the string to allow changes and ensure a NUL terminator */
scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags); if (!scontext2) return -ENOMEM;
if (!selinux_initialized()) {
u32 i;
for (i = 1; i < SECINITSID_NUM; i++) { constchar *s = initial_sid_to_string[i];
if (force) { /* Save another copy for storing in uninterpreted form */
rc = -ENOMEM;
str = kstrdup(scontext2, gfp_flags); if (!str) goto out;
}
retry:
rcu_read_lock();
policy = rcu_dereference(selinux_state.policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
rc = string_to_context_struct(policydb, sidtab, scontext2,
&context, def_sid); if (rc == -EINVAL && force) {
context.str = str;
context.len = strlen(str) + 1;
str = NULL;
} elseif (rc) goto out_unlock;
rc = sidtab_context_to_sid(sidtab, &context, sid); if (rc == -ESTALE) {
rcu_read_unlock(); if (context.str) {
str = context.str;
context.str = NULL;
}
context_destroy(&context); goto retry;
}
context_destroy(&context);
out_unlock:
rcu_read_unlock();
out:
kfree(scontext2);
kfree(str); return rc;
}
/** * security_context_to_sid - Obtain a SID for a given security context. * @scontext: security context * @scontext_len: length in bytes * @sid: security identifier, SID * @gfp: context for the allocation * * Obtains a SID associated with the security context that * has the string representation specified by @scontext. * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * memory is available, or 0 on success.
*/ int security_context_to_sid(constchar *scontext, u32 scontext_len, u32 *sid,
gfp_t gfp)
{ return security_context_to_sid_core(scontext, scontext_len,
sid, SECSID_NULL, gfp, 0);
}
/** * security_context_to_sid_default - Obtain a SID for a given security context, * falling back to specified default if needed. * * @scontext: security context * @scontext_len: length in bytes * @sid: security identifier, SID * @def_sid: default SID to assign on error * @gfp_flags: the allocator get-free-page (GFP) flags * * Obtains a SID associated with the security context that * has the string representation specified by @scontext. * The default SID is passed to the MLS layer to be used to allow * kernel labeling of the MLS field if the MLS field is not present * (for upgrading to MLS without full relabel). * Implicitly forces adding of the context even if it cannot be mapped yet. * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * memory is available, or 0 on success.
*/ int security_context_to_sid_default(constchar *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{ return security_context_to_sid_core(scontext, scontext_len,
sid, def_sid, gfp_flags, 1);
}
/* * Most filename trans rules are going to live in specific directories * like /dev or /var/run. This bitmap will quickly skip rule searches * if the ttype does not contain any rules.
*/ if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype)) return;
/* Set the user identity. */ switch (specified) { case AVTAB_TRANSITION: case AVTAB_CHANGE: if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
newcontext.user = tcontext->user;
} else { /* notice this gets both DEFAULT_SOURCE and unset */ /* Use the process user identity. */
newcontext.user = scontext->user;
} break; case AVTAB_MEMBER: /* Use the related object owner. */
newcontext.user = tcontext->user; break;
}
/* Set the role to default values. */ if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
newcontext.role = scontext->role;
} elseif (cladatum && cladatum->default_role == DEFAULT_TARGET) {
newcontext.role = tcontext->role;
} else { if ((tclass == policydb->process_class) || sock)
newcontext.role = scontext->role; else
newcontext.role = OBJECT_R_VAL;
}
/* Set the type. * Look for a type transition/member/change rule.
*/
avkey.source_type = scontext->type;
avkey.target_type = tcontext->type;
avkey.target_class = tclass;
avkey.specified = specified;
avnode = avtab_search_node(&policydb->te_avtab, &avkey);
/* If no permanent rule, also check for enabled conditional rules */ if (!avnode) {
node = avtab_search_node(&policydb->te_cond_avtab, &avkey); for (; node; node = avtab_search_node_next(node, specified)) { if (node->key.specified & AVTAB_ENABLED) {
avnode = node; break;
}
}
}
/* If a permanent rule is found, use the type from * the type transition/member/change rule. Otherwise, * set the type to its default values.
*/ if (avnode) {
newcontext.type = avnode->datum.u.data;
} elseif (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
newcontext.type = scontext->type;
} elseif (cladatum && cladatum->default_type == DEFAULT_TARGET) {
newcontext.type = tcontext->type;
} else { if ((tclass == policydb->process_class) || sock) { /* Use the type of process. */
newcontext.type = scontext->type;
} else { /* Use the type of the related object. */
newcontext.type = tcontext->type;
}
}
/* if we have a objname this is a file trans check so check those rules */ if (objname)
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. */ struct role_trans_datum *rtd; struct role_trans_key rtk = {
.role = scontext->role,
.type = tcontext->type,
.tclass = tclass,
};
rtd = policydb_roletr_search(policydb, &rtk); if (rtd)
newcontext.role = rtd->new_role;
}
/* Set the MLS attributes.
This is done last because it may allocate memory. */
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(policy, sentry,
tentry, tclass,
&newcontext); if (rc) goto out_unlock;
} /* Obtain the sid for the context. */ if (context_equal(scontext, &newcontext))
*out_sid = ssid; elseif (context_equal(tcontext, &newcontext))
*out_sid = tsid; else {
rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid); if (rc == -ESTALE) {
rcu_read_unlock();
context_destroy(&newcontext); goto retry;
}
}
out_unlock:
rcu_read_unlock();
context_destroy(&newcontext);
out: return rc;
}
/** * security_transition_sid - Compute the SID for a new subject/object. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @qstr: object name * @out_sid: security identifier for new subject/object * * Compute a SID to use for labeling a new subject or object in the * class @tclass based on a SID pair (@ssid, @tsid). * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM * if insufficient memory is available, or %0 if the new SID was * computed successfully.
*/ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, conststruct qstr *qstr, u32 *out_sid)
{ return security_compute_sid(ssid, tsid, tclass,
AVTAB_TRANSITION,
qstr ? qstr->name : NULL, out_sid, true);
}
/** * security_member_sid - Compute the SID for member selection. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @out_sid: security identifier for selected member * * Compute a SID to use when selecting a member of a polyinstantiated * object of class @tclass based on a SID pair (@ssid, @tsid). * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM * if insufficient memory is available, or %0 if the SID was * computed successfully.
*/ int security_member_sid(u32 ssid,
u32 tsid,
u16 tclass,
u32 *out_sid)
{ return security_compute_sid(ssid, tsid, tclass,
AVTAB_MEMBER, NULL,
out_sid, false);
}
/** * security_change_sid - Compute the SID for object relabeling. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @out_sid: security identifier for selected member * * Compute a SID to use for relabeling an object of class @tclass * based on a SID pair (@ssid, @tsid). * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM * if insufficient memory is available, or %0 if the SID was * computed successfully.
*/ int security_change_sid(u32 ssid,
u32 tsid,
u16 tclass,
u32 *out_sid)
{ return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
out_sid, false);
}
if (!context_struct_to_string(policydb, context, &s, &len)) {
pr_warn("SELinux: Context %s would be invalid if enforcing\n",
s);
kfree(s);
} return 0;
}
/** * services_convert_context - Convert a security context across policies. * @args: populated convert_context_args struct * @oldc: original context * @newc: converted context * @gfp_flags: allocation flags * * Convert the values in the security context structure @oldc from the values * specified in the policy @args->oldp to the values specified in the policy * @args->newp, storing the new context in @newc, and verifying that the * context is valid under the new policy.
*/ int services_convert_context(struct convert_context_args *args, struct context *oldc, struct context *newc,
gfp_t gfp_flags)
{ struct ocontext *oc; struct role_datum *role; struct type_datum *typdatum; struct user_datum *usrdatum; char *s;
u32 len; int rc;
if (oldc->str) {
s = kstrdup(oldc->str, gfp_flags); if (!s) return -ENOMEM;
rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL); if (rc == -EINVAL) { /* * Retain string representation for later mapping. * * IMPORTANT: We need to copy the contents of oldc->str * back into s again because string_to_context_struct() * may have garbled it.
*/
memcpy(s, oldc->str, oldc->len);
context_init(newc);
newc->str = s;
newc->len = oldc->len; return 0;
}
kfree(s); if (rc) { /* Other error condition, e.g. ENOMEM. */
pr_err("SELinux: Unable to map context %s, rc = %d.\n",
oldc->str, -rc); return rc;
}
pr_info("SELinux: Context %s became valid (mapped).\n",
oldc->str); return 0;
}
context_init(newc);
/* Convert the user. */
usrdatum = symtab_search(&args->newp->p_users,
sym_name(args->oldp, SYM_USERS, oldc->user - 1)); if (!usrdatum) goto bad;
newc->user = usrdatum->value;
/* Convert the role. */
role = symtab_search(&args->newp->p_roles,
sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); if (!role) goto bad;
newc->role = role->value;
/* Convert the type. */
typdatum = symtab_search(&args->newp->p_types,
sym_name(args->oldp, SYM_TYPES, oldc->type - 1)); if (!typdatum) goto bad;
newc->type = typdatum->value;
/* Convert the MLS fields if dealing with MLS policies */ if (args->oldp->mls_enabled && args->newp->mls_enabled) {
rc = mls_convert_context(args->oldp, args->newp, oldc, newc); if (rc) goto bad;
} elseif (!args->oldp->mls_enabled && args->newp->mls_enabled) { /* * Switching between non-MLS and MLS policy: * ensure that the MLS fields of the context for all * existing entries in the sidtab are filled in with a * suitable default value, likely taken from one of the * initial SIDs.
*/
oc = args->newp->ocontexts[OCON_ISID]; while (oc && oc->sid[0] != SECINITSID_UNLABELED)
oc = oc->next; if (!oc) {
pr_err("SELinux: unable to look up" " the initial SIDs list\n"); goto bad;
}
rc = mls_range_set(newc, &oc->context[0].range); if (rc) goto bad;
}
/* Check the validity of the new context. */ if (!policydb_context_isvalid(args->newp, newc)) {
rc = convert_context_handle_invalid_context(args->oldp, oldc); if (rc) goto bad;
}
return 0;
bad: /* Map old representation to string and save it. */
rc = context_struct_to_string(args->oldp, oldc, &s, &len); if (rc) return rc;
context_destroy(newc);
newc->str = s;
newc->len = len;
pr_info("SELinux: Context %s became invalid (unmapped).\n",
newc->str); return 0;
}
for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
WRITE_ONCE(selinux_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(&p->policycaps, 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);
}
}
/* If switching between different policy types, log MLS status */ if (oldpolicy) { if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
pr_info("SELinux: Disabling MLS support...\n"); elseif (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
pr_info("SELinux: Enabling MLS support...\n");
}
/* Set latest granting seqno for new policy. */ if (oldpolicy)
newpolicy->latest_granting = oldpolicy->latest_granting + 1; else
newpolicy->latest_granting = 1;
seqno = newpolicy->latest_granting;
/* Install the new policy. */ if (oldpolicy) {
sidtab_freeze_begin(oldpolicy->sidtab, &flags);
rcu_assign_pointer(state->policy, newpolicy);
sidtab_freeze_end(oldpolicy->sidtab, &flags);
} else {
rcu_assign_pointer(state->policy, newpolicy);
}
/* Load the policycaps from the new policy */
security_load_policycaps(newpolicy);
if (!selinux_initialized()) { /* * After first policy load, the security server is * marked as initialized and ready to handle requests and * any objects created prior to policy load are then labeled.
*/
selinux_mark_initialized();
selinux_complete_init();
}
/* Free the old policy */
synchronize_rcu();
selinux_policy_free(oldpolicy);
kfree(load_state->convert_data);
/* Notify others of the policy change */
selinux_notify_policy_change(seqno);
}
/** * security_load_policy - Load a security policy configuration. * @data: binary policy data * @len: length of data in bytes * @load_state: policy load state * * Load a new set of security policy configuration data, * validate it and convert the SID table as necessary. * This function will flush the access vector cache after * loading the new policy.
*/ int security_load_policy(void *data, size_t len, struct selinux_load_state *load_state)
{ struct selinux_state *state = &selinux_state; struct selinux_policy *newpolicy, *oldpolicy; struct selinux_policy_convert_data *convert_data; int rc = 0; struct policy_file file = { data, len }, *fp = &file;
newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL); if (!newpolicy) return -ENOMEM;
rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab); if (rc) {
pr_err("SELinux: unable to load the initial SIDs\n"); goto err_mapping;
}
if (!selinux_initialized()) { /* First policy load, so no need to preserve state from old policy */
load_state->policy = newpolicy;
load_state->convert_data = NULL; return 0;
}
/* Preserve active boolean values from the old policy */
rc = security_preserve_bools(oldpolicy, newpolicy); if (rc) {
pr_err("SELinux: unable to preserve booleans\n"); goto err_free_isids;
}
/* * Convert the internal representations of contexts * in the new SID table.
*/
rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params); if (rc) {
pr_err("SELinux: unable to convert the internal" " representation of contexts in the new SID" " table\n"); goto err_free_convert_data;
}
/** * ocontext_to_sid - Helper to safely get sid for an ocontext * @sidtab: SID table * @c: ocontext structure * @index: index of the context entry (0 or 1) * @out_sid: pointer to the resulting SID value * * For all ocontexts except OCON_ISID the SID fields are populated * on-demand when needed. Since updating the SID value is an SMP-sensitive * operation, this helper must be used to do that safely. * * WARNING: This function may return -ESTALE, indicating that the caller * must retry the operation after re-acquiring the policy pointer!
*/ staticint ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
size_t index, u32 *out_sid)
{ int rc;
u32 sid;
/* Ensure the associated sidtab entry is visible to this thread. */
sid = smp_load_acquire(&c->sid[index]); if (!sid) {
rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid); if (rc) return rc;
/* * Ensure the new sidtab entry is visible to other threads * when they see the SID.
*/
smp_store_release(&c->sid[index], sid);
}
*out_sid = sid; return 0;
}
/** * security_port_sid - Obtain the SID for a port. * @protocol: protocol number * @port: port number * @out_sid: security identifier
*/ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
{ struct selinux_policy *policy; struct policydb *policydb; struct sidtab *sidtab; struct ocontext *c; int rc;
if (!selinux_initialized()) {
*out_sid = SECINITSID_PORT; return 0;
}
c = policydb->ocontexts[OCON_PORT]; while (c) { if (c->u.port.protocol == protocol &&
c->u.port.low_port <= port &&
c->u.port.high_port >= port) break;
c = c->next;
}
if (c) {
rc = ocontext_to_sid(sidtab, c, 0, out_sid); if (rc == -ESTALE) {
rcu_read_unlock(); goto retry;
} if (rc) goto out;
} else {
*out_sid = SECINITSID_PORT;
}
out:
rcu_read_unlock(); return rc;
}
/** * security_ib_pkey_sid - Obtain the SID for a pkey. * @subnet_prefix: Subnet Prefix * @pkey_num: pkey number * @out_sid: security identifier
*/ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
{ struct selinux_policy *policy; struct policydb *policydb; struct sidtab *sidtab; struct ocontext *c; int rc;
if (!selinux_initialized()) {
*out_sid = SECINITSID_UNLABELED; return 0;
}
c = policydb->ocontexts[OCON_IBENDPORT]; while (c) { if (c->u.ibendport.port == port_num &&
!strncmp(c->u.ibendport.dev_name,
dev_name,
IB_DEVICE_NAME_MAX)) break;
c = c->next;
}
if (c) {
rc = ocontext_to_sid(sidtab, c, 0, out_sid); if (rc == -ESTALE) {
rcu_read_unlock(); goto retry;
} if (rc) goto out;
} else
*out_sid = SECINITSID_UNLABELED;
out:
rcu_read_unlock(); return rc;
}
/** * security_netif_sid - Obtain the SID for a network interface. * @name: interface name
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.