diff options
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/evm/evm_crypto.c | 4 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 3 | ||||
-rw-r--r-- | security/integrity/iint.c | 64 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 16 | ||||
-rw-r--r-- | security/integrity/ima/Makefile | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 39 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 86 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 263 | ||||
-rw-r--r-- | security/integrity/ima/ima_audit.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 8 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 93 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 209 | ||||
-rw-r--r-- | security/integrity/integrity.h | 22 |
13 files changed, 662 insertions, 151 deletions
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 49a464f5595b..dfb26918699c 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c | |||
@@ -106,8 +106,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, | |||
106 | memset(&hmac_misc, 0, sizeof hmac_misc); | 106 | memset(&hmac_misc, 0, sizeof hmac_misc); |
107 | hmac_misc.ino = inode->i_ino; | 107 | hmac_misc.ino = inode->i_ino; |
108 | hmac_misc.generation = inode->i_generation; | 108 | hmac_misc.generation = inode->i_generation; |
109 | hmac_misc.uid = inode->i_uid; | 109 | hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); |
110 | hmac_misc.gid = inode->i_gid; | 110 | hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); |
111 | hmac_misc.mode = inode->i_mode; | 111 | hmac_misc.mode = inode->i_mode; |
112 | crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc); | 112 | crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc); |
113 | crypto_shash_final(desc, digest); | 113 | crypto_shash_final(desc, digest); |
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..d82a5a13d855 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "integrity.h" | 22 | #include "integrity.h" |
23 | 23 | ||
24 | static struct rb_root integrity_iint_tree = RB_ROOT; | 24 | static struct rb_root integrity_iint_tree = RB_ROOT; |
25 | static DEFINE_SPINLOCK(integrity_iint_lock); | 25 | static DEFINE_RWLOCK(integrity_iint_lock); |
26 | static struct kmem_cache *iint_cache __read_mostly; | 26 | static struct kmem_cache *iint_cache __read_mostly; |
27 | 27 | ||
28 | int iint_initialized; | 28 | int iint_initialized; |
@@ -35,8 +35,6 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) | |||
35 | struct integrity_iint_cache *iint; | 35 | struct integrity_iint_cache *iint; |
36 | struct rb_node *n = integrity_iint_tree.rb_node; | 36 | struct rb_node *n = integrity_iint_tree.rb_node; |
37 | 37 | ||
38 | assert_spin_locked(&integrity_iint_lock); | ||
39 | |||
40 | while (n) { | 38 | while (n) { |
41 | iint = rb_entry(n, struct integrity_iint_cache, rb_node); | 39 | iint = rb_entry(n, struct integrity_iint_cache, rb_node); |
42 | 40 | ||
@@ -63,9 +61,9 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) | |||
63 | if (!IS_IMA(inode)) | 61 | if (!IS_IMA(inode)) |
64 | return NULL; | 62 | return NULL; |
65 | 63 | ||
66 | spin_lock(&integrity_iint_lock); | 64 | read_lock(&integrity_iint_lock); |
67 | iint = __integrity_iint_find(inode); | 65 | iint = __integrity_iint_find(inode); |
68 | spin_unlock(&integrity_iint_lock); | 66 | read_unlock(&integrity_iint_lock); |
69 | 67 | ||
70 | return iint; | 68 | return iint; |
71 | } | 69 | } |
@@ -74,59 +72,53 @@ static void iint_free(struct integrity_iint_cache *iint) | |||
74 | { | 72 | { |
75 | iint->version = 0; | 73 | iint->version = 0; |
76 | iint->flags = 0UL; | 74 | iint->flags = 0UL; |
75 | iint->ima_status = INTEGRITY_UNKNOWN; | ||
77 | iint->evm_status = INTEGRITY_UNKNOWN; | 76 | iint->evm_status = INTEGRITY_UNKNOWN; |
78 | kmem_cache_free(iint_cache, iint); | 77 | kmem_cache_free(iint_cache, iint); |
79 | } | 78 | } |
80 | 79 | ||
81 | /** | 80 | /** |
82 | * integrity_inode_alloc - allocate an iint associated with an inode | 81 | * integrity_inode_get - find or allocate an iint associated with an inode |
83 | * @inode: pointer to the inode | 82 | * @inode: pointer to the inode |
83 | * @return: allocated iint | ||
84 | * | ||
85 | * Caller must lock i_mutex | ||
84 | */ | 86 | */ |
85 | int integrity_inode_alloc(struct inode *inode) | 87 | struct integrity_iint_cache *integrity_inode_get(struct inode *inode) |
86 | { | 88 | { |
87 | struct rb_node **p; | 89 | struct rb_node **p; |
88 | struct rb_node *new_node, *parent = NULL; | 90 | struct rb_node *node, *parent = NULL; |
89 | struct integrity_iint_cache *new_iint, *test_iint; | 91 | struct integrity_iint_cache *iint, *test_iint; |
90 | int rc; | ||
91 | 92 | ||
92 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | 93 | iint = integrity_iint_find(inode); |
93 | if (!new_iint) | 94 | if (iint) |
94 | return -ENOMEM; | 95 | return iint; |
95 | 96 | ||
96 | new_iint->inode = inode; | 97 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
97 | new_node = &new_iint->rb_node; | 98 | if (!iint) |
99 | return NULL; | ||
98 | 100 | ||
99 | mutex_lock(&inode->i_mutex); /* i_flags */ | 101 | write_lock(&integrity_iint_lock); |
100 | spin_lock(&integrity_iint_lock); | ||
101 | 102 | ||
102 | p = &integrity_iint_tree.rb_node; | 103 | p = &integrity_iint_tree.rb_node; |
103 | while (*p) { | 104 | while (*p) { |
104 | parent = *p; | 105 | parent = *p; |
105 | test_iint = rb_entry(parent, struct integrity_iint_cache, | 106 | test_iint = rb_entry(parent, struct integrity_iint_cache, |
106 | rb_node); | 107 | rb_node); |
107 | rc = -EEXIST; | ||
108 | if (inode < test_iint->inode) | 108 | if (inode < test_iint->inode) |
109 | p = &(*p)->rb_left; | 109 | p = &(*p)->rb_left; |
110 | else if (inode > test_iint->inode) | ||
111 | p = &(*p)->rb_right; | ||
112 | else | 110 | else |
113 | goto out_err; | 111 | p = &(*p)->rb_right; |
114 | } | 112 | } |
115 | 113 | ||
114 | iint->inode = inode; | ||
115 | node = &iint->rb_node; | ||
116 | inode->i_flags |= S_IMA; | 116 | inode->i_flags |= S_IMA; |
117 | rb_link_node(new_node, parent, p); | 117 | rb_link_node(node, parent, p); |
118 | rb_insert_color(new_node, &integrity_iint_tree); | 118 | rb_insert_color(node, &integrity_iint_tree); |
119 | 119 | ||
120 | spin_unlock(&integrity_iint_lock); | 120 | write_unlock(&integrity_iint_lock); |
121 | mutex_unlock(&inode->i_mutex); /* i_flags */ | 121 | return iint; |
122 | |||
123 | return 0; | ||
124 | out_err: | ||
125 | spin_unlock(&integrity_iint_lock); | ||
126 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
127 | iint_free(new_iint); | ||
128 | |||
129 | return rc; | ||
130 | } | 122 | } |
131 | 123 | ||
132 | /** | 124 | /** |
@@ -142,10 +134,10 @@ void integrity_inode_free(struct inode *inode) | |||
142 | if (!IS_IMA(inode)) | 134 | if (!IS_IMA(inode)) |
143 | return; | 135 | return; |
144 | 136 | ||
145 | spin_lock(&integrity_iint_lock); | 137 | write_lock(&integrity_iint_lock); |
146 | iint = __integrity_iint_find(inode); | 138 | iint = __integrity_iint_find(inode); |
147 | rb_erase(&iint->rb_node, &integrity_iint_tree); | 139 | rb_erase(&iint->rb_node, &integrity_iint_tree); |
148 | spin_unlock(&integrity_iint_lock); | 140 | write_unlock(&integrity_iint_lock); |
149 | 141 | ||
150 | iint_free(iint); | 142 | iint_free(iint); |
151 | } | 143 | } |
@@ -157,7 +149,7 @@ static void init_once(void *foo) | |||
157 | memset(iint, 0, sizeof *iint); | 149 | memset(iint, 0, sizeof *iint); |
158 | iint->version = 0; | 150 | iint->version = 0; |
159 | iint->flags = 0UL; | 151 | iint->flags = 0UL; |
160 | mutex_init(&iint->mutex); | 152 | iint->ima_status = INTEGRITY_UNKNOWN; |
161 | iint->evm_status = INTEGRITY_UNKNOWN; | 153 | iint->evm_status = INTEGRITY_UNKNOWN; |
162 | } | 154 | } |
163 | 155 | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index b9c1219924f1..d232c73647ae 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -11,6 +11,7 @@ config IMA | |||
11 | select CRYPTO_SHA1 | 11 | select CRYPTO_SHA1 |
12 | select TCG_TPM if HAS_IOMEM && !UML | 12 | select TCG_TPM if HAS_IOMEM && !UML |
13 | select TCG_TIS if TCG_TPM && X86 | 13 | select TCG_TIS if TCG_TPM && X86 |
14 | select TCG_IBMVTPM if TCG_TPM && PPC64 | ||
14 | help | 15 | help |
15 | The Trusted Computing Group(TCG) runtime Integrity | 16 | The Trusted Computing Group(TCG) runtime Integrity |
16 | Measurement Architecture(IMA) maintains a list of hash | 17 | Measurement Architecture(IMA) maintains a list of hash |
@@ -55,3 +56,18 @@ config IMA_LSM_RULES | |||
55 | default y | 56 | default y |
56 | help | 57 | help |
57 | 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..6ee8826662cc 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,11 +108,14 @@ 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_get_action(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); |
113 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, | 115 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, |
114 | const unsigned char *filename); | 116 | const unsigned char *filename); |
117 | void ima_audit_measurement(struct integrity_iint_cache *iint, | ||
118 | const unsigned char *filename); | ||
115 | int ima_store_template(struct ima_template_entry *entry, int violation, | 119 | int ima_store_template(struct ima_template_entry *entry, int violation, |
116 | struct inode *inode); | 120 | struct inode *inode); |
117 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); | 121 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); |
@@ -123,14 +127,45 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); | |||
123 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 127 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
124 | 128 | ||
125 | /* IMA policy related functions */ | 129 | /* IMA policy related functions */ |
126 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; |
127 | 131 | ||
128 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 132 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
133 | int flags); | ||
129 | void ima_init_policy(void); | 134 | void ima_init_policy(void); |
130 | void ima_update_policy(void); | 135 | void ima_update_policy(void); |
131 | ssize_t ima_parse_add_rule(char *); | 136 | ssize_t ima_parse_add_rule(char *); |
132 | void ima_delete_rules(void); | 137 | void ima_delete_rules(void); |
133 | 138 | ||
139 | /* Appraise integrity measurements */ | ||
140 | #define IMA_APPRAISE_ENFORCE 0x01 | ||
141 | #define IMA_APPRAISE_FIX 0x02 | ||
142 | |||
143 | #ifdef CONFIG_IMA_APPRAISE | ||
144 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
145 | struct file *file, const unsigned char *filename); | ||
146 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); | ||
147 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); | ||
148 | |||
149 | #else | ||
150 | static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
151 | struct file *file, | ||
152 | const unsigned char *filename) | ||
153 | { | ||
154 | return INTEGRITY_UNKNOWN; | ||
155 | } | ||
156 | |||
157 | static inline int ima_must_appraise(struct inode *inode, int mask, | ||
158 | enum ima_hooks func) | ||
159 | { | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static inline void ima_update_xattr(struct integrity_iint_cache *iint, | ||
164 | struct file *file) | ||
165 | { | ||
166 | } | ||
167 | #endif | ||
168 | |||
134 | /* LSM based policy rules require audit */ | 169 | /* LSM based policy rules require audit */ |
135 | #ifdef CONFIG_IMA_LSM_RULES | 170 | #ifdef CONFIG_IMA_LSM_RULES |
136 | 171 | ||
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 032ff03ad907..b356884fb3ef 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_get_action - 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_get_action(struct inode *inode, int mask, int function) |
112 | { | 116 | { |
113 | int must_measure; | 117 | int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; |
118 | |||
119 | if (!ima_appraise) | ||
120 | flags &= ~IMA_APPRAISE; | ||
114 | 121 | ||
115 | must_measure = ima_match_policy(inode, function, mask); | 122 | return ima_match_policy(inode, function, mask, flags); |
116 | return must_measure ? 0 : -EACCES; | 123 | } |
124 | |||
125 | int ima_must_measure(struct inode *inode, int mask, int function) | ||
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 | iint->ima_xattr.type = IMA_XATTR_DIGEST; |
138 | result = ima_calc_hash(file, iint->digest); | 151 | result = ima_calc_hash(file, iint->ima_xattr.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, |
@@ -174,7 +196,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
174 | return; | 196 | return; |
175 | } | 197 | } |
176 | memset(&entry->template, 0, sizeof(entry->template)); | 198 | memset(&entry->template, 0, sizeof(entry->template)); |
177 | memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE); | 199 | memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE); |
178 | strcpy(entry->template.file_name, | 200 | strcpy(entry->template.file_name, |
179 | (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? | 201 | (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? |
180 | file->f_dentry->d_name.name : filename); | 202 | file->f_dentry->d_name.name : filename); |
@@ -185,3 +207,33 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
185 | if (result < 0) | 207 | if (result < 0) |
186 | kfree(entry); | 208 | kfree(entry); |
187 | } | 209 | } |
210 | |||
211 | void ima_audit_measurement(struct integrity_iint_cache *iint, | ||
212 | const unsigned char *filename) | ||
213 | { | ||
214 | struct audit_buffer *ab; | ||
215 | char hash[(IMA_DIGEST_SIZE * 2) + 1]; | ||
216 | int i; | ||
217 | |||
218 | if (iint->flags & IMA_AUDITED) | ||
219 | return; | ||
220 | |||
221 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | ||
222 | hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); | ||
223 | hash[i * 2] = '\0'; | ||
224 | |||
225 | ab = audit_log_start(current->audit_context, GFP_KERNEL, | ||
226 | AUDIT_INTEGRITY_RULE); | ||
227 | if (!ab) | ||
228 | return; | ||
229 | |||
230 | audit_log_format(ab, "file="); | ||
231 | audit_log_untrustedstring(ab, filename); | ||
232 | audit_log_format(ab, " hash="); | ||
233 | audit_log_untrustedstring(ab, hash); | ||
234 | |||
235 | audit_log_task_info(ab, current); | ||
236 | audit_log_end(ab); | ||
237 | |||
238 | iint->flags |= IMA_AUDITED; | ||
239 | } | ||
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c new file mode 100644 index 000000000000..bdc8ba1d1d27 --- /dev/null +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -0,0 +1,263 @@ | |||
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, int mask, enum ima_hooks func) | ||
38 | { | ||
39 | if (!ima_appraise) | ||
40 | return 0; | ||
41 | |||
42 | return ima_match_policy(inode, func, mask, IMA_APPRAISE); | ||
43 | } | ||
44 | |||
45 | static void ima_fix_xattr(struct dentry *dentry, | ||
46 | struct integrity_iint_cache *iint) | ||
47 | { | ||
48 | iint->ima_xattr.type = IMA_XATTR_DIGEST; | ||
49 | __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, (u8 *)&iint->ima_xattr, | ||
50 | sizeof iint->ima_xattr, 0); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * ima_appraise_measurement - appraise file measurement | ||
55 | * | ||
56 | * Call evm_verifyxattr() to verify the integrity of 'security.ima'. | ||
57 | * Assuming success, compare the xattr hash with the collected measurement. | ||
58 | * | ||
59 | * Return 0 on success, error code otherwise | ||
60 | */ | ||
61 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
62 | struct file *file, const unsigned char *filename) | ||
63 | { | ||
64 | struct dentry *dentry = file->f_dentry; | ||
65 | struct inode *inode = dentry->d_inode; | ||
66 | struct evm_ima_xattr_data *xattr_value = NULL; | ||
67 | enum integrity_status status = INTEGRITY_UNKNOWN; | ||
68 | const char *op = "appraise_data"; | ||
69 | char *cause = "unknown"; | ||
70 | int rc; | ||
71 | |||
72 | if (!ima_appraise) | ||
73 | return 0; | ||
74 | if (!inode->i_op->getxattr) | ||
75 | return INTEGRITY_UNKNOWN; | ||
76 | |||
77 | if (iint->flags & IMA_APPRAISED) | ||
78 | return iint->ima_status; | ||
79 | |||
80 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, | ||
81 | 0, GFP_NOFS); | ||
82 | if (rc <= 0) { | ||
83 | if (rc && rc != -ENODATA) | ||
84 | goto out; | ||
85 | |||
86 | cause = "missing-hash"; | ||
87 | status = | ||
88 | (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL; | ||
89 | goto out; | ||
90 | } | ||
91 | |||
92 | status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); | ||
93 | if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { | ||
94 | if ((status == INTEGRITY_NOLABEL) | ||
95 | || (status == INTEGRITY_NOXATTRS)) | ||
96 | cause = "missing-HMAC"; | ||
97 | else if (status == INTEGRITY_FAIL) | ||
98 | cause = "invalid-HMAC"; | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | switch (xattr_value->type) { | ||
103 | case IMA_XATTR_DIGEST: | ||
104 | rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, | ||
105 | IMA_DIGEST_SIZE); | ||
106 | if (rc) { | ||
107 | cause = "invalid-hash"; | ||
108 | status = INTEGRITY_FAIL; | ||
109 | print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE, | ||
110 | xattr_value, sizeof(*xattr_value)); | ||
111 | print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE, | ||
112 | (u8 *)&iint->ima_xattr, | ||
113 | sizeof iint->ima_xattr); | ||
114 | break; | ||
115 | } | ||
116 | status = INTEGRITY_PASS; | ||
117 | break; | ||
118 | case EVM_IMA_XATTR_DIGSIG: | ||
119 | iint->flags |= IMA_DIGSIG; | ||
120 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | ||
121 | xattr_value->digest, rc - 1, | ||
122 | iint->ima_xattr.digest, | ||
123 | IMA_DIGEST_SIZE); | ||
124 | if (rc == -EOPNOTSUPP) { | ||
125 | status = INTEGRITY_UNKNOWN; | ||
126 | } else if (rc) { | ||
127 | cause = "invalid-signature"; | ||
128 | status = INTEGRITY_FAIL; | ||
129 | } else { | ||
130 | status = INTEGRITY_PASS; | ||
131 | } | ||
132 | break; | ||
133 | default: | ||
134 | status = INTEGRITY_UNKNOWN; | ||
135 | cause = "unknown-ima-data"; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | out: | ||
140 | if (status != INTEGRITY_PASS) { | ||
141 | if ((ima_appraise & IMA_APPRAISE_FIX) && | ||
142 | (!xattr_value || | ||
143 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { | ||
144 | ima_fix_xattr(dentry, iint); | ||
145 | status = INTEGRITY_PASS; | ||
146 | } | ||
147 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, | ||
148 | op, cause, rc, 0); | ||
149 | } else { | ||
150 | iint->flags |= IMA_APPRAISED; | ||
151 | } | ||
152 | iint->ima_status = status; | ||
153 | kfree(xattr_value); | ||
154 | return status; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * ima_update_xattr - update 'security.ima' hash value | ||
159 | */ | ||
160 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | ||
161 | { | ||
162 | struct dentry *dentry = file->f_dentry; | ||
163 | int rc = 0; | ||
164 | |||
165 | /* do not collect and update hash for digital signatures */ | ||
166 | if (iint->flags & IMA_DIGSIG) | ||
167 | return; | ||
168 | |||
169 | rc = ima_collect_measurement(iint, file); | ||
170 | if (rc < 0) | ||
171 | return; | ||
172 | |||
173 | ima_fix_xattr(dentry, iint); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * ima_inode_post_setattr - reflect file metadata changes | ||
178 | * @dentry: pointer to the affected dentry | ||
179 | * | ||
180 | * Changes to a dentry's metadata might result in needing to appraise. | ||
181 | * | ||
182 | * This function is called from notify_change(), which expects the caller | ||
183 | * to lock the inode's i_mutex. | ||
184 | */ | ||
185 | void ima_inode_post_setattr(struct dentry *dentry) | ||
186 | { | ||
187 | struct inode *inode = dentry->d_inode; | ||
188 | struct integrity_iint_cache *iint; | ||
189 | int must_appraise, rc; | ||
190 | |||
191 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) | ||
192 | || !inode->i_op->removexattr) | ||
193 | return; | ||
194 | |||
195 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); | ||
196 | iint = integrity_iint_find(inode); | ||
197 | if (iint) { | ||
198 | if (must_appraise) | ||
199 | iint->flags |= IMA_APPRAISE; | ||
200 | else | ||
201 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); | ||
202 | } | ||
203 | if (!must_appraise) | ||
204 | rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * ima_protect_xattr - protect 'security.ima' | ||
210 | * | ||
211 | * Ensure that not just anyone can modify or remove 'security.ima'. | ||
212 | */ | ||
213 | static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, | ||
214 | const void *xattr_value, size_t xattr_value_len) | ||
215 | { | ||
216 | if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) { | ||
217 | if (!capable(CAP_SYS_ADMIN)) | ||
218 | return -EPERM; | ||
219 | return 1; | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static void ima_reset_appraise_flags(struct inode *inode) | ||
225 | { | ||
226 | struct integrity_iint_cache *iint; | ||
227 | |||
228 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)) | ||
229 | return; | ||
230 | |||
231 | iint = integrity_iint_find(inode); | ||
232 | if (!iint) | ||
233 | return; | ||
234 | |||
235 | iint->flags &= ~IMA_DONE_MASK; | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | ||
240 | const void *xattr_value, size_t xattr_value_len) | ||
241 | { | ||
242 | int result; | ||
243 | |||
244 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, | ||
245 | xattr_value_len); | ||
246 | if (result == 1) { | ||
247 | ima_reset_appraise_flags(dentry->d_inode); | ||
248 | result = 0; | ||
249 | } | ||
250 | return result; | ||
251 | } | ||
252 | |||
253 | int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) | ||
254 | { | ||
255 | int result; | ||
256 | |||
257 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); | ||
258 | if (result == 1) { | ||
259 | ima_reset_appraise_flags(dentry->d_inode); | ||
260 | result = 0; | ||
261 | } | ||
262 | return result; | ||
263 | } | ||
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 7a57f6769e9c..c586faae8fd6 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c | |||
@@ -39,8 +39,9 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
39 | 39 | ||
40 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); | 40 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); |
41 | audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u", | 41 | audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u", |
42 | current->pid, current_cred()->uid, | 42 | current->pid, |
43 | audit_get_loginuid(current), | 43 | from_kuid(&init_user_ns, current_cred()->uid), |
44 | from_kuid(&init_user_ns, audit_get_loginuid(current)), | ||
44 | audit_get_sessionid(current)); | 45 | audit_get_sessionid(current)); |
45 | audit_log_task_context(ab); | 46 | audit_log_task_context(ab); |
46 | audit_log_format(ab, " op="); | 47 | audit_log_format(ab, " op="); |
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..73c9a268253e 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_DONE_MASK; | ||
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,28 +151,37 @@ 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/audit/measurement policy, |
149 | if (rc != 0) | 160 | * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */ |
150 | return rc; | 161 | action = ima_get_action(inode, mask, function); |
151 | retry: | 162 | if (!action) |
152 | iint = integrity_iint_find(inode); | 163 | return 0; |
153 | if (!iint) { | ||
154 | rc = integrity_inode_alloc(inode); | ||
155 | if (!rc || rc == -EEXIST) | ||
156 | goto retry; | ||
157 | return rc; | ||
158 | } | ||
159 | 164 | ||
160 | mutex_lock(&iint->mutex); | 165 | must_appraise = action & IMA_APPRAISE; |
161 | 166 | ||
162 | rc = iint->flags & IMA_MEASURED ? 1 : 0; | 167 | mutex_lock(&inode->i_mutex); |
163 | if (rc != 0) | 168 | |
169 | iint = integrity_inode_get(inode); | ||
170 | if (!iint) | ||
171 | goto out; | ||
172 | |||
173 | /* Determine if already appraised/measured based on bitmask | ||
174 | * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, | ||
175 | * IMA_AUDIT, IMA_AUDITED) */ | ||
176 | iint->flags |= action; | ||
177 | action &= ~((iint->flags & IMA_DONE_MASK) >> 1); | ||
178 | |||
179 | /* Nothing to do, just return existing appraised status */ | ||
180 | if (!action) { | ||
181 | if (iint->flags & IMA_APPRAISED) | ||
182 | rc = iint->ima_status; | ||
164 | goto out; | 183 | goto out; |
184 | } | ||
165 | 185 | ||
166 | rc = ima_collect_measurement(iint, file); | 186 | rc = ima_collect_measurement(iint, file); |
167 | if (rc != 0) | 187 | if (rc != 0) |
@@ -177,11 +197,18 @@ retry: | |||
177 | pathname = NULL; | 197 | pathname = NULL; |
178 | } | 198 | } |
179 | } | 199 | } |
180 | ima_store_measurement(iint, file, !pathname ? filename : pathname); | 200 | if (action & IMA_MEASURE) |
201 | ima_store_measurement(iint, file, | ||
202 | !pathname ? filename : pathname); | ||
203 | if (action & IMA_APPRAISE) | ||
204 | rc = ima_appraise_measurement(iint, file, | ||
205 | !pathname ? filename : pathname); | ||
206 | if (action & IMA_AUDIT) | ||
207 | ima_audit_measurement(iint, !pathname ? filename : pathname); | ||
181 | kfree(pathbuf); | 208 | kfree(pathbuf); |
182 | out: | 209 | out: |
183 | mutex_unlock(&iint->mutex); | 210 | mutex_unlock(&inode->i_mutex); |
184 | return rc; | 211 | return (rc && must_appraise) ? -EACCES : 0; |
185 | } | 212 | } |
186 | 213 | ||
187 | /** | 214 | /** |
@@ -197,14 +224,14 @@ out: | |||
197 | */ | 224 | */ |
198 | int ima_file_mmap(struct file *file, unsigned long prot) | 225 | int ima_file_mmap(struct file *file, unsigned long prot) |
199 | { | 226 | { |
200 | int rc; | 227 | int rc = 0; |
201 | 228 | ||
202 | if (!file) | 229 | if (!file) |
203 | return 0; | 230 | return 0; |
204 | if (prot & PROT_EXEC) | 231 | if (prot & PROT_EXEC) |
205 | rc = process_measurement(file, file->f_dentry->d_name.name, | 232 | rc = process_measurement(file, file->f_dentry->d_name.name, |
206 | MAY_EXEC, FILE_MMAP); | 233 | MAY_EXEC, FILE_MMAP); |
207 | return 0; | 234 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
208 | } | 235 | } |
209 | 236 | ||
210 | /** | 237 | /** |
@@ -228,7 +255,7 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
228 | (strcmp(bprm->filename, bprm->interp) == 0) ? | 255 | (strcmp(bprm->filename, bprm->interp) == 0) ? |
229 | bprm->filename : bprm->interp, | 256 | bprm->filename : bprm->interp, |
230 | MAY_EXEC, BPRM_CHECK); | 257 | MAY_EXEC, BPRM_CHECK); |
231 | return 0; | 258 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
232 | } | 259 | } |
233 | 260 | ||
234 | /** | 261 | /** |
@@ -249,7 +276,7 @@ int ima_file_check(struct file *file, int mask) | |||
249 | rc = process_measurement(file, file->f_dentry->d_name.name, | 276 | rc = process_measurement(file, file->f_dentry->d_name.name, |
250 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 277 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
251 | FILE_CHECK); | 278 | FILE_CHECK); |
252 | return 0; | 279 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
253 | } | 280 | } |
254 | EXPORT_SYMBOL_GPL(ima_file_check); | 281 | EXPORT_SYMBOL_GPL(ima_file_check); |
255 | 282 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 1a9583008aae..c7dacd2eab7a 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -24,22 +24,29 @@ | |||
24 | #define IMA_MASK 0x0002 | 24 | #define IMA_MASK 0x0002 |
25 | #define IMA_FSMAGIC 0x0004 | 25 | #define IMA_FSMAGIC 0x0004 |
26 | #define IMA_UID 0x0008 | 26 | #define IMA_UID 0x0008 |
27 | #define IMA_FOWNER 0x0010 | ||
27 | 28 | ||
28 | enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; | 29 | #define UNKNOWN 0 |
30 | #define MEASURE 0x0001 /* same as IMA_MEASURE */ | ||
31 | #define DONT_MEASURE 0x0002 | ||
32 | #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ | ||
33 | #define DONT_APPRAISE 0x0008 | ||
34 | #define AUDIT 0x0040 | ||
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, |
32 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | 38 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE |
33 | }; | 39 | }; |
34 | 40 | ||
35 | struct ima_measure_rule_entry { | 41 | struct ima_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; |
41 | unsigned long fsmagic; | 47 | unsigned long fsmagic; |
42 | uid_t uid; | 48 | kuid_t uid; |
49 | kuid_t fowner; | ||
43 | struct { | 50 | struct { |
44 | void *rule; /* LSM file metadata specific */ | 51 | void *rule; /* LSM file metadata specific */ |
45 | int type; /* audit type */ | 52 | int type; /* audit type */ |
@@ -48,7 +55,7 @@ struct ima_measure_rule_entry { | |||
48 | 55 | ||
49 | /* | 56 | /* |
50 | * Without LSM specific knowledge, the default policy can only be | 57 | * Without LSM specific knowledge, the default policy can only be |
51 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | 58 | * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner |
52 | */ | 59 | */ |
53 | 60 | ||
54 | /* | 61 | /* |
@@ -57,7 +64,7 @@ struct ima_measure_rule_entry { | |||
57 | * normal users can easily run the machine out of memory simply building | 64 | * normal users can easily run the machine out of memory simply building |
58 | * and running executables. | 65 | * and running executables. |
59 | */ | 66 | */ |
60 | static struct ima_measure_rule_entry default_rules[] = { | 67 | static struct ima_rule_entry default_rules[] = { |
61 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | 68 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
62 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | 69 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
63 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | 70 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, |
@@ -71,23 +78,45 @@ static struct ima_measure_rule_entry default_rules[] = { | |||
71 | .flags = IMA_FUNC | IMA_MASK}, | 78 | .flags = IMA_FUNC | IMA_MASK}, |
72 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, | 79 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, |
73 | .flags = IMA_FUNC | IMA_MASK}, | 80 | .flags = IMA_FUNC | IMA_MASK}, |
74 | {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = 0, | 81 | {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, |
75 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 82 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
76 | }; | 83 | }; |
77 | 84 | ||
78 | static LIST_HEAD(measure_default_rules); | 85 | static struct ima_rule_entry default_appraise_rules[] = { |
79 | static LIST_HEAD(measure_policy_rules); | 86 | {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
80 | static struct list_head *ima_measure; | 87 | {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
88 | {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
89 | {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
90 | {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
91 | {.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | ||
92 | {.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
93 | {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
94 | {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, | ||
95 | {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | ||
96 | {.action = APPRAISE,.fowner = GLOBAL_ROOT_UID,.flags = IMA_FOWNER}, | ||
97 | }; | ||
98 | |||
99 | static LIST_HEAD(ima_default_rules); | ||
100 | static LIST_HEAD(ima_policy_rules); | ||
101 | static struct list_head *ima_rules; | ||
81 | 102 | ||
82 | static DEFINE_MUTEX(ima_measure_mutex); | 103 | static DEFINE_MUTEX(ima_rules_mutex); |
83 | 104 | ||
84 | static bool ima_use_tcb __initdata; | 105 | static bool ima_use_tcb __initdata; |
85 | static int __init default_policy_setup(char *str) | 106 | static int __init default_measure_policy_setup(char *str) |
86 | { | 107 | { |
87 | ima_use_tcb = 1; | 108 | ima_use_tcb = 1; |
88 | return 1; | 109 | return 1; |
89 | } | 110 | } |
90 | __setup("ima_tcb", default_policy_setup); | 111 | __setup("ima_tcb", default_measure_policy_setup); |
112 | |||
113 | static bool ima_use_appraise_tcb __initdata; | ||
114 | static int __init default_appraise_policy_setup(char *str) | ||
115 | { | ||
116 | ima_use_appraise_tcb = 1; | ||
117 | return 1; | ||
118 | } | ||
119 | __setup("ima_appraise_tcb", default_appraise_policy_setup); | ||
91 | 120 | ||
92 | /** | 121 | /** |
93 | * ima_match_rules - determine whether an inode matches the measure rule. | 122 | * ima_match_rules - determine whether an inode matches the measure rule. |
@@ -98,7 +127,7 @@ __setup("ima_tcb", default_policy_setup); | |||
98 | * | 127 | * |
99 | * Returns true on rule match, false on failure. | 128 | * Returns true on rule match, false on failure. |
100 | */ | 129 | */ |
101 | static bool ima_match_rules(struct ima_measure_rule_entry *rule, | 130 | static bool ima_match_rules(struct ima_rule_entry *rule, |
102 | struct inode *inode, enum ima_hooks func, int mask) | 131 | struct inode *inode, enum ima_hooks func, int mask) |
103 | { | 132 | { |
104 | struct task_struct *tsk = current; | 133 | struct task_struct *tsk = current; |
@@ -112,7 +141,9 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
112 | if ((rule->flags & IMA_FSMAGIC) | 141 | if ((rule->flags & IMA_FSMAGIC) |
113 | && rule->fsmagic != inode->i_sb->s_magic) | 142 | && rule->fsmagic != inode->i_sb->s_magic) |
114 | return false; | 143 | return false; |
115 | if ((rule->flags & IMA_UID) && rule->uid != cred->uid) | 144 | if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) |
145 | return false; | ||
146 | if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) | ||
116 | return false; | 147 | return false; |
117 | for (i = 0; i < MAX_LSM_RULES; i++) { | 148 | for (i = 0; i < MAX_LSM_RULES; i++) { |
118 | int rc = 0; | 149 | int rc = 0; |
@@ -163,39 +194,61 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
163 | * as elements in the list are never deleted, nor does the list | 194 | * as elements in the list are never deleted, nor does the list |
164 | * change.) | 195 | * change.) |
165 | */ | 196 | */ |
166 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | 197 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
198 | int flags) | ||
167 | { | 199 | { |
168 | struct ima_measure_rule_entry *entry; | 200 | struct ima_rule_entry *entry; |
201 | int action = 0, actmask = flags | (flags << 1); | ||
202 | |||
203 | list_for_each_entry(entry, ima_rules, list) { | ||
204 | |||
205 | if (!(entry->action & actmask)) | ||
206 | continue; | ||
207 | |||
208 | if (!ima_match_rules(entry, inode, func, mask)) | ||
209 | continue; | ||
169 | 210 | ||
170 | list_for_each_entry(entry, ima_measure, list) { | 211 | action |= entry->action & IMA_DO_MASK; |
171 | bool rc; | 212 | if (entry->action & IMA_DO_MASK) |
213 | actmask &= ~(entry->action | entry->action << 1); | ||
214 | else | ||
215 | actmask &= ~(entry->action | entry->action >> 1); | ||
172 | 216 | ||
173 | rc = ima_match_rules(entry, inode, func, mask); | 217 | if (!actmask) |
174 | if (rc) | 218 | break; |
175 | return entry->action; | ||
176 | } | 219 | } |
177 | return 0; | 220 | |
221 | return action; | ||
178 | } | 222 | } |
179 | 223 | ||
180 | /** | 224 | /** |
181 | * ima_init_policy - initialize the default measure rules. | 225 | * ima_init_policy - initialize the default measure rules. |
182 | * | 226 | * |
183 | * ima_measure points to either the measure_default_rules or the | 227 | * ima_rules points to either the ima_default_rules or the |
184 | * the new measure_policy_rules. | 228 | * the new ima_policy_rules. |
185 | */ | 229 | */ |
186 | void __init ima_init_policy(void) | 230 | void __init ima_init_policy(void) |
187 | { | 231 | { |
188 | int i, entries; | 232 | int i, measure_entries, appraise_entries; |
189 | 233 | ||
190 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ | 234 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ |
191 | if (ima_use_tcb) | 235 | measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; |
192 | entries = ARRAY_SIZE(default_rules); | 236 | appraise_entries = ima_use_appraise_tcb ? |
193 | else | 237 | ARRAY_SIZE(default_appraise_rules) : 0; |
194 | entries = 0; | 238 | |
195 | 239 | for (i = 0; i < measure_entries + appraise_entries; i++) { | |
196 | for (i = 0; i < entries; i++) | 240 | if (i < measure_entries) |
197 | list_add_tail(&default_rules[i].list, &measure_default_rules); | 241 | list_add_tail(&default_rules[i].list, |
198 | ima_measure = &measure_default_rules; | 242 | &ima_default_rules); |
243 | else { | ||
244 | int j = i - measure_entries; | ||
245 | |||
246 | list_add_tail(&default_appraise_rules[j].list, | ||
247 | &ima_default_rules); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | ima_rules = &ima_default_rules; | ||
199 | } | 252 | } |
200 | 253 | ||
201 | /** | 254 | /** |
@@ -212,8 +265,8 @@ void ima_update_policy(void) | |||
212 | int result = 1; | 265 | int result = 1; |
213 | int audit_info = 0; | 266 | int audit_info = 0; |
214 | 267 | ||
215 | if (ima_measure == &measure_default_rules) { | 268 | if (ima_rules == &ima_default_rules) { |
216 | ima_measure = &measure_policy_rules; | 269 | ima_rules = &ima_policy_rules; |
217 | cause = "complete"; | 270 | cause = "complete"; |
218 | result = 0; | 271 | result = 0; |
219 | } | 272 | } |
@@ -224,14 +277,19 @@ void ima_update_policy(void) | |||
224 | enum { | 277 | enum { |
225 | Opt_err = -1, | 278 | Opt_err = -1, |
226 | Opt_measure = 1, Opt_dont_measure, | 279 | Opt_measure = 1, Opt_dont_measure, |
280 | Opt_appraise, Opt_dont_appraise, | ||
281 | Opt_audit, | ||
227 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | 282 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
228 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | 283 | Opt_subj_user, Opt_subj_role, Opt_subj_type, |
229 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid | 284 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner |
230 | }; | 285 | }; |
231 | 286 | ||
232 | static match_table_t policy_tokens = { | 287 | static match_table_t policy_tokens = { |
233 | {Opt_measure, "measure"}, | 288 | {Opt_measure, "measure"}, |
234 | {Opt_dont_measure, "dont_measure"}, | 289 | {Opt_dont_measure, "dont_measure"}, |
290 | {Opt_appraise, "appraise"}, | ||
291 | {Opt_dont_appraise, "dont_appraise"}, | ||
292 | {Opt_audit, "audit"}, | ||
235 | {Opt_obj_user, "obj_user=%s"}, | 293 | {Opt_obj_user, "obj_user=%s"}, |
236 | {Opt_obj_role, "obj_role=%s"}, | 294 | {Opt_obj_role, "obj_role=%s"}, |
237 | {Opt_obj_type, "obj_type=%s"}, | 295 | {Opt_obj_type, "obj_type=%s"}, |
@@ -242,10 +300,11 @@ static match_table_t policy_tokens = { | |||
242 | {Opt_mask, "mask=%s"}, | 300 | {Opt_mask, "mask=%s"}, |
243 | {Opt_fsmagic, "fsmagic=%s"}, | 301 | {Opt_fsmagic, "fsmagic=%s"}, |
244 | {Opt_uid, "uid=%s"}, | 302 | {Opt_uid, "uid=%s"}, |
303 | {Opt_fowner, "fowner=%s"}, | ||
245 | {Opt_err, NULL} | 304 | {Opt_err, NULL} |
246 | }; | 305 | }; |
247 | 306 | ||
248 | static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | 307 | static int ima_lsm_rule_init(struct ima_rule_entry *entry, |
249 | char *args, int lsm_rule, int audit_type) | 308 | char *args, int lsm_rule, int audit_type) |
250 | { | 309 | { |
251 | int result; | 310 | int result; |
@@ -269,7 +328,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | |||
269 | audit_log_format(ab, " "); | 328 | audit_log_format(ab, " "); |
270 | } | 329 | } |
271 | 330 | ||
272 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | 331 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
273 | { | 332 | { |
274 | struct audit_buffer *ab; | 333 | struct audit_buffer *ab; |
275 | char *p; | 334 | char *p; |
@@ -277,7 +336,8 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
277 | 336 | ||
278 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); | 337 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
279 | 338 | ||
280 | entry->uid = -1; | 339 | entry->uid = INVALID_UID; |
340 | entry->fowner = INVALID_UID; | ||
281 | entry->action = UNKNOWN; | 341 | entry->action = UNKNOWN; |
282 | while ((p = strsep(&rule, " \t")) != NULL) { | 342 | while ((p = strsep(&rule, " \t")) != NULL) { |
283 | substring_t args[MAX_OPT_ARGS]; | 343 | substring_t args[MAX_OPT_ARGS]; |
@@ -306,11 +366,35 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
306 | 366 | ||
307 | entry->action = DONT_MEASURE; | 367 | entry->action = DONT_MEASURE; |
308 | break; | 368 | break; |
369 | case Opt_appraise: | ||
370 | ima_log_string(ab, "action", "appraise"); | ||
371 | |||
372 | if (entry->action != UNKNOWN) | ||
373 | result = -EINVAL; | ||
374 | |||
375 | entry->action = APPRAISE; | ||
376 | break; | ||
377 | case Opt_dont_appraise: | ||
378 | ima_log_string(ab, "action", "dont_appraise"); | ||
379 | |||
380 | if (entry->action != UNKNOWN) | ||
381 | result = -EINVAL; | ||
382 | |||
383 | entry->action = DONT_APPRAISE; | ||
384 | break; | ||
385 | case Opt_audit: | ||
386 | ima_log_string(ab, "action", "audit"); | ||
387 | |||
388 | if (entry->action != UNKNOWN) | ||
389 | result = -EINVAL; | ||
390 | |||
391 | entry->action = AUDIT; | ||
392 | break; | ||
309 | case Opt_func: | 393 | case Opt_func: |
310 | ima_log_string(ab, "func", args[0].from); | 394 | ima_log_string(ab, "func", args[0].from); |
311 | 395 | ||
312 | if (entry->func) | 396 | if (entry->func) |
313 | result = -EINVAL; | 397 | result = -EINVAL; |
314 | 398 | ||
315 | if (strcmp(args[0].from, "FILE_CHECK") == 0) | 399 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
316 | entry->func = FILE_CHECK; | 400 | entry->func = FILE_CHECK; |
@@ -361,20 +445,37 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
361 | case Opt_uid: | 445 | case Opt_uid: |
362 | ima_log_string(ab, "uid", args[0].from); | 446 | ima_log_string(ab, "uid", args[0].from); |
363 | 447 | ||
364 | if (entry->uid != -1) { | 448 | if (uid_valid(entry->uid)) { |
365 | result = -EINVAL; | 449 | result = -EINVAL; |
366 | break; | 450 | break; |
367 | } | 451 | } |
368 | 452 | ||
369 | result = strict_strtoul(args[0].from, 10, &lnum); | 453 | result = strict_strtoul(args[0].from, 10, &lnum); |
370 | if (!result) { | 454 | if (!result) { |
371 | entry->uid = (uid_t) lnum; | 455 | entry->uid = make_kuid(current_user_ns(), (uid_t)lnum); |
372 | if (entry->uid != lnum) | 456 | if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum)) |
373 | result = -EINVAL; | 457 | result = -EINVAL; |
374 | else | 458 | else |
375 | entry->flags |= IMA_UID; | 459 | entry->flags |= IMA_UID; |
376 | } | 460 | } |
377 | break; | 461 | break; |
462 | case Opt_fowner: | ||
463 | ima_log_string(ab, "fowner", args[0].from); | ||
464 | |||
465 | if (uid_valid(entry->fowner)) { | ||
466 | result = -EINVAL; | ||
467 | break; | ||
468 | } | ||
469 | |||
470 | result = strict_strtoul(args[0].from, 10, &lnum); | ||
471 | if (!result) { | ||
472 | entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum); | ||
473 | if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) | ||
474 | result = -EINVAL; | ||
475 | else | ||
476 | entry->flags |= IMA_FOWNER; | ||
477 | } | ||
478 | break; | ||
378 | case Opt_obj_user: | 479 | case Opt_obj_user: |
379 | ima_log_string(ab, "obj_user", args[0].from); | 480 | ima_log_string(ab, "obj_user", args[0].from); |
380 | result = ima_lsm_rule_init(entry, args[0].from, | 481 | result = ima_lsm_rule_init(entry, args[0].from, |
@@ -426,7 +527,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
426 | } | 527 | } |
427 | 528 | ||
428 | /** | 529 | /** |
429 | * ima_parse_add_rule - add a rule to measure_policy_rules | 530 | * ima_parse_add_rule - add a rule to ima_policy_rules |
430 | * @rule - ima measurement policy rule | 531 | * @rule - ima measurement policy rule |
431 | * | 532 | * |
432 | * Uses a mutex to protect the policy list from multiple concurrent writers. | 533 | * Uses a mutex to protect the policy list from multiple concurrent writers. |
@@ -436,12 +537,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
436 | { | 537 | { |
437 | const char *op = "update_policy"; | 538 | const char *op = "update_policy"; |
438 | char *p; | 539 | char *p; |
439 | struct ima_measure_rule_entry *entry; | 540 | struct ima_rule_entry *entry; |
440 | ssize_t result, len; | 541 | ssize_t result, len; |
441 | int audit_info = 0; | 542 | int audit_info = 0; |
442 | 543 | ||
443 | /* Prevent installed policy from changing */ | 544 | /* Prevent installed policy from changing */ |
444 | if (ima_measure != &measure_default_rules) { | 545 | if (ima_rules != &ima_default_rules) { |
445 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 546 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
446 | NULL, op, "already exists", | 547 | NULL, op, "already exists", |
447 | -EACCES, audit_info); | 548 | -EACCES, audit_info); |
@@ -474,9 +575,9 @@ ssize_t ima_parse_add_rule(char *rule) | |||
474 | return result; | 575 | return result; |
475 | } | 576 | } |
476 | 577 | ||
477 | mutex_lock(&ima_measure_mutex); | 578 | mutex_lock(&ima_rules_mutex); |
478 | list_add_tail(&entry->list, &measure_policy_rules); | 579 | list_add_tail(&entry->list, &ima_policy_rules); |
479 | mutex_unlock(&ima_measure_mutex); | 580 | mutex_unlock(&ima_rules_mutex); |
480 | 581 | ||
481 | return len; | 582 | return len; |
482 | } | 583 | } |
@@ -484,12 +585,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
484 | /* ima_delete_rules called to cleanup invalid policy */ | 585 | /* ima_delete_rules called to cleanup invalid policy */ |
485 | void ima_delete_rules(void) | 586 | void ima_delete_rules(void) |
486 | { | 587 | { |
487 | struct ima_measure_rule_entry *entry, *tmp; | 588 | struct ima_rule_entry *entry, *tmp; |
488 | 589 | ||
489 | mutex_lock(&ima_measure_mutex); | 590 | mutex_lock(&ima_rules_mutex); |
490 | list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { | 591 | list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) { |
491 | list_del(&entry->list); | 592 | list_del(&entry->list); |
492 | kfree(entry); | 593 | kfree(entry); |
493 | } | 594 | } |
494 | mutex_unlock(&ima_measure_mutex); | 595 | mutex_unlock(&ima_rules_mutex); |
495 | } | 596 | } |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 7a25ecec5aaa..e9db763a875e 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -15,8 +15,22 @@ | |||
15 | #include <linux/integrity.h> | 15 | #include <linux/integrity.h> |
16 | #include <crypto/sha.h> | 16 | #include <crypto/sha.h> |
17 | 17 | ||
18 | /* iint action cache flags */ | ||
19 | #define IMA_MEASURE 0x0001 | ||
20 | #define IMA_MEASURED 0x0002 | ||
21 | #define IMA_APPRAISE 0x0004 | ||
22 | #define IMA_APPRAISED 0x0008 | ||
23 | /*#define IMA_COLLECT 0x0010 do not use this flag */ | ||
24 | #define IMA_COLLECTED 0x0020 | ||
25 | #define IMA_AUDIT 0x0040 | ||
26 | #define IMA_AUDITED 0x0080 | ||
27 | |||
18 | /* iint cache flags */ | 28 | /* iint cache flags */ |
19 | #define IMA_MEASURED 0x01 | 29 | #define IMA_DIGSIG 0x0100 |
30 | |||
31 | #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) | ||
32 | #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ | ||
33 | | IMA_COLLECTED) | ||
20 | 34 | ||
21 | enum evm_ima_xattr_type { | 35 | enum evm_ima_xattr_type { |
22 | IMA_XATTR_DIGEST = 0x01, | 36 | IMA_XATTR_DIGEST = 0x01, |
@@ -34,9 +48,9 @@ struct integrity_iint_cache { | |||
34 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ | 48 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ |
35 | struct inode *inode; /* back pointer to inode in question */ | 49 | struct inode *inode; /* back pointer to inode in question */ |
36 | u64 version; /* track inode changes */ | 50 | u64 version; /* track inode changes */ |
37 | unsigned char flags; | 51 | unsigned short flags; |
38 | u8 digest[SHA1_DIGEST_SIZE]; | 52 | struct evm_ima_xattr_data ima_xattr; |
39 | struct mutex mutex; /* protects: version, flags, digest */ | 53 | enum integrity_status ima_status; |
40 | enum integrity_status evm_status; | 54 | enum integrity_status evm_status; |
41 | }; | 55 | }; |
42 | 56 | ||