1 /*
2  * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3  * Decription: function for update crl.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  */
14 #include "tz_update_crl.h"
15 #include <linux/namei.h>
16 #include <linux/dcache.h>
17 #include <linux/fs.h>
18 #include <linux/vmalloc.h>
19 #include <linux/uaccess.h>
20 #include "mailbox_mempool.h"
21 #include "smc_smp.h"
22 
23 #define D_PATH_LEN 256
24 
25 static DEFINE_MUTEX(g_cms_crl_update_lock);
26 
send_crl_to_tee(const char *crl_buffer, uint32_t crl_len, const struct tc_ns_dev_file *dev_file)27 int send_crl_to_tee(const char *crl_buffer, uint32_t crl_len, const struct tc_ns_dev_file *dev_file)
28 {
29 	int ret;
30 	struct tc_ns_smc_cmd smc_cmd = { {0}, 0 };
31 	struct mb_cmd_pack *mb_pack = NULL;
32 	char *mb_param = NULL;
33 
34 	/* dev_file not need check null */
35 	if (crl_buffer == NULL || crl_len == 0 || crl_len > DEVICE_CRL_MAX) {
36 		tloge("invalid params\n");
37 		return -EINVAL;
38 	}
39 
40 	mb_pack = mailbox_alloc_cmd_pack();
41 	if (!mb_pack) {
42 		tloge("alloc mb pack failed\n");
43 		return -ENOMEM;
44 	}
45 	mb_param = mailbox_copy_alloc(crl_buffer, crl_len);
46 	if (!mb_param) {
47 		tloge("alloc mb param failed\n");
48 		ret = -ENOMEM;
49 		goto clean;
50 	}
51 	mb_pack->operation.paramtypes = TEEC_MEMREF_TEMP_INPUT;
52 	mb_pack->operation.params[0].memref.buffer = (unsigned int )mailbox_virt_to_phys((uintptr_t)mb_param);
53 	mb_pack->operation.buffer_h_addr[0] =
54 		(unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)mb_param) >> ADDR_TRANS_NUM);
55 	mb_pack->operation.params[0].memref.size = crl_len;
56 	smc_cmd.cmd_id = GLOBAL_CMD_ID_UPDATE_TA_CRL;
57 	smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
58 	if (dev_file != NULL)
59 		smc_cmd.dev_file_id = dev_file->dev_file_id;
60 	smc_cmd.context_id = 0;
61 	smc_cmd.operation_phys = (unsigned int)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation);
62 	smc_cmd.operation_h_phys =
63 		(unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM);
64 
65 	mutex_lock(&g_cms_crl_update_lock);
66 	ret = tc_ns_smc(&smc_cmd);
67 	mutex_unlock(&g_cms_crl_update_lock);
68 	if (ret != 0)
69 		tloge("smc call returns error ret 0x%x\n", ret);
70 clean:
71 	mailbox_free(mb_pack);
72 	mb_pack = NULL;
73 	if (mb_param)
74 		mailbox_free(mb_param);
75 
76 	return ret;
77 }
78 
tc_ns_update_ta_crl(const struct tc_ns_dev_file *dev_file, void __user *argp)79 int tc_ns_update_ta_crl(const struct tc_ns_dev_file *dev_file, void __user *argp)
80 {
81 	int ret;
82 	struct tc_ns_client_crl context = {0};
83 	void *buffer_addr = NULL;
84 	uint8_t *crl_buffer = NULL;
85 
86 	if (!dev_file || !argp) {
87 		tloge("invalid params\n");
88 		return -EINVAL;
89 	}
90 
91 	if (copy_from_user(&context, argp, sizeof(context)) != 0) {
92 		tloge("copy from user failed\n");
93 		return -ENOMEM;
94 	}
95 
96 	if (context.size > DEVICE_CRL_MAX) {
97 		tloge("crl size is too long\n");
98 		return -ENOMEM;
99 	}
100 
101 	crl_buffer = kmalloc(context.size, GFP_KERNEL);
102 	if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(crl_buffer))) {
103 		tloge("failed to allocate crl buffer\n");
104 		return -ENOMEM;
105 	}
106 
107 	buffer_addr = (void *)(uintptr_t)(context.memref.buffer_addr |
108 		(((uint64_t)context.memref.buffer_h_addr) << ADDR_TRANS_NUM));
109 	if (copy_from_user(crl_buffer, buffer_addr, context.size) != 0) {
110 		tloge("copy from user failed\n");
111 		goto clean;
112 	}
113 
114 	ret = send_crl_to_tee(crl_buffer, context.size, dev_file);
115 	if (ret != 0) {
116 		tloge("send crl to tee failed\n");
117 		goto clean;
118 	}
119 
120 clean:
121 	kfree(crl_buffer);
122 	return ret;
123 }
124 
crl_file_open(const char *file_path)125 static struct file *crl_file_open(const char *file_path)
126 {
127 	struct file *fp = NULL;
128 	int ret;
129 	char *dpath = NULL;
130 	char tmp_buf[D_PATH_LEN] = {0};
131 	struct path base_path = {
132 		.mnt = NULL,
133 		.dentry = NULL
134 	};
135 
136 	ret = kern_path(file_path, LOOKUP_FOLLOW, &base_path);
137 	if (ret != 0)
138 		return NULL;
139 
140 	dpath = d_path(&base_path, tmp_buf, D_PATH_LEN);
141 	if (!dpath || IS_ERR(dpath))
142 		goto clean;
143 
144 	fp = filp_open(dpath, O_RDONLY, 0);
145 
146 clean:
147 	path_put(&base_path);
148 	return fp;
149 }
150 
tz_update_crl(const char *file_path, const struct tc_ns_dev_file *dev_file)151 int tz_update_crl(const char *file_path, const struct tc_ns_dev_file *dev_file)
152 {
153 	struct file *fp = NULL;
154 	uint32_t crl_len;
155 	char *crl_buffer = NULL;
156 	uint32_t read_size;
157 	loff_t pos = 0;
158 	int ret = 0;
159 
160 	if (!dev_file || !file_path) {
161 		tloge("invalid params\n");
162 		return -EINVAL;
163 	}
164 
165 	fp = crl_file_open(file_path);
166 	if (!fp || IS_ERR(fp)) {
167 		tloge("open crl file error, ret = %ld\n", PTR_ERR(fp));
168 		return -ENOENT;
169 	}
170 	if (!fp->f_inode) {
171 		tloge("node is NULL\n");
172 		ret = -EINVAL;
173 		goto clean;
174 	}
175 
176 	crl_len = (uint32_t)(fp->f_inode->i_size);
177 	if (crl_len > DEVICE_CRL_MAX) {
178 		tloge("crl file len is invalid %u\n", crl_len);
179 		ret = -EINVAL;
180 		goto clean;
181 	}
182 
183 	crl_buffer = vmalloc(crl_len);
184 	if (!crl_buffer) {
185 		tloge("alloc crl file buffer(size=%u) failed\n", crl_len);
186 		ret = -ENOMEM;
187 		goto clean;
188 	}
189 
190 	read_size = (uint32_t)kernel_read(fp, crl_buffer, crl_len, &pos);
191 	if (read_size != crl_len) {
192 		tloge("read crl file failed, read size/total size=%u/%u\n", read_size, crl_len);
193 		ret = -ENOENT;
194 		goto clean;
195 	}
196 
197 	ret = send_crl_to_tee(crl_buffer, crl_len, dev_file);
198 	if (ret != 0) {
199 		tloge("send crl to tee failed\n");
200 		goto clean;
201 	}
202 
203 clean:
204 	filp_close(fp, 0);
205 	fp = NULL;
206 	if (crl_buffer)
207 		vfree(crl_buffer);
208 	return ret;
209 }