cregit-Linux how code gets into the kernel

Release 4.11 security/selinux/ss/conditional.c

/* Authors: Karl MacMillan <kmacmillan@tresys.com>
 *          Frank Mayer <mayerf@tresys.com>
 *
 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, version 2.
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/slab.h>

#include "security.h"
#include "conditional.h"
#include "services.h"

/*
 * cond_evaluate_expr evaluates a conditional expr
 * in reverse polish notation. It returns true (1), false (0),
 * or undefined (-1). Undefined occurs when the expression
 * exceeds the stack depth of COND_EXPR_MAXDEPTH.
 */

static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr) { struct cond_expr *cur; int s[COND_EXPR_MAXDEPTH]; int sp = -1; for (cur = expr; cur; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: if (sp == (COND_EXPR_MAXDEPTH - 1)) return -1; sp++; s[sp] = p->bool_val_to_struct[cur->bool - 1]->state; break; case COND_NOT: if (sp < 0) return -1; s[sp] = !s[sp]; break; case COND_OR: if (sp < 1) return -1; sp--; s[sp] |= s[sp + 1]; break; case COND_AND: if (sp < 1) return -1; sp--; s[sp] &= s[sp + 1]; break; case COND_XOR: if (sp < 1) return -1; sp--; s[sp] ^= s[sp + 1]; break; case COND_EQ: if (sp < 1) return -1; sp--; s[sp] = (s[sp] == s[sp + 1]); break; case COND_NEQ: if (sp < 1) return -1; sp--; s[sp] = (s[sp] != s[sp + 1]); break; default: return -1; } } return s[0]; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton291100.00%1100.00%
Total291100.00%1100.00%

