1 /* 2 * Copyright (C) 2008 IBM Corporation 3 * 4 * Authors: 5 * Mimi Zohar <zohar@us.ibm.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation, version 2 of the 10 * License. 11 * 12 * File: ima_iint.c 13 * - implements the IMA hooks: ima_inode_alloc, ima_inode_free 14 * - cache integrity information associated with an inode 15 * using a rbtree tree. 16 */ 17 #include <linux/slab.h> 18 #include <linux/module.h> 19 #include <linux/spinlock.h> 20 #include <linux/rbtree.h> 21 #include "ima.h" 22 23 static struct rb_root ima_iint_tree = RB_ROOT; 24 static DEFINE_SPINLOCK(ima_iint_lock); 25 static struct kmem_cache *iint_cache __read_mostly; 26 27 int iint_initialized = 0; 28 29 /* 30 * __ima_iint_find - return the iint associated with an inode 31 */ 32 static struct ima_iint_cache *__ima_iint_find(struct inode *inode) 33 { 34 struct ima_iint_cache *iint; 35 struct rb_node *n = ima_iint_tree.rb_node; 36 37 assert_spin_locked(&ima_iint_lock); 38 39 while (n) { 40 iint = rb_entry(n, struct ima_iint_cache, rb_node); 41 42 if (inode < iint->inode) 43 n = n->rb_left; 44 else if (inode > iint->inode) 45 n = n->rb_right; 46 else 47 break; 48 } 49 if (!n) 50 return NULL; 51 52 return iint; 53 } 54 55 /* 56 * ima_iint_find - return the iint associated with an inode 57 */ 58 struct ima_iint_cache *ima_iint_find(struct inode *inode) 59 { 60 struct ima_iint_cache *iint; 61 62 if (!IS_IMA(inode)) 63 return NULL; 64 65 spin_lock(&ima_iint_lock); 66 iint = __ima_iint_find(inode); 67 spin_unlock(&ima_iint_lock); 68 69 return iint; 70 } 71 72 static void iint_free(struct ima_iint_cache *iint) 73 { 74 iint->version = 0; 75 iint->flags = 0UL; 76 kmem_cache_free(iint_cache, iint); 77 } 78 79 /** 80 * ima_inode_alloc - allocate an iint associated with an inode 81 * @inode: pointer to the inode 82 */ 83 int ima_inode_alloc(struct inode *inode) 84 { 85 struct rb_node **p; 86 struct rb_node *new_node, *parent = NULL; 87 struct ima_iint_cache *new_iint, *test_iint; 88 int rc; 89 90 new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); 91 if (!new_iint) 92 return -ENOMEM; 93 94 new_iint->inode = inode; 95 new_node = &new_iint->rb_node; 96 97 mutex_lock(&inode->i_mutex); /* i_flags */ 98 spin_lock(&ima_iint_lock); 99 100 p = &ima_iint_tree.rb_node; 101 while (*p) { 102 parent = *p; 103 test_iint = rb_entry(parent, struct ima_iint_cache, rb_node); 104 105 rc = -EEXIST; 106 if (inode < test_iint->inode) 107 p = &(*p)->rb_left; 108 else if (inode > test_iint->inode) 109 p = &(*p)->rb_right; 110 else 111 goto out_err; 112 } 113 114 inode->i_flags |= S_IMA; 115 rb_link_node(new_node, parent, p); 116 rb_insert_color(new_node, &ima_iint_tree); 117 118 spin_unlock(&ima_iint_lock); 119 mutex_unlock(&inode->i_mutex); /* i_flags */ 120 121 return 0; 122 out_err: 123 spin_unlock(&ima_iint_lock); 124 mutex_unlock(&inode->i_mutex); /* i_flags */ 125 iint_free(new_iint); 126 127 return rc; 128 } 129 130 /** 131 * ima_inode_free - called on security_inode_free 132 * @inode: pointer to the inode 133 * 134 * Free the integrity information(iint) associated with an inode. 135 */ 136 void ima_inode_free(struct inode *inode) 137 { 138 struct ima_iint_cache *iint; 139 140 if (!IS_IMA(inode)) 141 return; 142 143 spin_lock(&ima_iint_lock); 144 iint = __ima_iint_find(inode); 145 rb_erase(&iint->rb_node, &ima_iint_tree); 146 spin_unlock(&ima_iint_lock); 147 148 iint_free(iint); 149 } 150 151 static void init_once(void *foo) 152 { 153 struct ima_iint_cache *iint = foo; 154 155 memset(iint, 0, sizeof *iint); 156 iint->version = 0; 157 iint->flags = 0UL; 158 mutex_init(&iint->mutex); 159 } 160 161 static int __init ima_iintcache_init(void) 162 { 163 iint_cache = 164 kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, 165 SLAB_PANIC, init_once); 166 iint_initialized = 1; 167 return 0; 168 } 169 security_initcall(ima_iintcache_init); 170