diff options
Diffstat (limited to 'security/integrity/ima/ima_appraise.c')
| -rw-r--r-- | security/integrity/ima/ima_appraise.c | 106 |
1 files changed, 86 insertions, 20 deletions
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 2d4becab8918..734e9468aca0 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/magic.h> | 15 | #include <linux/magic.h> |
| 16 | #include <linux/ima.h> | 16 | #include <linux/ima.h> |
| 17 | #include <linux/evm.h> | 17 | #include <linux/evm.h> |
| 18 | #include <crypto/hash_info.h> | ||
| 18 | 19 | ||
| 19 | #include "ima.h" | 20 | #include "ima.h" |
| 20 | 21 | ||
| @@ -43,19 +44,31 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) | |||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | static int ima_fix_xattr(struct dentry *dentry, | 46 | static int ima_fix_xattr(struct dentry *dentry, |
| 46 | struct integrity_iint_cache *iint) | 47 | struct integrity_iint_cache *iint) |
| 47 | { | 48 | { |
| 48 | iint->ima_xattr.type = IMA_XATTR_DIGEST; | 49 | int rc, offset; |
| 49 | return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | 50 | u8 algo = iint->ima_hash->algo; |
| 50 | (u8 *)&iint->ima_xattr, | 51 | |
| 51 | sizeof(iint->ima_xattr), 0); | 52 | if (algo <= HASH_ALGO_SHA1) { |
| 53 | offset = 1; | ||
| 54 | iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST; | ||
| 55 | } else { | ||
| 56 | offset = 0; | ||
| 57 | iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; | ||
| 58 | iint->ima_hash->xattr.ng.algo = algo; | ||
| 59 | } | ||
| 60 | rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | ||
| 61 | &iint->ima_hash->xattr.data[offset], | ||
| 62 | (sizeof(iint->ima_hash->xattr) - offset) + | ||
| 63 | iint->ima_hash->length, 0); | ||
| 64 | return rc; | ||
| 52 | } | 65 | } |
| 53 | 66 | ||
| 54 | /* Return specific func appraised cached result */ | 67 | /* Return specific func appraised cached result */ |
| 55 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | 68 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, |
| 56 | int func) | 69 | int func) |
| 57 | { | 70 | { |
| 58 | switch(func) { | 71 | switch (func) { |
| 59 | case MMAP_CHECK: | 72 | case MMAP_CHECK: |
| 60 | return iint->ima_mmap_status; | 73 | return iint->ima_mmap_status; |
| 61 | case BPRM_CHECK: | 74 | case BPRM_CHECK: |
| @@ -71,7 +84,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | |||
| 71 | static void ima_set_cache_status(struct integrity_iint_cache *iint, | 84 | static void ima_set_cache_status(struct integrity_iint_cache *iint, |
| 72 | int func, enum integrity_status status) | 85 | int func, enum integrity_status status) |
| 73 | { | 86 | { |
| 74 | switch(func) { | 87 | switch (func) { |
| 75 | case MMAP_CHECK: | 88 | case MMAP_CHECK: |
| 76 | iint->ima_mmap_status = status; | 89 | iint->ima_mmap_status = status; |
| 77 | break; | 90 | break; |
| @@ -90,7 +103,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, | |||
| 90 | 103 | ||
| 91 | static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | 104 | static void ima_cache_flags(struct integrity_iint_cache *iint, int func) |
| 92 | { | 105 | { |
| 93 | switch(func) { | 106 | switch (func) { |
| 94 | case MMAP_CHECK: | 107 | case MMAP_CHECK: |
| 95 | iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); | 108 | iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); |
| 96 | break; | 109 | break; |
| @@ -107,6 +120,50 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 107 | } | 120 | } |
| 108 | } | 121 | } |
| 109 | 122 | ||
| 123 | void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 124 | struct ima_digest_data *hash) | ||
| 125 | { | ||
| 126 | struct signature_v2_hdr *sig; | ||
| 127 | |||
| 128 | if (!xattr_value || xattr_len < 2) | ||
| 129 | return; | ||
| 130 | |||
| 131 | switch (xattr_value->type) { | ||
| 132 | case EVM_IMA_XATTR_DIGSIG: | ||
| 133 | sig = (typeof(sig))xattr_value; | ||
| 134 | if (sig->version != 2 || xattr_len <= sizeof(*sig)) | ||
| 135 | return; | ||
| 136 | hash->algo = sig->hash_algo; | ||
| 137 | break; | ||
| 138 | case IMA_XATTR_DIGEST_NG: | ||
| 139 | hash->algo = xattr_value->digest[0]; | ||
| 140 | break; | ||
| 141 | case IMA_XATTR_DIGEST: | ||
| 142 | /* this is for backward compatibility */ | ||
| 143 | if (xattr_len == 21) { | ||
| 144 | unsigned int zero = 0; | ||
| 145 | if (!memcmp(&xattr_value->digest[16], &zero, 4)) | ||
| 146 | hash->algo = HASH_ALGO_MD5; | ||
| 147 | else | ||
| 148 | hash->algo = HASH_ALGO_SHA1; | ||
| 149 | } else if (xattr_len == 17) | ||
| 150 | hash->algo = HASH_ALGO_MD5; | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | int ima_read_xattr(struct dentry *dentry, | ||
| 156 | struct evm_ima_xattr_data **xattr_value) | ||
| 157 | { | ||
| 158 | struct inode *inode = dentry->d_inode; | ||
| 159 | |||
| 160 | if (!inode->i_op->getxattr) | ||
| 161 | return 0; | ||
| 162 | |||
| 163 | return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, | ||
| 164 | 0, GFP_NOFS); | ||
| 165 | } | ||
| 166 | |||
| 110 | /* | 167 | /* |
| 111 | * ima_appraise_measurement - appraise file measurement | 168 | * ima_appraise_measurement - appraise file measurement |
| 112 | * | 169 | * |
| @@ -116,23 +173,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 116 | * Return 0 on success, error code otherwise | 173 | * Return 0 on success, error code otherwise |
| 117 | */ | 174 | */ |
| 118 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 175 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
| 119 | struct file *file, const unsigned char *filename) | 176 | struct file *file, const unsigned char *filename, |
| 177 | struct evm_ima_xattr_data *xattr_value, | ||
| 178 | int xattr_len) | ||
| 120 | { | 179 | { |
| 121 | struct dentry *dentry = file->f_dentry; | 180 | struct dentry *dentry = file->f_dentry; |
| 122 | struct inode *inode = dentry->d_inode; | 181 | struct inode *inode = dentry->d_inode; |
| 123 | struct evm_ima_xattr_data *xattr_value = NULL; | ||
| 124 | enum integrity_status status = INTEGRITY_UNKNOWN; | 182 | enum integrity_status status = INTEGRITY_UNKNOWN; |
| 125 | const char *op = "appraise_data"; | 183 | const char *op = "appraise_data"; |
| 126 | char *cause = "unknown"; | 184 | char *cause = "unknown"; |
| 127 | int rc; | 185 | int rc = xattr_len, hash_start = 0; |
| 128 | 186 | ||
| 129 | if (!ima_appraise) | 187 | if (!ima_appraise) |
| 130 | return 0; | 188 | return 0; |
| 131 | if (!inode->i_op->getxattr) | 189 | if (!inode->i_op->getxattr) |
| 132 | return INTEGRITY_UNKNOWN; | 190 | return INTEGRITY_UNKNOWN; |
| 133 | 191 | ||
| 134 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, | ||
| 135 | 0, GFP_NOFS); | ||
| 136 | if (rc <= 0) { | 192 | if (rc <= 0) { |
| 137 | if (rc && rc != -ENODATA) | 193 | if (rc && rc != -ENODATA) |
| 138 | goto out; | 194 | goto out; |
| @@ -153,14 +209,25 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
| 153 | goto out; | 209 | goto out; |
| 154 | } | 210 | } |
| 155 | switch (xattr_value->type) { | 211 | switch (xattr_value->type) { |
| 212 | case IMA_XATTR_DIGEST_NG: | ||
| 213 | /* first byte contains algorithm id */ | ||
| 214 | hash_start = 1; | ||
| 156 | case IMA_XATTR_DIGEST: | 215 | case IMA_XATTR_DIGEST: |
| 157 | if (iint->flags & IMA_DIGSIG_REQUIRED) { | 216 | if (iint->flags & IMA_DIGSIG_REQUIRED) { |
| 158 | cause = "IMA signature required"; | 217 | cause = "IMA signature required"; |
| 159 | status = INTEGRITY_FAIL; | 218 | status = INTEGRITY_FAIL; |
| 160 | break; | 219 | break; |
| 161 | } | 220 | } |
| 162 | rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, | 221 | if (xattr_len - sizeof(xattr_value->type) - hash_start >= |
| 163 | IMA_DIGEST_SIZE); | 222 | iint->ima_hash->length) |
| 223 | /* xattr length may be longer. md5 hash in previous | ||
| 224 | version occupied 20 bytes in xattr, instead of 16 | ||
| 225 | */ | ||
| 226 | rc = memcmp(&xattr_value->digest[hash_start], | ||
| 227 | iint->ima_hash->digest, | ||
| 228 | iint->ima_hash->length); | ||
| 229 | else | ||
| 230 | rc = -EINVAL; | ||
| 164 | if (rc) { | 231 | if (rc) { |
| 165 | cause = "invalid-hash"; | 232 | cause = "invalid-hash"; |
| 166 | status = INTEGRITY_FAIL; | 233 | status = INTEGRITY_FAIL; |
| @@ -171,9 +238,9 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
| 171 | case EVM_IMA_XATTR_DIGSIG: | 238 | case EVM_IMA_XATTR_DIGSIG: |
| 172 | iint->flags |= IMA_DIGSIG; | 239 | iint->flags |= IMA_DIGSIG; |
| 173 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | 240 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, |
| 174 | xattr_value->digest, rc - 1, | 241 | (const char *)xattr_value, rc, |
| 175 | iint->ima_xattr.digest, | 242 | iint->ima_hash->digest, |
| 176 | IMA_DIGEST_SIZE); | 243 | iint->ima_hash->length); |
| 177 | if (rc == -EOPNOTSUPP) { | 244 | if (rc == -EOPNOTSUPP) { |
| 178 | status = INTEGRITY_UNKNOWN; | 245 | status = INTEGRITY_UNKNOWN; |
| 179 | } else if (rc) { | 246 | } else if (rc) { |
| @@ -203,7 +270,6 @@ out: | |||
| 203 | ima_cache_flags(iint, func); | 270 | ima_cache_flags(iint, func); |
| 204 | } | 271 | } |
| 205 | ima_set_cache_status(iint, func, status); | 272 | ima_set_cache_status(iint, func, status); |
| 206 | kfree(xattr_value); | ||
| 207 | return status; | 273 | return status; |
| 208 | } | 274 | } |
| 209 | 275 | ||
| @@ -219,7 +285,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | |||
| 219 | if (iint->flags & IMA_DIGSIG) | 285 | if (iint->flags & IMA_DIGSIG) |
| 220 | return; | 286 | return; |
| 221 | 287 | ||
| 222 | rc = ima_collect_measurement(iint, file); | 288 | rc = ima_collect_measurement(iint, file, NULL, NULL); |
| 223 | if (rc < 0) | 289 | if (rc < 0) |
| 224 | return; | 290 | return; |
| 225 | 291 | ||
