int add_rule(char *s, char *t, char *c, char *p, policydb_t *policy) { type_datum_t *src, *tgt; class_datum_t *cls; perm_datum_t *perm; avtab_datum_t *av; avtab_key_t key; src = hashtab_search(policy->p_types.table, s); if (src == NULL) { fprintf(stderr, "source type %s does not exist\n", s); return 2; } tgt = hashtab_search(policy->p_types.table, t); if (tgt == NULL) { fprintf(stderr, "target type %s does not exist\n", t); return 2; } cls = hashtab_search(policy->p_classes.table, c); if (cls == NULL) { fprintf(stderr, "class %s does not exist\n", c); return 2; } perm = hashtab_search(cls->permissions.table, p); if (perm == NULL) { if (cls->comdatum == NULL) { fprintf(stderr, "perm %s does not exist in class %s\n", p, c); return 2; } perm = hashtab_search(cls->comdatum->permissions.table, p); if (perm == NULL) { fprintf(stderr, "perm %s does not exist in class %s\n", p, c); return 2; } } // See if there is already a rule key.source_type = src->s.value; key.target_type = tgt->s.value; key.target_class = cls->s.value; key.specified = AVTAB_ALLOWED; av = avtab_search(&policy->te_avtab, &key); if (av == NULL) { int ret; av = cmalloc(sizeof av); av->data |= 1U << (perm->s.value - 1); ret = avtab_insert(&policy->te_avtab, &key, av); if (ret) { fprintf(stderr, "Error inserting into avtab\n"); return 1; } } av->data |= 1U << (perm->s.value - 1); return 0; }
static int security_compute_sid(u32 ssid, u32 tsid, u16 tclass, u32 specified, u32 *out_sid) { struct context *scontext = 0, *tcontext = 0, newcontext; struct role_trans *roletr = 0; struct avtab_key avkey; struct avtab_datum *avdatum; unsigned int type_change = 0; int rc = 0; if (!ss_initialized) { switch (tclass) { case SECCLASS_PROCESS: *out_sid = ssid; break; default: *out_sid = tsid; break; } goto out; } POLICY_RDLOCK; scontext = sidtab_search(&sidtab, ssid); if (!scontext) { printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", ssid); rc = -EINVAL; goto out_unlock; } tcontext = sidtab_search(&sidtab, tsid); if (!tcontext) { printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", tsid); rc = -EINVAL; goto out_unlock; } context_init(&newcontext); /* Set the user identity. */ switch (specified) { case AVTAB_TRANSITION: case AVTAB_CHANGE: /* 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 and type to default values. */ switch (tclass) { case SECCLASS_PROCESS: /* Use the current role and type of process. */ newcontext.role = scontext->role; newcontext.type = scontext->type; break; default: /* Use the well-defined object role. */ newcontext.role = OBJECT_R_VAL; /* Use the type of the related object. */ newcontext.type = tcontext->type; } /* Look for a type transition/member/change rule. */ avkey.source_type = scontext->type; avkey.target_type = tcontext->type; avkey.target_class = tclass; avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE); type_change = (avdatum && (avdatum->specified & specified)); if (type_change) { /* Use the type from the type transition/member/change rule. */ switch (specified) { case AVTAB_TRANSITION: newcontext.type = avtab_transition(avdatum); break; case AVTAB_MEMBER: newcontext.type = avtab_member(avdatum); break; case AVTAB_CHANGE: newcontext.type = avtab_change(avdatum); break; } } /* Check for class-specific changes. */ switch (tclass) { case SECCLASS_PROCESS: if (specified & AVTAB_TRANSITION) { /* Look for a role transition rule. */ for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { if (roletr->role == scontext->role && roletr->type == tcontext->type) { /* Use the role transition rule. */ newcontext.role = roletr->new_role; break; } } } if (!type_change && !roletr) { /* No change in process role or type. */ *out_sid = ssid; goto out_unlock; } break; default: if (!type_change && (newcontext.user == tcontext->user) && mls_context_cmp(scontext, tcontext)) { /* No change in object type, owner, or MLS attributes. */ *out_sid = tsid; goto out_unlock; } break; } /* Set the MLS attributes. This is done last because it may allocate memory. */ rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); if (rc) goto out_unlock; /* Check the validity of the context. */ if (!policydb_context_isvalid(&policydb, &newcontext)) { rc = compute_sid_handle_invalid_context(scontext, tcontext, tclass, &newcontext); if (rc) goto out_unlock; } /* Obtain the sid for the context. */ rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); out_unlock: POLICY_RDUNLOCK; context_destroy(&newcontext); out: return rc; }
// Based on public domain code from sepolicy-inject: // https://bitbucket.org/joshua_brindle/sepolicy-inject/ // See the following commit about the hashtab_key_t casts: // https://github.com/TresysTechnology/setools/commit/2994d1ca1da9e6f25f082c0dd1a49b5f958bd2ca bool selinux_add_rule(policydb_t *pdb, const std::string &source_str, const std::string &target_str, const std::string &class_str, const std::string &perm_str) { type_datum_t *source, *target; class_datum_t *clazz; perm_datum_t *perm; avtab_datum_t *av; avtab_key_t key; source = (type_datum_t *) hashtab_search( pdb->p_types.table, (hashtab_key_t) source_str.c_str()); if (!source) { LOGE("Source type %s does not exist", source_str.c_str()); return false; } target = (type_datum_t *) hashtab_search( pdb->p_types.table, (hashtab_key_t) target_str.c_str()); if (!target) { LOGE("Target type %s does not exist", target_str.c_str()); return false; } clazz = (class_datum_t *) hashtab_search( pdb->p_classes.table, (hashtab_key_t) class_str.c_str()); if (!clazz) { LOGE("Class %s does not exist", class_str.c_str()); return false; } perm = (perm_datum_t *) hashtab_search( clazz->permissions.table, (hashtab_key_t) perm_str.c_str()); if (!perm) { if (clazz->comdatum == nullptr) { LOGE("Perm %s does not exist in class %s", perm_str.c_str(), class_str.c_str()); return false; } perm = (perm_datum_t *) hashtab_search( clazz->comdatum->permissions.table, (hashtab_key_t) perm_str.c_str()); if (!perm) { LOGE("Perm %s does not exist in class %s", perm_str.c_str(), class_str.c_str()); return false; } } // See if there is already a rule key.source_type = source->s.value; key.target_type = target->s.value; key.target_class = clazz->s.value; key.specified = AVTAB_ALLOWED; av = avtab_search(&pdb->te_avtab, &key); bool exists = false; if (!av) { avtab_datum_t av_new; av_new.data = (1U << (perm->s.value - 1)); if (avtab_insert(&pdb->te_avtab, &key, &av_new) != 0) { LOGE("Failed to add rule to avtab"); return false; } } else { if (av->data & (1U << (perm->s.value - 1))) { exists = true; } av->data |= (1U << (perm->s.value - 1)); } if (exists) { LOGD("Rule already exists: \"allow %s %s:%s %s;\"", source_str.c_str(), target_str.c_str(), class_str.c_str(), perm_str.c_str()); } else { LOGD("Added rule: \"allow %s %s:%s %s;\"", source_str.c_str(), target_str.c_str(), class_str.c_str(), perm_str.c_str()); } return true; }
/* * Compute access vectors based on a context structure pair for * the permissions in a particular class. */ static int context_struct_compute_av(struct context *scontext, struct context *tcontext, u16 tclass, u32 requested, struct av_decision *avd) { struct constraint_node *constraint; struct role_allow *ra; struct avtab_key avkey; struct avtab_datum *avdatum; struct class_datum *tclass_datum; if (!tclass || tclass > policydb.p_classes.nprim) { printk(KERN_ERR "security_compute_av: unrecognized class %d\n", tclass); return -EINVAL; } tclass_datum = policydb.class_val_to_struct[tclass - 1]; /* * Initialize the access vectors to the default values. */ avd->allowed = 0; avd->decided = 0xffffffff; avd->auditallow = 0; avd->auditdeny = 0xffffffff; avd->seqno = latest_granting; /* * If a specific type enforcement rule was defined for * this permission check, then use it. */ avkey.source_type = scontext->type; avkey.target_type = tcontext->type; avkey.target_class = tclass; avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_AV); if (avdatum) { if (avdatum->specified & AVTAB_ALLOWED) avd->allowed = avtab_allowed(avdatum); if (avdatum->specified & AVTAB_AUDITDENY) avd->auditdeny = avtab_auditdeny(avdatum); if (avdatum->specified & AVTAB_AUDITALLOW) avd->auditallow = avtab_auditallow(avdatum); } /* * Remove any permissions prohibited by the MLS policy. */ mls_compute_av(scontext, tcontext, tclass_datum, &avd->allowed); /* * Remove any permissions prohibited by a constraint. */ constraint = tclass_datum->constraints; while (constraint) { if ((constraint->permissions & (avd->allowed)) && !constraint_expr_eval(scontext, tcontext, constraint->expr)) { avd->allowed = (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 == SECCLASS_PROCESS && avd->allowed && PROCESS__TRANSITION && 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 = (avd->allowed) & ~(PROCESS__TRANSITION); } return 0; }