diff options
Diffstat (limited to 'security/integrity/ima')
-rw-r--r-- | security/integrity/ima/ima_api.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 46 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 92 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 32 | ||||
-rw-r--r-- | security/integrity/ima/ima_template.c | 11 |
5 files changed, 127 insertions, 56 deletions
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c6ae42266270..08fe405338e1 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -175,7 +175,7 @@ err_out: | |||
175 | */ | 175 | */ |
176 | int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr) | 176 | int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr) |
177 | { | 177 | { |
178 | int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; | 178 | int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; |
179 | 179 | ||
180 | flags &= ima_policy_flag; | 180 | flags &= ima_policy_flag; |
181 | 181 | ||
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 65fbcf3c32c7..f2803a40ff82 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -46,14 +46,15 @@ bool is_ima_appraise_enabled(void) | |||
46 | /* | 46 | /* |
47 | * ima_must_appraise - set appraise flag | 47 | * ima_must_appraise - set appraise flag |
48 | * | 48 | * |
49 | * Return 1 to appraise | 49 | * Return 1 to appraise or hash |
50 | */ | 50 | */ |
51 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) | 51 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) |
52 | { | 52 | { |
53 | if (!ima_appraise) | 53 | if (!ima_appraise) |
54 | return 0; | 54 | return 0; |
55 | 55 | ||
56 | return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL); | 56 | return ima_match_policy(inode, func, mask, IMA_APPRAISE | IMA_HASH, |
57 | NULL); | ||
57 | } | 58 | } |
58 | 59 | ||
59 | static int ima_fix_xattr(struct dentry *dentry, | 60 | static int ima_fix_xattr(struct dentry *dentry, |
@@ -223,13 +224,16 @@ int ima_appraise_measurement(enum ima_hooks func, | |||
223 | if (opened & FILE_CREATED) | 224 | if (opened & FILE_CREATED) |
224 | iint->flags |= IMA_NEW_FILE; | 225 | iint->flags |= IMA_NEW_FILE; |
225 | if ((iint->flags & IMA_NEW_FILE) && | 226 | if ((iint->flags & IMA_NEW_FILE) && |
226 | !(iint->flags & IMA_DIGSIG_REQUIRED)) | 227 | (!(iint->flags & IMA_DIGSIG_REQUIRED) || |
228 | (inode->i_size == 0))) | ||
227 | status = INTEGRITY_PASS; | 229 | status = INTEGRITY_PASS; |
228 | goto out; | 230 | goto out; |
229 | } | 231 | } |
230 | 232 | ||
231 | status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); | 233 | status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); |
232 | if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { | 234 | if ((status != INTEGRITY_PASS) && |
235 | (status != INTEGRITY_PASS_IMMUTABLE) && | ||
236 | (status != INTEGRITY_UNKNOWN)) { | ||
233 | if ((status == INTEGRITY_NOLABEL) | 237 | if ((status == INTEGRITY_NOLABEL) |
234 | || (status == INTEGRITY_NOXATTRS)) | 238 | || (status == INTEGRITY_NOXATTRS)) |
235 | cause = "missing-HMAC"; | 239 | cause = "missing-HMAC"; |
@@ -248,6 +252,7 @@ int ima_appraise_measurement(enum ima_hooks func, | |||
248 | status = INTEGRITY_FAIL; | 252 | status = INTEGRITY_FAIL; |
249 | break; | 253 | break; |
250 | } | 254 | } |
255 | clear_bit(IMA_DIGSIG, &iint->atomic_flags); | ||
251 | if (xattr_len - sizeof(xattr_value->type) - hash_start >= | 256 | if (xattr_len - sizeof(xattr_value->type) - hash_start >= |
252 | iint->ima_hash->length) | 257 | iint->ima_hash->length) |
253 | /* xattr length may be longer. md5 hash in previous | 258 | /* xattr length may be longer. md5 hash in previous |
@@ -266,7 +271,7 @@ int ima_appraise_measurement(enum ima_hooks func, | |||
266 | status = INTEGRITY_PASS; | 271 | status = INTEGRITY_PASS; |
267 | break; | 272 | break; |
268 | case EVM_IMA_XATTR_DIGSIG: | 273 | case EVM_IMA_XATTR_DIGSIG: |
269 | iint->flags |= IMA_DIGSIG; | 274 | set_bit(IMA_DIGSIG, &iint->atomic_flags); |
270 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | 275 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, |
271 | (const char *)xattr_value, rc, | 276 | (const char *)xattr_value, rc, |
272 | iint->ima_hash->digest, | 277 | iint->ima_hash->digest, |
@@ -317,17 +322,20 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | |||
317 | int rc = 0; | 322 | int rc = 0; |
318 | 323 | ||
319 | /* do not collect and update hash for digital signatures */ | 324 | /* do not collect and update hash for digital signatures */ |
320 | if (iint->flags & IMA_DIGSIG) | 325 | if (test_bit(IMA_DIGSIG, &iint->atomic_flags)) |
321 | return; | 326 | return; |
322 | 327 | ||
323 | if (iint->ima_file_status != INTEGRITY_PASS) | 328 | if ((iint->ima_file_status != INTEGRITY_PASS) && |
329 | !(iint->flags & IMA_HASH)) | ||
324 | return; | 330 | return; |
325 | 331 | ||
326 | rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); | 332 | rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); |
327 | if (rc < 0) | 333 | if (rc < 0) |
328 | return; | 334 | return; |
329 | 335 | ||
336 | inode_lock(file_inode(file)); | ||
330 | ima_fix_xattr(dentry, iint); | 337 | ima_fix_xattr(dentry, iint); |
338 | inode_unlock(file_inode(file)); | ||
331 | } | 339 | } |
332 | 340 | ||
333 | /** | 341 | /** |
@@ -343,23 +351,21 @@ void ima_inode_post_setattr(struct dentry *dentry) | |||
343 | { | 351 | { |
344 | struct inode *inode = d_backing_inode(dentry); | 352 | struct inode *inode = d_backing_inode(dentry); |
345 | struct integrity_iint_cache *iint; | 353 | struct integrity_iint_cache *iint; |
346 | int must_appraise; | 354 | int action; |
347 | 355 | ||
348 | if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) | 356 | if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) |
349 | || !(inode->i_opflags & IOP_XATTR)) | 357 | || !(inode->i_opflags & IOP_XATTR)) |
350 | return; | 358 | return; |
351 | 359 | ||
352 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); | 360 | action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); |
361 | if (!action) | ||
362 | __vfs_removexattr(dentry, XATTR_NAME_IMA); | ||
353 | iint = integrity_iint_find(inode); | 363 | iint = integrity_iint_find(inode); |
354 | if (iint) { | 364 | if (iint) { |
355 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | | 365 | set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); |
356 | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | | 366 | if (!action) |
357 | IMA_ACTION_RULE_FLAGS); | 367 | clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); |
358 | if (must_appraise) | ||
359 | iint->flags |= IMA_APPRAISE; | ||
360 | } | 368 | } |
361 | if (!must_appraise) | ||
362 | __vfs_removexattr(dentry, XATTR_NAME_IMA); | ||
363 | } | 369 | } |
364 | 370 | ||
365 | /* | 371 | /* |
@@ -388,12 +394,12 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) | |||
388 | iint = integrity_iint_find(inode); | 394 | iint = integrity_iint_find(inode); |
389 | if (!iint) | 395 | if (!iint) |
390 | return; | 396 | return; |
391 | |||
392 | iint->flags &= ~IMA_DONE_MASK; | ||
393 | iint->measured_pcrs = 0; | 397 | iint->measured_pcrs = 0; |
398 | set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags); | ||
394 | if (digsig) | 399 | if (digsig) |
395 | iint->flags |= IMA_DIGSIG; | 400 | set_bit(IMA_DIGSIG, &iint->atomic_flags); |
396 | return; | 401 | else |
402 | clear_bit(IMA_DIGSIG, &iint->atomic_flags); | ||
397 | } | 403 | } |
398 | 404 | ||
399 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | 405 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 06a70c5a2329..061425dd6400 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -85,10 +85,10 @@ static void ima_rdwr_violation_check(struct file *file, | |||
85 | struct integrity_iint_cache *iint, | 85 | struct integrity_iint_cache *iint, |
86 | int must_measure, | 86 | int must_measure, |
87 | char **pathbuf, | 87 | char **pathbuf, |
88 | const char **pathname) | 88 | const char **pathname, |
89 | char *filename) | ||
89 | { | 90 | { |
90 | struct inode *inode = file_inode(file); | 91 | struct inode *inode = file_inode(file); |
91 | char filename[NAME_MAX]; | ||
92 | fmode_t mode = file->f_mode; | 92 | fmode_t mode = file->f_mode; |
93 | bool send_tomtou = false, send_writers = false; | 93 | bool send_tomtou = false, send_writers = false; |
94 | 94 | ||
@@ -97,10 +97,13 @@ static void ima_rdwr_violation_check(struct file *file, | |||
97 | if (!iint) | 97 | if (!iint) |
98 | iint = integrity_iint_find(inode); | 98 | iint = integrity_iint_find(inode); |
99 | /* IMA_MEASURE is set from reader side */ | 99 | /* IMA_MEASURE is set from reader side */ |
100 | if (iint && (iint->flags & IMA_MEASURE)) | 100 | if (iint && test_bit(IMA_MUST_MEASURE, |
101 | &iint->atomic_flags)) | ||
101 | send_tomtou = true; | 102 | send_tomtou = true; |
102 | } | 103 | } |
103 | } else { | 104 | } else { |
105 | if (must_measure) | ||
106 | set_bit(IMA_MUST_MEASURE, &iint->atomic_flags); | ||
104 | if ((atomic_read(&inode->i_writecount) > 0) && must_measure) | 107 | if ((atomic_read(&inode->i_writecount) > 0) && must_measure) |
105 | send_writers = true; | 108 | send_writers = true; |
106 | } | 109 | } |
@@ -122,22 +125,25 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint, | |||
122 | struct inode *inode, struct file *file) | 125 | struct inode *inode, struct file *file) |
123 | { | 126 | { |
124 | fmode_t mode = file->f_mode; | 127 | fmode_t mode = file->f_mode; |
128 | bool update; | ||
125 | 129 | ||
126 | if (!(mode & FMODE_WRITE)) | 130 | if (!(mode & FMODE_WRITE)) |
127 | return; | 131 | return; |
128 | 132 | ||
129 | inode_lock(inode); | 133 | mutex_lock(&iint->mutex); |
130 | if (atomic_read(&inode->i_writecount) == 1) { | 134 | if (atomic_read(&inode->i_writecount) == 1) { |
135 | update = test_and_clear_bit(IMA_UPDATE_XATTR, | ||
136 | &iint->atomic_flags); | ||
131 | if (!IS_I_VERSION(inode) || | 137 | if (!IS_I_VERSION(inode) || |
132 | inode_cmp_iversion(inode, iint->version) || | 138 | inode_cmp_iversion(inode, iint->version) || |
133 | (iint->flags & IMA_NEW_FILE)) { | 139 | (iint->flags & IMA_NEW_FILE)) { |
134 | iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE); | 140 | iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE); |
135 | iint->measured_pcrs = 0; | 141 | iint->measured_pcrs = 0; |
136 | if (iint->flags & IMA_APPRAISE) | 142 | if (update) |
137 | ima_update_xattr(iint, file); | 143 | ima_update_xattr(iint, file); |
138 | } | 144 | } |
139 | } | 145 | } |
140 | inode_unlock(inode); | 146 | mutex_unlock(&iint->mutex); |
141 | } | 147 | } |
142 | 148 | ||
143 | /** | 149 | /** |
@@ -170,7 +176,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
170 | char *pathbuf = NULL; | 176 | char *pathbuf = NULL; |
171 | char filename[NAME_MAX]; | 177 | char filename[NAME_MAX]; |
172 | const char *pathname = NULL; | 178 | const char *pathname = NULL; |
173 | int rc = -ENOMEM, action, must_appraise; | 179 | int rc = 0, action, must_appraise = 0; |
174 | int pcr = CONFIG_IMA_MEASURE_PCR_IDX; | 180 | int pcr = CONFIG_IMA_MEASURE_PCR_IDX; |
175 | struct evm_ima_xattr_data *xattr_value = NULL; | 181 | struct evm_ima_xattr_data *xattr_value = NULL; |
176 | int xattr_len = 0; | 182 | int xattr_len = 0; |
@@ -201,17 +207,31 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
201 | if (action) { | 207 | if (action) { |
202 | iint = integrity_inode_get(inode); | 208 | iint = integrity_inode_get(inode); |
203 | if (!iint) | 209 | if (!iint) |
204 | goto out; | 210 | rc = -ENOMEM; |
205 | } | 211 | } |
206 | 212 | ||
207 | if (violation_check) { | 213 | if (!rc && violation_check) |
208 | ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, | 214 | ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, |
209 | &pathbuf, &pathname); | 215 | &pathbuf, &pathname, filename); |
210 | if (!action) { | 216 | |
211 | rc = 0; | 217 | inode_unlock(inode); |
212 | goto out_free; | 218 | |
213 | } | 219 | if (rc) |
214 | } | 220 | goto out; |
221 | if (!action) | ||
222 | goto out; | ||
223 | |||
224 | mutex_lock(&iint->mutex); | ||
225 | |||
226 | if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) | ||
227 | /* reset appraisal flags if ima_inode_post_setattr was called */ | ||
228 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | | ||
229 | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | | ||
230 | IMA_ACTION_FLAGS); | ||
231 | |||
232 | if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags)) | ||
233 | /* reset all flags if ima_inode_setxattr was called */ | ||
234 | iint->flags &= ~IMA_DONE_MASK; | ||
215 | 235 | ||
216 | /* Determine if already appraised/measured based on bitmask | 236 | /* Determine if already appraised/measured based on bitmask |
217 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, | 237 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, |
@@ -225,11 +245,23 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
225 | if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr))) | 245 | if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr))) |
226 | action ^= IMA_MEASURE; | 246 | action ^= IMA_MEASURE; |
227 | 247 | ||
248 | /* HASH sets the digital signature and update flags, nothing else */ | ||
249 | if ((action & IMA_HASH) && | ||
250 | !(test_bit(IMA_DIGSIG, &iint->atomic_flags))) { | ||
251 | xattr_len = ima_read_xattr(file_dentry(file), &xattr_value); | ||
252 | if ((xattr_value && xattr_len > 2) && | ||
253 | (xattr_value->type == EVM_IMA_XATTR_DIGSIG)) | ||
254 | set_bit(IMA_DIGSIG, &iint->atomic_flags); | ||
255 | iint->flags |= IMA_HASHED; | ||
256 | action ^= IMA_HASH; | ||
257 | set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); | ||
258 | } | ||
259 | |||
228 | /* Nothing to do, just return existing appraised status */ | 260 | /* Nothing to do, just return existing appraised status */ |
229 | if (!action) { | 261 | if (!action) { |
230 | if (must_appraise) | 262 | if (must_appraise) |
231 | rc = ima_get_cache_status(iint, func); | 263 | rc = ima_get_cache_status(iint, func); |
232 | goto out_digsig; | 264 | goto out_locked; |
233 | } | 265 | } |
234 | 266 | ||
235 | template_desc = ima_template_desc_current(); | 267 | template_desc = ima_template_desc_current(); |
@@ -242,7 +274,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
242 | 274 | ||
243 | rc = ima_collect_measurement(iint, file, buf, size, hash_algo); | 275 | rc = ima_collect_measurement(iint, file, buf, size, hash_algo); |
244 | if (rc != 0 && rc != -EBADF && rc != -EINVAL) | 276 | if (rc != 0 && rc != -EBADF && rc != -EINVAL) |
245 | goto out_digsig; | 277 | goto out_locked; |
246 | 278 | ||
247 | if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ | 279 | if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ |
248 | pathname = ima_d_path(&file->f_path, &pathbuf, filename); | 280 | pathname = ima_d_path(&file->f_path, &pathbuf, filename); |
@@ -250,26 +282,32 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
250 | if (action & IMA_MEASURE) | 282 | if (action & IMA_MEASURE) |
251 | ima_store_measurement(iint, file, pathname, | 283 | ima_store_measurement(iint, file, pathname, |
252 | xattr_value, xattr_len, pcr); | 284 | xattr_value, xattr_len, pcr); |
253 | if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) | 285 | if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { |
286 | inode_lock(inode); | ||
254 | rc = ima_appraise_measurement(func, iint, file, pathname, | 287 | rc = ima_appraise_measurement(func, iint, file, pathname, |
255 | xattr_value, xattr_len, opened); | 288 | xattr_value, xattr_len, opened); |
289 | inode_unlock(inode); | ||
290 | } | ||
256 | if (action & IMA_AUDIT) | 291 | if (action & IMA_AUDIT) |
257 | ima_audit_measurement(iint, pathname); | 292 | ima_audit_measurement(iint, pathname); |
258 | 293 | ||
259 | if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) | 294 | if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) |
260 | rc = 0; | 295 | rc = 0; |
261 | out_digsig: | 296 | out_locked: |
262 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && | 297 | if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) && |
263 | !(iint->flags & IMA_NEW_FILE)) | 298 | !(iint->flags & IMA_NEW_FILE)) |
264 | rc = -EACCES; | 299 | rc = -EACCES; |
300 | mutex_unlock(&iint->mutex); | ||
265 | kfree(xattr_value); | 301 | kfree(xattr_value); |
266 | out_free: | 302 | out: |
267 | if (pathbuf) | 303 | if (pathbuf) |
268 | __putname(pathbuf); | 304 | __putname(pathbuf); |
269 | out: | 305 | if (must_appraise) { |
270 | inode_unlock(inode); | 306 | if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE)) |
271 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) | 307 | return -EACCES; |
272 | return -EACCES; | 308 | if (file->f_mode & FMODE_WRITE) |
309 | set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); | ||
310 | } | ||
273 | return 0; | 311 | return 0; |
274 | } | 312 | } |
275 | 313 | ||
@@ -368,8 +406,10 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) | |||
368 | 406 | ||
369 | if (!file && read_id == READING_MODULE) { | 407 | if (!file && read_id == READING_MODULE) { |
370 | if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) && | 408 | if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) && |
371 | (ima_appraise & IMA_APPRAISE_ENFORCE)) | 409 | (ima_appraise & IMA_APPRAISE_ENFORCE)) { |
410 | pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); | ||
372 | return -EACCES; /* INTEGRITY_UNKNOWN */ | 411 | return -EACCES; /* INTEGRITY_UNKNOWN */ |
412 | } | ||
373 | return 0; /* We rely on module signature checking */ | 413 | return 0; /* We rely on module signature checking */ |
374 | } | 414 | } |
375 | return 0; | 415 | return 0; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index ee4613fa5840..915f5572c6ff 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ | 40 | #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ |
41 | #define DONT_APPRAISE 0x0008 | 41 | #define DONT_APPRAISE 0x0008 |
42 | #define AUDIT 0x0040 | 42 | #define AUDIT 0x0040 |
43 | #define HASH 0x0100 | ||
44 | #define DONT_HASH 0x0200 | ||
43 | 45 | ||
44 | #define INVALID_PCR(a) (((a) < 0) || \ | 46 | #define INVALID_PCR(a) (((a) < 0) || \ |
45 | (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8)) | 47 | (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8)) |
@@ -380,8 +382,10 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | |||
380 | action |= entry->flags & IMA_ACTION_FLAGS; | 382 | action |= entry->flags & IMA_ACTION_FLAGS; |
381 | 383 | ||
382 | action |= entry->action & IMA_DO_MASK; | 384 | action |= entry->action & IMA_DO_MASK; |
383 | if (entry->action & IMA_APPRAISE) | 385 | if (entry->action & IMA_APPRAISE) { |
384 | action |= get_subaction(entry, func); | 386 | action |= get_subaction(entry, func); |
387 | action ^= IMA_HASH; | ||
388 | } | ||
385 | 389 | ||
386 | if (entry->action & IMA_DO_MASK) | 390 | if (entry->action & IMA_DO_MASK) |
387 | actmask &= ~(entry->action | entry->action << 1); | 391 | actmask &= ~(entry->action | entry->action << 1); |
@@ -521,7 +525,7 @@ enum { | |||
521 | Opt_err = -1, | 525 | Opt_err = -1, |
522 | Opt_measure = 1, Opt_dont_measure, | 526 | Opt_measure = 1, Opt_dont_measure, |
523 | Opt_appraise, Opt_dont_appraise, | 527 | Opt_appraise, Opt_dont_appraise, |
524 | Opt_audit, | 528 | Opt_audit, Opt_hash, Opt_dont_hash, |
525 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | 529 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
526 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | 530 | Opt_subj_user, Opt_subj_role, Opt_subj_type, |
527 | Opt_func, Opt_mask, Opt_fsmagic, | 531 | Opt_func, Opt_mask, Opt_fsmagic, |
@@ -538,6 +542,8 @@ static match_table_t policy_tokens = { | |||
538 | {Opt_appraise, "appraise"}, | 542 | {Opt_appraise, "appraise"}, |
539 | {Opt_dont_appraise, "dont_appraise"}, | 543 | {Opt_dont_appraise, "dont_appraise"}, |
540 | {Opt_audit, "audit"}, | 544 | {Opt_audit, "audit"}, |
545 | {Opt_hash, "hash"}, | ||
546 | {Opt_dont_hash, "dont_hash"}, | ||
541 | {Opt_obj_user, "obj_user=%s"}, | 547 | {Opt_obj_user, "obj_user=%s"}, |
542 | {Opt_obj_role, "obj_role=%s"}, | 548 | {Opt_obj_role, "obj_role=%s"}, |
543 | {Opt_obj_type, "obj_type=%s"}, | 549 | {Opt_obj_type, "obj_type=%s"}, |
@@ -671,6 +677,22 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
671 | 677 | ||
672 | entry->action = AUDIT; | 678 | entry->action = AUDIT; |
673 | break; | 679 | break; |
680 | case Opt_hash: | ||
681 | ima_log_string(ab, "action", "hash"); | ||
682 | |||
683 | if (entry->action != UNKNOWN) | ||
684 | result = -EINVAL; | ||
685 | |||
686 | entry->action = HASH; | ||
687 | break; | ||
688 | case Opt_dont_hash: | ||
689 | ima_log_string(ab, "action", "dont_hash"); | ||
690 | |||
691 | if (entry->action != UNKNOWN) | ||
692 | result = -EINVAL; | ||
693 | |||
694 | entry->action = DONT_HASH; | ||
695 | break; | ||
674 | case Opt_func: | 696 | case Opt_func: |
675 | ima_log_string(ab, "func", args[0].from); | 697 | ima_log_string(ab, "func", args[0].from); |
676 | 698 | ||
@@ -743,7 +765,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
743 | case Opt_fsuuid: | 765 | case Opt_fsuuid: |
744 | ima_log_string(ab, "fsuuid", args[0].from); | 766 | ima_log_string(ab, "fsuuid", args[0].from); |
745 | 767 | ||
746 | if (uuid_is_null(&entry->fsuuid)) { | 768 | if (!uuid_is_null(&entry->fsuuid)) { |
747 | result = -EINVAL; | 769 | result = -EINVAL; |
748 | break; | 770 | break; |
749 | } | 771 | } |
@@ -1040,6 +1062,10 @@ int ima_policy_show(struct seq_file *m, void *v) | |||
1040 | seq_puts(m, pt(Opt_dont_appraise)); | 1062 | seq_puts(m, pt(Opt_dont_appraise)); |
1041 | if (entry->action & AUDIT) | 1063 | if (entry->action & AUDIT) |
1042 | seq_puts(m, pt(Opt_audit)); | 1064 | seq_puts(m, pt(Opt_audit)); |
1065 | if (entry->action & HASH) | ||
1066 | seq_puts(m, pt(Opt_hash)); | ||
1067 | if (entry->action & DONT_HASH) | ||
1068 | seq_puts(m, pt(Opt_dont_hash)); | ||
1043 | 1069 | ||
1044 | seq_puts(m, " "); | 1070 | seq_puts(m, " "); |
1045 | 1071 | ||
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 7412d0291ab9..30db39b23804 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c | |||
@@ -377,8 +377,7 @@ int ima_restore_measurement_list(loff_t size, void *buf) | |||
377 | break; | 377 | break; |
378 | 378 | ||
379 | if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) { | 379 | if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) { |
380 | pr_err("attempting to restore a template name \ | 380 | pr_err("attempting to restore a template name that is too long\n"); |
381 | that is too long\n"); | ||
382 | ret = -EINVAL; | 381 | ret = -EINVAL; |
383 | break; | 382 | break; |
384 | } | 383 | } |
@@ -389,8 +388,8 @@ int ima_restore_measurement_list(loff_t size, void *buf) | |||
389 | template_name[hdr[HDR_TEMPLATE_NAME].len] = 0; | 388 | template_name[hdr[HDR_TEMPLATE_NAME].len] = 0; |
390 | 389 | ||
391 | if (strcmp(template_name, "ima") == 0) { | 390 | if (strcmp(template_name, "ima") == 0) { |
392 | pr_err("attempting to restore an unsupported \ | 391 | pr_err("attempting to restore an unsupported template \"%s\" failed\n", |
393 | template \"%s\" failed\n", template_name); | 392 | template_name); |
394 | ret = -EINVAL; | 393 | ret = -EINVAL; |
395 | break; | 394 | break; |
396 | } | 395 | } |
@@ -410,8 +409,8 @@ int ima_restore_measurement_list(loff_t size, void *buf) | |||
410 | &(template_desc->fields), | 409 | &(template_desc->fields), |
411 | &(template_desc->num_fields)); | 410 | &(template_desc->num_fields)); |
412 | if (ret < 0) { | 411 | if (ret < 0) { |
413 | pr_err("attempting to restore the template fmt \"%s\" \ | 412 | pr_err("attempting to restore the template fmt \"%s\" failed\n", |
414 | failed\n", template_desc->fmt); | 413 | template_desc->fmt); |
415 | ret = -EINVAL; | 414 | ret = -EINVAL; |
416 | break; | 415 | break; |
417 | } | 416 | } |