Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ima: per hook cache integrity appraisal status

With the new IMA policy 'appraise_type=' option, different hooks
can require different methods for appraising a file's integrity.

For example, the existing 'ima_appraise_tcb' policy defines a
generic rule, requiring all root files to be appraised, without
specfying the appraisal method. A more specific rule could require
all kernel modules, for example, to be signed.

appraise fowner=0 func=MODULE_CHECK appraise_type=imasig
appraise fowner=0

As a result, the integrity appraisal results for the same inode, but
for different hooks, could differ. This patch caches the integrity
appraisal results on a per hook basis.

Changelog v2:
- Rename ima_cache_status() to ima_set_cache_status()
- Rename and move get_appraise_status() to ima_get_cache_status()
Changelog v0:
- include IMA_APPRAISE/APPRAISED_SUBMASK in IMA_DO/DONE_MASK (Dmitry)
- Support independent MODULE_CHECK appraise status.
- fixed IMA_XXXX_APPRAISE/APPRAISED flags

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>

+136 -25
+8 -2
security/integrity/iint.c
··· 72 72 { 73 73 iint->version = 0; 74 74 iint->flags = 0UL; 75 - iint->ima_status = INTEGRITY_UNKNOWN; 75 + iint->ima_file_status = INTEGRITY_UNKNOWN; 76 + iint->ima_mmap_status = INTEGRITY_UNKNOWN; 77 + iint->ima_bprm_status = INTEGRITY_UNKNOWN; 78 + iint->ima_module_status = INTEGRITY_UNKNOWN; 76 79 iint->evm_status = INTEGRITY_UNKNOWN; 77 80 kmem_cache_free(iint_cache, iint); 78 81 } ··· 152 149 memset(iint, 0, sizeof *iint); 153 150 iint->version = 0; 154 151 iint->flags = 0UL; 155 - iint->ima_status = INTEGRITY_UNKNOWN; 152 + iint->ima_file_status = INTEGRITY_UNKNOWN; 153 + iint->ima_mmap_status = INTEGRITY_UNKNOWN; 154 + iint->ima_bprm_status = INTEGRITY_UNKNOWN; 155 + iint->ima_module_status = INTEGRITY_UNKNOWN; 156 156 iint->evm_status = INTEGRITY_UNKNOWN; 157 157 } 158 158
+11 -2
security/integrity/ima/ima.h
··· 142 142 #define IMA_APPRAISE_FIX 0x02 143 143 144 144 #ifdef CONFIG_IMA_APPRAISE 145 - int ima_appraise_measurement(struct integrity_iint_cache *iint, 145 + int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, 146 146 struct file *file, const unsigned char *filename); 147 147 int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); 148 148 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); 149 + enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, 150 + int func); 149 151 150 152 #else 151 - static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, 153 + static inline int ima_appraise_measurement(int func, 154 + struct integrity_iint_cache *iint, 152 155 struct file *file, 153 156 const unsigned char *filename) 154 157 { ··· 167 164 static inline void ima_update_xattr(struct integrity_iint_cache *iint, 168 165 struct file *file) 169 166 { 167 + } 168 + 169 + static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache 170 + *iint, int func) 171 + { 172 + return INTEGRITY_UNKNOWN; 170 173 } 171 174 #endif 172 175
+62 -9
security/integrity/ima/ima_appraise.c
··· 51 51 sizeof(iint->ima_xattr), 0); 52 52 } 53 53 54 + /* Return specific func appraised cached result */ 55 + enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, 56 + int func) 57 + { 58 + switch(func) { 59 + case MMAP_CHECK: 60 + return iint->ima_mmap_status; 61 + case BPRM_CHECK: 62 + return iint->ima_bprm_status; 63 + case MODULE_CHECK: 64 + return iint->ima_module_status; 65 + case FILE_CHECK: 66 + default: 67 + return iint->ima_file_status; 68 + } 69 + } 70 + 71 + static void ima_set_cache_status(struct integrity_iint_cache *iint, 72 + int func, enum integrity_status status) 73 + { 74 + switch(func) { 75 + case MMAP_CHECK: 76 + iint->ima_mmap_status = status; 77 + break; 78 + case BPRM_CHECK: 79 + iint->ima_bprm_status = status; 80 + break; 81 + case MODULE_CHECK: 82 + iint->ima_module_status = status; 83 + break; 84 + case FILE_CHECK: 85 + default: 86 + iint->ima_file_status = status; 87 + break; 88 + } 89 + } 90 + 91 + static void ima_cache_flags(struct integrity_iint_cache *iint, int func) 92 + { 93 + switch(func) { 94 + case MMAP_CHECK: 95 + iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); 96 + break; 97 + case BPRM_CHECK: 98 + iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED); 99 + break; 100 + case MODULE_CHECK: 101 + iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); 102 + break; 103 + case FILE_CHECK: 104 + default: 105 + iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); 106 + break; 107 + } 108 + } 109 + 54 110 /* 55 111 * ima_appraise_measurement - appraise file measurement 56 112 * ··· 115 59 * 116 60 * Return 0 on success, error code otherwise 117 61 */ 118 - int ima_appraise_measurement(struct integrity_iint_cache *iint, 62 + int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, 119 63 struct file *file, const unsigned char *filename) 120 64 { 121 65 struct dentry *dentry = file->f_dentry; ··· 130 74 return 0; 131 75 if (!inode->i_op->getxattr) 132 76 return INTEGRITY_UNKNOWN; 133 - 134 - if (iint->flags & IMA_APPRAISED) 135 - return iint->ima_status; 136 77 137 78 rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, 138 79 0, GFP_NOFS); ··· 152 99 cause = "invalid-HMAC"; 153 100 goto out; 154 101 } 155 - 156 102 switch (xattr_value->type) { 157 103 case IMA_XATTR_DIGEST: 158 104 if (iint->flags & IMA_DIGSIG_REQUIRED) { ··· 200 148 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, 201 149 op, cause, rc, 0); 202 150 } else { 203 - iint->flags |= IMA_APPRAISED; 151 + ima_cache_flags(iint, func); 204 152 } 205 - iint->ima_status = status; 153 + ima_set_cache_status(iint, func, status); 206 154 kfree(xattr_value); 207 155 return status; 208 156 } ··· 248 196 must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); 249 197 iint = integrity_iint_find(inode); 250 198 if (iint) { 199 + iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | 200 + IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | 201 + IMA_ACTION_FLAGS); 251 202 if (must_appraise) 252 203 iint->flags |= IMA_APPRAISE; 253 - else 254 - iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); 255 204 } 256 205 if (!must_appraise) 257 206 rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
+11 -8
security/integrity/ima/ima_main.c
··· 151 151 if (!ima_initialized || !S_ISREG(inode->i_mode)) 152 152 return 0; 153 153 154 - /* Determine if in appraise/audit/measurement policy, 155 - * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */ 154 + /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action 155 + * bitmask based on the appraise/audit/measurement policy. 156 + * Included is the appraise submask. 157 + */ 156 158 action = ima_get_action(inode, mask, function); 157 159 if (!action) 158 160 return 0; ··· 168 166 goto out; 169 167 170 168 /* Determine if already appraised/measured based on bitmask 171 - * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, 172 - * IMA_AUDIT, IMA_AUDITED) */ 169 + * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, 170 + * IMA_AUDIT, IMA_AUDITED) 171 + */ 173 172 iint->flags |= action; 174 173 action &= IMA_DO_MASK; 175 174 action &= ~((iint->flags & IMA_DONE_MASK) >> 1); 176 175 177 176 /* Nothing to do, just return existing appraised status */ 178 177 if (!action) { 179 - if (iint->flags & IMA_APPRAISED) 180 - rc = iint->ima_status; 178 + if (must_appraise) 179 + rc = ima_get_cache_status(iint, function); 181 180 goto out_digsig; 182 181 } 183 182 ··· 194 191 195 192 if (action & IMA_MEASURE) 196 193 ima_store_measurement(iint, file, pathname); 197 - if (action & IMA_APPRAISE) 198 - rc = ima_appraise_measurement(iint, file, pathname); 194 + if (action & IMA_APPRAISE_SUBMASK) 195 + rc = ima_appraise_measurement(function, iint, file, pathname); 199 196 if (action & IMA_AUDIT) 200 197 ima_audit_measurement(iint, pathname); 201 198 kfree(pathbuf);
+22
security/integrity/ima/ima_policy.c
··· 218 218 return true; 219 219 } 220 220 221 + /* 222 + * In addition to knowing that we need to appraise the file in general, 223 + * we need to differentiate between calling hooks. 224 + */ 225 + static int get_subaction(int func) 226 + { 227 + switch(func) { 228 + case MMAP_CHECK: 229 + return IMA_MMAP_APPRAISE; 230 + case BPRM_CHECK: 231 + return IMA_BPRM_APPRAISE; 232 + case MODULE_CHECK: 233 + return IMA_MODULE_APPRAISE; 234 + case FILE_CHECK: 235 + default: 236 + return IMA_FILE_APPRAISE; 237 + } 238 + } 239 + 221 240 /** 222 241 * ima_match_policy - decision based on LSM and other conditions 223 242 * @inode: pointer to an inode for which the policy decision is being made ··· 267 248 action |= entry->flags & IMA_ACTION_FLAGS; 268 249 269 250 action |= entry->action & IMA_DO_MASK; 251 + if (entry->action & IMA_APPRAISE) 252 + action |= get_subaction(func); 253 + 270 254 if (entry->action & IMA_DO_MASK) 271 255 actmask &= ~(entry->action | entry->action << 1); 272 256 else
+22 -4
security/integrity/integrity.h
··· 30 30 #define IMA_DIGSIG 0x01000000 31 31 #define IMA_DIGSIG_REQUIRED 0x02000000 32 32 33 - #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) 34 - #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ 35 - | IMA_COLLECTED) 33 + #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ 34 + IMA_APPRAISE_SUBMASK) 35 + #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \ 36 + IMA_COLLECTED | IMA_APPRAISED_SUBMASK) 37 + 38 + /* iint subaction appraise cache flags */ 39 + #define IMA_FILE_APPRAISE 0x00000100 40 + #define IMA_FILE_APPRAISED 0x00000200 41 + #define IMA_MMAP_APPRAISE 0x00000400 42 + #define IMA_MMAP_APPRAISED 0x00000800 43 + #define IMA_BPRM_APPRAISE 0x00001000 44 + #define IMA_BPRM_APPRAISED 0x00002000 45 + #define IMA_MODULE_APPRAISE 0x00004000 46 + #define IMA_MODULE_APPRAISED 0x00008000 47 + #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ 48 + IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE) 49 + #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ 50 + IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED) 36 51 37 52 enum evm_ima_xattr_type { 38 53 IMA_XATTR_DIGEST = 0x01, ··· 67 52 u64 version; /* track inode changes */ 68 53 unsigned long flags; 69 54 struct evm_ima_xattr_data ima_xattr; 70 - enum integrity_status ima_status:4; 55 + enum integrity_status ima_file_status:4; 56 + enum integrity_status ima_mmap_status:4; 57 + enum integrity_status ima_bprm_status:4; 58 + enum integrity_status ima_module_status:4; 71 59 enum integrity_status evm_status:4; 72 60 }; 73 61