/* * evaluate_cond_node evaluates the conditional stored in * a struct cond_node and if the result is different than the * current state of the node it sets the rules in the true/false * list appropriately. If the result of the expression is undefined * all of the rules are disabled for safety. */
int evaluate_cond_node(struct policydb *p, struct cond_node *node) { int new_state; struct cond_av_list *cur; new_state = cond_evaluate_expr(p, node->expr); if (new_state != node->cur_state) { node->cur_state = new_state; if (new_state == -1) printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); /* turn the rules on or off */ for (cur = node->true_list; cur; cur = cur->next) { if (new_state <= 0) cur->node->key.specified &= ~AVTAB_ENABLED; else cur->node->key.specified |= AVTAB_ENABLED; } for (cur = node->false_list; cur; cur = cur->next) { /* -1 or 1 */ if (new_state) cur->node->key.specified &= ~AVTAB_ENABLED; else cur->node->key.specified |= AVTAB_ENABLED; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton15396.84%133.33%
Stephen D. Smalley42.53%133.33%
James Morris10.63%133.33%
Total158100.00%3100.00%


int cond_policydb_init(struct policydb *p) { int rc; p->bool_val_to_struct = NULL; p->cond_list = NULL; rc = avtab_init(&p->te_cond_avtab); if (rc) return rc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton3577.78%150.00%
Dan Carpenter1022.22%150.00%
Total45100.00%2100.00%


static void cond_av_list_destroy(struct cond_av_list *list) { struct cond_av_list *cur, *next; for (cur = list; cur; cur = next) { next = cur->next; /* the avtab_ptr_t node is destroy by the avtab */ kfree(cur); } }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton45100.00%1100.00%
Total45100.00%1100.00%


static void cond_node_destroy(struct cond_node *node) { struct cond_expr *cur_expr, *next_expr; for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) { next_expr = cur_expr->next; kfree(cur_expr); } cond_av_list_destroy(node->true_list); cond_av_list_destroy(node->false_list); kfree(node); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton65100.00%1100.00%
Total65100.00%1100.00%


static void cond_list_destroy(struct cond_node *list) { struct cond_node *next, *cur; if (list == NULL) return; for (cur = list; cur; cur = next) { next = cur->next; cond_node_destroy(cur); } }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton51100.00%1100.00%
Total51100.00%1100.00%


void cond_policydb_destroy(struct policydb *p) { kfree(p->bool_val_to_struct); avtab_destroy(&p->te_cond_avtab); cond_list_destroy(p->cond_list); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton32100.00%1100.00%
Total32100.00%1100.00%


int cond_init_bool_indexes(struct policydb *p) { kfree(p->bool_val_to_struct); p->bool_val_to_struct = kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); if (!p->bool_val_to_struct) return -ENOMEM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton5298.11%150.00%
Davidlohr Bueso A11.89%150.00%
Total53100.00%2100.00%


int cond_destroy_bool(void *key, void *datum, void *p) { kfree(key); kfree(datum); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton30100.00%1100.00%
Total30100.00%1100.00%


int cond_index_bool(void *key, void *datum, void *datap) { struct policydb *p; struct cond_bool_datum *booldatum; struct flex_array *fa; booldatum = datum; p = datap; if (!booldatum->value || booldatum->value > p->p_bools.nprim) return -EINVAL; fa = p->sym_val_to_name[SYM_BOOLS]; if (flex_array_put_ptr(fa, booldatum->value - 1, key, GFP_KERNEL | __GFP_ZERO)) BUG(); p->bool_val_to_struct[booldatum->value - 1] = booldatum; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton8275.93%150.00%
Eric Paris2624.07%150.00%
Total108100.00%2100.00%


static int bool_isvalid(struct cond_bool_datum *b) { if (!(b->state == 0 || b->state == 1)) return 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton3397.06%150.00%
Stephen D. Smalley12.94%150.00%
Total34100.00%2100.00%


int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp) { char *key = NULL; struct cond_bool_datum *booldatum; __le32 buf[3]; u32 len; int rc; booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL); if (!booldatum) return -ENOMEM; rc = next_entry(buf, fp, sizeof buf); if (rc) goto err; booldatum->value = le32_to_cpu(buf[0]); booldatum->state = le32_to_cpu(buf[1]); rc = -EINVAL; if (!bool_isvalid(booldatum)) goto err; len = le32_to_cpu(buf[2]); if (((len == 0) || (len == (u32)-1))) goto err; rc = -ENOMEM; key = kmalloc(len + 1, GFP_KERNEL); if (!key) goto err; rc = next_entry(key, fp, len); if (rc) goto err; key[len] = '\0'; rc = hashtab_insert(h, key, booldatum); if (rc) goto err; return 0; err: cond_destroy_bool(key, booldatum, NULL); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton17070.83%112.50%
William Roberts239.58%112.50%
Stephen D. Smalley229.17%112.50%
Dan Carpenter187.50%112.50%
Alexey Dobriyan31.25%112.50%
Chris Wright20.83%112.50%
James Morris10.42%112.50%
Vesa-Matti J Kari10.42%112.50%
Total240100.00%8100.00%

struct cond_insertf_data { struct policydb *p; struct cond_av_list *other; struct cond_av_list *head; struct cond_av_list *tail; };
static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr) { struct cond_insertf_data *data = ptr; struct policydb *p = data->p; struct cond_av_list *other = data->other, *list, *cur; struct avtab_node *node_ptr; u8 found; int rc = -EINVAL; /* * For type rules we have to make certain there aren't any * conflicting rules by searching the te_avtab and the * cond_te_avtab. */ if (k->specified & AVTAB_TYPE) { if (avtab_search(&p->te_avtab, k)) { printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n"); goto err; } /* * If we are reading the false list other will be a pointer to * the true list. We can have duplicate entries if there is only * 1 other entry and it is in our true list. * * If we are reading the true list (other == NULL) there shouldn't * be any other entries. */ if (other) { node_ptr = avtab_search_node(&p->te_cond_avtab, k); if (node_ptr) { if (avtab_search_node_next(node_ptr, k->specified)) { printk(KERN_ERR "SELinux: too many conflicting type rules.\n"); goto err; } found = 0; for (cur = other; cur; cur = cur->next) { if (cur->node == node_ptr) { found = 1; break; } } if (!found) { printk(KERN_ERR "SELinux: conflicting type rules.\n"); goto err; } } } else { if (avtab_search(&p->te_cond_avtab, k)) { printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n"); goto err; } } } node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); if (!node_ptr) { printk(KERN_ERR "SELinux: could not insert rule.\n"); rc = -ENOMEM; goto err; } list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL); if (!list) { rc = -ENOMEM; goto err; } list->node = node_ptr; if (!data->head) data->head = list; else data->tail->next = list; data->tail = list; return 0; err: cond_av_list_destroy(data->head); data->head = NULL; return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton24671.10%114.29%
Stephen D. Smalley7020.23%228.57%
Dan Carpenter195.49%114.29%
Eric Paris82.31%114.29%
James Morris30.87%228.57%
Total346100.00%7100.00%


static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other) { int i, rc; __le32 buf[1]; u32 len; struct cond_insertf_data data; *ret_list = NULL; len = 0; rc = next_entry(buf, fp, sizeof(u32)); if (rc) return rc; len = le32_to_cpu(buf[0]); if (len == 0) return 0; data.p = p; data.other = other; data.head = NULL; data.tail = NULL; for (i = 0; i < len; i++) { rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf, &data); if (rc) return rc; } *ret_list = data.head; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen D. Smalley15692.86%240.00%
Andrew Morton84.76%120.00%
Alexey Dobriyan31.79%120.00%
Dan Carpenter10.60%120.00%
Total168100.00%5100.00%


static int expr_isvalid(struct policydb *p, struct cond_expr *expr) { if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n"); return 0; } if (expr->bool > p->p_bools.nprim) { printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n"); return 0; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton6394.03%133.33%
James Morris22.99%133.33%
Eric Paris22.99%133.33%
Total67100.00%3100.00%


static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) { __le32 buf[2]; u32 len, i; int rc; struct cond_expr *expr = NULL, *last = NULL; rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) goto err; node->cur_state = le32_to_cpu(buf[0]); /* expr */ len = le32_to_cpu(buf[1]); for (i = 0; i < len; i++) { rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) goto err; rc = -ENOMEM; expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL); if (!expr) goto err; expr->expr_type = le32_to_cpu(buf[0]); expr->bool = le32_to_cpu(buf[1]); if (!expr_isvalid(p, expr)) { rc = -EINVAL; kfree(expr); goto err; } if (i == 0) node->expr = expr; else last->next = expr; last = expr; } rc = cond_read_av_list(p, fp, &node->true_list, NULL); if (rc) goto err; rc = cond_read_av_list(p, fp, &node->false_list, node->true_list); if (rc) goto err; return 0; err: cond_node_destroy(node); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton23380.62%112.50%
Dan Carpenter237.96%112.50%
Stephen D. Smalley165.54%112.50%
Alexander Nyberg72.42%112.50%
Namhyung Kim62.08%225.00%
Alexey Dobriyan31.04%112.50%
James Morris10.35%112.50%
Total289100.00%8100.00%


