|
@@ -96,10 +96,13 @@ static void ima_rdwr_violation_check(struct file *file,
|
|
|
if (!iint)
|
|
|
iint = integrity_iint_find(inode);
|
|
|
/* IMA_MEASURE is set from reader side */
|
|
|
- if (iint && (iint->flags & IMA_MEASURE))
|
|
|
+ if (iint && test_bit(IMA_MUST_MEASURE,
|
|
|
+ &iint->atomic_flags))
|
|
|
send_tomtou = true;
|
|
|
}
|
|
|
} else {
|
|
|
+ if (must_measure)
|
|
|
+ set_bit(IMA_MUST_MEASURE, &iint->atomic_flags);
|
|
|
if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
|
|
|
send_writers = true;
|
|
|
}
|
|
@@ -121,21 +124,24 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
|
|
struct inode *inode, struct file *file)
|
|
|
{
|
|
|
fmode_t mode = file->f_mode;
|
|
|
+ bool update;
|
|
|
|
|
|
if (!(mode & FMODE_WRITE))
|
|
|
return;
|
|
|
|
|
|
- inode_lock(inode);
|
|
|
+ mutex_lock(&iint->mutex);
|
|
|
if (atomic_read(&inode->i_writecount) == 1) {
|
|
|
+ update = test_and_clear_bit(IMA_UPDATE_XATTR,
|
|
|
+ &iint->atomic_flags);
|
|
|
if ((iint->version != inode->i_version) ||
|
|
|
(iint->flags & IMA_NEW_FILE)) {
|
|
|
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
|
|
|
iint->measured_pcrs = 0;
|
|
|
- if (iint->flags & IMA_APPRAISE)
|
|
|
+ if (update)
|
|
|
ima_update_xattr(iint, file);
|
|
|
}
|
|
|
}
|
|
|
- inode_unlock(inode);
|
|
|
+ mutex_unlock(&iint->mutex);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -168,7 +174,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
|
char *pathbuf = NULL;
|
|
|
char filename[NAME_MAX];
|
|
|
const char *pathname = NULL;
|
|
|
- int rc = -ENOMEM, action, must_appraise;
|
|
|
+ int rc = 0, action, must_appraise = 0;
|
|
|
int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
|
|
|
struct evm_ima_xattr_data *xattr_value = NULL;
|
|
|
int xattr_len = 0;
|
|
@@ -199,17 +205,31 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
|
if (action) {
|
|
|
iint = integrity_inode_get(inode);
|
|
|
if (!iint)
|
|
|
- goto out;
|
|
|
+ rc = -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- if (violation_check) {
|
|
|
+ if (!rc && violation_check)
|
|
|
ima_rdwr_violation_check(file, iint, action & IMA_MEASURE,
|
|
|
&pathbuf, &pathname);
|
|
|
- if (!action) {
|
|
|
- rc = 0;
|
|
|
- goto out_free;
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
+ inode_unlock(inode);
|
|
|
+
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+ if (!action)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ mutex_lock(&iint->mutex);
|
|
|
+
|
|
|
+ if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags))
|
|
|
+ /* reset appraisal flags if ima_inode_post_setattr was called */
|
|
|
+ iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
|
|
|
+ IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
|
|
|
+ IMA_ACTION_FLAGS);
|
|
|
+
|
|
|
+ if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags))
|
|
|
+ /* reset all flags if ima_inode_setxattr was called */
|
|
|
+ iint->flags &= ~IMA_DONE_MASK;
|
|
|
|
|
|
/* Determine if already appraised/measured based on bitmask
|
|
|
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
|
|
@@ -227,7 +247,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
|
if (!action) {
|
|
|
if (must_appraise)
|
|
|
rc = ima_get_cache_status(iint, func);
|
|
|
- goto out_digsig;
|
|
|
+ goto out_locked;
|
|
|
}
|
|
|
|
|
|
template_desc = ima_template_desc_current();
|
|
@@ -240,7 +260,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
|
|
|
|
rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
|
|
|
if (rc != 0 && rc != -EBADF && rc != -EINVAL)
|
|
|
- goto out_digsig;
|
|
|
+ goto out_locked;
|
|
|
|
|
|
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
|
|
|
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
|
|
@@ -248,26 +268,32 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
|
|
if (action & IMA_MEASURE)
|
|
|
ima_store_measurement(iint, file, pathname,
|
|
|
xattr_value, xattr_len, pcr);
|
|
|
- if (rc == 0 && (action & IMA_APPRAISE_SUBMASK))
|
|
|
+ if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
|
|
|
+ inode_lock(inode);
|
|
|
rc = ima_appraise_measurement(func, iint, file, pathname,
|
|
|
xattr_value, xattr_len, opened);
|
|
|
+ inode_unlock(inode);
|
|
|
+ }
|
|
|
if (action & IMA_AUDIT)
|
|
|
ima_audit_measurement(iint, pathname);
|
|
|
|
|
|
if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
|
|
|
rc = 0;
|
|
|
-out_digsig:
|
|
|
- if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
|
|
|
+out_locked:
|
|
|
+ if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) &&
|
|
|
!(iint->flags & IMA_NEW_FILE))
|
|
|
rc = -EACCES;
|
|
|
+ mutex_unlock(&iint->mutex);
|
|
|
kfree(xattr_value);
|
|
|
-out_free:
|
|
|
+out:
|
|
|
if (pathbuf)
|
|
|
__putname(pathbuf);
|
|
|
-out:
|
|
|
- inode_unlock(inode);
|
|
|
- if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
|
- return -EACCES;
|
|
|
+ if (must_appraise) {
|
|
|
+ if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
|
+ return -EACCES;
|
|
|
+ if (file->f_mode & FMODE_WRITE)
|
|
|
+ set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|