1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <pthread.h>
35 
36 #include <teec_trace.h>
37 #include <teec_ta_load.h>
38 
39 /*
40  * Attempt to first load TAs from a writable directory.  This is
41  * intended for testing (xtest 1008, load_corrupt_ta specifically),
42  * and should not be enabled in a production system, as it would
43  * greatly facilitate loading rogue TA code.
44  */
45 #ifdef CFG_TA_TEST_PATH
46 # ifndef TEEC_TEST_LOAD_PATH
47 #  ifdef __ANDROID__
48 #   define TEEC_TEST_LOAD_PATH "/data/vendor/tee"
49 #  else
50 #   define TEEC_TEST_LOAD_PATH "/tmp"
51 #  endif
52 # endif
53 #endif
54 
55 #ifndef PATH_MAX
56 #define PATH_MAX 255
57 #endif
58 
59 struct tee_rpc_cmd {
60 	void *buffer;
61 	uint32_t size;
62 	uint32_t type;
63 	int fd;
64 };
65 
66 /*
67  * Based on the uuid this function will try to find a TA-binary on the
68  * filesystem and return it back to the caller in the parameter ta.
69  *
70  * @param: prefix       Prefix for TA load path
71  * @param: dev_path     Where to load the TA from. The full path to the TA
72  *                      binary is @prefix/@dev_path/@destination.ta.
73  * @param: destination  The uuid of the TA we are searching for.
74  * @param: ta           A pointer which this function will allocate and copy
75  *                      the TA from the filesystem to the pointer itself. It is
76  *                      the callers responsibility to free the pointer.
77  * @param: ta_size      The size of the TA found on file system. It will be 0
78  *                      if no TA was not found.
79  *
80  * @return              0 if TA was found, otherwise -1.
81  */
try_load_secure_module(const char * prefix,const char * dev_path,const TEEC_UUID * destination,void * ta,size_t * ta_size)82 static int try_load_secure_module(const char* prefix,
83 				  const char* dev_path,
84 				  const TEEC_UUID *destination, void *ta,
85 				  size_t *ta_size)
86 {
87 	char fname[PATH_MAX] = { 0 };
88 	FILE *file = NULL;
89 	bool first_try = true;
90 	size_t s = 0;
91 	long l = 0;
92 	int n = 0;
93 
94 	if (!ta_size || !destination) {
95 		DMSG("wrong inparameter to TEECI_LoadSecureModule");
96 		return TA_BINARY_NOT_FOUND;
97 	}
98 
99 	/*
100 	 * We expect the TA binary to be named after the UUID as per RFC4122,
101 	 * that is: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.ta
102 	 * If the file cannot be open, try the deprecated format:
103 	 * xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx.ta
104 	 */
105 again:
106 	n = snprintf(fname, PATH_MAX,
107 		     "%s/%s/%08x-%04x-%04x-%02x%02x%s%02x%02x%02x%02x%02x%02x.ta",
108 		     prefix, dev_path,
109 		     destination->timeLow,
110 		     destination->timeMid,
111 		     destination->timeHiAndVersion,
112 		     destination->clockSeqAndNode[0],
113 		     destination->clockSeqAndNode[1],
114 		     first_try ? "-" : "",
115 		     destination->clockSeqAndNode[2],
116 		     destination->clockSeqAndNode[3],
117 		     destination->clockSeqAndNode[4],
118 		     destination->clockSeqAndNode[5],
119 		     destination->clockSeqAndNode[6],
120 		     destination->clockSeqAndNode[7]);
121 
122 	DMSG("Attempt to load %s", fname);
123 
124 	if ((n < 0) || (n >= PATH_MAX)) {
125 		EMSG("wrong TA path [%s]", fname);
126 		return TA_BINARY_NOT_FOUND;
127 	}
128 
129 	file = fopen(fname, "r");
130 	if (file == NULL) {
131 		DMSG("failed to open the ta %s TA-file", fname);
132 		if (first_try) {
133 			first_try = false;
134 			goto again;
135 		}
136 		return TA_BINARY_NOT_FOUND;
137 	}
138 
139 	if (fseek(file, 0, SEEK_END) != 0) {
140 		fclose(file);
141 		return TA_BINARY_NOT_FOUND;
142 	}
143 
144 	l = ftell(file);
145 	if (l < 0) {
146 		DMSG("failed to ftell the ta %s TA-file", fname);
147 		fclose(file);
148 		return TA_BINARY_NOT_FOUND;
149 	}
150 
151 	s = l;
152 	if (s > *ta_size || !ta) {
153 		/*
154 		 * Buffer isn't large enough, return the required size to
155 		 * let the caller increase the size of the buffer and try
156 		 * again.
157 		 */
158 		goto out;
159 	}
160 
161 	if (fseek(file, 0, SEEK_SET) != 0) {
162 		fclose(file);
163 		return TA_BINARY_NOT_FOUND;
164 	}
165 
166 	if (s != fread(ta, 1, s, file)) {
167 		DMSG("failed to fread the ta %s TA-file", fname);
168 		fclose(file);
169 		return TA_BINARY_NOT_FOUND;
170 	}
171 
172 out:
173 	*ta_size = s;
174 	fclose(file);
175 	return TA_BINARY_FOUND;
176 }
177 
TEECI_LoadSecureModule(const char * dev_path,const TEEC_UUID * destination,void * ta,size_t * ta_size)178 int TEECI_LoadSecureModule(const char* dev_path,
179 			   const TEEC_UUID *destination, void *ta,
180 			   size_t *ta_size)
181 {
182 	int res = TA_BINARY_NOT_FOUND;
183 	char **path = NULL;
184 
185 	for (path = ta_path; *path; path++) {
186 		res = try_load_secure_module(*path, dev_path, destination, ta,
187 					     ta_size);
188 		if (res == TA_BINARY_FOUND)
189 			break;
190 	}
191 	return res;
192 }
193