]>
Commit | Line | Data |
---|---|---|
3323eec9 MZ |
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 | */ | |
5a0e3ad6 | 17 | #include <linux/slab.h> |
3323eec9 MZ |
18 | #include <linux/module.h> |
19 | #include <linux/spinlock.h> | |
20 | #include <linux/radix-tree.h> | |
21 | #include "ima.h" | |
22 | ||
3323eec9 MZ |
23 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); |
24 | DEFINE_SPINLOCK(ima_iint_lock); | |
3323eec9 MZ |
25 | static struct kmem_cache *iint_cache __read_mostly; |
26 | ||
e950598d MZ |
27 | int iint_initialized = 0; |
28 | ||
3323eec9 MZ |
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 | */ | |
34 | struct 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); | |
43 | out: | |
44 | rcu_read_unlock(); | |
45 | return iint; | |
46 | } | |
47 | ||
9353384e EP |
48 | /** |
49 | * ima_inode_alloc - allocate an iint associated with an inode | |
50 | * @inode: pointer to the inode | |
3323eec9 | 51 | */ |
9353384e | 52 | int ima_inode_alloc(struct inode *inode) |
3323eec9 MZ |
53 | { |
54 | struct ima_iint_cache *iint = NULL; | |
55 | int rc = 0; | |
56 | ||
c09c59e6 | 57 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
3323eec9 | 58 | if (!iint) |
9353384e | 59 | return -ENOMEM; |
3323eec9 | 60 | |
c09c59e6 | 61 | rc = radix_tree_preload(GFP_NOFS); |
3323eec9 MZ |
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); | |
baac35c4 | 68 | radix_tree_preload_end(); |
3323eec9 | 69 | out: |
9353384e | 70 | if (rc < 0) |
3323eec9 | 71 | kmem_cache_free(iint_cache, iint); |
3323eec9 | 72 | |
9353384e | 73 | return rc; |
3323eec9 MZ |
74 | } |
75 | ||
76 | /* iint_free - called when the iint refcount goes to zero */ | |
77 | void 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; | |
1df9f0a7 | 83 | if (iint->readcount != 0) { |
a19c5bbe | 84 | printk(KERN_INFO "%s: readcount: %ld\n", __func__, |
1df9f0a7 MZ |
85 | iint->readcount); |
86 | iint->readcount = 0; | |
87 | } | |
88 | if (iint->writecount != 0) { | |
a19c5bbe | 89 | printk(KERN_INFO "%s: writecount: %ld\n", __func__, |
1df9f0a7 MZ |
90 | iint->writecount); |
91 | iint->writecount = 0; | |
92 | } | |
93 | if (iint->opencount != 0) { | |
a19c5bbe | 94 | printk(KERN_INFO "%s: opencount: %ld\n", __func__, |
1df9f0a7 MZ |
95 | iint->opencount); |
96 | iint->opencount = 0; | |
97 | } | |
db1afffa | 98 | kref_init(&iint->refcount); |
3323eec9 MZ |
99 | kmem_cache_free(iint_cache, iint); |
100 | } | |
101 | ||
102 | void 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 | /** | |
85a17f55 | 110 | * ima_inode_free - called on security_inode_free |
3323eec9 MZ |
111 | * @inode: pointer to the inode |
112 | * | |
113 | * Free the integrity information(iint) associated with an inode. | |
114 | */ | |
85a17f55 | 115 | void ima_inode_free(struct inode *inode) |
3323eec9 MZ |
116 | { |
117 | struct ima_iint_cache *iint; | |
118 | ||
3323eec9 MZ |
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 | ||
126 | static 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; | |
1df9f0a7 | 136 | iint->opencount = 0; |
db1afffa | 137 | kref_init(&iint->refcount); |
3323eec9 MZ |
138 | } |
139 | ||
54bb6552 | 140 | static int __init ima_iintcache_init(void) |
3323eec9 MZ |
141 | { |
142 | iint_cache = | |
143 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | |
144 | SLAB_PANIC, init_once); | |
e950598d | 145 | iint_initialized = 1; |
54bb6552 | 146 | return 0; |
3323eec9 | 147 | } |
54bb6552 | 148 | security_initcall(ima_iintcache_init); |