summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2017-11-07 10:17:42 -0500
committerMimi Zohar <zohar@linux.vnet.ibm.com>2017-12-11 17:20:39 -0500
commit50b977481fce90aa5fbda55e330b9d722733e358 (patch)
treef7852b45d6d4207e37cd89c397905e1a7558c527
parentae1ba1676b88e6c62368a433c7e2d0417e9879fd (diff)
EVM: Add support for portable signature format
The EVM signature includes the inode number and (optionally) the filesystem UUID, making it impractical to ship EVM signatures in packages. This patch adds a new portable format intended to allow distributions to include EVM signatures. It is identical to the existing format but hardcodes the inode and generation numbers to 0 and does not include the filesystem UUID even if the kernel is configured to do so. Removing the inode means that the metadata and signature from one file could be copied to another file without invalidating it. This is avoided by ensuring that an IMA xattr is present during EVM validation. Portable signatures are intended to be immutable - ie, they will never be transformed into HMACs. Based on earlier work by Dmitry Kasatkin and Mikhail Kurinnoi. Signed-off-by: Matthew Garrett <mjg59@google.com> Cc: Dmitry Kasatkin <dmitry.kasatkin@huawei.com> Cc: Mikhail Kurinnoi <viewizard@viewizard.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
-rw-r--r--include/linux/integrity.h1
-rw-r--r--security/integrity/evm/evm.h2
-rw-r--r--security/integrity/evm/evm_crypto.c75
-rw-r--r--security/integrity/evm/evm_main.c29
-rw-r--r--security/integrity/ima/ima_appraise.c4
-rw-r--r--security/integrity/integrity.h2
6 files changed, 92 insertions, 21 deletions
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index c2d6082a1a4c..858d3f4a2241 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -14,6 +14,7 @@
14 14
15enum integrity_status { 15enum integrity_status {
16 INTEGRITY_PASS = 0, 16 INTEGRITY_PASS = 0,
17 INTEGRITY_PASS_IMMUTABLE,
17 INTEGRITY_FAIL, 18 INTEGRITY_FAIL,
18 INTEGRITY_NOLABEL, 19 INTEGRITY_NOLABEL,
19 INTEGRITY_NOXATTRS, 20 INTEGRITY_NOXATTRS,
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 3d05250e8313..04825393facb 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -54,7 +54,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
54 size_t req_xattr_value_len, char *digest); 54 size_t req_xattr_value_len, char *digest);
55int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, 55int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
56 const char *req_xattr_value, 56 const char *req_xattr_value,
57 size_t req_xattr_value_len, char *digest); 57 size_t req_xattr_value_len, char type, char *digest);
58int evm_init_hmac(struct inode *inode, const struct xattr *xattr, 58int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
59 char *hmac_val); 59 char *hmac_val);
60int evm_init_secfs(void); 60int evm_init_secfs(void);
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index bcd64baf8788..691f3e09154c 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -138,7 +138,7 @@ out:
138 * protection.) 138 * protection.)
139 */ 139 */
140static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, 140static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
141 char *digest) 141 char type, char *digest)
142{ 142{
143 struct h_misc { 143 struct h_misc {
144 unsigned long ino; 144 unsigned long ino;
@@ -149,8 +149,13 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
149 } hmac_misc; 149 } hmac_misc;
150 150
151 memset(&hmac_misc, 0, sizeof(hmac_misc)); 151 memset(&hmac_misc, 0, sizeof(hmac_misc));
152 hmac_misc.ino = inode->i_ino; 152 /* Don't include the inode or generation number in portable
153 hmac_misc.generation = inode->i_generation; 153 * signatures
154 */
155 if (type != EVM_XATTR_PORTABLE_DIGSIG) {
156 hmac_misc.ino = inode->i_ino;
157 hmac_misc.generation = inode->i_generation;
158 }
154 /* The hmac uid and gid must be encoded in the initial user 159 /* The hmac uid and gid must be encoded in the initial user
155 * namespace (not the filesystems user namespace) as encoding 160 * namespace (not the filesystems user namespace) as encoding
156 * them in the filesystems user namespace allows an attack 161 * them in the filesystems user namespace allows an attack
@@ -163,7 +168,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
163 hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); 168 hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
164 hmac_misc.mode = inode->i_mode; 169 hmac_misc.mode = inode->i_mode;
165 crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); 170 crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
166 if (evm_hmac_attrs & EVM_ATTR_FSUUID) 171 if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
172 type != EVM_XATTR_PORTABLE_DIGSIG)
167 crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0], 173 crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0],
168 sizeof(inode->i_sb->s_uuid)); 174 sizeof(inode->i_sb->s_uuid));
169 crypto_shash_final(desc, digest); 175 crypto_shash_final(desc, digest);
@@ -189,6 +195,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
189 char *xattr_value = NULL; 195 char *xattr_value = NULL;
190 int error; 196 int error;
191 int size; 197 int size;
198 bool ima_present = false;
192 199
193 if (!(inode->i_opflags & IOP_XATTR)) 200 if (!(inode->i_opflags & IOP_XATTR))
194 return -EOPNOTSUPP; 201 return -EOPNOTSUPP;
@@ -199,11 +206,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
199 206
200 error = -ENODATA; 207 error = -ENODATA;
201 for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { 208 for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
209 bool is_ima = false;
210
211 if (strcmp(*xattrname, XATTR_NAME_IMA) == 0)
212 is_ima = true;
213
202 if ((req_xattr_name && req_xattr_value) 214 if ((req_xattr_name && req_xattr_value)
203 && !strcmp(*xattrname, req_xattr_name)) { 215 && !strcmp(*xattrname, req_xattr_name)) {
204 error = 0; 216 error = 0;
205 crypto_shash_update(desc, (const u8 *)req_xattr_value, 217 crypto_shash_update(desc, (const u8 *)req_xattr_value,
206 req_xattr_value_len); 218 req_xattr_value_len);
219 if (is_ima)
220 ima_present = true;
207 continue; 221 continue;
208 } 222 }
209 size = vfs_getxattr_alloc(dentry, *xattrname, 223 size = vfs_getxattr_alloc(dentry, *xattrname,
@@ -218,9 +232,14 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
218 error = 0; 232 error = 0;
219 xattr_size = size; 233 xattr_size = size;
220 crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size); 234 crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
235 if (is_ima)
236 ima_present = true;
221 } 237 }
222 hmac_add_misc(desc, inode, digest); 238 hmac_add_misc(desc, inode, type, digest);
223 239
240 /* Portable EVM signatures must include an IMA hash */
241 if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
242 return -EPERM;
224out: 243out:
225 kfree(xattr_value); 244 kfree(xattr_value);
226 kfree(desc); 245 kfree(desc);
@@ -232,17 +251,45 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
232 char *digest) 251 char *digest)
233{ 252{
234 return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, 253 return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
235 req_xattr_value_len, EVM_XATTR_HMAC, digest); 254 req_xattr_value_len, EVM_XATTR_HMAC, digest);
236} 255}
237 256
238int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, 257int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
239 const char *req_xattr_value, size_t req_xattr_value_len, 258 const char *req_xattr_value, size_t req_xattr_value_len,
240 char *digest) 259 char type, char *digest)
241{ 260{
242 return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, 261 return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
243 req_xattr_value_len, IMA_XATTR_DIGEST, digest); 262 req_xattr_value_len, type, digest);
263}
264
265static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
266{
267 const struct evm_ima_xattr_data *xattr_data = NULL;
268 struct integrity_iint_cache *iint;
269 int rc = 0;
270
271 iint = integrity_iint_find(inode);
272 if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG))
273 return 1;
274
275 /* Do this the hard way */
276 rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
277 GFP_NOFS);
278 if (rc <= 0) {
279 if (rc == -ENODATA)
280 return 0;
281 return rc;
282 }
283 if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG)
284 rc = 1;
285 else
286 rc = 0;
287
288 kfree(xattr_data);
289 return rc;
244} 290}
245 291
292
246/* 293/*
247 * Calculate the hmac and update security.evm xattr 294 * Calculate the hmac and update security.evm xattr
248 * 295 *
@@ -255,6 +302,16 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
255 struct evm_ima_xattr_data xattr_data; 302 struct evm_ima_xattr_data xattr_data;
256 int rc = 0; 303 int rc = 0;
257 304
305 /*
306 * Don't permit any transformation of the EVM xattr if the signature
307 * is of an immutable type
308 */
309 rc = evm_is_immutable(dentry, inode);
310 if (rc < 0)
311 return rc;
312 if (rc)
313 return -EPERM;
314
258 rc = evm_calc_hmac(dentry, xattr_name, xattr_value, 315 rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
259 xattr_value_len, xattr_data.digest); 316 xattr_value_len, xattr_data.digest);
260 if (rc == 0) { 317 if (rc == 0) {
@@ -280,7 +337,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
280 } 337 }
281 338
282 crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len); 339 crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len);
283 hmac_add_misc(desc, inode, hmac_val); 340 hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
284 kfree(desc); 341 kfree(desc);
285 return 0; 342 return 0;
286} 343}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index ba89c2468298..a8d502827270 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -31,7 +31,7 @@
31int evm_initialized; 31int evm_initialized;
32 32
33static char *integrity_status_msg[] = { 33static char *integrity_status_msg[] = {
34 "pass", "fail", "no_label", "no_xattrs", "unknown" 34 "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
35}; 35};
36char *evm_hmac = "hmac(sha1)"; 36char *evm_hmac = "hmac(sha1)";
37char *evm_hash = "sha1"; 37char *evm_hash = "sha1";
@@ -128,7 +128,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
128 enum integrity_status evm_status = INTEGRITY_PASS; 128 enum integrity_status evm_status = INTEGRITY_PASS;
129 int rc, xattr_len; 129 int rc, xattr_len;
130 130
131 if (iint && iint->evm_status == INTEGRITY_PASS) 131 if (iint && (iint->evm_status == INTEGRITY_PASS ||
132 iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
132 return iint->evm_status; 133 return iint->evm_status;
133 134
134 /* if status is not PASS, try to check again - against -ENOMEM */ 135 /* if status is not PASS, try to check again - against -ENOMEM */
@@ -169,22 +170,26 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
169 rc = -EINVAL; 170 rc = -EINVAL;
170 break; 171 break;
171 case EVM_IMA_XATTR_DIGSIG: 172 case EVM_IMA_XATTR_DIGSIG:
173 case EVM_XATTR_PORTABLE_DIGSIG:
172 rc = evm_calc_hash(dentry, xattr_name, xattr_value, 174 rc = evm_calc_hash(dentry, xattr_name, xattr_value,
173 xattr_value_len, calc.digest); 175 xattr_value_len, xattr_data->type,
176 calc.digest);
174 if (rc) 177 if (rc)
175 break; 178 break;
176 rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, 179 rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
177 (const char *)xattr_data, xattr_len, 180 (const char *)xattr_data, xattr_len,
178 calc.digest, sizeof(calc.digest)); 181 calc.digest, sizeof(calc.digest));
179 if (!rc) { 182 if (!rc) {
180 /* Replace RSA with HMAC if not mounted readonly and 183 if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) {
181 * not immutable 184 if (iint)
182 */ 185 iint->flags |= EVM_IMMUTABLE_DIGSIG;
183 if (!IS_RDONLY(d_backing_inode(dentry)) && 186 evm_status = INTEGRITY_PASS_IMMUTABLE;
184 !IS_IMMUTABLE(d_backing_inode(dentry))) 187 } else if (!IS_RDONLY(d_backing_inode(dentry)) &&
188 !IS_IMMUTABLE(d_backing_inode(dentry))) {
185 evm_update_evmxattr(dentry, xattr_name, 189 evm_update_evmxattr(dentry, xattr_name,
186 xattr_value, 190 xattr_value,
187 xattr_value_len); 191 xattr_value_len);
192 }
188 } 193 }
189 break; 194 break;
190 default: 195 default:
@@ -285,7 +290,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
285 * affect security.evm. An interesting side affect of writing posix xattr 290 * affect security.evm. An interesting side affect of writing posix xattr
286 * acls is their modifying of the i_mode, which is included in security.evm. 291 * acls is their modifying of the i_mode, which is included in security.evm.
287 * For posix xattr acls only, permit security.evm, even if it currently 292 * For posix xattr acls only, permit security.evm, even if it currently
288 * doesn't exist, to be updated. 293 * doesn't exist, to be updated unless the EVM signature is immutable.
289 */ 294 */
290static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, 295static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
291 const void *xattr_value, size_t xattr_value_len) 296 const void *xattr_value, size_t xattr_value_len)
@@ -360,7 +365,8 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
360 if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 365 if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
361 if (!xattr_value_len) 366 if (!xattr_value_len)
362 return -EINVAL; 367 return -EINVAL;
363 if (xattr_data->type != EVM_IMA_XATTR_DIGSIG) 368 if (xattr_data->type != EVM_IMA_XATTR_DIGSIG &&
369 xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG)
364 return -EPERM; 370 return -EPERM;
365 } 371 }
366 return evm_protect_xattr(dentry, xattr_name, xattr_value, 372 return evm_protect_xattr(dentry, xattr_name, xattr_value,
@@ -443,6 +449,9 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
443/** 449/**
444 * evm_inode_setattr - prevent updating an invalid EVM extended attribute 450 * evm_inode_setattr - prevent updating an invalid EVM extended attribute
445 * @dentry: pointer to the affected dentry 451 * @dentry: pointer to the affected dentry
452 *
453 * Permit update of file attributes when files have a valid EVM signature,
454 * except in the case of them having an immutable portable signature.
446 */ 455 */
447int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) 456int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
448{ 457{
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index d32e6a1d931a..084c19e45668 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -230,7 +230,9 @@ int ima_appraise_measurement(enum ima_hooks func,
230 } 230 }
231 231
232 status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); 232 status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
233 if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { 233 if ((status != INTEGRITY_PASS) &&
234 (status != INTEGRITY_PASS_IMMUTABLE) &&
235 (status != INTEGRITY_UNKNOWN)) {
234 if ((status == INTEGRITY_NOLABEL) 236 if ((status == INTEGRITY_NOLABEL)
235 || (status == INTEGRITY_NOXATTRS)) 237 || (status == INTEGRITY_NOXATTRS))
236 cause = "missing-HMAC"; 238 cause = "missing-HMAC";
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index e1bf040fb110..e324bf98c856 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -33,6 +33,7 @@
33#define IMA_DIGSIG_REQUIRED 0x02000000 33#define IMA_DIGSIG_REQUIRED 0x02000000
34#define IMA_PERMIT_DIRECTIO 0x04000000 34#define IMA_PERMIT_DIRECTIO 0x04000000
35#define IMA_NEW_FILE 0x08000000 35#define IMA_NEW_FILE 0x08000000
36#define EVM_IMMUTABLE_DIGSIG 0x10000000
36 37
37#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ 38#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
38 IMA_APPRAISE_SUBMASK) 39 IMA_APPRAISE_SUBMASK)
@@ -58,6 +59,7 @@ enum evm_ima_xattr_type {
58 EVM_XATTR_HMAC, 59 EVM_XATTR_HMAC,
59 EVM_IMA_XATTR_DIGSIG, 60 EVM_IMA_XATTR_DIGSIG,
60 IMA_XATTR_DIGEST_NG, 61 IMA_XATTR_DIGEST_NG,
62 EVM_XATTR_PORTABLE_DIGSIG,
61 IMA_XATTR_LAST 63 IMA_XATTR_LAST
62}; 64};
63 65