/* * using a linked list for extended_perms_decision lookup because the list is * always small. i.e. less than 5, typically 1
*/ staticstruct extended_perms_decision *
avc_xperms_decision_lookup(u8 driver, u8 base_perm, struct avc_xperms_node *xp_node)
{ struct avc_xperms_decision_node *xpd_node;
/* * similar to avc_copy_xperms_decision, but only copy decision * information relevant to this perm
*/ staticinlinevoid avc_quick_copy_xperms_decision(u8 perm, struct extended_perms_decision *dest, struct extended_perms_decision *src)
{ /* * compute index of the u32 of the 256 bits (8 u32s) that contain this * command permission
*/
u8 i = perm >> 5;
dest->base_perm = src->base_perm;
dest->used = src->used; if (dest->used & XPERMS_ALLOWED)
dest->allowed->p[i] = src->allowed->p[i]; if (dest->used & XPERMS_AUDITALLOW)
dest->auditallow->p[i] = src->auditallow->p[i]; if (dest->used & XPERMS_DONTAUDIT)
dest->dontaudit->p[i] = src->dontaudit->p[i];
}
/** * avc_lookup - Look up an AVC entry. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * * Look up an AVC entry that is valid for the * (@ssid, @tsid), interpreting the permissions * based on @tclass. If a valid AVC entry exists, * then this function returns the avc_node. * Otherwise, this function returns NULL.
*/ staticstruct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
{ struct avc_node *node;
staticint avc_latest_notif_update(u32 seqno, int is_insert)
{ int ret = 0; static DEFINE_SPINLOCK(notif_lock); unsignedlong flag;
spin_lock_irqsave(¬if_lock, flag); if (is_insert) { if (seqno < selinux_avc.avc_cache.latest_notif) {
pr_warn("SELinux: avc: seqno %d < latest_notif %d\n",
seqno, selinux_avc.avc_cache.latest_notif);
ret = -EAGAIN;
}
} else { if (seqno > selinux_avc.avc_cache.latest_notif)
selinux_avc.avc_cache.latest_notif = seqno;
}
spin_unlock_irqrestore(¬if_lock, flag);
return ret;
}
/** * avc_insert - Insert an AVC entry. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @avd: resulting av decision * @xp_node: resulting extended permissions * * Insert an AVC entry for the SID pair * (@ssid, @tsid) and class @tclass. * The access vectors and the sequence number are * normally provided by the security server in * response to a security_compute_av() call. If the * sequence number @avd->seqno is not less than the latest * revocation notification, then the function copies * the access vectors into a cache entry.
*/ staticvoid avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_xperms_node *xp_node)
{ struct avc_node *pos, *node = NULL;
u32 hvalue; unsignedlong flag;
spinlock_t *lock; struct hlist_head *head;
if (avc_latest_notif_update(avd->seqno, 1)) return;
/* in case of invalid context report also the actual context string */
rc = security_sid_to_context_inval(sad->ssid, &scontext,
&scontext_len); if (!rc && scontext) { if (scontext_len && scontext[scontext_len - 1] == '\0')
scontext_len--;
audit_log_format(ab, " srawcon=");
audit_log_n_untrustedstring(ab, scontext, scontext_len);
kfree(scontext);
}
/* * This is the slow part of avc audit with big stack footprint. * Note that it is non-blocking and can be called from under * rcu_read_lock().
*/
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a)
{ struct common_audit_data stack_data; struct selinux_audit_data sad;
if (WARN_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map))) return -EINVAL;
if (!a) {
a = &stack_data;
a->type = LSM_AUDIT_DATA_NONE;
}
/** * avc_add_callback - Register a callback for security events. * @callback: callback function * @events: security events * * Register a callback function for events in the set @events. * Returns %0 on success or -%ENOMEM if insufficient memory * exists to add the callback.
*/ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
{ struct avc_callback_node *c; int rc = 0;
c = kmalloc(sizeof(*c), GFP_KERNEL); if (!c) {
rc = -ENOMEM; goto out;
}
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
head = &selinux_avc.avc_cache.slots[i];
lock = &selinux_avc.avc_cache.slots_lock[i];
spin_lock_irqsave(lock, flag); /* * With preemptible RCU, the outer spinlock does not * prevent RCU grace periods from ending.
*/
rcu_read_lock();
hlist_for_each_entry(node, head, list)
avc_node_delete(node);
rcu_read_unlock();
spin_unlock_irqrestore(lock, flag);
}
}
/** * avc_ss_reset - Flush the cache and revalidate migrated permissions. * @seqno: policy sequence number
*/ int avc_ss_reset(u32 seqno)
{ struct avc_callback_node *c; int rc = 0, tmprc;
avc_flush();
for (c = avc_callbacks; c; c = c->next) { if (c->events & AVC_CALLBACK_RESET) {
tmprc = c->callback(AVC_CALLBACK_RESET); /* save the first error encountered for the return
value and continue processing the callbacks */ if (!rc)
rc = tmprc;
}
}
avc_latest_notif_update(seqno, 0); return rc;
}
/** * avc_compute_av - Add an entry to the AVC based on the security policy * @ssid: subject * @tsid: object/target * @tclass: object class * @avd: access vector decision * @xp_node: AVC extended permissions node * * Slow-path helper function for avc_has_perm_noaudit, when the avc_node lookup * fails. Don't inline this, since it's the slow-path and just results in a * bigger stack frame.
*/ static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_xperms_node *xp_node)
{
INIT_LIST_HEAD(&xp_node->xpd_head);
security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp);
avc_insert(ssid, tsid, tclass, avd, xp_node);
}
/* * The avc extended permissions logic adds an additional 256 bits of * permissions to an avc node when extended permissions for that node are * specified in the avtab. If the additional 256 permissions is not adequate, * as-is the case with ioctls, then multiple may be chained together and the * driver field is used to specify which set contains the permission.
*/ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
u8 driver, u8 base_perm, u8 xperm, struct common_audit_data *ad)
{ struct avc_node *node; struct av_decision avd;
u32 denied; struct extended_perms_decision local_xpd; struct extended_perms_decision *xpd = NULL; struct extended_perms_data allowed; struct extended_perms_data auditallow; struct extended_perms_data dontaudit; struct avc_xperms_node local_xp_node; struct avc_xperms_node *xp_node; int rc = 0, rc2;
xp_node = &local_xp_node; if (WARN_ON(!requested)) return -EACCES;
rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) {
avc_compute_av(ssid, tsid, tclass, &avd, xp_node);
} else {
memcpy(&avd, &node->ae.avd, sizeof(avd));
xp_node = node->ae.xp_node;
} /* if extended permissions are not defined, only consider av_decision */ if (!xp_node || !xp_node->xp.len) goto decision;
/** * avc_perm_nonode - Add an entry to the AVC * @ssid: subject * @tsid: object/target * @tclass: object class * @requested: requested permissions * @flags: AVC flags * @avd: access vector decision * * This is the "we have no node" part of avc_has_perm_noaudit(), which is * unlikely and needs extra stack space for the new node that we generate, so * don't inline it.
*/ static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
u32 requested, unsignedint flags, struct av_decision *avd)
{
u32 denied; struct avc_xperms_node xp_node;
/** * avc_has_perm_noaudit - Check permissions but perform no auditing. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass * @flags: AVC_STRICT or 0 * @avd: access vector decisions * * Check the AVC to determine whether the @requested permissions are granted * for the SID pair (@ssid, @tsid), interpreting the permissions * based on @tclass, and call the security server on a cache miss to obtain * a new decision and add it to the cache. Return a copy of the decisions * in @avd. Return %0 if all @requested permissions are granted, * -%EACCES if any permissions are denied, or another -errno upon * other errors. This function is typically called by avc_has_perm(), * but may also be called directly to separate permission checking from * auditing, e.g. in cases where a lock must be held for the check but * should be released for the auditing.
*/ inlineint avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested, unsignedint flags, struct av_decision *avd)
{
u32 denied; struct avc_node *node;
/** * avc_has_perm - Check permissions and perform any appropriate auditing. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass * @auditdata: auxiliary audit data * * Check the AVC to determine whether the @requested permissions are granted * for the SID pair (@ssid, @tsid), interpreting the permissions * based on @tclass, and call the security server on a cache miss to obtain * a new decision and add it to the cache. Audit the granting or denial of * permissions in accordance with the policy. Return %0 if all @requested * permissions are granted, -%EACCES if any permissions are denied, or * another -errno upon other errors.
*/ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *auditdata)
{ struct av_decision avd; int rc, rc2;
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.