tizen 2.3 release
[framework/system/deviced.git] / src / tima / tima-pkm.c
1 /*
2  * LKM in TIMA(TZ based Integrity Measurement Architecture)
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <assert.h>
22 #include <limits.h>
23 #include <libudev.h>
24 #include <Ecore.h>
25 #include <QSEEComAPI.h>
26
27 #include "core/log.h"
28 #include "core/common.h"
29 #include "core/devices.h"
30 #include "core/udev.h"
31
32 #include "noti.h"
33
34 /*
35  * tzapp interface - commands for tima tzapp
36  */
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)
46
47 /* return value from tzapp(lkmauth) */
48 #define PKM_MODIFIED            -1
49 #define PKM_SUCCESS             0
50 #define PKM_ERROR               1
51 #define PKM_META_MODIFIED       2
52 #define PKM_INIT_FAIL           3
53 #define PKM_INIT_SUCCESS        4
54
55 struct tima_gen_req {
56         int cmd_id;
57         union {
58                 unsigned int buf_size;
59                 struct {
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));
65
66 struct tima_measure_rsp_s {
67         int cmd_id;
68         int ret;
69         union {
70                 unsigned char hash[20];
71                 char result_ondemand[4096];
72         }  __attribute__((packed)) result;
73 } __attribute__((packed));
74
75 /*
76  * QSEECom interface
77  */
78 #define FIRMWARE_PATH           "/lib/firmware"
79
80 struct QSEECom_handle *qseecom_handle = NULL;
81
82 /*
83  * ECore interface
84  */
85 #define TIMA_TIMER_START        (5)
86 #define TIMA_TIMER_INTERVAL     (5 * 60)
87
88 static Ecore_Timer *timer_id;
89
90 /*
91  * kernel signature file handle
92  */
93 #define KERN_HASH_FILE          "/usr/system/kern_sec_info"
94
95 static int kern_info_fd = -1;
96 static unsigned int kern_info_len;
97
98 static int noti_id = 0;
99
100
101 /*
102  * tima_shutdown_tzapp
103  *
104  * This function is written to temporarily bypass a problem in QSEECOM
105  * driver. In ideal situations, this fuction should not be needed.
106  *
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.
111  */
112 static int tima_shutdown_tzapp(void)
113 {
114         int ret = -1;
115
116         if ((qseecom_handle != NULL) &&
117             (QSEECom_app_load_query(qseecom_handle, "tima") == QSEECOM_APP_ALREADY_LOADED)) {
118                 ret = QSEECom_shutdown_app(&qseecom_handle);
119                 if (!ret) {
120                         qseecom_handle = NULL;
121                         _D("tzapp is shut down!");
122                 } else {
123                         _E("Unable to shut down the TIMA tzapp; ret(%d)", errno);
124                 }
125         } else {
126                 _D("tzapp is not loaded! nothing to shut down.");
127         }
128
129         return ret;
130 }
131
132 /*
133  * tima_send_initcmd
134  *
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
140  */
141 static int tima_send_initcmd(uint32_t req_len, struct tima_measure_rsp_s *recv_cmd)
142 {
143         int ret = -1;
144         void *file_ptr = NULL;
145         struct tima_gen_req *req;
146         struct tima_measure_rsp_s *rsp;
147         uint32_t rsp_len = 0;
148
149         _D("signature load request\n");
150
151         if ((kern_info_fd < 0) || (kern_info_len == 0)) {
152                 _E("%s not loaded", KERN_HASH_FILE);
153                 return ret;
154         }
155
156         rsp_len = sizeof(struct tima_measure_rsp_s);
157
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));
162
163         if (read(kern_info_fd, file_ptr, kern_info_len) != kern_info_len) {
164                 _E("cann't load signature, ret(%d)", errno);
165                 return ret;
166         }
167
168         rsp = (struct tima_measure_rsp_s *)(qseecom_handle->ion_sbuffer + req_len);
169
170         _D("req: cmd(0x%08X), size(%d)@%p", req->cmd_id, req_len, req);
171
172         QSEECom_set_bandwidth(qseecom_handle, true);
173         do {
174                 ret = QSEECom_send_cmd(qseecom_handle, req, req_len, rsp, rsp_len);
175                 if (ret) {
176                         _E("QSEECom_send_cmd failed, ret(%d)", ret);
177                         break;
178                 } else if ((rsp->ret != 0) && (rsp->ret != 512)) {
179                         _E("internal error in tima tzapp, ret(%d)", rsp->ret);
180                         ret = -1;
181                         break;
182                 }
183         } while(rsp->ret == 512);
184         QSEECom_set_bandwidth(qseecom_handle, false);
185
186         _D("rsp: cmd(0x%08x), ret(%d), msg(%s)", rsp->cmd_id, rsp->ret, rsp->result.result_ondemand);
187
188         return ret;
189 }
190
191 static int tima_load_tzapp(struct tima_measure_rsp_s *recv_cmd)
192 {
193         int ret = -1;
194         uint32_t req_len, rsp_len;
195
196         if ((qseecom_handle != NULL) &&
197             (QSEECom_app_load_query(qseecom_handle, "tima") == QSEECOM_APP_ALREADY_LOADED)) {
198                 recv_cmd->ret = 0;
199                 return 0;
200         }
201
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);
205                 /*
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.
209                  */
210                 recv_cmd->ret = 2;
211                 snprintf(recv_cmd->result.result_ondemand, 256, "MSG=kern_metadata_modified;");
212                 /* Indicate load_app succeed, but open kern_kern_info fail */
213                 return 0;
214         }
215
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);
220
221         req_len = kern_info_len + sizeof(struct tima_gen_req);
222         rsp_len = sizeof(struct tima_measure_rsp_s);
223
224         req_len = (req_len > rsp_len) ? req_len : rsp_len;
225
226         if (req_len & QSEECOM_ALIGN_MASK)
227                 req_len = QSEECOM_ALIGN(req_len);
228
229         _D("attempting to load tzapp");
230
231         /* Load up the secure world counter-part */
232         ret = QSEECom_start_app(&qseecom_handle, FIRMWARE_PATH, "tima", req_len * 2);
233         if (!ret) {
234                 _I("tzapp(%s) successfully loaded\n", FIRMWARE_PATH "/tima");
235
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();
239                         ret = -1;
240                         goto error;
241                 } else {
242                         _D("signature successfully loaded");
243                 }
244         } else {
245                 _E("failed to load the tzapp, ret(%d)", errno);
246         }
247
248 error:
249         close(kern_info_fd);
250         kern_info_fd = -1;
251         return ret;
252 }
253
254 static int tima_send_command(struct tima_measure_rsp_s *recv_cmd)
255 {
256         int req_len = 0, rsp_len = 0;
257         struct tima_gen_req *req;
258         struct tima_measure_rsp_s *rsp;
259         int ret = -1;
260
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);
265
266         if (rsp_len & QSEECOM_ALIGN_MASK)
267                 rsp_len = QSEECOM_ALIGN(rsp_len);
268
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);
272
273         _D("req: cmd(0x%08X), size(%d)@%p", req->cmd_id, req_len, req);
274
275         QSEECom_set_bandwidth(qseecom_handle, true);
276         do {
277                 ret = QSEECom_send_cmd(qseecom_handle, req, req_len, rsp, rsp_len);
278                 if (ret) {
279                         _E("QSEECom_send_cmd failed, ret(%d)", errno);
280                         break;
281                 }
282
283                 usleep(5000);
284         } while (rsp->ret == 512);
285         QSEECom_set_bandwidth(qseecom_handle, false);
286
287         _D("rsp: cmd(0x%08x), ret(%d), msg(%s)", rsp->cmd_id, rsp->ret, rsp->result.result_ondemand);
288
289         memcpy(recv_cmd, rsp, sizeof(struct tima_measure_rsp_s));
290
291         return ret;
292 }
293
294 static int tima_check_event(void)
295 {
296         int ret = -1;
297         struct tima_measure_rsp_s recv_cmd;
298
299         if (tima_load_tzapp(&recv_cmd)) {
300                 _E("Failed to load tzapp!");
301                 return -1;
302         } else if (recv_cmd.ret != 0) {
303                 goto skip_measurement;
304         }
305
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 ();
310
311                 return -1;
312         }
313
314         /* The following call needs to be removed after fixing the -22 error problem */
315         tima_shutdown_tzapp ();
316
317         if ((recv_cmd.ret == 0) &&
318             (recv_cmd.cmd_id != TIMA_MEASURE_KERNEL_ONDEMAND)) {
319                 _E("Invalid QSEE result!");
320                 return -1;
321         }
322
323         switch (recv_cmd.ret) {
324         case PKM_SUCCESS:
325                 _I("verify successed");
326                 ret = 0;
327                 break;
328         case PKM_MODIFIED:
329                 _I("verify failed");
330                 ret = 1;
331                 break;
332         case PKM_META_MODIFIED:
333                 _I("check metadata (%s)", KERN_HASH_FILE);
334                 ret = 1;
335                 break;
336         default:
337                 _E("internal error (%d)", recv_cmd.ret);
338                 break;
339         }
340
341 skip_measurement:
342         return ret;
343 }
344
345 static Eina_Bool tima_pkm_monitor(void *data)
346 {
347         int ret;
348         static int is_first = 1;
349
350         ret = tima_check_event();
351         if (ret) {
352                 noti_id = tima_pkm_detection_noti_on();
353                 if (noti_id < 0) {
354                         _E("FAIL: tima_pkm_detection_noti_on()");
355                         noti_id = 0;
356                 }
357
358                 ecore_timer_del(timer_id);
359                 timer_id = NULL;
360                 return EINA_FALSE;
361         }
362
363         if (is_first) {
364                 is_first = 0;
365                 ecore_timer_interval_set(timer_id, TIMA_TIMER_INTERVAL);
366         }
367
368         return EINA_TRUE;
369 }
370
371 /* tima-pkm init funcion */
372 void tima_pkm_init(void)
373 {
374         timer_id = ecore_timer_add(TIMA_TIMER_START, tima_pkm_monitor, NULL);
375         if (!timer_id) {
376                 _E("can't add timer for tima-pkm");
377                 return;
378         }
379 }
380
381 /* tima-pkm exit funcion */
382 void tima_pkm_exit(void)
383 {
384         if (timer_id) {
385                 ecore_timer_del(timer_id);
386                 timer_id = NULL;
387         }
388 }