aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2018-05-15 13:38:26 -0400
committerMimi Zohar <zohar@linux.vnet.ibm.com>2018-05-18 15:34:45 -0400
commitfa516b66a1bfce1d72f1620c54bdfebc493000d1 (patch)
tree26b2887ece19ada7ec0f756a9cc7720cee4d1291
parent21af76631476030709f85f48e20bb9429a912b6f (diff)
EVM: Allow runtime modification of the set of verified xattrs
Sites may wish to provide additional metadata alongside files in order to make more fine-grained security decisions[1]. The security of this is enhanced if this metadata is protected, something that EVM makes possible. However, the kernel cannot know about the set of extended attributes that local admins may wish to protect, and hardcoding this policy in the kernel makes it difficult to change over time and less convenient for distributions to enable. This patch adds a new /sys/kernel/security/integrity/evm/evm_xattrs node, which can be read to obtain the current set of EVM-protected extended attributes or written to in order to add new entries. Extending this list will not change the validity of any existing signatures provided that the file in question does not have any of the additional extended attributes - missing xattrs are skipped when calculating the EVM hash. [1] For instance, a package manager could install information about the package uploader in an additional extended attribute. Local LSM policy could then be associated with that extended attribute in order to restrict the privileges available to packages from less trusted uploaders. Signed-off-by: Matthew Garrett <mjg59@google.com> Reviewed-by: James Morris <james.morris@microsoft.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
-rw-r--r--Documentation/ABI/testing/evm13
-rw-r--r--include/uapi/linux/audit.h1
-rw-r--r--security/integrity/evm/Kconfig11
-rw-r--r--security/integrity/evm/evm_crypto.c2
-rw-r--r--security/integrity/evm/evm_main.c6
-rw-r--r--security/integrity/evm/evm_secfs.c173
6 files changed, 202 insertions, 4 deletions
diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm
index d12cb2eae9ee..201d10319fa1 100644
--- a/Documentation/ABI/testing/evm
+++ b/Documentation/ABI/testing/evm
@@ -57,3 +57,16 @@ Description:
57 dracut (via 97masterkey and 98integrity) and systemd (via 57 dracut (via 97masterkey and 98integrity) and systemd (via
58 core/ima-setup) have support for loading keys at boot 58 core/ima-setup) have support for loading keys at boot
59 time. 59 time.
60
61What: security/integrity/evm/evm_xattrs
62Date: April 2018
63Contact: Matthew Garrett <mjg59@google.com>
64Description:
65 Shows the set of extended attributes used to calculate or
66 validate the EVM signature, and allows additional attributes
67 to be added at runtime. Any signatures generated after
68 additional attributes are added (and on files posessing those
69 additional attributes) will only be valid if the same
70 additional attributes are configured on system boot. Writing
71 a single period (.) will lock the xattr list from any further
72 modification.
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 4e61a9e05132..65d9293f1fb8 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -147,6 +147,7 @@
147#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */ 147#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
148#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */ 148#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
149#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */ 149#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */
150#define AUDIT_INTEGRITY_EVM_XATTR 1806 /* New EVM-covered xattr */
150 151
151#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ 152#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
152 153
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index e825e0ae78e7..d593346d0bba 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -42,6 +42,17 @@ config EVM_EXTRA_SMACK_XATTRS
42 additional info to the calculation, requires existing EVM 42 additional info to the calculation, requires existing EVM
43 labeled file systems to be relabeled. 43 labeled file systems to be relabeled.
44 44
45config EVM_ADD_XATTRS
46 bool "Add additional EVM extended attributes at runtime"
47 depends on EVM
48 default n
49 help
50 Allow userland to provide additional xattrs for HMAC calculation.
51
52 When this option is enabled, root can add additional xattrs to the
53 list used by EVM by writing them into
54 /sys/kernel/security/integrity/evm/evm_xattrs.
55
45config EVM_LOAD_X509 56config EVM_LOAD_X509
46 bool "Load an X509 certificate onto the '.evm' trusted keyring" 57 bool "Load an X509 certificate onto the '.evm' trusted keyring"
47 depends on EVM && INTEGRITY_TRUSTED_KEYRING 58 depends on EVM && INTEGRITY_TRUSTED_KEYRING
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index caeea20670cc..494da5fcc092 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -208,7 +208,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
208 return PTR_ERR(desc); 208 return PTR_ERR(desc);
209 209
210 error = -ENODATA; 210 error = -ENODATA;
211 list_for_each_entry(xattr, &evm_config_xattrnames, list) { 211 list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
212 bool is_ima = false; 212 bool is_ima = false;
213 213
214 if (strcmp(xattr->name, XATTR_NAME_IMA) == 0) 214 if (strcmp(xattr->name, XATTR_NAME_IMA) == 0)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 09582d4fc4a8..f9eff5041e4c 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -35,7 +35,7 @@ static const char * const integrity_status_msg[] = {
35}; 35};
36int evm_hmac_attrs; 36int evm_hmac_attrs;
37 37
38static struct xattr_list evm_config_default_xattrnames[] __ro_after_init = { 38static struct xattr_list evm_config_default_xattrnames[] = {
39#ifdef CONFIG_SECURITY_SELINUX 39#ifdef CONFIG_SECURITY_SELINUX
40 {.name = XATTR_NAME_SELINUX}, 40 {.name = XATTR_NAME_SELINUX},
41#endif 41#endif
@@ -101,7 +101,7 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
101 if (!(inode->i_opflags & IOP_XATTR)) 101 if (!(inode->i_opflags & IOP_XATTR))
102 return -EOPNOTSUPP; 102 return -EOPNOTSUPP;
103 103
104 list_for_each_entry(xattr, &evm_config_xattrnames, list) { 104 list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
105 error = __vfs_getxattr(dentry, inode, xattr->name, NULL, 0); 105 error = __vfs_getxattr(dentry, inode, xattr->name, NULL, 0);
106 if (error < 0) { 106 if (error < 0) {
107 if (error == -ENODATA) 107 if (error == -ENODATA)
@@ -228,7 +228,7 @@ static int evm_protected_xattr(const char *req_xattr_name)
228 struct xattr_list *xattr; 228 struct xattr_list *xattr;
229 229
230 namelen = strlen(req_xattr_name); 230 namelen = strlen(req_xattr_name);
231 list_for_each_entry(xattr, &evm_config_xattrnames, list) { 231 list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
232 if ((strlen(xattr->name) == namelen) 232 if ((strlen(xattr->name) == namelen)
233 && (strncmp(req_xattr_name, xattr->name, namelen) == 0)) { 233 && (strncmp(req_xattr_name, xattr->name, namelen) == 0)) {
234 found = 1; 234 found = 1;
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index e44380f0cb45..a7a0a1acae99 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -15,14 +15,22 @@
15 15
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 17
18#include <linux/audit.h>
18#include <linux/uaccess.h> 19#include <linux/uaccess.h>
19#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/mutex.h>
20#include "evm.h" 22#include "evm.h"
21 23
22static struct dentry *evm_dir; 24static struct dentry *evm_dir;
23static struct dentry *evm_init_tpm; 25static struct dentry *evm_init_tpm;
24static struct dentry *evm_symlink; 26static struct dentry *evm_symlink;
25 27
28#ifdef CONFIG_EVM_ADD_XATTRS
29static struct dentry *evm_xattrs;
30static DEFINE_MUTEX(xattr_list_mutex);
31static int evm_xattrs_locked;
32#endif
33
26/** 34/**
27 * evm_read_key - read() for <securityfs>/evm 35 * evm_read_key - read() for <securityfs>/evm
28 * 36 *
@@ -109,6 +117,166 @@ static const struct file_operations evm_key_ops = {
109 .write = evm_write_key, 117 .write = evm_write_key,
110}; 118};
111 119
120#ifdef CONFIG_EVM_ADD_XATTRS
121/**
122 * evm_read_xattrs - read() for <securityfs>/evm_xattrs
123 *
124 * @filp: file pointer, not actually used
125 * @buf: where to put the result
126 * @count: maximum to send along
127 * @ppos: where to start
128 *
129 * Returns number of bytes read or error code, as appropriate
130 */
131static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
132 size_t count, loff_t *ppos)
133{
134 char *temp;
135 int offset = 0;
136 ssize_t rc, size = 0;
137 struct xattr_list *xattr;
138
139 if (*ppos != 0)
140 return 0;
141
142 rc = mutex_lock_interruptible(&xattr_list_mutex);
143 if (rc)
144 return -ERESTARTSYS;
145
146 list_for_each_entry(xattr, &evm_config_xattrnames, list)
147 size += strlen(xattr->name) + 1;
148
149 temp = kmalloc(size + 1, GFP_KERNEL);
150 if (!temp)
151 return -ENOMEM;
152
153 list_for_each_entry(xattr, &evm_config_xattrnames, list) {
154 sprintf(temp + offset, "%s\n", xattr->name);
155 offset += strlen(xattr->name) + 1;
156 }
157
158 mutex_unlock(&xattr_list_mutex);
159 rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
160
161 return rc;
162}
163
164/**
165 * evm_write_xattrs - write() for <securityfs>/evm_xattrs
166 * @file: file pointer, not actually used
167 * @buf: where to get the data from
168 * @count: bytes sent
169 * @ppos: where to start
170 *
171 * Returns number of bytes written or error code, as appropriate
172 */
173static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
174 size_t count, loff_t *ppos)
175{
176 int len, err;
177 struct xattr_list *xattr, *tmp;
178 struct audit_buffer *ab;
179 struct iattr newattrs;
180 struct inode *inode;
181
182 if (!capable(CAP_SYS_ADMIN) || evm_xattrs_locked)
183 return -EPERM;
184
185 if (*ppos != 0)
186 return -EINVAL;
187
188 if (count > XATTR_NAME_MAX)
189 return -E2BIG;
190
191 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_EVM_XATTR);
192 if (IS_ERR(ab))
193 return PTR_ERR(ab);
194
195 xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL);
196 if (!xattr) {
197 err = -ENOMEM;
198 goto out;
199 }
200
201 xattr->name = memdup_user_nul(buf, count);
202 if (IS_ERR(xattr->name)) {
203 err = PTR_ERR(xattr->name);
204 xattr->name = NULL;
205 goto out;
206 }
207
208 /* Remove any trailing newline */
209 len = strlen(xattr->name);
210 if (xattr->name[len-1] == '\n')
211 xattr->name[len-1] = '\0';
212
213 if (strcmp(xattr->name, ".") == 0) {
214 evm_xattrs_locked = 1;
215 newattrs.ia_mode = S_IFREG | 0440;
216 newattrs.ia_valid = ATTR_MODE;
217 inode = evm_xattrs->d_inode;
218 inode_lock(inode);
219 err = simple_setattr(evm_xattrs, &newattrs);
220 inode_unlock(inode);
221 audit_log_format(ab, "locked");
222 if (!err)
223 err = count;
224 goto out;
225 }
226
227 audit_log_format(ab, "xattr=");
228 audit_log_untrustedstring(ab, xattr->name);
229
230 if (strncmp(xattr->name, XATTR_SECURITY_PREFIX,
231 XATTR_SECURITY_PREFIX_LEN) != 0) {
232 err = -EINVAL;
233 goto out;
234 }
235
236 /* Guard against races in evm_read_xattrs */
237 mutex_lock(&xattr_list_mutex);
238 list_for_each_entry(tmp, &evm_config_xattrnames, list) {
239 if (strcmp(xattr->name, tmp->name) == 0) {
240 err = -EEXIST;
241 mutex_unlock(&xattr_list_mutex);
242 goto out;
243 }
244 }
245 list_add_tail_rcu(&xattr->list, &evm_config_xattrnames);
246 mutex_unlock(&xattr_list_mutex);
247
248 audit_log_format(ab, " res=0");
249 audit_log_end(ab);
250 return count;
251out:
252 audit_log_format(ab, " res=%d", err);
253 audit_log_end(ab);
254 kfree(xattr->name);
255 kfree(xattr);
256 return err;
257}
258
259static const struct file_operations evm_xattr_ops = {
260 .read = evm_read_xattrs,
261 .write = evm_write_xattrs,
262};
263
264static int evm_init_xattrs(void)
265{
266 evm_xattrs = securityfs_create_file("evm_xattrs", 0660, evm_dir, NULL,
267 &evm_xattr_ops);
268 if (!evm_xattrs || IS_ERR(evm_xattrs))
269 return -EFAULT;
270
271 return 0;
272}
273#else
274static int evm_init_xattrs(void)
275{
276 return 0;
277}
278#endif
279
112int __init evm_init_secfs(void) 280int __init evm_init_secfs(void)
113{ 281{
114 int error = 0; 282 int error = 0;
@@ -131,6 +299,11 @@ int __init evm_init_secfs(void)
131 goto out; 299 goto out;
132 } 300 }
133 301
302 if (evm_init_xattrs() != 0) {
303 error = -EFAULT;
304 goto out;
305 }
306
134 return 0; 307 return 0;
135out: 308out:
136 securityfs_remove(evm_symlink); 309 securityfs_remove(evm_symlink);