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: destination  The uuid of the TA we are searching for.
71  * @param: ta           A pointer which this function will allocate and copy
72  *                      the TA from the filesystem to the pointer itself. It is
73  *                      the callers responsibility to free the pointer.
74  * @param: ta_size      The size of the TA found on file system. It will be 0
75  *                      if no TA was not found.
76  *
77  * @return              0 if TA was found, otherwise -1.
78  */
try_load_secure_module(const char * prefix,const char * dev_path,const TEEC_UUID * destination,void * ta,size_t * ta_size)79 static int try_load_secure_module(const char* prefix,
80 				  const char* dev_path,
81 				  const TEEC_UUID *destination, void *ta,
82 				  size_t *ta_size)
83 {
84 	char fname[PATH_MAX] = { 0 };
85 	FILE *file = NULL;
86 	bool first_try = true;
87 	size_t s = 0;
88 	long l = 0;
89 	int n = 0;
90 
91 	if (!ta_size || !destination) {
92 		DMSG("wrong inparameter to TEECI_LoadSecureModule");
93 		return TA_BINARY_NOT_FOUND;
94 	}
95 
96 	/*
97 	 * We expect the TA binary to be named after the UUID as per RFC4122,
98 	 * that is: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.ta
99 	 * If the file cannot be open, try the deprecated format:
100 	 * xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx.ta
101 	 */
102 again:
103 	n = snprintf(fname, PATH_MAX,
104 		     "%s/%s/%08x-%04x-%04x-%02x%02x%s%02x%02x%02x%02x%02x%02x.ta",
105 		     prefix, dev_path,
106 		     destination->timeLow,
107 		     destination->timeMid,
108 		     destination->timeHiAndVersion,
109 		     destination->clockSeqAndNode[0],
110 		     destination->clockSeqAndNode[1],
111 		     first_try ? "-" : "",
112 		     destination->clockSeqAndNode[2],
113 		     destination->clockSeqAndNode[3],
114 		     destination->clockSeqAndNode[4],
115 		     destination->clockSeqAndNode[5],
116 		     destination->clockSeqAndNode[6],
117 		     destination->clockSeqAndNode[7]);
118 
119 	DMSG("Attempt to load %s", fname);
120 
121 	if ((n < 0) || (n >= PATH_MAX)) {
122 		EMSG("wrong TA path [%s]", fname);
123 		return TA_BINARY_NOT_FOUND;
124 	}
125 
126 	file = fopen(fname, "r");
127 	if (file == NULL) {
128 		DMSG("failed to open the ta %s TA-file", fname);
129 		if (first_try) {
130 			first_try = false;
131 			goto again;
132 		}
133 		return TA_BINARY_NOT_FOUND;
134 	}
135 
136 	if (fseek(file, 0, SEEK_END) != 0) {
137 		fclose(file);
138 		return TA_BINARY_NOT_FOUND;
139 	}
140 
141 	l = ftell(file);
142 	if (l < 0) {
143 		DMSG("failed to ftell the ta %s TA-file", fname);
144 		fclose(file);
145 		return TA_BINARY_NOT_FOUND;
146 	}
147 
148 	s = l;
149 	if (s > *ta_size || !ta) {
150 		/*
151 		 * Buffer isn't large enough, return the required size to
152 		 * let the caller increase the size of the buffer and try
153 		 * again.
154 		 */
155 		goto out;
156 	}
157 
158 	if (fseek(file, 0, SEEK_SET) != 0) {
159 		fclose(file);
160 		return TA_BINARY_NOT_FOUND;
161 	}
162 
163 	if (s != fread(ta, 1, s, file)) {
164 		DMSG("failed to fread the ta %s TA-file", fname);
165 		fclose(file);
166 		return TA_BINARY_NOT_FOUND;
167 	}
168 
169 out:
170 	*ta_size = s;
171 	fclose(file);
172 	return TA_BINARY_FOUND;
173 }
174 
TEECI_LoadSecureModule(const char * dev_path,const TEEC_UUID * destination,void * ta,size_t * ta_size)175 int TEECI_LoadSecureModule(const char* dev_path,
176 			   const TEEC_UUID *destination, void *ta,
177 			   size_t *ta_size)
178 {
179 #ifdef TEEC_TEST_LOAD_PATH
180 	int res = 0;
181 
182 	res = try_load_secure_module(TEEC_TEST_LOAD_PATH,
183 				     dev_path, destination, ta, ta_size);
184 	if (res != TA_BINARY_NOT_FOUND)
185 		return res;
186 #endif
187 
188 	return try_load_secure_module(TEEC_LOAD_PATH,
189 				      dev_path, destination, ta, ta_size);
190 }
191