diff options
Diffstat (limited to 'security/integrity/iint.c')
-rw-r--r-- | security/integrity/iint.c | 64 |
1 files changed, 28 insertions, 36 deletions
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 399641c3e846..d82a5a13d855 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "integrity.h" | 22 | #include "integrity.h" |
23 | 23 | ||
24 | static struct rb_root integrity_iint_tree = RB_ROOT; | 24 | static struct rb_root integrity_iint_tree = RB_ROOT; |
25 | static DEFINE_SPINLOCK(integrity_iint_lock); | 25 | static DEFINE_RWLOCK(integrity_iint_lock); |
26 | static struct kmem_cache *iint_cache __read_mostly; | 26 | static struct kmem_cache *iint_cache __read_mostly; |
27 | 27 | ||
28 | int iint_initialized; | 28 | int iint_initialized; |
@@ -35,8 +35,6 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) | |||
35 | struct integrity_iint_cache *iint; | 35 | struct integrity_iint_cache *iint; |
36 | struct rb_node *n = integrity_iint_tree.rb_node; | 36 | struct rb_node *n = integrity_iint_tree.rb_node; |
37 | 37 | ||
38 | assert_spin_locked(&integrity_iint_lock); | ||
39 | |||
40 | while (n) { | 38 | while (n) { |
41 | iint = rb_entry(n, struct integrity_iint_cache, rb_node); | 39 | iint = rb_entry(n, struct integrity_iint_cache, rb_node); |
42 | 40 | ||
@@ -63,9 +61,9 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) | |||
63 | if (!IS_IMA(inode)) | 61 | if (!IS_IMA(inode)) |
64 | return NULL; | 62 | return NULL; |
65 | 63 | ||
66 | spin_lock(&integrity_iint_lock); | 64 | read_lock(&integrity_iint_lock); |
67 | iint = __integrity_iint_find(inode); | 65 | iint = __integrity_iint_find(inode); |
68 | spin_unlock(&integrity_iint_lock); | 66 | read_unlock(&integrity_iint_lock); |
69 | 67 | ||
70 | return iint; | 68 | return iint; |
71 | } | 69 | } |
@@ -74,59 +72,53 @@ static void iint_free(struct integrity_iint_cache *iint) | |||
74 | { | 72 | { |
75 | iint->version = 0; | 73 | iint->version = 0; |
76 | iint->flags = 0UL; | 74 | iint->flags = 0UL; |
75 | iint->ima_status = INTEGRITY_UNKNOWN; | ||
77 | iint->evm_status = INTEGRITY_UNKNOWN; | 76 | iint->evm_status = INTEGRITY_UNKNOWN; |
78 | kmem_cache_free(iint_cache, iint); | 77 | kmem_cache_free(iint_cache, iint); |
79 | } | 78 | } |
80 | 79 | ||
81 | /** | 80 | /** |
82 | * integrity_inode_alloc - allocate an iint associated with an inode | 81 | * integrity_inode_get - find or allocate an iint associated with an inode |
83 | * @inode: pointer to the inode | 82 | * @inode: pointer to the inode |
83 | * @return: allocated iint | ||
84 | * | ||
85 | * Caller must lock i_mutex | ||
84 | */ | 86 | */ |
85 | int integrity_inode_alloc(struct inode *inode) | 87 | struct integrity_iint_cache *integrity_inode_get(struct inode *inode) |
86 | { | 88 | { |
87 | struct rb_node **p; | 89 | struct rb_node **p; |
88 | struct rb_node *new_node, *parent = NULL; | 90 | struct rb_node *node, *parent = NULL; |
89 | struct integrity_iint_cache *new_iint, *test_iint; | 91 | struct integrity_iint_cache *iint, *test_iint; |
90 | int rc; | ||
91 | 92 | ||
92 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | 93 | iint = integrity_iint_find(inode); |
93 | if (!new_iint) | 94 | if (iint) |
94 | return -ENOMEM; | 95 | return iint; |
95 | 96 | ||
96 | new_iint->inode = inode; | 97 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
97 | new_node = &new_iint->rb_node; | 98 | if (!iint) |
99 | return NULL; | ||
98 | 100 | ||
99 | mutex_lock(&inode->i_mutex); /* i_flags */ | 101 | write_lock(&integrity_iint_lock); |
100 | spin_lock(&integrity_iint_lock); | ||
101 | 102 | ||
102 | p = &integrity_iint_tree.rb_node; | 103 | p = &integrity_iint_tree.rb_node; |
103 | while (*p) { | 104 | while (*p) { |
104 | parent = *p; | 105 | parent = *p; |
105 | test_iint = rb_entry(parent, struct integrity_iint_cache, | 106 | test_iint = rb_entry(parent, struct integrity_iint_cache, |
106 | rb_node); | 107 | rb_node); |
107 | rc = -EEXIST; | ||
108 | if (inode < test_iint->inode) | 108 | if (inode < test_iint->inode) |
109 | p = &(*p)->rb_left; | 109 | p = &(*p)->rb_left; |
110 | else if (inode > test_iint->inode) | ||
111 | p = &(*p)->rb_right; | ||
112 | else | 110 | else |
113 | goto out_err; | 111 | p = &(*p)->rb_right; |
114 | } | 112 | } |
115 | 113 | ||
114 | iint->inode = inode; | ||
115 | node = &iint->rb_node; | ||
116 | inode->i_flags |= S_IMA; | 116 | inode->i_flags |= S_IMA; |
117 | rb_link_node(new_node, parent, p); | 117 | rb_link_node(node, parent, p); |
118 | rb_insert_color(new_node, &integrity_iint_tree); | 118 | rb_insert_color(node, &integrity_iint_tree); |
119 | 119 | ||
120 | spin_unlock(&integrity_iint_lock); | 120 | write_unlock(&integrity_iint_lock); |
121 | mutex_unlock(&inode->i_mutex); /* i_flags */ | 121 | return iint; |
122 | |||
123 | return 0; | ||
124 | out_err: | ||
125 | spin_unlock(&integrity_iint_lock); | ||
126 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
127 | iint_free(new_iint); | ||
128 | |||
129 | return rc; | ||
130 | } | 122 | } |
131 | 123 | ||
132 | /** | 124 | /** |
@@ -142,10 +134,10 @@ void integrity_inode_free(struct inode *inode) | |||
142 | if (!IS_IMA(inode)) | 134 | if (!IS_IMA(inode)) |
143 | return; | 135 | return; |
144 | 136 | ||
145 | spin_lock(&integrity_iint_lock); | 137 | write_lock(&integrity_iint_lock); |
146 | iint = __integrity_iint_find(inode); | 138 | iint = __integrity_iint_find(inode); |
147 | rb_erase(&iint->rb_node, &integrity_iint_tree); | 139 | rb_erase(&iint->rb_node, &integrity_iint_tree); |
148 | spin_unlock(&integrity_iint_lock); | 140 | write_unlock(&integrity_iint_lock); |
149 | 141 | ||
150 | iint_free(iint); | 142 | iint_free(iint); |
151 | } | 143 | } |
@@ -157,7 +149,7 @@ static void init_once(void *foo) | |||
157 | memset(iint, 0, sizeof *iint); | 149 | memset(iint, 0, sizeof *iint); |
158 | iint->version = 0; | 150 | iint->version = 0; |
159 | iint->flags = 0UL; | 151 | iint->flags = 0UL; |
160 | mutex_init(&iint->mutex); | 152 | iint->ima_status = INTEGRITY_UNKNOWN; |
161 | iint->evm_status = INTEGRITY_UNKNOWN; | 153 | iint->evm_status = INTEGRITY_UNKNOWN; |
162 | } | 154 | } |
163 | 155 | ||