2 * LKM in TIMA(TZ based Integrity Measurement Architecture)
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
25 #include <QSEEComAPI.h>
28 #include "core/common.h"
29 #include "core/devices.h"
30 #include "core/udev.h"
35 * tzapp interface - commands for tima tzapp
37 #define TIMA_PKM_ID 0x00070000
38 #define TIMA_MEASURE_REG_PROC (TIMA_PKM_ID | 0x00)
39 #define TIMA_MEASURE_PROC (TIMA_PKM_ID | 0x01)
40 #define TIMA_MEASURE_KERNEL (TIMA_PKM_ID | 0x02)
41 #define TIMA_MEASURE_UNREG_PROC (TIMA_PKM_ID | 0x03)
42 #define TIMA_MEASURE_VERIFY (TIMA_PKM_ID | 0x04)
43 #define TIMA_MEASURE_KERNEL_ONDEMAND (TIMA_PKM_ID | 0x05)
44 #define TIMA_SECURE_LOG (TIMA_PKM_ID | 0x06)
45 #define TIMA_INIT (TIMA_PKM_ID | 0x07)
47 /* return value from tzapp(lkmauth) */
48 #define PKM_MODIFIED -1
51 #define PKM_META_MODIFIED 2
52 #define PKM_INIT_FAIL 3
53 #define PKM_INIT_SUCCESS 4
58 unsigned int buf_size;
60 int log_region; /* 0: Page Table, 1: Periodic TIMA & LKM */
61 int log_entry_index; /* 0: Log Meta Data, others: Log Entry Index */
62 } __attribute__((packed)) log;
63 } __attribute__((packed)) param;
64 } __attribute__((packed));
66 struct tima_measure_rsp_s {
70 unsigned char hash[20];
71 char result_ondemand[4096];
72 } __attribute__((packed)) result;
73 } __attribute__((packed));
78 #define FIRMWARE_PATH "/lib/firmware"
80 struct QSEECom_handle *qseecom_handle = NULL;
85 #define TIMA_TIMER_START (5)
86 #define TIMA_TIMER_INTERVAL (5 * 60)
88 static Ecore_Timer *timer_id;
91 * kernel signature file handle
93 #define KERN_HASH_FILE "/usr/system/kern_sec_info"
95 static int kern_info_fd = -1;
96 static unsigned int kern_info_len;
98 static int noti_id = 0;
102 * tima_shutdown_tzapp
104 * This function is written to temporarily bypass a problem in QSEECOM
105 * driver. In ideal situations, this fuction should not be needed.
107 * We are running into the -22 error, which stops the tima tzapp from
108 * working after it occurs. This function is used to shut down the tima
109 * tzapp every time when a periodic measurement is done.
110 * When the -22 error is fixed, this function shouldn't be needed.
112 static int tima_shutdown_tzapp(void)
116 if ((qseecom_handle != NULL) &&
117 (QSEECom_app_load_query(qseecom_handle, "tima") == QSEECOM_APP_ALREADY_LOADED)) {
118 ret = QSEECom_shutdown_app(&qseecom_handle);
120 qseecom_handle = NULL;
121 _D("tzapp is shut down!");
123 _E("Unable to shut down the TIMA tzapp; ret(%d)", errno);
126 _D("tzapp is not loaded! nothing to shut down.");
135 * This function is written explictly to tell the TIMA periodic
136 * Trustzone application to accept the passed KERN_HASH_FILE
137 * via the buffer. We saw a lot of issues with the listener
138 * service, when the TIMA application was explicitly calling
139 * the filesystem API's to load this file on the TZ side
141 static int tima_send_initcmd(uint32_t req_len, struct tima_measure_rsp_s *recv_cmd)
144 void *file_ptr = NULL;
145 struct tima_gen_req *req;
146 struct tima_measure_rsp_s *rsp;
147 uint32_t rsp_len = 0;
149 _D("signature load request\n");
151 if ((kern_info_fd < 0) || (kern_info_len == 0)) {
152 _E("%s not loaded", KERN_HASH_FILE);
156 rsp_len = sizeof(struct tima_measure_rsp_s);
158 req = (struct tima_gen_req *)qseecom_handle->ion_sbuffer;
159 req->cmd_id = TIMA_INIT;
160 req->param.buf_size = kern_info_len;
161 file_ptr = (void *)((char *)req + sizeof(struct tima_gen_req));
163 if (read(kern_info_fd, file_ptr, kern_info_len) != kern_info_len) {
164 _E("cann't load signature, ret(%d)", errno);
168 rsp = (struct tima_measure_rsp_s *)(qseecom_handle->ion_sbuffer + req_len);
170 _D("req: cmd(0x%08X), size(%d)@%p", req->cmd_id, req_len, req);
172 QSEECom_set_bandwidth(qseecom_handle, true);
174 ret = QSEECom_send_cmd(qseecom_handle, req, req_len, rsp, rsp_len);
176 _E("QSEECom_send_cmd failed, ret(%d)", ret);
178 } else if ((rsp->ret != 0) && (rsp->ret != 512)) {
179 _E("internal error in tima tzapp, ret(%d)", rsp->ret);
183 } while(rsp->ret == 512);
184 QSEECom_set_bandwidth(qseecom_handle, false);
186 _D("rsp: cmd(0x%08x), ret(%d), msg(%s)", rsp->cmd_id, rsp->ret, rsp->result.result_ondemand);
191 static int tima_load_tzapp(struct tima_measure_rsp_s *recv_cmd)
194 uint32_t req_len, rsp_len;
196 if ((qseecom_handle != NULL) &&
197 (QSEECom_app_load_query(qseecom_handle, "tima") == QSEECOM_APP_ALREADY_LOADED)) {
202 kern_info_fd = open(KERN_HASH_FILE, O_RDONLY);
203 if (kern_info_fd < 0) {
204 _E("%s open failed, ret(%d)", KERN_HASH_FILE, errno);
206 * Simulate TZ response for kern metadata modified
207 * This is necessary for the notification to show up.
208 * I cringed while writing this code, so that makes the two of us.
211 snprintf(recv_cmd->result.result_ondemand, 256, "MSG=kern_metadata_modified;");
212 /* Indicate load_app succeed, but open kern_kern_info fail */
216 /* determine the length of the kern_info file */
217 lseek(kern_info_fd, 0, SEEK_END);
218 kern_info_len = lseek(kern_info_fd, 0, SEEK_CUR);
219 lseek(kern_info_fd, 0, SEEK_SET);
221 req_len = kern_info_len + sizeof(struct tima_gen_req);
222 rsp_len = sizeof(struct tima_measure_rsp_s);
224 req_len = (req_len > rsp_len) ? req_len : rsp_len;
226 if (req_len & QSEECOM_ALIGN_MASK)
227 req_len = QSEECOM_ALIGN(req_len);
229 _D("attempting to load tzapp");
231 /* Load up the secure world counter-part */
232 ret = QSEECom_start_app(&qseecom_handle, FIRMWARE_PATH, "tima", req_len * 2);
234 _I("tzapp(%s) successfully loaded\n", FIRMWARE_PATH "/tima");
236 if ((ret = tima_send_initcmd(req_len, recv_cmd)) != 0) {
237 _E("failed to send QSEE cmd (TIMA_INIT) to tzapp!");
238 tima_shutdown_tzapp();
242 _D("signature successfully loaded");
245 _E("failed to load the tzapp, ret(%d)", errno);
254 static int tima_send_command(struct tima_measure_rsp_s *recv_cmd)
256 int req_len = 0, rsp_len = 0;
257 struct tima_gen_req *req;
258 struct tima_measure_rsp_s *rsp;
261 req_len = sizeof(struct tima_gen_req);
262 rsp_len = sizeof(struct tima_measure_rsp_s);
263 if (req_len & QSEECOM_ALIGN_MASK)
264 req_len = QSEECOM_ALIGN(req_len);
266 if (rsp_len & QSEECOM_ALIGN_MASK)
267 rsp_len = QSEECOM_ALIGN(rsp_len);
269 req = (struct tima_gen_req *)qseecom_handle->ion_sbuffer;
270 req->cmd_id = TIMA_MEASURE_KERNEL_ONDEMAND;
271 rsp = (struct tima_measure_rsp_s *)(qseecom_handle->ion_sbuffer + req_len);
273 _D("req: cmd(0x%08X), size(%d)@%p", req->cmd_id, req_len, req);
275 QSEECom_set_bandwidth(qseecom_handle, true);
277 ret = QSEECom_send_cmd(qseecom_handle, req, req_len, rsp, rsp_len);
279 _E("QSEECom_send_cmd failed, ret(%d)", errno);
284 } while (rsp->ret == 512);
285 QSEECom_set_bandwidth(qseecom_handle, false);
287 _D("rsp: cmd(0x%08x), ret(%d), msg(%s)", rsp->cmd_id, rsp->ret, rsp->result.result_ondemand);
289 memcpy(recv_cmd, rsp, sizeof(struct tima_measure_rsp_s));
294 static int tima_check_event(void)
297 struct tima_measure_rsp_s recv_cmd;
299 if (tima_load_tzapp(&recv_cmd)) {
300 _E("Failed to load tzapp!");
302 } else if (recv_cmd.ret != 0) {
303 goto skip_measurement;
306 if (tima_send_command(&recv_cmd)) {
307 _E("Failed to send QSEE cmd to tzapp!");
308 /* The following call needs to be removed after fixing the -22 error problem */
309 tima_shutdown_tzapp ();
314 /* The following call needs to be removed after fixing the -22 error problem */
315 tima_shutdown_tzapp ();
317 if ((recv_cmd.ret == 0) &&
318 (recv_cmd.cmd_id != TIMA_MEASURE_KERNEL_ONDEMAND)) {
319 _E("Invalid QSEE result!");
323 switch (recv_cmd.ret) {
325 _I("verify successed");
332 case PKM_META_MODIFIED:
333 _I("check metadata (%s)", KERN_HASH_FILE);
337 _E("internal error (%d)", recv_cmd.ret);
345 static Eina_Bool tima_pkm_monitor(void *data)
348 static int is_first = 1;
350 ret = tima_check_event();
352 noti_id = tima_pkm_detection_noti_on();
354 _E("FAIL: tima_pkm_detection_noti_on()");
358 ecore_timer_del(timer_id);
365 ecore_timer_interval_set(timer_id, TIMA_TIMER_INTERVAL);
371 /* tima-pkm init funcion */
372 void tima_pkm_init(void)
374 timer_id = ecore_timer_add(TIMA_TIMER_START, tima_pkm_monitor, NULL);
376 _E("can't add timer for tima-pkm");
381 /* tima-pkm exit funcion */
382 void tima_pkm_exit(void)
385 ecore_timer_del(timer_id);