diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-14 23:36:37 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-14 23:36:37 -0500 |
commit | 67e2c3883828b39548cee2091b36656787775d95 (patch) | |
tree | 975a0f546a604beda30d4ede34f8e9cca9a88b71 /security/integrity | |
parent | 6ae840e7cc4be0be3aa40d9f67c35c75cfc67d83 (diff) | |
parent | b2d1965dcea148100ffc4e7199470bf5fad13871 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
"In terms of changes, there's general maintenance to the Smack,
SELinux, and integrity code.
The IMA code adds a new kconfig option, IMA_APPRAISE_SIGNED_INIT,
which allows IMA appraisal to require signatures. Support for reading
keys from rootfs before init is call is also added"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (23 commits)
selinux: Remove security_ops extern
security: smack: fix out-of-bounds access in smk_parse_smack()
VFS: refactor vfs_read()
ima: require signature based appraisal
integrity: provide a hook to load keys when rootfs is ready
ima: load x509 certificate from the kernel
integrity: provide a function to load x509 certificate from the kernel
integrity: define a new function integrity_read_file()
Security: smack: replace kzalloc with kmem_cache for inode_smack
Smack: Lock mode for the floor and hat labels
ima: added support for new kernel cmdline parameter ima_template_fmt
ima: allocate field pointers array on demand in template_desc_init_fields()
ima: don't allocate a copy of template_fmt in template_desc_init_fields()
ima: display template format in meas. list if template name length is zero
ima: added error messages to template-related functions
ima: use atomic bit operations to protect policy update interface
ima: ignore empty and with whitespaces policy lines
ima: no need to allocate entry for comment
ima: report policy load status
ima: use path names cache
...
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/digsig.c | 38 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 11 | ||||
-rw-r--r-- | security/integrity/iint.c | 88 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 25 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 7 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 35 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 37 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 17 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 42 | ||||
-rw-r--r-- | security/integrity/ima/ima_template.c | 103 | ||||
-rw-r--r-- | security/integrity/integrity.h | 19 |
12 files changed, 308 insertions, 119 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 8d4fbff8b87c..5e3bd72b299a 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/rbtree.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/cred.h> | 18 | #include <linux/cred.h> |
19 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
20 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
@@ -63,7 +63,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
63 | return -EOPNOTSUPP; | 63 | return -EOPNOTSUPP; |
64 | } | 64 | } |
65 | 65 | ||
66 | int integrity_init_keyring(const unsigned int id) | 66 | int __init integrity_init_keyring(const unsigned int id) |
67 | { | 67 | { |
68 | const struct cred *cred = current_cred(); | 68 | const struct cred *cred = current_cred(); |
69 | int err = 0; | 69 | int err = 0; |
@@ -84,3 +84,37 @@ int integrity_init_keyring(const unsigned int id) | |||
84 | } | 84 | } |
85 | return err; | 85 | return err; |
86 | } | 86 | } |
87 | |||
88 | int __init integrity_load_x509(const unsigned int id, char *path) | ||
89 | { | ||
90 | key_ref_t key; | ||
91 | char *data; | ||
92 | int rc; | ||
93 | |||
94 | if (!keyring[id]) | ||
95 | return -EINVAL; | ||
96 | |||
97 | rc = integrity_read_file(path, &data); | ||
98 | if (rc < 0) | ||
99 | return rc; | ||
100 | |||
101 | key = key_create_or_update(make_key_ref(keyring[id], 1), | ||
102 | "asymmetric", | ||
103 | NULL, | ||
104 | data, | ||
105 | rc, | ||
106 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
107 | KEY_USR_VIEW | KEY_USR_READ), | ||
108 | KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED); | ||
109 | if (IS_ERR(key)) { | ||
110 | rc = PTR_ERR(key); | ||
111 | pr_err("Problem loading X.509 certificate (%d): %s\n", | ||
112 | rc, path); | ||
113 | } else { | ||
114 | pr_notice("Loaded X.509 cert '%s': %s\n", | ||
115 | key_ref_to_ptr(key)->description, path); | ||
116 | key_ref_put(key); | ||
117 | } | ||
118 | kfree(data); | ||
119 | return 0; | ||
120 | } | ||
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index c5ee1a7c5e8a..f589c9a05da2 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
@@ -162,9 +162,14 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, | |||
162 | (const char *)xattr_data, xattr_len, | 162 | (const char *)xattr_data, xattr_len, |
163 | calc.digest, sizeof(calc.digest)); | 163 | calc.digest, sizeof(calc.digest)); |
164 | if (!rc) { | 164 | if (!rc) { |
165 | /* we probably want to replace rsa with hmac here */ | 165 | /* Replace RSA with HMAC if not mounted readonly and |
166 | evm_update_evmxattr(dentry, xattr_name, xattr_value, | 166 | * not immutable |
167 | xattr_value_len); | 167 | */ |
168 | if (!IS_RDONLY(dentry->d_inode) && | ||
169 | !IS_IMMUTABLE(dentry->d_inode)) | ||
170 | evm_update_evmxattr(dentry, xattr_name, | ||
171 | xattr_value, | ||
172 | xattr_value_len); | ||
168 | } | 173 | } |
169 | break; | 174 | break; |
170 | default: | 175 | default: |
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index a521edf4cbd6..dbb6d141c3db 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
@@ -19,14 +19,14 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/rbtree.h> | 21 | #include <linux/rbtree.h> |
22 | #include <linux/file.h> | ||
23 | #include <linux/uaccess.h> | ||
22 | #include "integrity.h" | 24 | #include "integrity.h" |
23 | 25 | ||
24 | static struct rb_root integrity_iint_tree = RB_ROOT; | 26 | static struct rb_root integrity_iint_tree = RB_ROOT; |
25 | static DEFINE_RWLOCK(integrity_iint_lock); | 27 | static DEFINE_RWLOCK(integrity_iint_lock); |
26 | static struct kmem_cache *iint_cache __read_mostly; | 28 | static struct kmem_cache *iint_cache __read_mostly; |
27 | 29 | ||
28 | int iint_initialized; | ||
29 | |||
30 | /* | 30 | /* |
31 | * __integrity_iint_find - return the iint associated with an inode | 31 | * __integrity_iint_find - return the iint associated with an inode |
32 | */ | 32 | */ |
@@ -166,7 +166,89 @@ static int __init integrity_iintcache_init(void) | |||
166 | iint_cache = | 166 | iint_cache = |
167 | kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache), | 167 | kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache), |
168 | 0, SLAB_PANIC, init_once); | 168 | 0, SLAB_PANIC, init_once); |
169 | iint_initialized = 1; | ||
170 | return 0; | 169 | return 0; |
171 | } | 170 | } |
172 | security_initcall(integrity_iintcache_init); | 171 | security_initcall(integrity_iintcache_init); |
172 | |||
173 | |||
174 | /* | ||
175 | * integrity_kernel_read - read data from the file | ||
176 | * | ||
177 | * This is a function for reading file content instead of kernel_read(). | ||
178 | * It does not perform locking checks to ensure it cannot be blocked. | ||
179 | * It does not perform security checks because it is irrelevant for IMA. | ||
180 | * | ||
181 | */ | ||
182 | int integrity_kernel_read(struct file *file, loff_t offset, | ||
183 | char *addr, unsigned long count) | ||
184 | { | ||
185 | mm_segment_t old_fs; | ||
186 | char __user *buf = (char __user *)addr; | ||
187 | ssize_t ret; | ||
188 | |||
189 | if (!(file->f_mode & FMODE_READ)) | ||
190 | return -EBADF; | ||
191 | |||
192 | old_fs = get_fs(); | ||
193 | set_fs(get_ds()); | ||
194 | ret = __vfs_read(file, buf, count, &offset); | ||
195 | set_fs(old_fs); | ||
196 | |||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * integrity_read_file - read entire file content into the buffer | ||
202 | * | ||
203 | * This is function opens a file, allocates the buffer of required | ||
204 | * size, read entire file content to the buffer and closes the file | ||
205 | * | ||
206 | * It is used only by init code. | ||
207 | * | ||
208 | */ | ||
209 | int __init integrity_read_file(const char *path, char **data) | ||
210 | { | ||
211 | struct file *file; | ||
212 | loff_t size; | ||
213 | char *buf; | ||
214 | int rc = -EINVAL; | ||
215 | |||
216 | file = filp_open(path, O_RDONLY, 0); | ||
217 | if (IS_ERR(file)) { | ||
218 | rc = PTR_ERR(file); | ||
219 | pr_err("Unable to open file: %s (%d)", path, rc); | ||
220 | return rc; | ||
221 | } | ||
222 | |||
223 | size = i_size_read(file_inode(file)); | ||
224 | if (size <= 0) | ||
225 | goto out; | ||
226 | |||
227 | buf = kmalloc(size, GFP_KERNEL); | ||
228 | if (!buf) { | ||
229 | rc = -ENOMEM; | ||
230 | goto out; | ||
231 | } | ||
232 | |||
233 | rc = integrity_kernel_read(file, 0, buf, size); | ||
234 | if (rc < 0) | ||
235 | kfree(buf); | ||
236 | else if (rc != size) | ||
237 | rc = -EIO; | ||
238 | else | ||
239 | *data = buf; | ||
240 | out: | ||
241 | fput(file); | ||
242 | return rc; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * integrity_load_keys - load integrity keys hook | ||
247 | * | ||
248 | * Hooks is called from init/main.c:kernel_init_freeable() | ||
249 | * when rootfs is ready | ||
250 | */ | ||
251 | void __init integrity_load_keys(void) | ||
252 | { | ||
253 | ima_load_x509(); | ||
254 | } | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index e099875643c5..b80a93ec1ccc 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -131,3 +131,28 @@ config IMA_TRUSTED_KEYRING | |||
131 | help | 131 | help |
132 | This option requires that all keys added to the .ima | 132 | This option requires that all keys added to the .ima |
133 | keyring be signed by a key on the system trusted keyring. | 133 | keyring be signed by a key on the system trusted keyring. |
134 | |||
135 | config IMA_LOAD_X509 | ||
136 | bool "Load X509 certificate onto the '.ima' trusted keyring" | ||
137 | depends on IMA_TRUSTED_KEYRING | ||
138 | default n | ||
139 | help | ||
140 | File signature verification is based on the public keys | ||
141 | loaded on the .ima trusted keyring. These public keys are | ||
142 | X509 certificates signed by a trusted key on the | ||
143 | .system keyring. This option enables X509 certificate | ||
144 | loading from the kernel onto the '.ima' trusted keyring. | ||
145 | |||
146 | config IMA_X509_PATH | ||
147 | string "IMA X509 certificate path" | ||
148 | depends on IMA_LOAD_X509 | ||
149 | default "/etc/keys/x509_ima.der" | ||
150 | help | ||
151 | This option defines IMA X509 certificate path. | ||
152 | |||
153 | config IMA_APPRAISE_SIGNED_INIT | ||
154 | bool "Require signed user-space initialization" | ||
155 | depends on IMA_LOAD_X509 | ||
156 | default n | ||
157 | help | ||
158 | This option requires user-space init to be signed. | ||
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index f92be1b14089..b8a27c5052d4 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -173,8 +173,7 @@ int ima_get_action(struct inode *inode, int mask, int function) | |||
173 | { | 173 | { |
174 | int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; | 174 | int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; |
175 | 175 | ||
176 | if (!ima_appraise) | 176 | flags &= ima_policy_flag; |
177 | flags &= ~IMA_APPRAISE; | ||
178 | 177 | ||
179 | return ima_match_policy(inode, function, mask, flags); | 178 | return ima_match_policy(inode, function, mask, flags); |
180 | } | 179 | } |
@@ -325,11 +324,11 @@ const char *ima_d_path(struct path *path, char **pathbuf) | |||
325 | { | 324 | { |
326 | char *pathname = NULL; | 325 | char *pathname = NULL; |
327 | 326 | ||
328 | *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); | 327 | *pathbuf = __getname(); |
329 | if (*pathbuf) { | 328 | if (*pathbuf) { |
330 | pathname = d_absolute_path(path, *pathbuf, PATH_MAX); | 329 | pathname = d_absolute_path(path, *pathbuf, PATH_MAX); |
331 | if (IS_ERR(pathname)) { | 330 | if (IS_ERR(pathname)) { |
332 | kfree(*pathbuf); | 331 | __putname(*pathbuf); |
333 | *pathbuf = NULL; | 332 | *pathbuf = NULL; |
334 | pathname = NULL; | 333 | pathname = NULL; |
335 | } | 334 | } |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 78d66dae15f4..686355fea7fd 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -67,36 +67,6 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size"); | |||
67 | static struct crypto_shash *ima_shash_tfm; | 67 | static struct crypto_shash *ima_shash_tfm; |
68 | static struct crypto_ahash *ima_ahash_tfm; | 68 | static struct crypto_ahash *ima_ahash_tfm; |
69 | 69 | ||
70 | /** | ||
71 | * ima_kernel_read - read file content | ||
72 | * | ||
73 | * This is a function for reading file content instead of kernel_read(). | ||
74 | * It does not perform locking checks to ensure it cannot be blocked. | ||
75 | * It does not perform security checks because it is irrelevant for IMA. | ||
76 | * | ||
77 | */ | ||
78 | static int ima_kernel_read(struct file *file, loff_t offset, | ||
79 | char *addr, unsigned long count) | ||
80 | { | ||
81 | mm_segment_t old_fs; | ||
82 | char __user *buf = addr; | ||
83 | ssize_t ret = -EINVAL; | ||
84 | |||
85 | if (!(file->f_mode & FMODE_READ)) | ||
86 | return -EBADF; | ||
87 | |||
88 | old_fs = get_fs(); | ||
89 | set_fs(get_ds()); | ||
90 | if (file->f_op->read) | ||
91 | ret = file->f_op->read(file, buf, count, &offset); | ||
92 | else if (file->f_op->aio_read) | ||
93 | ret = do_sync_read(file, buf, count, &offset); | ||
94 | else if (file->f_op->read_iter) | ||
95 | ret = new_sync_read(file, buf, count, &offset); | ||
96 | set_fs(old_fs); | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | int __init ima_init_crypto(void) | 70 | int __init ima_init_crypto(void) |
101 | { | 71 | { |
102 | long rc; | 72 | long rc; |
@@ -324,7 +294,8 @@ static int ima_calc_file_hash_atfm(struct file *file, | |||
324 | } | 294 | } |
325 | /* read buffer */ | 295 | /* read buffer */ |
326 | rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); | 296 | rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); |
327 | rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len); | 297 | rc = integrity_kernel_read(file, offset, rbuf[active], |
298 | rbuf_len); | ||
328 | if (rc != rbuf_len) | 299 | if (rc != rbuf_len) |
329 | goto out3; | 300 | goto out3; |
330 | 301 | ||
@@ -414,7 +385,7 @@ static int ima_calc_file_hash_tfm(struct file *file, | |||
414 | while (offset < i_size) { | 385 | while (offset < i_size) { |
415 | int rbuf_len; | 386 | int rbuf_len; |
416 | 387 | ||
417 | rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE); | 388 | rbuf_len = integrity_kernel_read(file, offset, rbuf, PAGE_SIZE); |
418 | if (rbuf_len < 0) { | 389 | if (rbuf_len < 0) { |
419 | rc = rbuf_len; | 390 | rc = rbuf_len; |
420 | break; | 391 | break; |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index da92fcc08d15..461215e5fd31 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -118,6 +118,7 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
118 | /* the list never shrinks, so we don't need a lock here */ | 118 | /* the list never shrinks, so we don't need a lock here */ |
119 | struct ima_queue_entry *qe = v; | 119 | struct ima_queue_entry *qe = v; |
120 | struct ima_template_entry *e; | 120 | struct ima_template_entry *e; |
121 | char *template_name; | ||
121 | int namelen; | 122 | int namelen; |
122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | 123 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; |
123 | bool is_ima_template = false; | 124 | bool is_ima_template = false; |
@@ -128,6 +129,9 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
128 | if (e == NULL) | 129 | if (e == NULL) |
129 | return -1; | 130 | return -1; |
130 | 131 | ||
132 | template_name = (e->template_desc->name[0] != '\0') ? | ||
133 | e->template_desc->name : e->template_desc->fmt; | ||
134 | |||
131 | /* | 135 | /* |
132 | * 1st: PCRIndex | 136 | * 1st: PCRIndex |
133 | * PCR used is always the same (config option) in | 137 | * PCR used is always the same (config option) in |
@@ -139,14 +143,14 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
139 | ima_putc(m, e->digest, TPM_DIGEST_SIZE); | 143 | ima_putc(m, e->digest, TPM_DIGEST_SIZE); |
140 | 144 | ||
141 | /* 3rd: template name size */ | 145 | /* 3rd: template name size */ |
142 | namelen = strlen(e->template_desc->name); | 146 | namelen = strlen(template_name); |
143 | ima_putc(m, &namelen, sizeof(namelen)); | 147 | ima_putc(m, &namelen, sizeof(namelen)); |
144 | 148 | ||
145 | /* 4th: template name */ | 149 | /* 4th: template name */ |
146 | ima_putc(m, e->template_desc->name, namelen); | 150 | ima_putc(m, template_name, namelen); |
147 | 151 | ||
148 | /* 5th: template length (except for 'ima' template) */ | 152 | /* 5th: template length (except for 'ima' template) */ |
149 | if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) | 153 | if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0) |
150 | is_ima_template = true; | 154 | is_ima_template = true; |
151 | 155 | ||
152 | if (!is_ima_template) | 156 | if (!is_ima_template) |
@@ -200,6 +204,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) | |||
200 | /* the list never shrinks, so we don't need a lock here */ | 204 | /* the list never shrinks, so we don't need a lock here */ |
201 | struct ima_queue_entry *qe = v; | 205 | struct ima_queue_entry *qe = v; |
202 | struct ima_template_entry *e; | 206 | struct ima_template_entry *e; |
207 | char *template_name; | ||
203 | int i; | 208 | int i; |
204 | 209 | ||
205 | /* get entry */ | 210 | /* get entry */ |
@@ -207,6 +212,9 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) | |||
207 | if (e == NULL) | 212 | if (e == NULL) |
208 | return -1; | 213 | return -1; |
209 | 214 | ||
215 | template_name = (e->template_desc->name[0] != '\0') ? | ||
216 | e->template_desc->name : e->template_desc->fmt; | ||
217 | |||
210 | /* 1st: PCR used (config option) */ | 218 | /* 1st: PCR used (config option) */ |
211 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); | 219 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); |
212 | 220 | ||
@@ -214,7 +222,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) | |||
214 | ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); | 222 | ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); |
215 | 223 | ||
216 | /* 3th: template name */ | 224 | /* 3th: template name */ |
217 | seq_printf(m, " %s", e->template_desc->name); | 225 | seq_printf(m, " %s", template_name); |
218 | 226 | ||
219 | /* 4th: template specific data */ | 227 | /* 4th: template specific data */ |
220 | for (i = 0; i < e->template_desc->num_fields; i++) { | 228 | for (i = 0; i < e->template_desc->num_fields; i++) { |
@@ -288,7 +296,12 @@ static struct dentry *runtime_measurements_count; | |||
288 | static struct dentry *violations; | 296 | static struct dentry *violations; |
289 | static struct dentry *ima_policy; | 297 | static struct dentry *ima_policy; |
290 | 298 | ||
291 | static atomic_t policy_opencount = ATOMIC_INIT(1); | 299 | enum ima_fs_flags { |
300 | IMA_FS_BUSY, | ||
301 | }; | ||
302 | |||
303 | static unsigned long ima_fs_flags; | ||
304 | |||
292 | /* | 305 | /* |
293 | * ima_open_policy: sequentialize access to the policy file | 306 | * ima_open_policy: sequentialize access to the policy file |
294 | */ | 307 | */ |
@@ -297,9 +310,9 @@ static int ima_open_policy(struct inode *inode, struct file *filp) | |||
297 | /* No point in being allowed to open it if you aren't going to write */ | 310 | /* No point in being allowed to open it if you aren't going to write */ |
298 | if (!(filp->f_flags & O_WRONLY)) | 311 | if (!(filp->f_flags & O_WRONLY)) |
299 | return -EACCES; | 312 | return -EACCES; |
300 | if (atomic_dec_and_test(&policy_opencount)) | 313 | if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags)) |
301 | return 0; | 314 | return -EBUSY; |
302 | return -EBUSY; | 315 | return 0; |
303 | } | 316 | } |
304 | 317 | ||
305 | /* | 318 | /* |
@@ -311,10 +324,16 @@ static int ima_open_policy(struct inode *inode, struct file *filp) | |||
311 | */ | 324 | */ |
312 | static int ima_release_policy(struct inode *inode, struct file *file) | 325 | static int ima_release_policy(struct inode *inode, struct file *file) |
313 | { | 326 | { |
327 | const char *cause = valid_policy ? "completed" : "failed"; | ||
328 | |||
329 | pr_info("IMA: policy update %s\n", cause); | ||
330 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, | ||
331 | "policy_update", cause, !valid_policy, 0); | ||
332 | |||
314 | if (!valid_policy) { | 333 | if (!valid_policy) { |
315 | ima_delete_rules(); | 334 | ima_delete_rules(); |
316 | valid_policy = 1; | 335 | valid_policy = 1; |
317 | atomic_set(&policy_opencount, 1); | 336 | clear_bit(IMA_FS_BUSY, &ima_fs_flags); |
318 | return 0; | 337 | return 0; |
319 | } | 338 | } |
320 | ima_update_policy(); | 339 | ima_update_policy(); |
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 9164fc8cac84..5e4c29d174ee 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
@@ -24,6 +24,12 @@ | |||
24 | #include <crypto/hash_info.h> | 24 | #include <crypto/hash_info.h> |
25 | #include "ima.h" | 25 | #include "ima.h" |
26 | 26 | ||
27 | #ifdef CONFIG_IMA_X509_PATH | ||
28 | #define IMA_X509_PATH CONFIG_IMA_X509_PATH | ||
29 | #else | ||
30 | #define IMA_X509_PATH "/etc/keys/x509_ima.der" | ||
31 | #endif | ||
32 | |||
27 | /* name for boot aggregate entry */ | 33 | /* name for boot aggregate entry */ |
28 | static const char *boot_aggregate_name = "boot_aggregate"; | 34 | static const char *boot_aggregate_name = "boot_aggregate"; |
29 | int ima_used_chip; | 35 | int ima_used_chip; |
@@ -91,6 +97,17 @@ err_out: | |||
91 | return result; | 97 | return result; |
92 | } | 98 | } |
93 | 99 | ||
100 | #ifdef CONFIG_IMA_LOAD_X509 | ||
101 | void __init ima_load_x509(void) | ||
102 | { | ||
103 | int unset_flags = ima_policy_flag & IMA_APPRAISE; | ||
104 | |||
105 | ima_policy_flag &= ~unset_flags; | ||
106 | integrity_load_x509(INTEGRITY_KEYRING_IMA, IMA_X509_PATH); | ||
107 | ima_policy_flag |= unset_flags; | ||
108 | } | ||
109 | #endif | ||
110 | |||
94 | int __init ima_init(void) | 111 | int __init ima_init(void) |
95 | { | 112 | { |
96 | u8 pcr_i[TPM_DIGEST_SIZE]; | 113 | u8 pcr_i[TPM_DIGEST_SIZE]; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 62f59eca32d3..eeee00dce729 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -143,7 +143,7 @@ void ima_file_free(struct file *file) | |||
143 | struct inode *inode = file_inode(file); | 143 | struct inode *inode = file_inode(file); |
144 | struct integrity_iint_cache *iint; | 144 | struct integrity_iint_cache *iint; |
145 | 145 | ||
146 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 146 | if (!ima_policy_flag || !S_ISREG(inode->i_mode)) |
147 | return; | 147 | return; |
148 | 148 | ||
149 | iint = integrity_iint_find(inode); | 149 | iint = integrity_iint_find(inode); |
@@ -246,7 +246,8 @@ out_digsig: | |||
246 | rc = -EACCES; | 246 | rc = -EACCES; |
247 | kfree(xattr_value); | 247 | kfree(xattr_value); |
248 | out_free: | 248 | out_free: |
249 | kfree(pathbuf); | 249 | if (pathbuf) |
250 | __putname(pathbuf); | ||
250 | out: | 251 | out: |
251 | mutex_unlock(&inode->i_mutex); | 252 | mutex_unlock(&inode->i_mutex); |
252 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) | 253 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index cdc620b2152f..d1eefb9d65fb 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -100,7 +100,13 @@ static struct ima_rule_entry default_appraise_rules[] = { | |||
100 | {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, | 100 | {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, |
101 | {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, | 101 | {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, |
102 | {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | 102 | {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
103 | #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT | ||
103 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, | 104 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, |
105 | #else | ||
106 | /* force signature */ | ||
107 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, | ||
108 | .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, | ||
109 | #endif | ||
104 | }; | 110 | }; |
105 | 111 | ||
106 | static LIST_HEAD(ima_default_rules); | 112 | static LIST_HEAD(ima_default_rules); |
@@ -356,19 +362,8 @@ void __init ima_init_policy(void) | |||
356 | */ | 362 | */ |
357 | void ima_update_policy(void) | 363 | void ima_update_policy(void) |
358 | { | 364 | { |
359 | static const char op[] = "policy_update"; | 365 | ima_rules = &ima_policy_rules; |
360 | const char *cause = "already-exists"; | 366 | ima_update_policy_flag(); |
361 | int result = 1; | ||
362 | int audit_info = 0; | ||
363 | |||
364 | if (ima_rules == &ima_default_rules) { | ||
365 | ima_rules = &ima_policy_rules; | ||
366 | ima_update_policy_flag(); | ||
367 | cause = "complete"; | ||
368 | result = 0; | ||
369 | } | ||
370 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
371 | NULL, op, cause, result, audit_info); | ||
372 | } | 367 | } |
373 | 368 | ||
374 | enum { | 369 | enum { |
@@ -686,13 +681,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
686 | ssize_t result, len; | 681 | ssize_t result, len; |
687 | int audit_info = 0; | 682 | int audit_info = 0; |
688 | 683 | ||
689 | /* Prevent installed policy from changing */ | 684 | p = strsep(&rule, "\n"); |
690 | if (ima_rules != &ima_default_rules) { | 685 | len = strlen(p) + 1; |
691 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 686 | p += strspn(p, " \t"); |
692 | NULL, op, "already-exists", | 687 | |
693 | -EACCES, audit_info); | 688 | if (*p == '#' || *p == '\0') |
694 | return -EACCES; | 689 | return len; |
695 | } | ||
696 | 690 | ||
697 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 691 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
698 | if (!entry) { | 692 | if (!entry) { |
@@ -703,14 +697,6 @@ ssize_t ima_parse_add_rule(char *rule) | |||
703 | 697 | ||
704 | INIT_LIST_HEAD(&entry->list); | 698 | INIT_LIST_HEAD(&entry->list); |
705 | 699 | ||
706 | p = strsep(&rule, "\n"); | ||
707 | len = strlen(p) + 1; | ||
708 | |||
709 | if (*p == '#') { | ||
710 | kfree(entry); | ||
711 | return len; | ||
712 | } | ||
713 | |||
714 | result = ima_parse_rule(p, entry); | 700 | result = ima_parse_rule(p, entry); |
715 | if (result) { | 701 | if (result) { |
716 | kfree(entry); | 702 | kfree(entry); |
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index e854862c9337..0b7404ebfa80 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c | |||
@@ -24,6 +24,7 @@ static struct ima_template_desc defined_templates[] = { | |||
24 | {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, | 24 | {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, |
25 | {.name = "ima-ng", .fmt = "d-ng|n-ng"}, | 25 | {.name = "ima-ng", .fmt = "d-ng|n-ng"}, |
26 | {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, | 26 | {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, |
27 | {.name = "", .fmt = ""}, /* placeholder for a custom format */ | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | static struct ima_template_field supported_fields[] = { | 30 | static struct ima_template_field supported_fields[] = { |
@@ -41,19 +42,28 @@ static struct ima_template_field supported_fields[] = { | |||
41 | 42 | ||
42 | static struct ima_template_desc *ima_template; | 43 | static struct ima_template_desc *ima_template; |
43 | static struct ima_template_desc *lookup_template_desc(const char *name); | 44 | static struct ima_template_desc *lookup_template_desc(const char *name); |
45 | static int template_desc_init_fields(const char *template_fmt, | ||
46 | struct ima_template_field ***fields, | ||
47 | int *num_fields); | ||
44 | 48 | ||
45 | static int __init ima_template_setup(char *str) | 49 | static int __init ima_template_setup(char *str) |
46 | { | 50 | { |
47 | struct ima_template_desc *template_desc; | 51 | struct ima_template_desc *template_desc; |
48 | int template_len = strlen(str); | 52 | int template_len = strlen(str); |
49 | 53 | ||
54 | if (ima_template) | ||
55 | return 1; | ||
56 | |||
50 | /* | 57 | /* |
51 | * Verify that a template with the supplied name exists. | 58 | * Verify that a template with the supplied name exists. |
52 | * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. | 59 | * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. |
53 | */ | 60 | */ |
54 | template_desc = lookup_template_desc(str); | 61 | template_desc = lookup_template_desc(str); |
55 | if (!template_desc) | 62 | if (!template_desc) { |
63 | pr_err("template %s not found, using %s\n", | ||
64 | str, CONFIG_IMA_DEFAULT_TEMPLATE); | ||
56 | return 1; | 65 | return 1; |
66 | } | ||
57 | 67 | ||
58 | /* | 68 | /* |
59 | * Verify whether the current hash algorithm is supported | 69 | * Verify whether the current hash algorithm is supported |
@@ -70,6 +80,25 @@ static int __init ima_template_setup(char *str) | |||
70 | } | 80 | } |
71 | __setup("ima_template=", ima_template_setup); | 81 | __setup("ima_template=", ima_template_setup); |
72 | 82 | ||
83 | static int __init ima_template_fmt_setup(char *str) | ||
84 | { | ||
85 | int num_templates = ARRAY_SIZE(defined_templates); | ||
86 | |||
87 | if (ima_template) | ||
88 | return 1; | ||
89 | |||
90 | if (template_desc_init_fields(str, NULL, NULL) < 0) { | ||
91 | pr_err("format string '%s' not valid, using template %s\n", | ||
92 | str, CONFIG_IMA_DEFAULT_TEMPLATE); | ||
93 | return 1; | ||
94 | } | ||
95 | |||
96 | defined_templates[num_templates - 1].fmt = str; | ||
97 | ima_template = defined_templates + num_templates - 1; | ||
98 | return 1; | ||
99 | } | ||
100 | __setup("ima_template_fmt=", ima_template_fmt_setup); | ||
101 | |||
73 | static struct ima_template_desc *lookup_template_desc(const char *name) | 102 | static struct ima_template_desc *lookup_template_desc(const char *name) |
74 | { | 103 | { |
75 | int i; | 104 | int i; |
@@ -113,43 +142,46 @@ static int template_desc_init_fields(const char *template_fmt, | |||
113 | struct ima_template_field ***fields, | 142 | struct ima_template_field ***fields, |
114 | int *num_fields) | 143 | int *num_fields) |
115 | { | 144 | { |
116 | char *c, *template_fmt_copy, *template_fmt_ptr; | 145 | const char *template_fmt_ptr; |
146 | struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; | ||
117 | int template_num_fields = template_fmt_size(template_fmt); | 147 | int template_num_fields = template_fmt_size(template_fmt); |
118 | int i, result = 0; | 148 | int i, len; |
119 | 149 | ||
120 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) | 150 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) { |
151 | pr_err("format string '%s' contains too many fields\n", | ||
152 | template_fmt); | ||
121 | return -EINVAL; | 153 | return -EINVAL; |
122 | |||
123 | /* copying is needed as strsep() modifies the original buffer */ | ||
124 | template_fmt_copy = kstrdup(template_fmt, GFP_KERNEL); | ||
125 | if (template_fmt_copy == NULL) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL); | ||
129 | if (*fields == NULL) { | ||
130 | result = -ENOMEM; | ||
131 | goto out; | ||
132 | } | 154 | } |
133 | 155 | ||
134 | template_fmt_ptr = template_fmt_copy; | 156 | for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields; |
135 | for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL && | 157 | i++, template_fmt_ptr += len + 1) { |
136 | i < template_num_fields; i++) { | 158 | char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1]; |
137 | struct ima_template_field *f = lookup_template_field(c); | 159 | |
160 | len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr; | ||
161 | if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) { | ||
162 | pr_err("Invalid field with length %d\n", len); | ||
163 | return -EINVAL; | ||
164 | } | ||
138 | 165 | ||
139 | if (!f) { | 166 | memcpy(tmp_field_id, template_fmt_ptr, len); |
140 | result = -ENOENT; | 167 | tmp_field_id[len] = '\0'; |
141 | goto out; | 168 | found_fields[i] = lookup_template_field(tmp_field_id); |
169 | if (!found_fields[i]) { | ||
170 | pr_err("field '%s' not found\n", tmp_field_id); | ||
171 | return -ENOENT; | ||
142 | } | 172 | } |
143 | (*fields)[i] = f; | ||
144 | } | 173 | } |
145 | *num_fields = i; | 174 | |
146 | out: | 175 | if (fields && num_fields) { |
147 | if (result < 0) { | 176 | *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); |
148 | kfree(*fields); | 177 | if (*fields == NULL) |
149 | *fields = NULL; | 178 | return -ENOMEM; |
179 | |||
180 | memcpy(*fields, found_fields, i * sizeof(*fields)); | ||
181 | *num_fields = i; | ||
150 | } | 182 | } |
151 | kfree(template_fmt_copy); | 183 | |
152 | return result; | 184 | return 0; |
153 | } | 185 | } |
154 | 186 | ||
155 | struct ima_template_desc *ima_template_desc_current(void) | 187 | struct ima_template_desc *ima_template_desc_current(void) |
@@ -163,8 +195,15 @@ struct ima_template_desc *ima_template_desc_current(void) | |||
163 | int __init ima_init_template(void) | 195 | int __init ima_init_template(void) |
164 | { | 196 | { |
165 | struct ima_template_desc *template = ima_template_desc_current(); | 197 | struct ima_template_desc *template = ima_template_desc_current(); |
198 | int result; | ||
199 | |||
200 | result = template_desc_init_fields(template->fmt, | ||
201 | &(template->fields), | ||
202 | &(template->num_fields)); | ||
203 | if (result < 0) | ||
204 | pr_err("template %s init failed, result: %d\n", | ||
205 | (strlen(template->name) ? | ||
206 | template->name : template->fmt), result); | ||
166 | 207 | ||
167 | return template_desc_init_fields(template->fmt, | 208 | return result; |
168 | &(template->fields), | ||
169 | &(template->num_fields)); | ||
170 | } | 209 | } |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 9d1c2ebfe12a..0fc9519fefa9 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -120,6 +120,10 @@ struct integrity_iint_cache { | |||
120 | */ | 120 | */ |
121 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 121 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
122 | 122 | ||
123 | int integrity_kernel_read(struct file *file, loff_t offset, | ||
124 | char *addr, unsigned long count); | ||
125 | int __init integrity_read_file(const char *path, char **data); | ||
126 | |||
123 | #define INTEGRITY_KEYRING_EVM 0 | 127 | #define INTEGRITY_KEYRING_EVM 0 |
124 | #define INTEGRITY_KEYRING_MODULE 1 | 128 | #define INTEGRITY_KEYRING_MODULE 1 |
125 | #define INTEGRITY_KEYRING_IMA 2 | 129 | #define INTEGRITY_KEYRING_IMA 2 |
@@ -130,7 +134,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
130 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 134 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
131 | const char *digest, int digestlen); | 135 | const char *digest, int digestlen); |
132 | 136 | ||
133 | int integrity_init_keyring(const unsigned int id); | 137 | int __init integrity_init_keyring(const unsigned int id); |
138 | int __init integrity_load_x509(const unsigned int id, char *path); | ||
134 | #else | 139 | #else |
135 | 140 | ||
136 | static inline int integrity_digsig_verify(const unsigned int id, | 141 | static inline int integrity_digsig_verify(const unsigned int id, |
@@ -144,6 +149,7 @@ static inline int integrity_init_keyring(const unsigned int id) | |||
144 | { | 149 | { |
145 | return 0; | 150 | return 0; |
146 | } | 151 | } |
152 | |||
147 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ | 153 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ |
148 | 154 | ||
149 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | 155 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS |
@@ -157,6 +163,14 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig, | |||
157 | } | 163 | } |
158 | #endif | 164 | #endif |
159 | 165 | ||
166 | #ifdef CONFIG_IMA_LOAD_X509 | ||
167 | void __init ima_load_x509(void); | ||
168 | #else | ||
169 | static inline void ima_load_x509(void) | ||
170 | { | ||
171 | } | ||
172 | #endif | ||
173 | |||
160 | #ifdef CONFIG_INTEGRITY_AUDIT | 174 | #ifdef CONFIG_INTEGRITY_AUDIT |
161 | /* declarations */ | 175 | /* declarations */ |
162 | void integrity_audit_msg(int audit_msgno, struct inode *inode, | 176 | void integrity_audit_msg(int audit_msgno, struct inode *inode, |
@@ -170,6 +184,3 @@ static inline void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
170 | { | 184 | { |
171 | } | 185 | } |
172 | #endif | 186 | #endif |
173 | |||
174 | /* set during initialization */ | ||
175 | extern int iint_initialized; | ||