diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-13 10:39:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-13 10:39:39 -0400 |
commit | aa569fa0ea32d1c24fb801a07d2d9174cbbdde23 (patch) | |
tree | 54c211a790684e0a93d6139634251152c703bbc2 /security | |
parent | 6d87c225f5d82d29243dc124f1ffcbb0e14ec358 (diff) | |
parent | 0430e49b6e7c6b5e076be8fefdee089958c9adad (diff) |
Merge branch 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security
Pull more security layer updates from Serge Hallyn:
"A few more commits had previously failed to make it through
security-next into linux-next but this week made it into linux-next.
At least commit "ima: introduce ima_kernel_read()" was deemed critical
by Mimi to make this merge window.
This is a temporary tree just for this request. Mimi has pointed me
to some previous threads about keeping maintainer trees at the
previous release, which I'll certainly do for anything long-term,
after talking with James"
* 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security:
ima: introduce ima_kernel_read()
evm: prohibit userspace writing 'security.evm' HMAC value
ima: check inode integrity cache in violation check
ima: prevent unnecessary policy checking
evm: provide option to protect additional SMACK xattrs
evm: replace HMAC version with attribute mask
ima: prevent new digsig xattr from being replaced
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/evm/Kconfig | 42 | ||||
-rw-r--r-- | security/integrity/evm/evm.h | 5 | ||||
-rw-r--r-- | security/integrity/evm/evm_crypto.c | 2 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 29 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 10 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 32 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 22 |
7 files changed, 114 insertions, 28 deletions
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index d35b4915b00d..d606f3d12d6b 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig | |||
@@ -12,15 +12,41 @@ config EVM | |||
12 | 12 | ||
13 | If you are unsure how to answer this question, answer N. | 13 | If you are unsure how to answer this question, answer N. |
14 | 14 | ||
15 | config EVM_HMAC_VERSION | 15 | if EVM |
16 | int "EVM HMAC version" | 16 | |
17 | menu "EVM options" | ||
18 | |||
19 | config EVM_ATTR_FSUUID | ||
20 | bool "FSUUID (version 2)" | ||
21 | default y | ||
17 | depends on EVM | 22 | depends on EVM |
18 | default 2 | ||
19 | help | 23 | help |
20 | This options adds EVM HMAC version support. | 24 | Include filesystem UUID for HMAC calculation. |
21 | 1 - original version | 25 | |
22 | 2 - add per filesystem unique identifier (UUID) (default) | 26 | Default value is 'selected', which is former version 2. |
27 | if 'not selected', it is former version 1 | ||
23 | 28 | ||
24 | WARNING: changing the HMAC calculation method or adding | 29 | WARNING: changing the HMAC calculation method or adding |
25 | additional info to the calculation, requires existing EVM | 30 | additional info to the calculation, requires existing EVM |
26 | labeled file systems to be relabeled. | 31 | labeled file systems to be relabeled. |
32 | |||
33 | config EVM_EXTRA_SMACK_XATTRS | ||
34 | bool "Additional SMACK xattrs" | ||
35 | depends on EVM && SECURITY_SMACK | ||
36 | default n | ||
37 | help | ||
38 | Include additional SMACK xattrs for HMAC calculation. | ||
39 | |||
40 | In addition to the original security xattrs (eg. security.selinux, | ||
41 | security.SMACK64, security.capability, and security.ima) included | ||
42 | in the HMAC calculation, enabling this option includes newly defined | ||
43 | Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and | ||
44 | security.SMACK64MMAP. | ||
45 | |||
46 | WARNING: changing the HMAC calculation method or adding | ||
47 | additional info to the calculation, requires existing EVM | ||
48 | labeled file systems to be relabeled. | ||
49 | |||
50 | endmenu | ||
51 | |||
52 | endif | ||
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 37c88ddb3cfe..88bfe77efa1c 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h | |||
@@ -24,7 +24,10 @@ | |||
24 | extern int evm_initialized; | 24 | extern int evm_initialized; |
25 | extern char *evm_hmac; | 25 | extern char *evm_hmac; |
26 | extern char *evm_hash; | 26 | extern char *evm_hash; |
27 | extern int evm_hmac_version; | 27 | |
28 | #define EVM_ATTR_FSUUID 0x0001 | ||
29 | |||
30 | extern int evm_hmac_attrs; | ||
28 | 31 | ||
29 | extern struct crypto_shash *hmac_tfm; | 32 | extern struct crypto_shash *hmac_tfm; |
30 | extern struct crypto_shash *hash_tfm; | 33 | extern struct crypto_shash *hash_tfm; |
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 6b540f1822e0..5e9687f02e1b 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c | |||
@@ -112,7 +112,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, | |||
112 | hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); | 112 | hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); |
113 | hmac_misc.mode = inode->i_mode; | 113 | hmac_misc.mode = inode->i_mode; |
114 | crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); | 114 | crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); |
115 | if (evm_hmac_version > 1) | 115 | if (evm_hmac_attrs & EVM_ATTR_FSUUID) |
116 | crypto_shash_update(desc, inode->i_sb->s_uuid, | 116 | crypto_shash_update(desc, inode->i_sb->s_uuid, |
117 | sizeof(inode->i_sb->s_uuid)); | 117 | sizeof(inode->i_sb->s_uuid)); |
118 | crypto_shash_final(desc, digest); | 118 | crypto_shash_final(desc, digest); |
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 6e0bd933b6a9..3bcb80df4d01 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
@@ -32,7 +32,7 @@ static char *integrity_status_msg[] = { | |||
32 | }; | 32 | }; |
33 | char *evm_hmac = "hmac(sha1)"; | 33 | char *evm_hmac = "hmac(sha1)"; |
34 | char *evm_hash = "sha1"; | 34 | char *evm_hash = "sha1"; |
35 | int evm_hmac_version = CONFIG_EVM_HMAC_VERSION; | 35 | int evm_hmac_attrs; |
36 | 36 | ||
37 | char *evm_config_xattrnames[] = { | 37 | char *evm_config_xattrnames[] = { |
38 | #ifdef CONFIG_SECURITY_SELINUX | 38 | #ifdef CONFIG_SECURITY_SELINUX |
@@ -40,6 +40,11 @@ char *evm_config_xattrnames[] = { | |||
40 | #endif | 40 | #endif |
41 | #ifdef CONFIG_SECURITY_SMACK | 41 | #ifdef CONFIG_SECURITY_SMACK |
42 | XATTR_NAME_SMACK, | 42 | XATTR_NAME_SMACK, |
43 | #ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS | ||
44 | XATTR_NAME_SMACKEXEC, | ||
45 | XATTR_NAME_SMACKTRANSMUTE, | ||
46 | XATTR_NAME_SMACKMMAP, | ||
47 | #endif | ||
43 | #endif | 48 | #endif |
44 | #ifdef CONFIG_IMA_APPRAISE | 49 | #ifdef CONFIG_IMA_APPRAISE |
45 | XATTR_NAME_IMA, | 50 | XATTR_NAME_IMA, |
@@ -57,6 +62,14 @@ static int __init evm_set_fixmode(char *str) | |||
57 | } | 62 | } |
58 | __setup("evm=", evm_set_fixmode); | 63 | __setup("evm=", evm_set_fixmode); |
59 | 64 | ||
65 | static void __init evm_init_config(void) | ||
66 | { | ||
67 | #ifdef CONFIG_EVM_ATTR_FSUUID | ||
68 | evm_hmac_attrs |= EVM_ATTR_FSUUID; | ||
69 | #endif | ||
70 | pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); | ||
71 | } | ||
72 | |||
60 | static int evm_find_protected_xattrs(struct dentry *dentry) | 73 | static int evm_find_protected_xattrs(struct dentry *dentry) |
61 | { | 74 | { |
62 | struct inode *inode = dentry->d_inode; | 75 | struct inode *inode = dentry->d_inode; |
@@ -287,12 +300,20 @@ out: | |||
287 | * @xattr_value: pointer to the new extended attribute value | 300 | * @xattr_value: pointer to the new extended attribute value |
288 | * @xattr_value_len: pointer to the new extended attribute value length | 301 | * @xattr_value_len: pointer to the new extended attribute value length |
289 | * | 302 | * |
290 | * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that | 303 | * Before allowing the 'security.evm' protected xattr to be updated, |
291 | * the current value is valid. | 304 | * verify the existing value is valid. As only the kernel should have |
305 | * access to the EVM encrypted key needed to calculate the HMAC, prevent | ||
306 | * userspace from writing HMAC value. Writing 'security.evm' requires | ||
307 | * requires CAP_SYS_ADMIN privileges. | ||
292 | */ | 308 | */ |
293 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, | 309 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, |
294 | const void *xattr_value, size_t xattr_value_len) | 310 | const void *xattr_value, size_t xattr_value_len) |
295 | { | 311 | { |
312 | const struct evm_ima_xattr_data *xattr_data = xattr_value; | ||
313 | |||
314 | if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0) | ||
315 | && (xattr_data->type == EVM_XATTR_HMAC)) | ||
316 | return -EPERM; | ||
296 | return evm_protect_xattr(dentry, xattr_name, xattr_value, | 317 | return evm_protect_xattr(dentry, xattr_name, xattr_value, |
297 | xattr_value_len); | 318 | xattr_value_len); |
298 | } | 319 | } |
@@ -432,6 +453,8 @@ static int __init init_evm(void) | |||
432 | { | 453 | { |
433 | int error; | 454 | int error; |
434 | 455 | ||
456 | evm_init_config(); | ||
457 | |||
435 | error = evm_init_secfs(); | 458 | error = evm_init_secfs(); |
436 | if (error < 0) { | 459 | if (error < 0) { |
437 | pr_info("Error registering secfs\n"); | 460 | pr_info("Error registering secfs\n"); |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 291bf0f3a46d..d3113d4aaa3c 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -341,7 +341,7 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, | |||
341 | return 0; | 341 | return 0; |
342 | } | 342 | } |
343 | 343 | ||
344 | static void ima_reset_appraise_flags(struct inode *inode) | 344 | static void ima_reset_appraise_flags(struct inode *inode, int digsig) |
345 | { | 345 | { |
346 | struct integrity_iint_cache *iint; | 346 | struct integrity_iint_cache *iint; |
347 | 347 | ||
@@ -353,18 +353,22 @@ static void ima_reset_appraise_flags(struct inode *inode) | |||
353 | return; | 353 | return; |
354 | 354 | ||
355 | iint->flags &= ~IMA_DONE_MASK; | 355 | iint->flags &= ~IMA_DONE_MASK; |
356 | if (digsig) | ||
357 | iint->flags |= IMA_DIGSIG; | ||
356 | return; | 358 | return; |
357 | } | 359 | } |
358 | 360 | ||
359 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | 361 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, |
360 | const void *xattr_value, size_t xattr_value_len) | 362 | const void *xattr_value, size_t xattr_value_len) |
361 | { | 363 | { |
364 | const struct evm_ima_xattr_data *xvalue = xattr_value; | ||
362 | int result; | 365 | int result; |
363 | 366 | ||
364 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, | 367 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, |
365 | xattr_value_len); | 368 | xattr_value_len); |
366 | if (result == 1) { | 369 | if (result == 1) { |
367 | ima_reset_appraise_flags(dentry->d_inode); | 370 | ima_reset_appraise_flags(dentry->d_inode, |
371 | (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); | ||
368 | result = 0; | 372 | result = 0; |
369 | } | 373 | } |
370 | return result; | 374 | return result; |
@@ -376,7 +380,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) | |||
376 | 380 | ||
377 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); | 381 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); |
378 | if (result == 1) { | 382 | if (result == 1) { |
379 | ima_reset_appraise_flags(dentry->d_inode); | 383 | ima_reset_appraise_flags(dentry->d_inode, 0); |
380 | result = 0; | 384 | result = 0; |
381 | } | 385 | } |
382 | return result; | 386 | return result; |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 1bde8e627766..ccd0ac8fa9a0 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -27,6 +27,36 @@ | |||
27 | 27 | ||
28 | static struct crypto_shash *ima_shash_tfm; | 28 | static struct crypto_shash *ima_shash_tfm; |
29 | 29 | ||
30 | /** | ||
31 | * ima_kernel_read - read file content | ||
32 | * | ||
33 | * This is a function for reading file content instead of kernel_read(). | ||
34 | * It does not perform locking checks to ensure it cannot be blocked. | ||
35 | * It does not perform security checks because it is irrelevant for IMA. | ||
36 | * | ||
37 | */ | ||
38 | static int ima_kernel_read(struct file *file, loff_t offset, | ||
39 | char *addr, unsigned long count) | ||
40 | { | ||
41 | mm_segment_t old_fs; | ||
42 | char __user *buf = addr; | ||
43 | ssize_t ret; | ||
44 | |||
45 | if (!(file->f_mode & FMODE_READ)) | ||
46 | return -EBADF; | ||
47 | if (!file->f_op->read && !file->f_op->aio_read) | ||
48 | return -EINVAL; | ||
49 | |||
50 | old_fs = get_fs(); | ||
51 | set_fs(get_ds()); | ||
52 | if (file->f_op->read) | ||
53 | ret = file->f_op->read(file, buf, count, &offset); | ||
54 | else | ||
55 | ret = do_sync_read(file, buf, count, &offset); | ||
56 | set_fs(old_fs); | ||
57 | return ret; | ||
58 | } | ||
59 | |||
30 | int ima_init_crypto(void) | 60 | int ima_init_crypto(void) |
31 | { | 61 | { |
32 | long rc; | 62 | long rc; |
@@ -104,7 +134,7 @@ static int ima_calc_file_hash_tfm(struct file *file, | |||
104 | while (offset < i_size) { | 134 | while (offset < i_size) { |
105 | int rbuf_len; | 135 | int rbuf_len; |
106 | 136 | ||
107 | rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE); | 137 | rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE); |
108 | if (rbuf_len < 0) { | 138 | if (rbuf_len < 0) { |
109 | rc = rbuf_len; | 139 | rc = rbuf_len; |
110 | break; | 140 | break; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index dcc98cf542d8..09baa335ebc7 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -81,7 +81,6 @@ static void ima_rdwr_violation_check(struct file *file) | |||
81 | { | 81 | { |
82 | struct inode *inode = file_inode(file); | 82 | struct inode *inode = file_inode(file); |
83 | fmode_t mode = file->f_mode; | 83 | fmode_t mode = file->f_mode; |
84 | int must_measure; | ||
85 | bool send_tomtou = false, send_writers = false; | 84 | bool send_tomtou = false, send_writers = false; |
86 | char *pathbuf = NULL; | 85 | char *pathbuf = NULL; |
87 | const char *pathname; | 86 | const char *pathname; |
@@ -92,18 +91,19 @@ static void ima_rdwr_violation_check(struct file *file) | |||
92 | mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ | 91 | mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ |
93 | 92 | ||
94 | if (mode & FMODE_WRITE) { | 93 | if (mode & FMODE_WRITE) { |
95 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) | 94 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { |
96 | send_tomtou = true; | 95 | struct integrity_iint_cache *iint; |
97 | goto out; | 96 | iint = integrity_iint_find(inode); |
97 | /* IMA_MEASURE is set from reader side */ | ||
98 | if (iint && (iint->flags & IMA_MEASURE)) | ||
99 | send_tomtou = true; | ||
100 | } | ||
101 | } else { | ||
102 | if ((atomic_read(&inode->i_writecount) > 0) && | ||
103 | ima_must_measure(inode, MAY_READ, FILE_CHECK)) | ||
104 | send_writers = true; | ||
98 | } | 105 | } |
99 | 106 | ||
100 | must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); | ||
101 | if (!must_measure) | ||
102 | goto out; | ||
103 | |||
104 | if (atomic_read(&inode->i_writecount) > 0) | ||
105 | send_writers = true; | ||
106 | out: | ||
107 | mutex_unlock(&inode->i_mutex); | 107 | mutex_unlock(&inode->i_mutex); |
108 | 108 | ||
109 | if (!send_tomtou && !send_writers) | 109 | if (!send_tomtou && !send_writers) |