int cond_read_list(struct policydb *p, void *fp) { struct cond_node *node, *last = NULL; __le32 buf[1]; u32 i, len; int rc; rc = next_entry(buf, fp, sizeof buf); if (rc) return rc; len = le32_to_cpu(buf[0]); rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel); if (rc) goto err; for (i = 0; i < len; i++) { rc = -ENOMEM; node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); if (!node) goto err; rc = cond_read_node(p, node, fp); if (rc) goto err; if (i == 0) p->cond_list = node; else last->next = node; last = node; } return 0; err: cond_list_destroy(p->cond_list); p->cond_list = NULL; return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton13669.74%114.29%
Yuichi Nakamura2512.82%114.29%
Stephen D. Smalley178.72%228.57%
Dan Carpenter136.67%114.29%
Alexey Dobriyan31.54%114.29%
James Morris10.51%114.29%
Total195100.00%7100.00%


int cond_write_bool(void *vkey, void *datum, void *ptr) { char *key = vkey; struct cond_bool_datum *booldatum = datum; struct policy_data *pd = ptr; void *fp = pd->fp; __le32 buf[3]; u32 len; int rc; len = strlen(key); buf[0] = cpu_to_le32(booldatum->value); buf[1] = cpu_to_le32(booldatum->state); buf[2] = cpu_to_le32(len); rc = put_entry(buf, sizeof(u32), 3, fp); if (rc) return rc; rc = put_entry(key, 1, len, fp); if (rc) return rc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Paris144100.00%1100.00%
Total144100.00%1100.00%

/* * cond_write_cond_av_list doesn't write out the av_list nodes. * Instead it writes out the key/value pairs from the avtab. This * is necessary because there is no way to uniquely identifying rules * in the avtab so it is not possible to associate individual rules * in the avtab with a conditional without saving them as part of * the conditional. This means that the avtab with the conditional * rules will not be saved but will be rebuilt on policy load. */
static int cond_write_av_list(struct policydb *p, struct cond_av_list *list, struct policy_file *fp) { __le32 buf[1]; struct cond_av_list *cur_list; u32 len; int rc; len = 0; for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) len++; buf[0] = cpu_to_le32(len); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) return rc; if (len == 0) return 0; for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { rc = avtab_write_item(p, cur_list->node, fp); if (rc) return rc; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Paris144100.00%1100.00%
Total144100.00%1100.00%


static int cond_write_node(struct policydb *p, struct cond_node *node, struct policy_file *fp) { struct cond_expr *cur_expr; __le32 buf[2]; int rc; u32 len = 0; buf[0] = cpu_to_le32(node->cur_state); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) return rc; for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) len++; buf[0] = cpu_to_le32(len); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) return rc; for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) { buf[0] = cpu_to_le32(cur_expr->expr_type); buf[1] = cpu_to_le32(cur_expr->bool); rc = put_entry(buf, sizeof(u32), 2, fp); if (rc) return rc; } rc = cond_write_av_list(p, node->true_list, fp); if (rc) return rc; rc = cond_write_av_list(p, node->false_list, fp); if (rc) return rc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Paris23899.58%150.00%
James Morris10.42%150.00%
Total239100.00%2100.00%


