diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 4 | ||||
-rw-r--r-- | include/linux/xattr.h | 3 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 3 | ||||
-rw-r--r-- | security/integrity/iint.c | 3 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 15 | ||||
-rw-r--r-- | security/integrity/ima/Makefile | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 37 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 50 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 168 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 8 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 79 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 32 | ||||
-rw-r--r-- | security/integrity/integrity.h | 8 |
13 files changed, 358 insertions, 53 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ad7e2e5088c1..fa09e64d9877 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1051,6 +1051,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
1051 | ihash_entries= [KNL] | 1051 | ihash_entries= [KNL] |
1052 | Set number of hash buckets for inode cache. | 1052 | Set number of hash buckets for inode cache. |
1053 | 1053 | ||
1054 | ima_appraise= [IMA] appraise integrity measurements | ||
1055 | Format: { "off" | "enforce" | "fix" } | ||
1056 | default: "enforce" | ||
1057 | |||
1054 | ima_audit= [IMA] | 1058 | ima_audit= [IMA] |
1055 | Format: { "0" | "1" } | 1059 | Format: { "0" | "1" } |
1056 | 0 -- integrity auditing messages. (Default) | 1060 | 0 -- integrity auditing messages. (Default) |
diff --git a/include/linux/xattr.h b/include/linux/xattr.h index e5d122031542..77a3e686d566 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h | |||
@@ -33,6 +33,9 @@ | |||
33 | #define XATTR_EVM_SUFFIX "evm" | 33 | #define XATTR_EVM_SUFFIX "evm" |
34 | #define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX | 34 | #define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX |
35 | 35 | ||
36 | #define XATTR_IMA_SUFFIX "ima" | ||
37 | #define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX | ||
38 | |||
36 | #define XATTR_SELINUX_SUFFIX "selinux" | 39 | #define XATTR_SELINUX_SUFFIX "selinux" |
37 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX | 40 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX |
38 | 41 | ||
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 8901501425f4..eb5484504f50 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
@@ -34,6 +34,9 @@ char *evm_config_xattrnames[] = { | |||
34 | #ifdef CONFIG_SECURITY_SMACK | 34 | #ifdef CONFIG_SECURITY_SMACK |
35 | XATTR_NAME_SMACK, | 35 | XATTR_NAME_SMACK, |
36 | #endif | 36 | #endif |
37 | #ifdef CONFIG_IMA_APPRAISE | ||
38 | XATTR_NAME_IMA, | ||
39 | #endif | ||
37 | XATTR_NAME_CAPS, | 40 | XATTR_NAME_CAPS, |
38 | NULL | 41 | NULL |
39 | }; | 42 | }; |
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 399641c3e846..e600986aa49f 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
@@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint) | |||
74 | { | 74 | { |
75 | iint->version = 0; | 75 | iint->version = 0; |
76 | iint->flags = 0UL; | 76 | iint->flags = 0UL; |
77 | iint->ima_status = INTEGRITY_UNKNOWN; | ||
77 | iint->evm_status = INTEGRITY_UNKNOWN; | 78 | iint->evm_status = INTEGRITY_UNKNOWN; |
78 | kmem_cache_free(iint_cache, iint); | 79 | kmem_cache_free(iint_cache, iint); |
79 | } | 80 | } |
@@ -157,7 +158,7 @@ static void init_once(void *foo) | |||
157 | memset(iint, 0, sizeof *iint); | 158 | memset(iint, 0, sizeof *iint); |
158 | iint->version = 0; | 159 | iint->version = 0; |
159 | iint->flags = 0UL; | 160 | iint->flags = 0UL; |
160 | mutex_init(&iint->mutex); | 161 | iint->ima_status = INTEGRITY_UNKNOWN; |
161 | iint->evm_status = INTEGRITY_UNKNOWN; | 162 | iint->evm_status = INTEGRITY_UNKNOWN; |
162 | } | 163 | } |
163 | 164 | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 809ccf19d09c..d232c73647ae 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -56,3 +56,18 @@ config IMA_LSM_RULES | |||
56 | default y | 56 | default y |
57 | help | 57 | help |
58 | Disabling this option will disregard LSM based policy rules. | 58 | Disabling this option will disregard LSM based policy rules. |
59 | |||
60 | config IMA_APPRAISE | ||
61 | bool "Appraise integrity measurements" | ||
62 | depends on IMA | ||
63 | default n | ||
64 | help | ||
65 | This option enables local measurement integrity appraisal. | ||
66 | It requires the system to be labeled with a security extended | ||
67 | attribute containing the file hash measurement. To protect | ||
68 | the security extended attributes from offline attack, enable | ||
69 | and configure EVM. | ||
70 | |||
71 | For more information on integrity appraisal refer to: | ||
72 | <http://linux-ima.sourceforge.net> | ||
73 | If unsure, say N. | ||
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 5f740f6971e1..3f2ca6bdc384 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o | |||
8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ |
9 | ima_policy.o | 9 | ima_policy.o |
10 | ima-$(CONFIG_IMA_AUDIT) += ima_audit.o | 10 | ima-$(CONFIG_IMA_AUDIT) += ima_audit.o |
11 | ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e7c99fd0d223..069a4aa63e95 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -40,6 +40,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | |||
40 | extern int ima_initialized; | 40 | extern int ima_initialized; |
41 | extern int ima_used_chip; | 41 | extern int ima_used_chip; |
42 | extern char *ima_hash; | 42 | extern char *ima_hash; |
43 | extern int ima_appraise; | ||
43 | 44 | ||
44 | /* IMA inode template definition */ | 45 | /* IMA inode template definition */ |
45 | struct ima_template_data { | 46 | struct ima_template_data { |
@@ -107,6 +108,7 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
107 | } | 108 | } |
108 | 109 | ||
109 | /* LIM API function definitions */ | 110 | /* LIM API function definitions */ |
111 | int ima_must_appraise_or_measure(struct inode *inode, int mask, int function); | ||
110 | int ima_must_measure(struct inode *inode, int mask, int function); | 112 | int ima_must_measure(struct inode *inode, int mask, int function); |
111 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 113 | int ima_collect_measurement(struct integrity_iint_cache *iint, |
112 | struct file *file); | 114 | struct file *file); |
@@ -123,14 +125,45 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); | |||
123 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 125 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
124 | 126 | ||
125 | /* IMA policy related functions */ | 127 | /* IMA policy related functions */ |
126 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 128 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; |
127 | 129 | ||
128 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 130 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
131 | int flags); | ||
129 | void ima_init_policy(void); | 132 | void ima_init_policy(void); |
130 | void ima_update_policy(void); | 133 | void ima_update_policy(void); |
131 | ssize_t ima_parse_add_rule(char *); | 134 | ssize_t ima_parse_add_rule(char *); |
132 | void ima_delete_rules(void); | 135 | void ima_delete_rules(void); |
133 | 136 | ||
137 | /* Appraise integrity measurements */ | ||
138 | #define IMA_APPRAISE_ENFORCE 0x01 | ||
139 | #define IMA_APPRAISE_FIX 0x02 | ||
140 | |||
141 | #ifdef CONFIG_IMA_APPRAISE | ||
142 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
143 | struct file *file, const unsigned char *filename); | ||
144 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask); | ||
145 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); | ||
146 | |||
147 | #else | ||
148 | static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
149 | struct file *file, | ||
150 | const unsigned char *filename) | ||
151 | { | ||
152 | return INTEGRITY_UNKNOWN; | ||
153 | } | ||
154 | |||
155 | static inline int ima_must_appraise(struct inode *inode, | ||
156 | enum ima_hooks func, int mask) | ||
157 | { | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static inline void ima_update_xattr(struct integrity_iint_cache *iint, | ||
162 | struct file *file) | ||
163 | { | ||
164 | } | ||
165 | #endif | ||
166 | |||
134 | /* LSM based policy rules require audit */ | 167 | /* LSM based policy rules require audit */ |
135 | #ifdef CONFIG_IMA_LSM_RULES | 168 | #ifdef CONFIG_IMA_LSM_RULES |
136 | 169 | ||
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 032ff03ad907..41cce84416c5 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -9,13 +9,17 @@ | |||
9 | * License. | 9 | * License. |
10 | * | 10 | * |
11 | * File: ima_api.c | 11 | * File: ima_api.c |
12 | * Implements must_measure, collect_measurement, store_measurement, | 12 | * Implements must_appraise_or_measure, collect_measurement, |
13 | * and store_template. | 13 | * appraise_measurement, store_measurement and store_template. |
14 | */ | 14 | */ |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | #include <linux/file.h> | |
18 | #include <linux/fs.h> | ||
19 | #include <linux/xattr.h> | ||
20 | #include <linux/evm.h> | ||
18 | #include "ima.h" | 21 | #include "ima.h" |
22 | |||
19 | static const char *IMA_TEMPLATE_NAME = "ima"; | 23 | static const char *IMA_TEMPLATE_NAME = "ima"; |
20 | 24 | ||
21 | /* | 25 | /* |
@@ -93,7 +97,7 @@ err_out: | |||
93 | } | 97 | } |
94 | 98 | ||
95 | /** | 99 | /** |
96 | * ima_must_measure - measure decision based on policy. | 100 | * ima_must_appraise_or_measure - appraise & measure decision based on policy. |
97 | * @inode: pointer to inode to measure | 101 | * @inode: pointer to inode to measure |
98 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | 102 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) |
99 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) | 103 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) |
@@ -105,15 +109,22 @@ err_out: | |||
105 | * mask: contains the permission mask | 109 | * mask: contains the permission mask |
106 | * fsmagic: hex value | 110 | * fsmagic: hex value |
107 | * | 111 | * |
108 | * Return 0 to measure. For matching a DONT_MEASURE policy, no policy, | 112 | * Returns IMA_MEASURE, IMA_APPRAISE mask. |
109 | * or other error, return an error code. | 113 | * |
110 | */ | 114 | */ |
111 | int ima_must_measure(struct inode *inode, int mask, int function) | 115 | int ima_must_appraise_or_measure(struct inode *inode, int mask, int function) |
112 | { | 116 | { |
113 | int must_measure; | 117 | int flags = IMA_MEASURE | IMA_APPRAISE; |
118 | |||
119 | if (!ima_appraise) | ||
120 | flags &= ~IMA_APPRAISE; | ||
121 | |||
122 | return ima_match_policy(inode, function, mask, flags); | ||
123 | } | ||
114 | 124 | ||
115 | must_measure = ima_match_policy(inode, function, mask); | 125 | int ima_must_measure(struct inode *inode, int mask, int function) |
116 | return must_measure ? 0 : -EACCES; | 126 | { |
127 | return ima_match_policy(inode, function, mask, IMA_MEASURE); | ||
117 | } | 128 | } |
118 | 129 | ||
119 | /* | 130 | /* |
@@ -129,16 +140,24 @@ int ima_must_measure(struct inode *inode, int mask, int function) | |||
129 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 140 | int ima_collect_measurement(struct integrity_iint_cache *iint, |
130 | struct file *file) | 141 | struct file *file) |
131 | { | 142 | { |
132 | int result = -EEXIST; | 143 | struct inode *inode = file->f_dentry->d_inode; |
144 | const char *filename = file->f_dentry->d_name.name; | ||
145 | int result = 0; | ||
133 | 146 | ||
134 | if (!(iint->flags & IMA_MEASURED)) { | 147 | if (!(iint->flags & IMA_COLLECTED)) { |
135 | u64 i_version = file->f_dentry->d_inode->i_version; | 148 | u64 i_version = file->f_dentry->d_inode->i_version; |
136 | 149 | ||
137 | memset(iint->digest, 0, IMA_DIGEST_SIZE); | 150 | memset(iint->digest, 0, IMA_DIGEST_SIZE); |
138 | result = ima_calc_hash(file, iint->digest); | 151 | result = ima_calc_hash(file, iint->digest); |
139 | if (!result) | 152 | if (!result) { |
140 | iint->version = i_version; | 153 | iint->version = i_version; |
154 | iint->flags |= IMA_COLLECTED; | ||
155 | } | ||
141 | } | 156 | } |
157 | if (result) | ||
158 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, | ||
159 | filename, "collect_data", "failed", | ||
160 | result, 0); | ||
142 | return result; | 161 | return result; |
143 | } | 162 | } |
144 | 163 | ||
@@ -167,6 +186,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
167 | struct ima_template_entry *entry; | 186 | struct ima_template_entry *entry; |
168 | int violation = 0; | 187 | int violation = 0; |
169 | 188 | ||
189 | if (iint->flags & IMA_MEASURED) | ||
190 | return; | ||
191 | |||
170 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 192 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
171 | if (!entry) { | 193 | if (!entry) { |
172 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | 194 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c new file mode 100644 index 000000000000..4865f61f9044 --- /dev/null +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 IBM Corporation | ||
3 | * | ||
4 | * Author: | ||
5 | * Mimi Zohar <zohar@us.ibm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, version 2 of the License. | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/file.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/xattr.h> | ||
15 | #include <linux/magic.h> | ||
16 | #include <linux/ima.h> | ||
17 | #include <linux/evm.h> | ||
18 | |||
19 | #include "ima.h" | ||
20 | |||
21 | static int __init default_appraise_setup(char *str) | ||
22 | { | ||
23 | if (strncmp(str, "off", 3) == 0) | ||
24 | ima_appraise = 0; | ||
25 | else if (strncmp(str, "fix", 3) == 0) | ||
26 | ima_appraise = IMA_APPRAISE_FIX; | ||
27 | return 1; | ||
28 | } | ||
29 | |||
30 | __setup("ima_appraise=", default_appraise_setup); | ||
31 | |||
32 | /* | ||
33 | * ima_must_appraise - set appraise flag | ||
34 | * | ||
35 | * Return 1 to appraise | ||
36 | */ | ||
37 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) | ||
38 | { | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static void ima_fix_xattr(struct dentry *dentry, | ||
43 | struct integrity_iint_cache *iint) | ||
44 | { | ||
45 | iint->digest[0] = IMA_XATTR_DIGEST; | ||
46 | __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | ||
47 | iint->digest, IMA_DIGEST_SIZE + 1, 0); | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * ima_appraise_measurement - appraise file measurement | ||
52 | * | ||
53 | * Call evm_verifyxattr() to verify the integrity of 'security.ima'. | ||
54 | * Assuming success, compare the xattr hash with the collected measurement. | ||
55 | * | ||
56 | * Return 0 on success, error code otherwise | ||
57 | */ | ||
58 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
59 | struct file *file, const unsigned char *filename) | ||
60 | { | ||
61 | struct dentry *dentry = file->f_dentry; | ||
62 | struct inode *inode = dentry->d_inode; | ||
63 | u8 xattr_value[IMA_DIGEST_SIZE]; | ||
64 | enum integrity_status status = INTEGRITY_UNKNOWN; | ||
65 | const char *op = "appraise_data"; | ||
66 | char *cause = "unknown"; | ||
67 | int rc; | ||
68 | |||
69 | if (!ima_appraise) | ||
70 | return 0; | ||
71 | if (!inode->i_op->getxattr) | ||
72 | return INTEGRITY_UNKNOWN; | ||
73 | |||
74 | if (iint->flags & IMA_APPRAISED) | ||
75 | return iint->ima_status; | ||
76 | |||
77 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, xattr_value, | ||
78 | IMA_DIGEST_SIZE); | ||
79 | if (rc <= 0) { | ||
80 | if (rc && rc != -ENODATA) | ||
81 | goto out; | ||
82 | |||
83 | cause = "missing-hash"; | ||
84 | status = | ||
85 | (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL; | ||
86 | goto out; | ||
87 | } | ||
88 | |||
89 | status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); | ||
90 | if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { | ||
91 | if ((status == INTEGRITY_NOLABEL) | ||
92 | || (status == INTEGRITY_NOXATTRS)) | ||
93 | cause = "missing-HMAC"; | ||
94 | else if (status == INTEGRITY_FAIL) | ||
95 | cause = "invalid-HMAC"; | ||
96 | goto out; | ||
97 | } | ||
98 | |||
99 | rc = memcmp(xattr_value, iint->digest, IMA_DIGEST_SIZE); | ||
100 | if (rc) { | ||
101 | status = INTEGRITY_FAIL; | ||
102 | cause = "invalid-hash"; | ||
103 | print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE, | ||
104 | xattr_value, IMA_DIGEST_SIZE); | ||
105 | print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE, | ||
106 | iint->digest, IMA_DIGEST_SIZE); | ||
107 | goto out; | ||
108 | } | ||
109 | status = INTEGRITY_PASS; | ||
110 | iint->flags |= IMA_APPRAISED; | ||
111 | out: | ||
112 | if (status != INTEGRITY_PASS) { | ||
113 | if (ima_appraise & IMA_APPRAISE_FIX) { | ||
114 | ima_fix_xattr(dentry, iint); | ||
115 | status = INTEGRITY_PASS; | ||
116 | } | ||
117 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, | ||
118 | op, cause, rc, 0); | ||
119 | } | ||
120 | iint->ima_status = status; | ||
121 | return status; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * ima_update_xattr - update 'security.ima' hash value | ||
126 | */ | ||
127 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | ||
128 | { | ||
129 | struct dentry *dentry = file->f_dentry; | ||
130 | int rc = 0; | ||
131 | |||
132 | rc = ima_collect_measurement(iint, file); | ||
133 | if (rc < 0) | ||
134 | return; | ||
135 | ima_fix_xattr(dentry, iint); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * ima_inode_post_setattr - reflect file metadata changes | ||
140 | * @dentry: pointer to the affected dentry | ||
141 | * | ||
142 | * Changes to a dentry's metadata might result in needing to appraise. | ||
143 | * | ||
144 | * This function is called from notify_change(), which expects the caller | ||
145 | * to lock the inode's i_mutex. | ||
146 | */ | ||
147 | void ima_inode_post_setattr(struct dentry *dentry) | ||
148 | { | ||
149 | struct inode *inode = dentry->d_inode; | ||
150 | struct integrity_iint_cache *iint; | ||
151 | int must_appraise, rc; | ||
152 | |||
153 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) | ||
154 | || !inode->i_op->removexattr) | ||
155 | return; | ||
156 | |||
157 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); | ||
158 | iint = integrity_iint_find(inode); | ||
159 | if (iint) { | ||
160 | if (must_appraise) | ||
161 | iint->flags |= IMA_APPRAISE; | ||
162 | else | ||
163 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); | ||
164 | } | ||
165 | if (!must_appraise) | ||
166 | rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); | ||
167 | return; | ||
168 | } | ||
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 9b3ade7468b2..b21ee5b5495a 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -48,7 +48,7 @@ int ima_calc_hash(struct file *file, char *digest) | |||
48 | struct scatterlist sg[1]; | 48 | struct scatterlist sg[1]; |
49 | loff_t i_size, offset = 0; | 49 | loff_t i_size, offset = 0; |
50 | char *rbuf; | 50 | char *rbuf; |
51 | int rc; | 51 | int rc, read = 0; |
52 | 52 | ||
53 | rc = init_desc(&desc); | 53 | rc = init_desc(&desc); |
54 | if (rc != 0) | 54 | if (rc != 0) |
@@ -59,6 +59,10 @@ int ima_calc_hash(struct file *file, char *digest) | |||
59 | rc = -ENOMEM; | 59 | rc = -ENOMEM; |
60 | goto out; | 60 | goto out; |
61 | } | 61 | } |
62 | if (!(file->f_mode & FMODE_READ)) { | ||
63 | file->f_mode |= FMODE_READ; | ||
64 | read = 1; | ||
65 | } | ||
62 | i_size = i_size_read(file->f_dentry->d_inode); | 66 | i_size = i_size_read(file->f_dentry->d_inode); |
63 | while (offset < i_size) { | 67 | while (offset < i_size) { |
64 | int rbuf_len; | 68 | int rbuf_len; |
@@ -80,6 +84,8 @@ int ima_calc_hash(struct file *file, char *digest) | |||
80 | kfree(rbuf); | 84 | kfree(rbuf); |
81 | if (!rc) | 85 | if (!rc) |
82 | rc = crypto_hash_final(&desc, digest); | 86 | rc = crypto_hash_final(&desc, digest); |
87 | if (read) | ||
88 | file->f_mode &= ~FMODE_READ; | ||
83 | out: | 89 | out: |
84 | crypto_free_hash(desc.tfm); | 90 | crypto_free_hash(desc.tfm); |
85 | return rc; | 91 | return rc; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index be8294915cf7..6eb28d47e74b 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -22,12 +22,19 @@ | |||
22 | #include <linux/mount.h> | 22 | #include <linux/mount.h> |
23 | #include <linux/mman.h> | 23 | #include <linux/mman.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/xattr.h> | ||
25 | #include <linux/ima.h> | 26 | #include <linux/ima.h> |
26 | 27 | ||
27 | #include "ima.h" | 28 | #include "ima.h" |
28 | 29 | ||
29 | int ima_initialized; | 30 | int ima_initialized; |
30 | 31 | ||
32 | #ifdef CONFIG_IMA_APPRAISE | ||
33 | int ima_appraise = IMA_APPRAISE_ENFORCE; | ||
34 | #else | ||
35 | int ima_appraise; | ||
36 | #endif | ||
37 | |||
31 | char *ima_hash = "sha1"; | 38 | char *ima_hash = "sha1"; |
32 | static int __init hash_setup(char *str) | 39 | static int __init hash_setup(char *str) |
33 | { | 40 | { |
@@ -52,7 +59,7 @@ static void ima_rdwr_violation_check(struct file *file) | |||
52 | struct dentry *dentry = file->f_path.dentry; | 59 | struct dentry *dentry = file->f_path.dentry; |
53 | struct inode *inode = dentry->d_inode; | 60 | struct inode *inode = dentry->d_inode; |
54 | fmode_t mode = file->f_mode; | 61 | fmode_t mode = file->f_mode; |
55 | int rc; | 62 | int must_measure; |
56 | bool send_tomtou = false, send_writers = false; | 63 | bool send_tomtou = false, send_writers = false; |
57 | unsigned char *pathname = NULL, *pathbuf = NULL; | 64 | unsigned char *pathname = NULL, *pathbuf = NULL; |
58 | 65 | ||
@@ -67,8 +74,8 @@ static void ima_rdwr_violation_check(struct file *file) | |||
67 | goto out; | 74 | goto out; |
68 | } | 75 | } |
69 | 76 | ||
70 | rc = ima_must_measure(inode, MAY_READ, FILE_CHECK); | 77 | must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); |
71 | if (rc < 0) | 78 | if (!must_measure) |
72 | goto out; | 79 | goto out; |
73 | 80 | ||
74 | if (atomic_read(&inode->i_writecount) > 0) | 81 | if (atomic_read(&inode->i_writecount) > 0) |
@@ -100,17 +107,21 @@ out: | |||
100 | } | 107 | } |
101 | 108 | ||
102 | static void ima_check_last_writer(struct integrity_iint_cache *iint, | 109 | static void ima_check_last_writer(struct integrity_iint_cache *iint, |
103 | struct inode *inode, | 110 | struct inode *inode, struct file *file) |
104 | struct file *file) | ||
105 | { | 111 | { |
106 | fmode_t mode = file->f_mode; | 112 | fmode_t mode = file->f_mode; |
107 | 113 | ||
108 | mutex_lock(&iint->mutex); | 114 | if (!(mode & FMODE_WRITE)) |
109 | if (mode & FMODE_WRITE && | 115 | return; |
110 | atomic_read(&inode->i_writecount) == 1 && | 116 | |
111 | iint->version != inode->i_version) | 117 | mutex_lock(&inode->i_mutex); |
112 | iint->flags &= ~IMA_MEASURED; | 118 | if (atomic_read(&inode->i_writecount) == 1 && |
113 | mutex_unlock(&iint->mutex); | 119 | iint->version != inode->i_version) { |
120 | iint->flags &= ~(IMA_COLLECTED | IMA_APPRAISED | IMA_MEASURED); | ||
121 | if (iint->flags & IMA_APPRAISE) | ||
122 | ima_update_xattr(iint, file); | ||
123 | } | ||
124 | mutex_unlock(&inode->i_mutex); | ||
114 | } | 125 | } |
115 | 126 | ||
116 | /** | 127 | /** |
@@ -140,14 +151,17 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
140 | struct inode *inode = file->f_dentry->d_inode; | 151 | struct inode *inode = file->f_dentry->d_inode; |
141 | struct integrity_iint_cache *iint; | 152 | struct integrity_iint_cache *iint; |
142 | unsigned char *pathname = NULL, *pathbuf = NULL; | 153 | unsigned char *pathname = NULL, *pathbuf = NULL; |
143 | int rc = 0; | 154 | int rc = -ENOMEM, action, must_appraise; |
144 | 155 | ||
145 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 156 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
146 | return 0; | 157 | return 0; |
147 | 158 | ||
148 | rc = ima_must_measure(inode, mask, function); | 159 | /* Determine if in appraise/measurement policy, |
149 | if (rc != 0) | 160 | * returns IMA_MEASURE, IMA_APPRAISE bitmask. */ |
150 | return rc; | 161 | action = ima_must_appraise_or_measure(inode, mask, function); |
162 | if (!action) | ||
163 | return 0; | ||
164 | |||
151 | retry: | 165 | retry: |
152 | iint = integrity_iint_find(inode); | 166 | iint = integrity_iint_find(inode); |
153 | if (!iint) { | 167 | if (!iint) { |
@@ -157,11 +171,21 @@ retry: | |||
157 | return rc; | 171 | return rc; |
158 | } | 172 | } |
159 | 173 | ||
160 | mutex_lock(&iint->mutex); | 174 | must_appraise = action & IMA_APPRAISE; |
161 | 175 | ||
162 | rc = iint->flags & IMA_MEASURED ? 1 : 0; | 176 | mutex_lock(&inode->i_mutex); |
163 | if (rc != 0) | 177 | |
178 | /* Determine if already appraised/measured based on bitmask | ||
179 | * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED) */ | ||
180 | iint->flags |= action; | ||
181 | action &= ~((iint->flags & (IMA_MEASURED | IMA_APPRAISED)) >> 1); | ||
182 | |||
183 | /* Nothing to do, just return existing appraised status */ | ||
184 | if (!action) { | ||
185 | if (iint->flags & IMA_APPRAISED) | ||
186 | rc = iint->ima_status; | ||
164 | goto out; | 187 | goto out; |
188 | } | ||
165 | 189 | ||
166 | rc = ima_collect_measurement(iint, file); | 190 | rc = ima_collect_measurement(iint, file); |
167 | if (rc != 0) | 191 | if (rc != 0) |
@@ -177,11 +201,16 @@ retry: | |||
177 | pathname = NULL; | 201 | pathname = NULL; |
178 | } | 202 | } |
179 | } | 203 | } |
180 | ima_store_measurement(iint, file, !pathname ? filename : pathname); | 204 | if (action & IMA_MEASURE) |
205 | ima_store_measurement(iint, file, | ||
206 | !pathname ? filename : pathname); | ||
207 | if (action & IMA_APPRAISE) | ||
208 | rc = ima_appraise_measurement(iint, file, | ||
209 | !pathname ? filename : pathname); | ||
181 | kfree(pathbuf); | 210 | kfree(pathbuf); |
182 | out: | 211 | out: |
183 | mutex_unlock(&iint->mutex); | 212 | mutex_unlock(&inode->i_mutex); |
184 | return rc; | 213 | return (rc && must_appraise) ? -EACCES : 0; |
185 | } | 214 | } |
186 | 215 | ||
187 | /** | 216 | /** |
@@ -197,14 +226,14 @@ out: | |||
197 | */ | 226 | */ |
198 | int ima_file_mmap(struct file *file, unsigned long prot) | 227 | int ima_file_mmap(struct file *file, unsigned long prot) |
199 | { | 228 | { |
200 | int rc; | 229 | int rc = 0; |
201 | 230 | ||
202 | if (!file) | 231 | if (!file) |
203 | return 0; | 232 | return 0; |
204 | if (prot & PROT_EXEC) | 233 | if (prot & PROT_EXEC) |
205 | rc = process_measurement(file, file->f_dentry->d_name.name, | 234 | rc = process_measurement(file, file->f_dentry->d_name.name, |
206 | MAY_EXEC, FILE_MMAP); | 235 | MAY_EXEC, FILE_MMAP); |
207 | return 0; | 236 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
208 | } | 237 | } |
209 | 238 | ||
210 | /** | 239 | /** |
@@ -228,7 +257,7 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
228 | (strcmp(bprm->filename, bprm->interp) == 0) ? | 257 | (strcmp(bprm->filename, bprm->interp) == 0) ? |
229 | bprm->filename : bprm->interp, | 258 | bprm->filename : bprm->interp, |
230 | MAY_EXEC, BPRM_CHECK); | 259 | MAY_EXEC, BPRM_CHECK); |
231 | return 0; | 260 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
232 | } | 261 | } |
233 | 262 | ||
234 | /** | 263 | /** |
@@ -249,7 +278,7 @@ int ima_file_check(struct file *file, int mask) | |||
249 | rc = process_measurement(file, file->f_dentry->d_name.name, | 278 | rc = process_measurement(file, file->f_dentry->d_name.name, |
250 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 279 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
251 | FILE_CHECK); | 280 | FILE_CHECK); |
252 | return 0; | 281 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
253 | } | 282 | } |
254 | EXPORT_SYMBOL_GPL(ima_file_check); | 283 | EXPORT_SYMBOL_GPL(ima_file_check); |
255 | 284 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 1a9583008aae..3e22e17da295 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -25,7 +25,13 @@ | |||
25 | #define IMA_FSMAGIC 0x0004 | 25 | #define IMA_FSMAGIC 0x0004 |
26 | #define IMA_UID 0x0008 | 26 | #define IMA_UID 0x0008 |
27 | 27 | ||
28 | enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; | 28 | #define UNKNOWN 0 |
29 | #define MEASURE 1 /* same as IMA_MEASURE */ | ||
30 | #define DONT_MEASURE 2 | ||
31 | #define MEASURE_MASK 3 | ||
32 | #define APPRAISE 4 /* same as IMA_APPRAISE */ | ||
33 | #define DONT_APPRAISE 8 | ||
34 | #define APPRAISE_MASK 12 | ||
29 | 35 | ||
30 | #define MAX_LSM_RULES 6 | 36 | #define MAX_LSM_RULES 6 |
31 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | 37 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, |
@@ -34,7 +40,7 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | |||
34 | 40 | ||
35 | struct ima_measure_rule_entry { | 41 | struct ima_measure_rule_entry { |
36 | struct list_head list; | 42 | struct list_head list; |
37 | enum ima_action action; | 43 | int action; |
38 | unsigned int flags; | 44 | unsigned int flags; |
39 | enum ima_hooks func; | 45 | enum ima_hooks func; |
40 | int mask; | 46 | int mask; |
@@ -163,18 +169,28 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
163 | * as elements in the list are never deleted, nor does the list | 169 | * as elements in the list are never deleted, nor does the list |
164 | * change.) | 170 | * change.) |
165 | */ | 171 | */ |
166 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | 172 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
173 | int flags) | ||
167 | { | 174 | { |
168 | struct ima_measure_rule_entry *entry; | 175 | struct ima_measure_rule_entry *entry; |
176 | int action = 0, actmask = flags | (flags << 1); | ||
169 | 177 | ||
170 | list_for_each_entry(entry, ima_measure, list) { | 178 | list_for_each_entry(entry, ima_measure, list) { |
171 | bool rc; | ||
172 | 179 | ||
173 | rc = ima_match_rules(entry, inode, func, mask); | 180 | if (!(entry->action & actmask)) |
174 | if (rc) | 181 | continue; |
175 | return entry->action; | 182 | |
183 | if (!ima_match_rules(entry, inode, func, mask)) | ||
184 | continue; | ||
185 | |||
186 | action |= (entry->action & (IMA_APPRAISE | IMA_MEASURE)); | ||
187 | actmask &= (entry->action & APPRAISE_MASK) ? | ||
188 | ~APPRAISE_MASK : ~MEASURE_MASK; | ||
189 | if (!actmask) | ||
190 | break; | ||
176 | } | 191 | } |
177 | return 0; | 192 | |
193 | return action; | ||
178 | } | 194 | } |
179 | 195 | ||
180 | /** | 196 | /** |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 7a25ecec5aaa..dac6b68e945a 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -16,7 +16,11 @@ | |||
16 | #include <crypto/sha.h> | 16 | #include <crypto/sha.h> |
17 | 17 | ||
18 | /* iint cache flags */ | 18 | /* iint cache flags */ |
19 | #define IMA_MEASURED 0x01 | 19 | #define IMA_MEASURE 0x01 |
20 | #define IMA_MEASURED 0x02 | ||
21 | #define IMA_APPRAISE 0x04 | ||
22 | #define IMA_APPRAISED 0x08 | ||
23 | #define IMA_COLLECTED 0x10 | ||
20 | 24 | ||
21 | enum evm_ima_xattr_type { | 25 | enum evm_ima_xattr_type { |
22 | IMA_XATTR_DIGEST = 0x01, | 26 | IMA_XATTR_DIGEST = 0x01, |
@@ -36,7 +40,7 @@ struct integrity_iint_cache { | |||
36 | u64 version; /* track inode changes */ | 40 | u64 version; /* track inode changes */ |
37 | unsigned char flags; | 41 | unsigned char flags; |
38 | u8 digest[SHA1_DIGEST_SIZE]; | 42 | u8 digest[SHA1_DIGEST_SIZE]; |
39 | struct mutex mutex; /* protects: version, flags, digest */ | 43 | enum integrity_status ima_status; |
40 | enum integrity_status evm_status; | 44 | enum integrity_status evm_status; |
41 | }; | 45 | }; |
42 | 46 | ||