aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r--security/integrity/ima/ima_main.c184
1 files changed, 94 insertions, 90 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index e662b89d407..203de979d30 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -85,50 +85,6 @@ out:
85 return found; 85 return found;
86} 86}
87 87
88/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
89 *
90 * When opening a file for read, if the file is already open for write,
91 * the file could change, resulting in a file measurement error.
92 *
93 * Opening a file for write, if the file is already open for read, results
94 * in a time of measure, time of use (ToMToU) error.
95 *
96 * In either case invalidate the PCR.
97 */
98enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
99static void ima_read_write_check(enum iint_pcr_error error,
100 struct ima_iint_cache *iint,
101 struct inode *inode,
102 const unsigned char *filename)
103{
104 switch (error) {
105 case TOMTOU:
106 if (iint->readcount > 0)
107 ima_add_violation(inode, filename, "invalid_pcr",
108 "ToMToU");
109 break;
110 case OPEN_WRITERS:
111 if (iint->writecount > 0)
112 ima_add_violation(inode, filename, "invalid_pcr",
113 "open_writers");
114 break;
115 }
116}
117
118/*
119 * Update the counts given an fmode_t
120 */
121static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
122{
123 BUG_ON(!mutex_is_locked(&iint->mutex));
124
125 iint->opencount++;
126 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
127 iint->readcount++;
128 if (mode & FMODE_WRITE)
129 iint->writecount++;
130}
131
132/* 88/*
133 * ima_counts_get - increment file counts 89 * ima_counts_get - increment file counts
134 * 90 *
@@ -145,62 +101,101 @@ void ima_counts_get(struct file *file)
145 struct dentry *dentry = file->f_path.dentry; 101 struct dentry *dentry = file->f_path.dentry;
146 struct inode *inode = dentry->d_inode; 102 struct inode *inode = dentry->d_inode;
147 fmode_t mode = file->f_mode; 103 fmode_t mode = file->f_mode;
148 struct ima_iint_cache *iint;
149 int rc; 104 int rc;
105 bool send_tomtou = false, send_writers = false;
150 106
151 if (!iint_initialized || !S_ISREG(inode->i_mode)) 107 if (!S_ISREG(inode->i_mode))
152 return; 108 return;
153 iint = ima_iint_find_get(inode); 109
154 if (!iint) 110 spin_lock(&inode->i_lock);
155 return; 111
156 mutex_lock(&iint->mutex);
157 if (!ima_initialized) 112 if (!ima_initialized)
158 goto out; 113 goto out;
159 rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK);
160 if (rc < 0)
161 goto out;
162 114
163 if (mode & FMODE_WRITE) { 115 if (mode & FMODE_WRITE) {
164 ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); 116 if (inode->i_readcount && IS_IMA(inode))
117 send_tomtou = true;
165 goto out; 118 goto out;
166 } 119 }
167 ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); 120
121 rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK);
122 if (rc < 0)
123 goto out;
124
125 if (atomic_read(&inode->i_writecount) > 0)
126 send_writers = true;
168out: 127out:
169 ima_inc_counts(iint, file->f_mode); 128 /* remember the vfs deals with i_writecount */
170 mutex_unlock(&iint->mutex); 129 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
130 inode->i_readcount++;
171 131
172 kref_put(&iint->refcount, iint_free); 132 spin_unlock(&inode->i_lock);
133
134 if (send_tomtou)
135 ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
136 "ToMToU");
137 if (send_writers)
138 ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
139 "open_writers");
173} 140}
174 141
175/* 142/*
176 * Decrement ima counts 143 * Decrement ima counts
177 */ 144 */
178static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, 145static void ima_dec_counts(struct inode *inode, struct file *file)
179 struct file *file)
180{ 146{
181 mode_t mode = file->f_mode; 147 mode_t mode = file->f_mode;
182 BUG_ON(!mutex_is_locked(&iint->mutex));
183 148
184 iint->opencount--; 149 assert_spin_locked(&inode->i_lock);
185 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) 150
186 iint->readcount--; 151 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
187 if (mode & FMODE_WRITE) { 152 if (unlikely(inode->i_readcount == 0)) {
188 iint->writecount--; 153 if (!ima_limit_imbalance(file)) {
189 if (iint->writecount == 0) { 154 printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
190 if (iint->version != inode->i_version) 155 __func__, inode->i_readcount);
191 iint->flags &= ~IMA_MEASURED; 156 dump_stack();
157 }
158 return;
192 } 159 }
160 inode->i_readcount--;
193 } 161 }
162}
194 163
195 if (((iint->opencount < 0) || 164static void ima_check_last_writer(struct ima_iint_cache *iint,
196 (iint->readcount < 0) || 165 struct inode *inode,
197 (iint->writecount < 0)) && 166 struct file *file)
198 !ima_limit_imbalance(file)) { 167{
199 printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", 168 mode_t mode = file->f_mode;
200 __func__, iint->readcount, iint->writecount, 169
201 iint->opencount); 170 BUG_ON(!mutex_is_locked(&iint->mutex));
202 dump_stack(); 171 assert_spin_locked(&inode->i_lock);
203 } 172
173 if (mode & FMODE_WRITE &&
174 atomic_read(&inode->i_writecount) == 1 &&
175 iint->version != inode->i_version)
176 iint->flags &= ~IMA_MEASURED;
177}
178
179static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
180 struct file *file)
181{
182 mutex_lock(&iint->mutex);
183 spin_lock(&inode->i_lock);
184
185 ima_dec_counts(inode, file);
186 ima_check_last_writer(iint, inode, file);
187
188 spin_unlock(&inode->i_lock);
189 mutex_unlock(&iint->mutex);
190}
191
192static void ima_file_free_noiint(struct inode *inode, struct file *file)
193{
194 spin_lock(&inode->i_lock);
195
196 ima_dec_counts(inode, file);
197
198 spin_unlock(&inode->i_lock);
204} 199}
205 200
206/** 201/**
@@ -208,7 +203,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
208 * @file: pointer to file structure being freed 203 * @file: pointer to file structure being freed
209 * 204 *
210 * Flag files that changed, based on i_version; 205 * Flag files that changed, based on i_version;
211 * and decrement the iint readcount/writecount. 206 * and decrement the i_readcount.
212 */ 207 */
213void ima_file_free(struct file *file) 208void ima_file_free(struct file *file)
214{ 209{
@@ -217,14 +212,14 @@ void ima_file_free(struct file *file)
217 212
218 if (!iint_initialized || !S_ISREG(inode->i_mode)) 213 if (!iint_initialized || !S_ISREG(inode->i_mode))
219 return; 214 return;
220 iint = ima_iint_find_get(inode);
221 if (!iint)
222 return;
223 215
224 mutex_lock(&iint->mutex); 216 iint = ima_iint_find(inode);
225 ima_dec_counts(iint, inode, file); 217
226 mutex_unlock(&iint->mutex); 218 if (iint)
227 kref_put(&iint->refcount, iint_free); 219 ima_file_free_iint(iint, inode, file);
220 else
221 ima_file_free_noiint(inode, file);
222
228} 223}
229 224
230static int process_measurement(struct file *file, const unsigned char *filename, 225static int process_measurement(struct file *file, const unsigned char *filename,
@@ -236,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename,
236 231
237 if (!ima_initialized || !S_ISREG(inode->i_mode)) 232 if (!ima_initialized || !S_ISREG(inode->i_mode))
238 return 0; 233 return 0;
239 iint = ima_iint_find_get(inode); 234
240 if (!iint) 235 rc = ima_must_measure(NULL, inode, mask, function);
241 return -ENOMEM; 236 if (rc != 0)
237 return rc;
238retry:
239 iint = ima_iint_find(inode);
240 if (!iint) {
241 rc = ima_inode_alloc(inode);
242 if (!rc || rc == -EEXIST)
243 goto retry;
244 return rc;
245 }
242 246
243 mutex_lock(&iint->mutex); 247 mutex_lock(&iint->mutex);
248
244 rc = ima_must_measure(iint, inode, mask, function); 249 rc = ima_must_measure(iint, inode, mask, function);
245 if (rc != 0) 250 if (rc != 0)
246 goto out; 251 goto out;
@@ -250,7 +255,6 @@ static int process_measurement(struct file *file, const unsigned char *filename,
250 ima_store_measurement(iint, file, filename); 255 ima_store_measurement(iint, file, filename);
251out: 256out:
252 mutex_unlock(&iint->mutex); 257 mutex_unlock(&iint->mutex);
253 kref_put(&iint->refcount, iint_free);
254 return rc; 258 return rc;
255} 259}
256 260