int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) { struct cond_node *cur; u32 len; __le32 buf[1]; int rc; len = 0; for (cur = list; cur != NULL; cur = cur->next) len++; buf[0] = cpu_to_le32(len); rc = put_entry(buf, sizeof(u32), 1, fp); if (rc) return rc; for (cur = list; cur != NULL; cur = cur->next) { rc = cond_write_node(p, cur, fp); if (rc) return rc; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Paris131100.00%1100.00%
Total131100.00%1100.00%


void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, struct extended_perms_decision *xpermd) { struct avtab_node *node; if (!ctab || !key || !xpermd) return; for (node = avtab_search_node(ctab, key); node; node = avtab_search_node_next(node, key->specified)) { if (node->key.specified & AVTAB_ENABLED) services_compute_xperms_decision(xpermd, node); } return; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Vander Stoep81100.00%1100.00%
Total81100.00%1100.00%

/* Determine whether additional permissions are granted by the conditional * av table, and if so, add them to the result */
void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd, struct extended_perms *xperms) { struct avtab_node *node; if (!ctab || !key || !avd) return; for (node = avtab_search_node(ctab, key); node; node = avtab_search_node_next(node, key->specified)) { if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) avd->allowed |= node->datum.u.data; if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) /* Since a '0' in an auditdeny mask represents a * permission we do NOT want to audit (dontaudit), we use * the '&' operand to ensure that all '0's in the mask * are retained (much unlike the allow and auditallow cases). */ avd->auditdeny &= node->datum.u.data; if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) avd->auditallow |= node->datum.u.data; if (xperms && (node->key.specified & AVTAB_ENABLED) && (node->key.specified & AVTAB_XPERMS)) services_compute_xperms_drivers(xperms, node); } return; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton15573.11%125.00%
Jeff Vander Stoep4018.87%125.00%
Stephen D. Smalley178.02%250.00%
Total212100.00%4100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton190459.09%13.57%
Eric Paris69521.57%414.29%
Stephen D. Smalley32810.18%517.86%
Jeff Vander Stoep1243.85%13.57%
Dan Carpenter842.61%517.86%
Yuichi Nakamura250.78%13.57%
William Roberts230.71%13.57%
Alexey Dobriyan120.37%13.57%
James Morris100.31%310.71%
Alexander Nyberg70.22%13.57%
Namhyung Kim60.19%27.14%
Chris Wright20.06%13.57%
Davidlohr Bueso A10.03%13.57%
Vesa-Matti J Kari10.03%13.57%
Total3222100.00%28100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.