1 /*
2  * Copyright (C) 2010 IBM Corporation
3  *
4  * Authors:
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  * File: evm_secfs.c
12  *	- Used to signal when key is on keyring
13  *	- Get the key and enable EVM
14  */
15 
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 
18 #include <linux/uaccess.h>
19 #include <linux/module.h>
20 #include "evm.h"
21 
22 static struct dentry *evm_dir;
23 static struct dentry *evm_init_tpm;
24 static struct dentry *evm_symlink;
25 
26 /**
27  * evm_read_key - read() for <securityfs>/evm
28  *
29  * @filp: file pointer, not actually used
30  * @buf: where to put the result
31  * @count: maximum to send along
32  * @ppos: where to start
33  *
34  * Returns number of bytes read or error code, as appropriate
35  */
36 static ssize_t evm_read_key(struct file *filp, char __user *buf,
37 			    size_t count, loff_t *ppos)
38 {
39 	char temp[80];
40 	ssize_t rc;
41 
42 	if (*ppos != 0)
43 		return 0;
44 
45 	sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP_COMPLETE));
46 	rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
47 
48 	return rc;
49 }
50 
51 /**
52  * evm_write_key - write() for <securityfs>/evm
53  * @file: file pointer, not actually used
54  * @buf: where to get the data from
55  * @count: bytes sent
56  * @ppos: where to start
57  *
58  * Used to signal that key is on the kernel key ring.
59  * - get the integrity hmac key from the kernel key ring
60  * - create list of hmac protected extended attributes
61  * Returns number of bytes written or error code, as appropriate
62  */
63 static ssize_t evm_write_key(struct file *file, const char __user *buf,
64 			     size_t count, loff_t *ppos)
65 {
66 	int i, ret;
67 
68 	if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP_COMPLETE))
69 		return -EPERM;
70 
71 	ret = kstrtoint_from_user(buf, count, 0, &i);
72 
73 	if (ret)
74 		return ret;
75 
76 	/* Reject invalid values */
77 	if (!i || (i & ~EVM_INIT_MASK) != 0)
78 		return -EINVAL;
79 
80 	/* Don't allow a request to freshly enable metadata writes if
81 	 * keys are loaded.
82 	 */
83 	if ((i & EVM_ALLOW_METADATA_WRITES) &&
84 	    ((evm_initialized & EVM_KEY_MASK) != 0) &&
85 	    !(evm_initialized & EVM_ALLOW_METADATA_WRITES))
86 		return -EPERM;
87 
88 	if (i & EVM_INIT_HMAC) {
89 		ret = evm_init_key();
90 		if (ret != 0)
91 			return ret;
92 		/* Forbid further writes after the symmetric key is loaded */
93 		i |= EVM_SETUP_COMPLETE;
94 	}
95 
96 	evm_initialized |= i;
97 
98 	/* Don't allow protected metadata modification if a symmetric key
99 	 * is loaded
100 	 */
101 	if (evm_initialized & EVM_INIT_HMAC)
102 		evm_initialized &= ~(EVM_ALLOW_METADATA_WRITES);
103 
104 	return count;
105 }
106 
107 static const struct file_operations evm_key_ops = {
108 	.read		= evm_read_key,
109 	.write		= evm_write_key,
110 };
111 
112 int __init evm_init_secfs(void)
113 {
114 	int error = 0;
115 
116 	evm_dir = securityfs_create_dir("evm", integrity_dir);
117 	if (!evm_dir || IS_ERR(evm_dir))
118 		return -EFAULT;
119 
120 	evm_init_tpm = securityfs_create_file("evm", 0660,
121 					      evm_dir, NULL, &evm_key_ops);
122 	if (!evm_init_tpm || IS_ERR(evm_init_tpm)) {
123 		error = -EFAULT;
124 		goto out;
125 	}
126 
127 	evm_symlink = securityfs_create_symlink("evm", NULL,
128 						"integrity/evm/evm", NULL);
129 	if (!evm_symlink || IS_ERR(evm_symlink)) {
130 		error = -EFAULT;
131 		goto out;
132 	}
133 
134 	return 0;
135 out:
136 	securityfs_remove(evm_symlink);
137 	securityfs_remove(evm_init_tpm);
138 	securityfs_remove(evm_dir);
139 	return error;
140 }
141