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 radix tree. 16 */ 17#include <linux/slab.h> 18#include <linux/module.h> 19#include <linux/spinlock.h> 20#include <linux/radix-tree.h> 21#include "ima.h" 22 23RADIX_TREE(ima_iint_store, GFP_ATOMIC); 24DEFINE_SPINLOCK(ima_iint_lock); 25static struct kmem_cache *iint_cache __read_mostly; 26 27int iint_initialized = 0; 28 29/* ima_iint_find_get - return the iint associated with an inode 30 * 31 * ima_iint_find_get gets a reference to the iint. Caller must 32 * remember to put the iint reference. 33 */ 34struct ima_iint_cache *ima_iint_find_get(struct inode *inode) 35{ 36 struct ima_iint_cache *iint; 37 38 rcu_read_lock(); 39 iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode); 40 if (!iint) 41 goto out; 42 kref_get(&iint->refcount); 43out: 44 rcu_read_unlock(); 45 return iint; 46} 47 48/** 49 * ima_inode_alloc - allocate an iint associated with an inode 50 * @inode: pointer to the inode 51 */ 52int ima_inode_alloc(struct inode *inode) 53{ 54 struct ima_iint_cache *iint = NULL; 55 int rc = 0; 56 57 iint = kmem_cache_alloc(iint_cache, GFP_NOFS); 58 if (!iint) 59 return -ENOMEM; 60 61 rc = radix_tree_preload(GFP_NOFS); 62 if (rc < 0) 63 goto out; 64 65 spin_lock(&ima_iint_lock); 66 rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); 67 spin_unlock(&ima_iint_lock); 68 radix_tree_preload_end(); 69out: 70 if (rc < 0) 71 kmem_cache_free(iint_cache, iint); 72 73 return rc; 74} 75 76/* iint_free - called when the iint refcount goes to zero */ 77void iint_free(struct kref *kref) 78{ 79 struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache, 80 refcount); 81 iint->version = 0; 82 iint->flags = 0UL; 83 if (iint->readcount != 0) { 84 printk(KERN_INFO "%s: readcount: %ld\n", __func__, 85 iint->readcount); 86 iint->readcount = 0; 87 } 88 if (iint->writecount != 0) { 89 printk(KERN_INFO "%s: writecount: %ld\n", __func__, 90 iint->writecount); 91 iint->writecount = 0; 92 } 93 if (iint->opencount != 0) { 94 printk(KERN_INFO "%s: opencount: %ld\n", __func__, 95 iint->opencount); 96 iint->opencount = 0; 97 } 98 kref_init(&iint->refcount); 99 kmem_cache_free(iint_cache, iint); 100} 101 102void iint_rcu_free(struct rcu_head *rcu_head) 103{ 104 struct ima_iint_cache *iint = container_of(rcu_head, 105 struct ima_iint_cache, rcu); 106 kref_put(&iint->refcount, iint_free); 107} 108 109/** 110 * ima_inode_free - called on security_inode_free 111 * @inode: pointer to the inode 112 * 113 * Free the integrity information(iint) associated with an inode. 114 */ 115void ima_inode_free(struct inode *inode) 116{ 117 struct ima_iint_cache *iint; 118 119 spin_lock(&ima_iint_lock); 120 iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); 121 spin_unlock(&ima_iint_lock); 122 if (iint) 123 call_rcu(&iint->rcu, iint_rcu_free); 124} 125 126static void init_once(void *foo) 127{ 128 struct ima_iint_cache *iint = foo; 129 130 memset(iint, 0, sizeof *iint); 131 iint->version = 0; 132 iint->flags = 0UL; 133 mutex_init(&iint->mutex); 134 iint->readcount = 0; 135 iint->writecount = 0; 136 iint->opencount = 0; 137 kref_init(&iint->refcount); 138} 139 140static int __init ima_iintcache_init(void) 141{ 142 iint_cache = 143 kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, 144 SLAB_PANIC, init_once); 145 iint_initialized = 1; 146 return 0; 147} 148security_initcall(ima_iintcache_init); 149