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

ima: read and use signature hash algorithm

All files on the filesystem, currently, are hashed using the same hash
algorithm. In preparation for files from different packages being
signed using different hash algorithms, this patch adds support for
reading the signature hash algorithm from the 'security.ima' extended
attribute and calculates the appropriate file data hash based on it.

Changelog:
- fix scripts Lindent and checkpatch msgs - Mimi
- fix md5 support for older version, which occupied 20 bytes in the
xattr, not the expected 16 bytes. Fix the comparison to compare
only the first 16 bytes.

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

authored by

Dmitry Kasatkin and committed by
Mimi Zohar
d3634d0f c7c8bb23

+94 -25
-11
security/integrity/digsig_asymmetric.c
··· 20 20 #include "integrity.h" 21 21 22 22 /* 23 - * signature format v2 - for using with asymmetric keys 24 - */ 25 - struct signature_v2_hdr { 26 - uint8_t version; /* signature format version */ 27 - uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ 28 - uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/ 29 - uint16_t sig_size; /* signature size */ 30 - uint8_t sig[0]; /* signature payload */ 31 - } __packed; 32 - 33 - /* 34 23 * Request an asymmetric key. 35 24 */ 36 25 static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
+26 -3
security/integrity/ima/ima.h
··· 99 99 int ima_get_action(struct inode *inode, int mask, int function); 100 100 int ima_must_measure(struct inode *inode, int mask, int function); 101 101 int ima_collect_measurement(struct integrity_iint_cache *iint, 102 - struct file *file); 102 + struct file *file, 103 + struct evm_ima_xattr_data **xattr_value, 104 + int *xattr_len); 103 105 void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, 104 106 const unsigned char *filename); 105 107 void ima_audit_measurement(struct integrity_iint_cache *iint, ··· 134 132 135 133 #ifdef CONFIG_IMA_APPRAISE 136 134 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, 137 - struct file *file, const unsigned char *filename); 135 + struct file *file, const unsigned char *filename, 136 + struct evm_ima_xattr_data *xattr_value, 137 + int xattr_len); 138 138 int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); 139 139 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); 140 140 enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, 141 141 int func); 142 + void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, 143 + struct ima_digest_data *hash); 144 + int ima_read_xattr(struct dentry *dentry, 145 + struct evm_ima_xattr_data **xattr_value); 142 146 143 147 #else 144 148 static inline int ima_appraise_measurement(int func, 145 149 struct integrity_iint_cache *iint, 146 150 struct file *file, 147 - const unsigned char *filename) 151 + const unsigned char *filename, 152 + struct evm_ima_xattr_data *xattr_value, 153 + int xattr_len) 148 154 { 149 155 return INTEGRITY_UNKNOWN; 150 156 } ··· 173 163 { 174 164 return INTEGRITY_UNKNOWN; 175 165 } 166 + 167 + static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, 168 + int xattr_len, 169 + struct ima_digest_data *hash) 170 + { 171 + } 172 + 173 + static inline int ima_read_xattr(struct dentry *dentry, 174 + struct evm_ima_xattr_data **xattr_value) 175 + { 176 + return 0; 177 + } 178 + 176 179 #endif 177 180 178 181 /* LSM based policy rules require audit */
+11 -1
security/integrity/ima/ima_api.c
··· 139 139 * Return 0 on success, error code otherwise 140 140 */ 141 141 int ima_collect_measurement(struct integrity_iint_cache *iint, 142 - struct file *file) 142 + struct file *file, 143 + struct evm_ima_xattr_data **xattr_value, 144 + int *xattr_len) 143 145 { 144 146 struct inode *inode = file_inode(file); 145 147 const char *filename = file->f_dentry->d_name.name; 146 148 int result = 0; 149 + 150 + if (xattr_value) 151 + *xattr_len = ima_read_xattr(file->f_dentry, xattr_value); 147 152 148 153 if (!(iint->flags & IMA_COLLECTED)) { 149 154 u64 i_version = file_inode(file)->i_version; 150 155 151 156 /* use default hash algorithm */ 152 157 iint->ima_hash.algo = ima_hash_algo; 158 + 159 + if (xattr_value) 160 + ima_get_hash_algo(*xattr_value, *xattr_len, 161 + &iint->ima_hash); 162 + 153 163 result = ima_calc_file_hash(file, &iint->ima_hash); 154 164 if (!result) { 155 165 iint->version = i_version;
+37 -8
security/integrity/ima/ima_appraise.c
··· 107 107 } 108 108 } 109 109 110 + void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, 111 + struct ima_digest_data *hash) 112 + { 113 + struct signature_v2_hdr *sig; 114 + 115 + if (!xattr_value || xattr_len < 0 || xattr_len <= 1 + sizeof(*sig)) 116 + return; 117 + 118 + sig = (typeof(sig)) xattr_value->digest; 119 + 120 + if (xattr_value->type != EVM_IMA_XATTR_DIGSIG || sig->version != 2) 121 + return; 122 + 123 + hash->algo = sig->hash_algo; 124 + } 125 + 126 + int ima_read_xattr(struct dentry *dentry, 127 + struct evm_ima_xattr_data **xattr_value) 128 + { 129 + struct inode *inode = dentry->d_inode; 130 + 131 + if (!inode->i_op->getxattr) 132 + return 0; 133 + 134 + return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, 135 + 0, GFP_NOFS); 136 + } 137 + 110 138 /* 111 139 * ima_appraise_measurement - appraise file measurement 112 140 * ··· 144 116 * Return 0 on success, error code otherwise 145 117 */ 146 118 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, 147 - struct file *file, const unsigned char *filename) 119 + struct file *file, const unsigned char *filename, 120 + struct evm_ima_xattr_data *xattr_value, 121 + int xattr_len) 148 122 { 149 123 struct dentry *dentry = file->f_dentry; 150 124 struct inode *inode = dentry->d_inode; 151 - struct evm_ima_xattr_data *xattr_value = NULL; 152 125 enum integrity_status status = INTEGRITY_UNKNOWN; 153 126 const char *op = "appraise_data"; 154 127 char *cause = "unknown"; 155 - int rc; 128 + int rc = xattr_len; 156 129 157 130 if (!ima_appraise) 158 131 return 0; 159 132 if (!inode->i_op->getxattr) 160 133 return INTEGRITY_UNKNOWN; 161 134 162 - rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, 163 - 0, GFP_NOFS); 164 135 if (rc <= 0) { 165 136 if (rc && rc != -ENODATA) 166 137 goto out; ··· 186 159 status = INTEGRITY_FAIL; 187 160 break; 188 161 } 189 - if (rc - 1 == iint->ima_hash.length) 162 + if (xattr_len - 1 >= iint->ima_hash.length) 163 + /* xattr length may be longer. md5 hash in previous 164 + version occupied 20 bytes in xattr, instead of 16 165 + */ 190 166 rc = memcmp(xattr_value->digest, 191 167 iint->ima_hash.digest, 192 168 iint->ima_hash.length); ··· 237 207 ima_cache_flags(iint, func); 238 208 } 239 209 ima_set_cache_status(iint, func, status); 240 - kfree(xattr_value); 241 210 return status; 242 211 } 243 212 ··· 252 223 if (iint->flags & IMA_DIGSIG) 253 224 return; 254 225 255 - rc = ima_collect_measurement(iint, file); 226 + rc = ima_collect_measurement(iint, file, NULL, NULL); 256 227 if (rc < 0) 257 228 return; 258 229
+9 -2
security/integrity/ima/ima_main.c
··· 149 149 char *pathbuf = NULL; 150 150 const char *pathname = NULL; 151 151 int rc = -ENOMEM, action, must_appraise, _func; 152 + struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; 153 + int xattr_len = 0; 152 154 153 155 if (!ima_initialized || !S_ISREG(inode->i_mode)) 154 156 return 0; ··· 189 187 goto out_digsig; 190 188 } 191 189 192 - rc = ima_collect_measurement(iint, file); 190 + if (action & IMA_APPRAISE_SUBMASK) 191 + xattr_ptr = &xattr_value; 192 + 193 + rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); 193 194 if (rc != 0) 194 195 goto out_digsig; 195 196 ··· 203 198 if (action & IMA_MEASURE) 204 199 ima_store_measurement(iint, file, pathname); 205 200 if (action & IMA_APPRAISE_SUBMASK) 206 - rc = ima_appraise_measurement(_func, iint, file, pathname); 201 + rc = ima_appraise_measurement(_func, iint, file, pathname, 202 + xattr_value, xattr_len); 207 203 if (action & IMA_AUDIT) 208 204 ima_audit_measurement(iint, pathname); 209 205 kfree(pathbuf); ··· 213 207 rc = -EACCES; 214 208 out: 215 209 mutex_unlock(&inode->i_mutex); 210 + kfree(xattr_value); 216 211 if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) 217 212 return -EACCES; 218 213 return 0;
+11
security/integrity/integrity.h
··· 70 70 u8 digest[IMA_MAX_DIGEST_SIZE]; 71 71 } __packed; 72 72 73 + /* 74 + * signature format v2 - for using with asymmetric keys 75 + */ 76 + struct signature_v2_hdr { 77 + uint8_t version; /* signature format version */ 78 + uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ 79 + uint32_t keyid; /* IMA key identifier - not X509/PGP specific */ 80 + uint16_t sig_size; /* signature size */ 81 + uint8_t sig[0]; /* signature payload */ 82 + } __packed; 83 + 73 84 /* integrity data associated with an inode */ 74 85 struct integrity_iint_cache { 75 86 struct rb_node rb_node; /* rooted in integrity_iint_tree */