diff options
| -rw-r--r-- | security/integrity/ima/ima_main.c | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2191b36ad1da..03bb52ecf490 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -77,21 +77,19 @@ __setup("ima_hash=", hash_setup); | |||
| 77 | * could result in a file measurement error. | 77 | * could result in a file measurement error. |
| 78 | * | 78 | * |
| 79 | */ | 79 | */ |
| 80 | static void ima_rdwr_violation_check(struct file *file) | 80 | static void ima_rdwr_violation_check(struct file *file, |
| 81 | struct integrity_iint_cache *iint, | ||
| 82 | char **pathbuf, | ||
| 83 | const char **pathname) | ||
| 81 | { | 84 | { |
| 82 | struct inode *inode = file_inode(file); | 85 | struct inode *inode = file_inode(file); |
| 83 | fmode_t mode = file->f_mode; | 86 | fmode_t mode = file->f_mode; |
| 84 | bool send_tomtou = false, send_writers = false; | 87 | bool send_tomtou = false, send_writers = false; |
| 85 | char *pathbuf = NULL; | ||
| 86 | const char *pathname; | ||
| 87 | |||
| 88 | if (!S_ISREG(inode->i_mode) || !(ima_policy_flag & IMA_MEASURE)) | ||
| 89 | return; | ||
| 90 | 88 | ||
| 91 | if (mode & FMODE_WRITE) { | 89 | if (mode & FMODE_WRITE) { |
| 92 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { | 90 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { |
| 93 | struct integrity_iint_cache *iint; | 91 | if (!iint) |
| 94 | iint = integrity_iint_find(inode); | 92 | iint = integrity_iint_find(inode); |
| 95 | /* IMA_MEASURE is set from reader side */ | 93 | /* IMA_MEASURE is set from reader side */ |
| 96 | if (iint && (iint->flags & IMA_MEASURE)) | 94 | if (iint && (iint->flags & IMA_MEASURE)) |
| 97 | send_tomtou = true; | 95 | send_tomtou = true; |
| @@ -105,14 +103,13 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 105 | if (!send_tomtou && !send_writers) | 103 | if (!send_tomtou && !send_writers) |
| 106 | return; | 104 | return; |
| 107 | 105 | ||
| 108 | pathname = ima_d_path(&file->f_path, &pathbuf); | 106 | *pathname = ima_d_path(&file->f_path, pathbuf); |
| 109 | 107 | ||
| 110 | if (send_tomtou) | 108 | if (send_tomtou) |
| 111 | ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); | 109 | ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU"); |
| 112 | if (send_writers) | 110 | if (send_writers) |
| 113 | ima_add_violation(file, pathname, | 111 | ima_add_violation(file, *pathname, |
| 114 | "invalid_pcr", "open_writers"); | 112 | "invalid_pcr", "open_writers"); |
| 115 | kfree(pathbuf); | ||
| 116 | } | 113 | } |
| 117 | 114 | ||
| 118 | static void ima_check_last_writer(struct integrity_iint_cache *iint, | 115 | static void ima_check_last_writer(struct integrity_iint_cache *iint, |
| @@ -160,13 +157,14 @@ static int process_measurement(struct file *file, int mask, int function, | |||
| 160 | int opened) | 157 | int opened) |
| 161 | { | 158 | { |
| 162 | struct inode *inode = file_inode(file); | 159 | struct inode *inode = file_inode(file); |
| 163 | struct integrity_iint_cache *iint; | 160 | struct integrity_iint_cache *iint = NULL; |
| 164 | struct ima_template_desc *template_desc; | 161 | struct ima_template_desc *template_desc; |
| 165 | char *pathbuf = NULL; | 162 | char *pathbuf = NULL; |
| 166 | const char *pathname = NULL; | 163 | const char *pathname = NULL; |
| 167 | int rc = -ENOMEM, action, must_appraise; | 164 | int rc = -ENOMEM, action, must_appraise; |
| 168 | struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; | 165 | struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; |
| 169 | int xattr_len = 0; | 166 | int xattr_len = 0; |
| 167 | bool violation_check; | ||
| 170 | 168 | ||
| 171 | if (!ima_policy_flag || !S_ISREG(inode->i_mode)) | 169 | if (!ima_policy_flag || !S_ISREG(inode->i_mode)) |
| 172 | return 0; | 170 | return 0; |
| @@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function, | |||
| 176 | * Included is the appraise submask. | 174 | * Included is the appraise submask. |
| 177 | */ | 175 | */ |
| 178 | action = ima_get_action(inode, mask, function); | 176 | action = ima_get_action(inode, mask, function); |
| 179 | if (!action) | 177 | violation_check = (function == FILE_CHECK && |
| 178 | (ima_policy_flag & IMA_MEASURE)); | ||
| 179 | if (!action && !violation_check) | ||
| 180 | return 0; | 180 | return 0; |
| 181 | 181 | ||
| 182 | must_appraise = action & IMA_APPRAISE; | 182 | must_appraise = action & IMA_APPRAISE; |
| @@ -187,9 +187,19 @@ static int process_measurement(struct file *file, int mask, int function, | |||
| 187 | 187 | ||
| 188 | mutex_lock(&inode->i_mutex); | 188 | mutex_lock(&inode->i_mutex); |
| 189 | 189 | ||
| 190 | iint = integrity_inode_get(inode); | 190 | if (action) { |
| 191 | if (!iint) | 191 | iint = integrity_inode_get(inode); |
| 192 | goto out; | 192 | if (!iint) |
| 193 | goto out; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (violation_check) { | ||
| 197 | ima_rdwr_violation_check(file, iint, &pathbuf, &pathname); | ||
| 198 | if (!action) { | ||
| 199 | rc = 0; | ||
| 200 | goto out_free; | ||
| 201 | } | ||
| 202 | } | ||
| 193 | 203 | ||
| 194 | /* Determine if already appraised/measured based on bitmask | 204 | /* Determine if already appraised/measured based on bitmask |
| 195 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, | 205 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, |
| @@ -218,7 +228,8 @@ static int process_measurement(struct file *file, int mask, int function, | |||
| 218 | goto out_digsig; | 228 | goto out_digsig; |
| 219 | } | 229 | } |
| 220 | 230 | ||
| 221 | pathname = ima_d_path(&file->f_path, &pathbuf); | 231 | if (!pathname) /* ima_rdwr_violation possibly pre-fetched */ |
| 232 | pathname = ima_d_path(&file->f_path, &pathbuf); | ||
| 222 | 233 | ||
| 223 | if (action & IMA_MEASURE) | 234 | if (action & IMA_MEASURE) |
| 224 | ima_store_measurement(iint, file, pathname, | 235 | ima_store_measurement(iint, file, pathname, |
| @@ -228,13 +239,15 @@ static int process_measurement(struct file *file, int mask, int function, | |||
| 228 | xattr_value, xattr_len, opened); | 239 | xattr_value, xattr_len, opened); |
| 229 | if (action & IMA_AUDIT) | 240 | if (action & IMA_AUDIT) |
| 230 | ima_audit_measurement(iint, pathname); | 241 | ima_audit_measurement(iint, pathname); |
| 231 | kfree(pathbuf); | 242 | |
| 232 | out_digsig: | 243 | out_digsig: |
| 233 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) | 244 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) |
| 234 | rc = -EACCES; | 245 | rc = -EACCES; |
| 246 | kfree(xattr_value); | ||
| 247 | out_free: | ||
| 248 | kfree(pathbuf); | ||
| 235 | out: | 249 | out: |
| 236 | mutex_unlock(&inode->i_mutex); | 250 | mutex_unlock(&inode->i_mutex); |
| 237 | kfree(xattr_value); | ||
| 238 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) | 251 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) |
| 239 | return -EACCES; | 252 | return -EACCES; |
| 240 | return 0; | 253 | return 0; |
| @@ -288,7 +301,6 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
| 288 | */ | 301 | */ |
| 289 | int ima_file_check(struct file *file, int mask, int opened) | 302 | int ima_file_check(struct file *file, int mask, int opened) |
| 290 | { | 303 | { |
| 291 | ima_rdwr_violation_check(file); | ||
| 292 | return process_measurement(file, | 304 | return process_measurement(file, |
| 293 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 305 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
| 294 | FILE_CHECK, opened); | 306 | FILE_CHECK, opened); |
