diff options
Diffstat (limited to 'security/integrity/evm/evm_main.c')
-rw-r--r-- | security/integrity/evm/evm_main.c | 94 |
1 files changed, 81 insertions, 13 deletions
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 92d3d99a9f7b..8901501425f4 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
@@ -25,6 +25,7 @@ | |||
25 | int evm_initialized; | 25 | int evm_initialized; |
26 | 26 | ||
27 | char *evm_hmac = "hmac(sha1)"; | 27 | char *evm_hmac = "hmac(sha1)"; |
28 | char *evm_hash = "sha1"; | ||
28 | 29 | ||
29 | char *evm_config_xattrnames[] = { | 30 | char *evm_config_xattrnames[] = { |
30 | #ifdef CONFIG_SECURITY_SELINUX | 31 | #ifdef CONFIG_SECURITY_SELINUX |
@@ -46,6 +47,29 @@ static int __init evm_set_fixmode(char *str) | |||
46 | } | 47 | } |
47 | __setup("evm=", evm_set_fixmode); | 48 | __setup("evm=", evm_set_fixmode); |
48 | 49 | ||
50 | static int evm_find_protected_xattrs(struct dentry *dentry) | ||
51 | { | ||
52 | struct inode *inode = dentry->d_inode; | ||
53 | char **xattr; | ||
54 | int error; | ||
55 | int count = 0; | ||
56 | |||
57 | if (!inode->i_op || !inode->i_op->getxattr) | ||
58 | return -EOPNOTSUPP; | ||
59 | |||
60 | for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { | ||
61 | error = inode->i_op->getxattr(dentry, *xattr, NULL, 0); | ||
62 | if (error < 0) { | ||
63 | if (error == -ENODATA) | ||
64 | continue; | ||
65 | return error; | ||
66 | } | ||
67 | count++; | ||
68 | } | ||
69 | |||
70 | return count; | ||
71 | } | ||
72 | |||
49 | /* | 73 | /* |
50 | * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr | 74 | * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr |
51 | * | 75 | * |
@@ -65,32 +89,72 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, | |||
65 | size_t xattr_value_len, | 89 | size_t xattr_value_len, |
66 | struct integrity_iint_cache *iint) | 90 | struct integrity_iint_cache *iint) |
67 | { | 91 | { |
68 | struct evm_ima_xattr_data xattr_data; | 92 | struct evm_ima_xattr_data *xattr_data = NULL; |
93 | struct evm_ima_xattr_data calc; | ||
69 | enum integrity_status evm_status = INTEGRITY_PASS; | 94 | enum integrity_status evm_status = INTEGRITY_PASS; |
70 | int rc; | 95 | int rc, xattr_len; |
71 | 96 | ||
72 | if (iint && iint->evm_status == INTEGRITY_PASS) | 97 | if (iint && iint->evm_status == INTEGRITY_PASS) |
73 | return iint->evm_status; | 98 | return iint->evm_status; |
74 | 99 | ||
75 | /* if status is not PASS, try to check again - against -ENOMEM */ | 100 | /* if status is not PASS, try to check again - against -ENOMEM */ |
76 | 101 | ||
77 | rc = evm_calc_hmac(dentry, xattr_name, xattr_value, | 102 | /* first need to know the sig type */ |
78 | xattr_value_len, xattr_data.digest); | 103 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0, |
79 | if (rc < 0) { | 104 | GFP_NOFS); |
80 | evm_status = (rc == -ENODATA) | 105 | if (rc <= 0) { |
81 | ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL; | 106 | if (rc == 0) |
107 | evm_status = INTEGRITY_FAIL; /* empty */ | ||
108 | else if (rc == -ENODATA) { | ||
109 | rc = evm_find_protected_xattrs(dentry); | ||
110 | if (rc > 0) | ||
111 | evm_status = INTEGRITY_NOLABEL; | ||
112 | else if (rc == 0) | ||
113 | evm_status = INTEGRITY_NOXATTRS; /* new file */ | ||
114 | } | ||
82 | goto out; | 115 | goto out; |
83 | } | 116 | } |
84 | 117 | ||
85 | xattr_data.type = EVM_XATTR_HMAC; | 118 | xattr_len = rc - 1; |
86 | rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data, | 119 | |
87 | sizeof xattr_data, GFP_NOFS); | 120 | /* check value type */ |
88 | if (rc < 0) | 121 | switch (xattr_data->type) { |
89 | evm_status = (rc == -ENODATA) | 122 | case EVM_XATTR_HMAC: |
90 | ? INTEGRITY_NOLABEL : INTEGRITY_FAIL; | 123 | rc = evm_calc_hmac(dentry, xattr_name, xattr_value, |
124 | xattr_value_len, calc.digest); | ||
125 | if (rc) | ||
126 | break; | ||
127 | rc = memcmp(xattr_data->digest, calc.digest, | ||
128 | sizeof(calc.digest)); | ||
129 | if (rc) | ||
130 | rc = -EINVAL; | ||
131 | break; | ||
132 | case EVM_IMA_XATTR_DIGSIG: | ||
133 | rc = evm_calc_hash(dentry, xattr_name, xattr_value, | ||
134 | xattr_value_len, calc.digest); | ||
135 | if (rc) | ||
136 | break; | ||
137 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, | ||
138 | xattr_data->digest, xattr_len, | ||
139 | calc.digest, sizeof(calc.digest)); | ||
140 | if (!rc) { | ||
141 | /* we probably want to replace rsa with hmac here */ | ||
142 | evm_update_evmxattr(dentry, xattr_name, xattr_value, | ||
143 | xattr_value_len); | ||
144 | } | ||
145 | break; | ||
146 | default: | ||
147 | rc = -EINVAL; | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | if (rc) | ||
152 | evm_status = (rc == -ENODATA) ? | ||
153 | INTEGRITY_NOXATTRS : INTEGRITY_FAIL; | ||
91 | out: | 154 | out: |
92 | if (iint) | 155 | if (iint) |
93 | iint->evm_status = evm_status; | 156 | iint->evm_status = evm_status; |
157 | kfree(xattr_data); | ||
94 | return evm_status; | 158 | return evm_status; |
95 | } | 159 | } |
96 | 160 | ||
@@ -354,6 +418,8 @@ static int __init init_evm(void) | |||
354 | printk(KERN_INFO "EVM: Error registering secfs\n"); | 418 | printk(KERN_INFO "EVM: Error registering secfs\n"); |
355 | goto err; | 419 | goto err; |
356 | } | 420 | } |
421 | |||
422 | return 0; | ||
357 | err: | 423 | err: |
358 | return error; | 424 | return error; |
359 | } | 425 | } |
@@ -363,6 +429,8 @@ static void __exit cleanup_evm(void) | |||
363 | evm_cleanup_secfs(); | 429 | evm_cleanup_secfs(); |
364 | if (hmac_tfm) | 430 | if (hmac_tfm) |
365 | crypto_free_shash(hmac_tfm); | 431 | crypto_free_shash(hmac_tfm); |
432 | if (hash_tfm) | ||
433 | crypto_free_shash(hash_tfm); | ||
366 | } | 434 | } |
367 | 435 | ||
368 | /* | 436 | /* |