LCOV - code coverage report
Current view: top level - security/selinux/ss - sidtab.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 132 0.0 %
Date: 2014-02-18 Functions: 0 12 0.0 %
Branches: 0 110 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Implementation of the SID table type.
       3                 :            :  *
       4                 :            :  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
       5                 :            :  */
       6                 :            : #include <linux/kernel.h>
       7                 :            : #include <linux/slab.h>
       8                 :            : #include <linux/spinlock.h>
       9                 :            : #include <linux/errno.h>
      10                 :            : #include "flask.h"
      11                 :            : #include "security.h"
      12                 :            : #include "sidtab.h"
      13                 :            : 
      14                 :            : #define SIDTAB_HASH(sid) \
      15                 :            : (sid & SIDTAB_HASH_MASK)
      16                 :            : 
      17                 :          0 : int sidtab_init(struct sidtab *s)
      18                 :            : {
      19                 :            :         int i;
      20                 :            : 
      21                 :          0 :         s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
      22         [ #  # ]:          0 :         if (!s->htable)
      23                 :            :                 return -ENOMEM;
      24         [ #  # ]:          0 :         for (i = 0; i < SIDTAB_SIZE; i++)
      25                 :          0 :                 s->htable[i] = NULL;
      26                 :          0 :         s->nel = 0;
      27                 :          0 :         s->next_sid = 1;
      28                 :          0 :         s->shutdown = 0;
      29                 :          0 :         spin_lock_init(&s->lock);
      30                 :          0 :         return 0;
      31                 :            : }
      32                 :            : 
      33                 :          0 : int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
      34                 :            : {
      35                 :            :         int hvalue, rc = 0;
      36                 :            :         struct sidtab_node *prev, *cur, *newnode;
      37                 :            : 
      38         [ #  # ]:          0 :         if (!s) {
      39                 :            :                 rc = -ENOMEM;
      40                 :            :                 goto out;
      41                 :            :         }
      42                 :            : 
      43                 :          0 :         hvalue = SIDTAB_HASH(sid);
      44                 :            :         prev = NULL;
      45                 :          0 :         cur = s->htable[hvalue];
      46 [ #  # ][ #  # ]:          0 :         while (cur && sid > cur->sid) {
      47                 :            :                 prev = cur;
      48                 :          0 :                 cur = cur->next;
      49                 :            :         }
      50                 :            : 
      51 [ #  # ][ #  # ]:          0 :         if (cur && sid == cur->sid) {
      52                 :            :                 rc = -EEXIST;
      53                 :            :                 goto out;
      54                 :            :         }
      55                 :            : 
      56                 :            :         newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
      57         [ #  # ]:          0 :         if (newnode == NULL) {
      58                 :            :                 rc = -ENOMEM;
      59                 :            :                 goto out;
      60                 :            :         }
      61                 :          0 :         newnode->sid = sid;
      62         [ #  # ]:          0 :         if (context_cpy(&newnode->context, context)) {
      63                 :          0 :                 kfree(newnode);
      64                 :            :                 rc = -ENOMEM;
      65                 :          0 :                 goto out;
      66                 :            :         }
      67                 :            : 
      68         [ #  # ]:          0 :         if (prev) {
      69                 :          0 :                 newnode->next = prev->next;
      70                 :          0 :                 wmb();
      71                 :          0 :                 prev->next = newnode;
      72                 :            :         } else {
      73                 :          0 :                 newnode->next = s->htable[hvalue];
      74                 :          0 :                 wmb();
      75                 :          0 :                 s->htable[hvalue] = newnode;
      76                 :            :         }
      77                 :            : 
      78                 :          0 :         s->nel++;
      79         [ #  # ]:          0 :         if (sid >= s->next_sid)
      80                 :          0 :                 s->next_sid = sid + 1;
      81                 :            : out:
      82                 :          0 :         return rc;
      83                 :            : }
      84                 :            : 
      85                 :          0 : static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
      86                 :            : {
      87                 :            :         int hvalue;
      88                 :            :         struct sidtab_node *cur;
      89                 :            : 
      90         [ #  # ]:          0 :         if (!s)
      91                 :            :                 return NULL;
      92                 :            : 
      93                 :          0 :         hvalue = SIDTAB_HASH(sid);
      94                 :          0 :         cur = s->htable[hvalue];
      95 [ #  # ][ #  # ]:          0 :         while (cur && sid > cur->sid)
      96                 :          0 :                 cur = cur->next;
      97                 :            : 
      98 [ #  # ][ #  # ]:          0 :         if (force && cur && sid == cur->sid && cur->context.len)
                 [ #  # ]
      99                 :          0 :                 return &cur->context;
     100                 :            : 
     101 [ #  # ][ #  # ]:          0 :         if (cur == NULL || sid != cur->sid || cur->context.len) {
                 [ #  # ]
     102                 :            :                 /* Remap invalid SIDs to the unlabeled SID. */
     103                 :            :                 sid = SECINITSID_UNLABELED;
     104                 :            :                 hvalue = SIDTAB_HASH(sid);
     105                 :          0 :                 cur = s->htable[hvalue];
     106 [ #  # ][ #  # ]:          0 :                 while (cur && sid > cur->sid)
     107                 :          0 :                         cur = cur->next;
     108 [ #  # ][ #  # ]:          0 :                 if (!cur || sid != cur->sid)
     109                 :            :                         return NULL;
     110                 :            :         }
     111                 :            : 
     112                 :          0 :         return &cur->context;
     113                 :            : }
     114                 :            : 
     115                 :          0 : struct context *sidtab_search(struct sidtab *s, u32 sid)
     116                 :            : {
     117                 :          0 :         return sidtab_search_core(s, sid, 0);
     118                 :            : }
     119                 :            : 
     120                 :          0 : struct context *sidtab_search_force(struct sidtab *s, u32 sid)
     121                 :            : {
     122                 :          0 :         return sidtab_search_core(s, sid, 1);
     123                 :            : }
     124                 :            : 
     125                 :          0 : int sidtab_map(struct sidtab *s,
     126                 :            :                int (*apply) (u32 sid,
     127                 :            :                              struct context *context,
     128                 :            :                              void *args),
     129                 :            :                void *args)
     130                 :            : {
     131                 :            :         int i, rc = 0;
     132                 :            :         struct sidtab_node *cur;
     133                 :            : 
     134         [ #  # ]:          0 :         if (!s)
     135                 :            :                 goto out;
     136                 :            : 
     137         [ #  # ]:          0 :         for (i = 0; i < SIDTAB_SIZE; i++) {
     138                 :          0 :                 cur = s->htable[i];
     139         [ #  # ]:          0 :                 while (cur) {
     140                 :          0 :                         rc = apply(cur->sid, &cur->context, args);
     141         [ #  # ]:          0 :                         if (rc)
     142                 :            :                                 goto out;
     143                 :          0 :                         cur = cur->next;
     144                 :            :                 }
     145                 :            :         }
     146                 :            : out:
     147                 :          0 :         return rc;
     148                 :            : }
     149                 :            : 
     150                 :          0 : static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc)
     151                 :            : {
     152         [ #  # ]:          0 :         BUG_ON(loc >= SIDTAB_CACHE_LEN);
     153                 :            : 
     154         [ #  # ]:          0 :         while (loc > 0) {
     155                 :          0 :                 s->cache[loc] = s->cache[loc - 1];
     156                 :            :                 loc--;
     157                 :            :         }
     158                 :          0 :         s->cache[0] = n;
     159                 :          0 : }
     160                 :            : 
     161                 :            : static inline u32 sidtab_search_context(struct sidtab *s,
     162                 :            :                                                   struct context *context)
     163                 :            : {
     164                 :            :         int i;
     165                 :            :         struct sidtab_node *cur;
     166                 :            : 
     167 [ #  # ][ #  # ]:          0 :         for (i = 0; i < SIDTAB_SIZE; i++) {
     168                 :          0 :                 cur = s->htable[i];
     169 [ #  # ][ #  # ]:          0 :                 while (cur) {
     170 [ #  # ][ #  # ]:          0 :                         if (context_cmp(&cur->context, context)) {
     171                 :          0 :                                 sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);
     172                 :          0 :                                 return cur->sid;
     173                 :            :                         }
     174                 :          0 :                         cur = cur->next;
     175                 :            :                 }
     176                 :            :         }
     177                 :            :         return 0;
     178                 :            : }
     179                 :            : 
     180                 :            : static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context)
     181                 :            : {
     182                 :            :         int i;
     183                 :            :         struct sidtab_node *node;
     184                 :            : 
     185         [ #  # ]:          0 :         for (i = 0; i < SIDTAB_CACHE_LEN; i++) {
     186                 :          0 :                 node = s->cache[i];
     187         [ #  # ]:          0 :                 if (unlikely(!node))
     188                 :            :                         return 0;
     189         [ #  # ]:          0 :                 if (context_cmp(&node->context, context)) {
     190                 :          0 :                         sidtab_update_cache(s, node, i);
     191                 :          0 :                         return node->sid;
     192                 :            :                 }
     193                 :            :         }
     194                 :            :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :          0 : int sidtab_context_to_sid(struct sidtab *s,
     198                 :            :                           struct context *context,
     199                 :            :                           u32 *out_sid)
     200                 :            : {
     201                 :            :         u32 sid;
     202                 :            :         int ret = 0;
     203                 :            :         unsigned long flags;
     204                 :            : 
     205                 :          0 :         *out_sid = SECSID_NULL;
     206                 :            : 
     207                 :            :         sid  = sidtab_search_cache(s, context);
     208         [ #  # ]:          0 :         if (!sid)
     209                 :            :                 sid = sidtab_search_context(s, context);
     210         [ #  # ]:          0 :         if (!sid) {
     211                 :          0 :                 spin_lock_irqsave(&s->lock, flags);
     212                 :            :                 /* Rescan now that we hold the lock. */
     213                 :            :                 sid = sidtab_search_context(s, context);
     214         [ #  # ]:          0 :                 if (sid)
     215                 :            :                         goto unlock_out;
     216                 :            :                 /* No SID exists for the context.  Allocate a new one. */
     217 [ #  # ][ #  # ]:          0 :                 if (s->next_sid == UINT_MAX || s->shutdown) {
     218                 :            :                         ret = -ENOMEM;
     219                 :            :                         goto unlock_out;
     220                 :            :                 }
     221                 :          0 :                 sid = s->next_sid++;
     222         [ #  # ]:          0 :                 if (context->len)
     223                 :          0 :                         printk(KERN_INFO
     224                 :            :                        "SELinux:  Context %s is not valid (left unmapped).\n",
     225                 :            :                                context->str);
     226                 :          0 :                 ret = sidtab_insert(s, sid, context);
     227         [ #  # ]:          0 :                 if (ret)
     228                 :          0 :                         s->next_sid--;
     229                 :            : unlock_out:
     230                 :            :                 spin_unlock_irqrestore(&s->lock, flags);
     231                 :            :         }
     232                 :            : 
     233         [ #  # ]:          0 :         if (ret)
     234                 :            :                 return ret;
     235                 :            : 
     236                 :          0 :         *out_sid = sid;
     237                 :          0 :         return 0;
     238                 :            : }
     239                 :            : 
     240                 :          0 : void sidtab_hash_eval(struct sidtab *h, char *tag)
     241                 :            : {
     242                 :            :         int i, chain_len, slots_used, max_chain_len;
     243                 :            :         struct sidtab_node *cur;
     244                 :            : 
     245                 :            :         slots_used = 0;
     246                 :            :         max_chain_len = 0;
     247         [ #  # ]:          0 :         for (i = 0; i < SIDTAB_SIZE; i++) {
     248                 :          0 :                 cur = h->htable[i];
     249         [ #  # ]:          0 :                 if (cur) {
     250                 :          0 :                         slots_used++;
     251                 :            :                         chain_len = 0;
     252         [ #  # ]:          0 :                         while (cur) {
     253                 :          0 :                                 chain_len++;
     254                 :          0 :                                 cur = cur->next;
     255                 :            :                         }
     256                 :            : 
     257         [ #  # ]:          0 :                         if (chain_len > max_chain_len)
     258                 :            :                                 max_chain_len = chain_len;
     259                 :            :                 }
     260                 :            :         }
     261                 :            : 
     262                 :          0 :         printk(KERN_DEBUG "%s:  %d entries and %d/%d buckets used, longest "
     263                 :            :                "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
     264                 :            :                max_chain_len);
     265                 :          0 : }
     266                 :            : 
     267                 :          0 : void sidtab_destroy(struct sidtab *s)
     268                 :            : {
     269                 :            :         int i;
     270                 :            :         struct sidtab_node *cur, *temp;
     271                 :            : 
     272         [ #  # ]:          0 :         if (!s)
     273                 :          0 :                 return;
     274                 :            : 
     275         [ #  # ]:          0 :         for (i = 0; i < SIDTAB_SIZE; i++) {
     276                 :          0 :                 cur = s->htable[i];
     277         [ #  # ]:          0 :                 while (cur) {
     278                 :            :                         temp = cur;
     279                 :          0 :                         cur = cur->next;
     280                 :            :                         context_destroy(&temp->context);
     281                 :          0 :                         kfree(temp);
     282                 :            :                 }
     283                 :          0 :                 s->htable[i] = NULL;
     284                 :            :         }
     285                 :          0 :         kfree(s->htable);
     286                 :          0 :         s->htable = NULL;
     287                 :          0 :         s->nel = 0;
     288                 :          0 :         s->next_sid = 1;
     289                 :            : }
     290                 :            : 
     291                 :          0 : void sidtab_set(struct sidtab *dst, struct sidtab *src)
     292                 :            : {
     293                 :            :         unsigned long flags;
     294                 :            :         int i;
     295                 :            : 
     296                 :          0 :         spin_lock_irqsave(&src->lock, flags);
     297                 :          0 :         dst->htable = src->htable;
     298                 :          0 :         dst->nel = src->nel;
     299                 :          0 :         dst->next_sid = src->next_sid;
     300                 :          0 :         dst->shutdown = 0;
     301         [ #  # ]:          0 :         for (i = 0; i < SIDTAB_CACHE_LEN; i++)
     302                 :          0 :                 dst->cache[i] = NULL;
     303                 :            :         spin_unlock_irqrestore(&src->lock, flags);
     304                 :          0 : }
     305                 :            : 
     306                 :          0 : void sidtab_shutdown(struct sidtab *s)
     307                 :            : {
     308                 :            :         unsigned long flags;
     309                 :            : 
     310                 :          0 :         spin_lock_irqsave(&s->lock, flags);
     311                 :          0 :         s->shutdown = 1;
     312                 :            :         spin_unlock_irqrestore(&s->lock, flags);
     313                 :          0 : }

Generated by: LCOV version 1.9