diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/integrity/digsig_asymmetric.c | 11 | ||||
| -rw-r--r-- | security/integrity/ima/ima.h | 29 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 12 | ||||
| -rw-r--r-- | security/integrity/ima/ima_appraise.c | 45 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 11 | ||||
| -rw-r--r-- | security/integrity/integrity.h | 11 |
6 files changed, 94 insertions, 25 deletions
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index b4754667659d..9eae4809006b 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c | |||
| @@ -20,17 +20,6 @@ | |||
| 20 | #include "integrity.h" | 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 | * Request an asymmetric key. | 23 | * Request an asymmetric key. |
| 35 | */ | 24 | */ |
| 36 | static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) | 25 | static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index eb86032f4f1e..efcdef2bf1bc 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -99,7 +99,9 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
| 99 | int ima_get_action(struct inode *inode, int mask, int function); | 99 | int ima_get_action(struct inode *inode, int mask, int function); |
| 100 | int ima_must_measure(struct inode *inode, int mask, int function); | 100 | int ima_must_measure(struct inode *inode, int mask, int function); |
| 101 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 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 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, | 105 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, |
| 104 | const unsigned char *filename); | 106 | const unsigned char *filename); |
| 105 | void ima_audit_measurement(struct integrity_iint_cache *iint, | 107 | void ima_audit_measurement(struct integrity_iint_cache *iint, |
| @@ -132,17 +134,25 @@ void ima_delete_rules(void); | |||
| 132 | 134 | ||
| 133 | #ifdef CONFIG_IMA_APPRAISE | 135 | #ifdef CONFIG_IMA_APPRAISE |
| 134 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 136 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
| 135 | struct file *file, const unsigned char *filename); | 137 | struct file *file, const unsigned char *filename, |
| 138 | struct evm_ima_xattr_data *xattr_value, | ||
| 139 | int xattr_len); | ||
| 136 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); | 140 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); |
| 137 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); | 141 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); |
| 138 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | 142 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, |
| 139 | int func); | 143 | int func); |
| 144 | void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 145 | struct ima_digest_data *hash); | ||
| 146 | int ima_read_xattr(struct dentry *dentry, | ||
| 147 | struct evm_ima_xattr_data **xattr_value); | ||
| 140 | 148 | ||
| 141 | #else | 149 | #else |
| 142 | static inline int ima_appraise_measurement(int func, | 150 | static inline int ima_appraise_measurement(int func, |
| 143 | struct integrity_iint_cache *iint, | 151 | struct integrity_iint_cache *iint, |
| 144 | struct file *file, | 152 | struct file *file, |
| 145 | const unsigned char *filename) | 153 | const unsigned char *filename, |
| 154 | struct evm_ima_xattr_data *xattr_value, | ||
| 155 | int xattr_len) | ||
| 146 | { | 156 | { |
| 147 | return INTEGRITY_UNKNOWN; | 157 | return INTEGRITY_UNKNOWN; |
| 148 | } | 158 | } |
| @@ -163,6 +173,19 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c | |||
| 163 | { | 173 | { |
| 164 | return INTEGRITY_UNKNOWN; | 174 | return INTEGRITY_UNKNOWN; |
| 165 | } | 175 | } |
| 176 | |||
| 177 | static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, | ||
| 178 | int xattr_len, | ||
| 179 | struct ima_digest_data *hash) | ||
| 180 | { | ||
| 181 | } | ||
| 182 | |||
| 183 | static inline int ima_read_xattr(struct dentry *dentry, | ||
| 184 | struct evm_ima_xattr_data **xattr_value) | ||
| 185 | { | ||
| 186 | return 0; | ||
| 187 | } | ||
| 188 | |||
| 166 | #endif | 189 | #endif |
| 167 | 190 | ||
| 168 | /* LSM based policy rules require audit */ | 191 | /* LSM based policy rules require audit */ |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index e531fe22e582..1dba98e2d7e9 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -139,17 +139,27 @@ int ima_must_measure(struct inode *inode, int mask, int function) | |||
| 139 | * Return 0 on success, error code otherwise | 139 | * Return 0 on success, error code otherwise |
| 140 | */ | 140 | */ |
| 141 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 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 | struct inode *inode = file_inode(file); | 146 | struct inode *inode = file_inode(file); |
| 145 | const char *filename = file->f_dentry->d_name.name; | 147 | const char *filename = file->f_dentry->d_name.name; |
| 146 | int result = 0; | 148 | int result = 0; |
| 147 | 149 | ||
| 150 | if (xattr_value) | ||
| 151 | *xattr_len = ima_read_xattr(file->f_dentry, xattr_value); | ||
| 152 | |||
| 148 | if (!(iint->flags & IMA_COLLECTED)) { | 153 | if (!(iint->flags & IMA_COLLECTED)) { |
| 149 | u64 i_version = file_inode(file)->i_version; | 154 | u64 i_version = file_inode(file)->i_version; |
| 150 | 155 | ||
| 151 | /* use default hash algorithm */ | 156 | /* use default hash algorithm */ |
| 152 | iint->ima_hash.algo = ima_hash_algo; | 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 | result = ima_calc_file_hash(file, &iint->ima_hash); | 163 | result = ima_calc_file_hash(file, &iint->ima_hash); |
| 154 | if (!result) { | 164 | if (!result) { |
| 155 | iint->version = i_version; | 165 | iint->version = i_version; |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 3833b0fa7108..00708a3052cc 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -107,6 +107,34 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 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 | * ima_appraise_measurement - appraise file measurement | 139 | * ima_appraise_measurement - appraise file measurement |
| 112 | * | 140 | * |
| @@ -116,23 +144,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 116 | * Return 0 on success, error code otherwise | 144 | * Return 0 on success, error code otherwise |
| 117 | */ | 145 | */ |
| 118 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 146 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
| 119 | struct file *file, const unsigned char *filename) | 147 | struct file *file, const unsigned char *filename, |
| 148 | struct evm_ima_xattr_data *xattr_value, | ||
| 149 | int xattr_len) | ||
| 120 | { | 150 | { |
| 121 | struct dentry *dentry = file->f_dentry; | 151 | struct dentry *dentry = file->f_dentry; |
| 122 | struct inode *inode = dentry->d_inode; | 152 | struct inode *inode = dentry->d_inode; |
| 123 | struct evm_ima_xattr_data *xattr_value = NULL; | ||
| 124 | enum integrity_status status = INTEGRITY_UNKNOWN; | 153 | enum integrity_status status = INTEGRITY_UNKNOWN; |
| 125 | const char *op = "appraise_data"; | 154 | const char *op = "appraise_data"; |
| 126 | char *cause = "unknown"; | 155 | char *cause = "unknown"; |
| 127 | int rc; | 156 | int rc = xattr_len; |
| 128 | 157 | ||
| 129 | if (!ima_appraise) | 158 | if (!ima_appraise) |
| 130 | return 0; | 159 | return 0; |
| 131 | if (!inode->i_op->getxattr) | 160 | if (!inode->i_op->getxattr) |
| 132 | return INTEGRITY_UNKNOWN; | 161 | return INTEGRITY_UNKNOWN; |
| 133 | 162 | ||
| 134 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, | ||
| 135 | 0, GFP_NOFS); | ||
| 136 | if (rc <= 0) { | 163 | if (rc <= 0) { |
| 137 | if (rc && rc != -ENODATA) | 164 | if (rc && rc != -ENODATA) |
| 138 | goto out; | 165 | goto out; |
| @@ -159,7 +186,10 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
| 159 | status = INTEGRITY_FAIL; | 186 | status = INTEGRITY_FAIL; |
| 160 | break; | 187 | break; |
| 161 | } | 188 | } |
| 162 | if (rc - 1 == iint->ima_hash.length) | 189 | if (xattr_len - 1 >= iint->ima_hash.length) |
| 190 | /* xattr length may be longer. md5 hash in previous | ||
| 191 | version occupied 20 bytes in xattr, instead of 16 | ||
| 192 | */ | ||
| 163 | rc = memcmp(xattr_value->digest, | 193 | rc = memcmp(xattr_value->digest, |
| 164 | iint->ima_hash.digest, | 194 | iint->ima_hash.digest, |
| 165 | iint->ima_hash.length); | 195 | iint->ima_hash.length); |
| @@ -207,7 +237,6 @@ out: | |||
| 207 | ima_cache_flags(iint, func); | 237 | ima_cache_flags(iint, func); |
| 208 | } | 238 | } |
| 209 | ima_set_cache_status(iint, func, status); | 239 | ima_set_cache_status(iint, func, status); |
| 210 | kfree(xattr_value); | ||
| 211 | return status; | 240 | return status; |
| 212 | } | 241 | } |
| 213 | 242 | ||
| @@ -223,7 +252,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | |||
| 223 | if (iint->flags & IMA_DIGSIG) | 252 | if (iint->flags & IMA_DIGSIG) |
| 224 | return; | 253 | return; |
| 225 | 254 | ||
| 226 | rc = ima_collect_measurement(iint, file); | 255 | rc = ima_collect_measurement(iint, file, NULL, NULL); |
| 227 | if (rc < 0) | 256 | if (rc < 0) |
| 228 | return; | 257 | return; |
| 229 | 258 | ||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 7708c2120d9c..95b5df2c6501 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -149,6 +149,8 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 149 | char *pathbuf = NULL; | 149 | char *pathbuf = NULL; |
| 150 | const char *pathname = NULL; | 150 | const char *pathname = NULL; |
| 151 | int rc = -ENOMEM, action, must_appraise, _func; | 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 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 155 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
| 154 | return 0; | 156 | return 0; |
| @@ -187,7 +189,10 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 187 | goto out_digsig; | 189 | goto out_digsig; |
| 188 | } | 190 | } |
| 189 | 191 | ||
| 190 | rc = ima_collect_measurement(iint, file); | 192 | if (action & IMA_APPRAISE_SUBMASK) |
| 193 | xattr_ptr = &xattr_value; | ||
| 194 | |||
| 195 | rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); | ||
| 191 | if (rc != 0) | 196 | if (rc != 0) |
| 192 | goto out_digsig; | 197 | goto out_digsig; |
| 193 | 198 | ||
| @@ -198,7 +203,8 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 198 | if (action & IMA_MEASURE) | 203 | if (action & IMA_MEASURE) |
| 199 | ima_store_measurement(iint, file, pathname); | 204 | ima_store_measurement(iint, file, pathname); |
| 200 | if (action & IMA_APPRAISE_SUBMASK) | 205 | if (action & IMA_APPRAISE_SUBMASK) |
| 201 | rc = ima_appraise_measurement(_func, iint, file, pathname); | 206 | rc = ima_appraise_measurement(_func, iint, file, pathname, |
| 207 | xattr_value, xattr_len); | ||
| 202 | if (action & IMA_AUDIT) | 208 | if (action & IMA_AUDIT) |
| 203 | ima_audit_measurement(iint, pathname); | 209 | ima_audit_measurement(iint, pathname); |
| 204 | kfree(pathbuf); | 210 | kfree(pathbuf); |
| @@ -207,6 +213,7 @@ out_digsig: | |||
| 207 | rc = -EACCES; | 213 | rc = -EACCES; |
| 208 | out: | 214 | out: |
| 209 | mutex_unlock(&inode->i_mutex); | 215 | mutex_unlock(&inode->i_mutex); |
| 216 | kfree(xattr_value); | ||
| 210 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) | 217 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) |
| 211 | return -EACCES; | 218 | return -EACCES; |
| 212 | return 0; | 219 | return 0; |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 0b02ea868e30..ea2318983d97 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -70,6 +70,17 @@ struct ima_digest_data { | |||
| 70 | u8 digest[IMA_MAX_DIGEST_SIZE]; | 70 | u8 digest[IMA_MAX_DIGEST_SIZE]; |
| 71 | } __packed; | 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 | /* integrity data associated with an inode */ | 84 | /* integrity data associated with an inode */ |
| 74 | struct integrity_iint_cache { | 85 | struct integrity_iint_cache { |
| 75 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ | 86 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ |
