1 : /*
2 : * Copyright (c) 2013 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include "native_client/src/trusted/validator/validation_cache.h"
8 :
9 : #include <string.h>
10 : #include <sys/stat.h>
11 :
12 : #include "native_client/src/public/desc_metadata_types.h"
13 : #include "native_client/src/shared/platform/nacl_check.h"
14 : #include "native_client/src/shared/platform/nacl_host_desc.h"
15 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
16 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
17 : #include "native_client/src/trusted/validator/rich_file_info.h"
18 : #include "native_client/src/trusted/validator/validation_cache_internal.h"
19 : #include "native_client/src/trusted/validator/validation_metadata.h"
20 :
21 : #if NACL_WINDOWS
22 : #include <Windows.h>
23 : #include <io.h>
24 : #endif
25 :
26 : #define ADD_LITERAL(cache, query, data) \
27 : ((cache)->AddData((query), (uint8_t*)&(data), sizeof(data)))
28 :
29 11 : int NaClCachingIsInexpensive(struct NaClValidationCache *cache,
30 11 : const struct NaClValidationMetadata *metadata) {
31 11 : if (cache->CachingIsInexpensive != NULL) {
32 11 : return cache->CachingIsInexpensive(metadata);
33 : } else {
34 0 : return NULL != metadata && metadata->identity_type == NaClCodeIdentityFile;
35 : }
36 11 : }
37 :
38 6 : void NaClMetadataFromFDCtor(struct NaClValidationMetadata *metadata,
39 6 : int file_desc,
40 6 : const char* file_name,
41 6 : size_t file_name_length) {
42 6 : struct NaClHostDesc wrapper;
43 6 : nacl_host_stat_t stat;
44 : #if NACL_WINDOWS
45 : BY_HANDLE_FILE_INFORMATION file_info;
46 : #endif
47 :
48 18 : memset(metadata, 0, sizeof(*metadata));
49 : /* If we early out, identity_type will be 0 / NaClCodeIdentityData. */
50 :
51 6 : wrapper.d = file_desc;
52 6 : if(NaClHostDescFstat(&wrapper, &stat))
53 0 : return;
54 :
55 : #if NACL_WINDOWS
56 : /*
57 : * This will not get us the complete file ID on ReFS, but doing the correct
58 : * thing (calling GetFileInformationByHandleEx) causes linkage issues on
59 : * Windows XP. We aren't relying on the file ID for security, just collision
60 : * resistance, so we don't need all of it.
61 : * In many cases (including on NTFS) we're also getting the 32 least
62 : * significant bits of a 64-bit volume serial number - but again, since it's
63 : * random we can live with it.
64 : */
65 : if (!GetFileInformationByHandle((HANDLE) _get_osfhandle(file_desc),
66 : &file_info))
67 : return;
68 : metadata->device_id = file_info.dwVolumeSerialNumber;
69 : metadata->file_id = ((((uint64_t)file_info.nFileIndexHigh) << 32) |
70 : file_info.nFileIndexLow);
71 : #else
72 : /* st_dev is not actually a property of the device, so skip it. */
73 6 : metadata->file_id = stat.st_ino;
74 : #endif
75 :
76 6 : metadata->file_size = stat.st_size;
77 6 : metadata->mtime = stat.st_mtime;
78 6 : metadata->ctime = stat.st_ctime;
79 :
80 18 : CHECK(0 < file_name_length);
81 6 : metadata->file_name = malloc(file_name_length);
82 18 : CHECK(NULL != metadata->file_name);
83 18 : memcpy(metadata->file_name, file_name, file_name_length);
84 6 : metadata->file_name_length = file_name_length;
85 :
86 : /* We have all the identity information we need. */
87 6 : metadata->identity_type = NaClCodeIdentityFile;
88 12 : }
89 :
90 11 : void NaClMetadataDtor(struct NaClValidationMetadata *metadata) {
91 11 : free(metadata->file_name);
92 : /* Prevent use after free. */
93 33 : memset(metadata, 0, sizeof(*metadata));
94 11 : }
95 :
96 36 : static void Serialize(uint8_t *buffer, const void *value, size_t size,
97 36 : uint32_t *offset) {
98 36 : if (buffer != NULL)
99 54 : memcpy(&buffer[*offset], value, size);
100 36 : *offset += (uint32_t) size;
101 36 : }
102 :
103 : static void SerializeNaClDescMetadataInternal(
104 16 : const struct NaClRichFileInfo *info,
105 16 : uint8_t *buffer,
106 16 : uint32_t *offset) {
107 16 : *offset = 0;
108 16 : Serialize(buffer, &info->known_file, sizeof(info->known_file), offset);
109 16 : if (info->known_file) {
110 10 : Serialize(buffer, &info->file_path_length, sizeof(info->file_path_length),
111 : offset);
112 10 : Serialize(buffer, info->file_path, info->file_path_length, offset);
113 10 : }
114 16 : }
115 :
116 : int NaClSerializeNaClDescMetadata(
117 8 : const struct NaClRichFileInfo *info,
118 8 : uint8_t **buffer,
119 8 : uint32_t *buffer_length) {
120 :
121 8 : *buffer = NULL;
122 :
123 : /* Calculate the buffer size. */
124 8 : SerializeNaClDescMetadataInternal(info, NULL, buffer_length);
125 :
126 : /* Allocate the buffer. */
127 8 : *buffer = malloc(*buffer_length);
128 8 : if (NULL == *buffer)
129 0 : return 1;
130 :
131 : /* Fill the buffer. */
132 8 : SerializeNaClDescMetadataInternal(info, *buffer, buffer_length);
133 8 : return 0;
134 8 : }
135 :
136 4 : int NaClSetFileOriginInfo(struct NaClDesc *desc,
137 4 : struct NaClRichFileInfo *info) {
138 4 : uint8_t *buffer = NULL;
139 4 : uint32_t buffer_length = 0;
140 4 : int status;
141 4 : if (NaClSerializeNaClDescMetadata(info, &buffer, &buffer_length)) {
142 0 : return 1;
143 : }
144 4 : status = NACL_VTBL(NaClDesc, desc)->SetMetadata(
145 : desc,
146 : NACL_DESC_METADATA_ORIGIN_INFO_TYPE,
147 : buffer_length,
148 : (uint8_t *) buffer);
149 4 : free(buffer);
150 4 : return status;
151 4 : }
152 :
153 14 : static int Deserialize(const uint8_t *buffer, uint32_t buffer_length,
154 14 : void *value, size_t size, uint32_t *offset) {
155 14 : if (*offset + size > buffer_length)
156 0 : return 1;
157 42 : memcpy(value, &buffer[*offset], size);
158 14 : *offset += (uint32_t) size;
159 14 : return 0;
160 14 : }
161 :
162 : int NaClDeserializeNaClDescMetadata(
163 6 : const uint8_t *buffer,
164 6 : uint32_t buffer_length,
165 6 : struct NaClRichFileInfo *info) {
166 : /* Work around const issues. */
167 6 : char *file_path = NULL;
168 6 : uint32_t offset = 0;
169 6 : NaClRichFileInfoCtor(info);
170 :
171 6 : if (Deserialize(buffer, buffer_length, &info->known_file,
172 : sizeof(info->known_file), &offset))
173 0 : goto on_error;
174 :
175 6 : if (info->known_file) {
176 4 : if (Deserialize(buffer, buffer_length, &info->file_path_length,
177 : sizeof(info->file_path_length), &offset))
178 0 : goto on_error;
179 4 : file_path = malloc(info->file_path_length);
180 4 : if (NULL == file_path)
181 0 : goto on_error;
182 4 : if (Deserialize(buffer, buffer_length, file_path, info->file_path_length,
183 : &offset))
184 0 : goto on_error;
185 4 : info->file_path = file_path;
186 4 : file_path = NULL;
187 4 : }
188 :
189 : /* Entire buffer consumed? */
190 6 : if (offset != buffer_length)
191 0 : goto on_error;
192 6 : return 0;
193 :
194 : on_error:
195 0 : free(file_path);
196 0 : NaClRichFileInfoDtor(info);
197 0 : return 1;
198 6 : }
199 :
200 29 : void NaClRichFileInfoCtor(struct NaClRichFileInfo *info) {
201 87 : memset(info, 0, sizeof(*info));
202 29 : }
203 :
204 16 : void NaClRichFileInfoDtor(struct NaClRichFileInfo *info) {
205 : /*
206 : * file_path is "const" to express intent, we need to cast away the const to
207 : * dallocate it.
208 : */
209 16 : free((void *) info->file_path);
210 : /* Prevent use after Dtor. */
211 48 : memset(info, 0, sizeof(*info));
212 16 : }
213 :
214 10 : int NaClGetFileOriginInfo(struct NaClDesc *desc,
215 10 : struct NaClRichFileInfo *info) {
216 10 : int32_t metadata_type;
217 10 : uint8_t *buffer = NULL;
218 10 : uint32_t buffer_length = 0;
219 10 : int status;
220 :
221 : /* Get the buffer length. */
222 10 : metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
223 : desc,
224 : &buffer_length,
225 : NULL);
226 10 : if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
227 6 : return 1;
228 :
229 4 : buffer = (uint8_t *) malloc(buffer_length);
230 4 : if (NULL == buffer)
231 0 : return 1;
232 :
233 4 : metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
234 : desc,
235 : &buffer_length,
236 : buffer);
237 4 : if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
238 0 : return 1;
239 :
240 4 : status = NaClDeserializeNaClDescMetadata(buffer, buffer_length, info);
241 4 : free(buffer);
242 4 : return status;
243 10 : }
244 :
245 7 : void NaClMetadataFromNaClDescCtor(struct NaClValidationMetadata *metadata,
246 7 : struct NaClDesc *desc) {
247 7 : struct NaClRichFileInfo info;
248 7 : int32_t fd = -1;
249 :
250 7 : NaClRichFileInfoCtor(&info);
251 21 : memset(metadata, 0, sizeof(*metadata));
252 :
253 7 : if (NACL_VTBL(NaClDesc, desc)->typeTag != NACL_DESC_HOST_IO)
254 0 : goto done;
255 7 : fd = ((struct NaClDescIoDesc *) desc)->hd->d;
256 7 : if (NaClGetFileOriginInfo(desc, &info))
257 5 : goto done;
258 6 : if (!info.known_file || info.file_path == NULL || info.file_path_length <= 0)
259 0 : goto done;
260 2 : NaClMetadataFromFDCtor(metadata, fd, info.file_path, info.file_path_length);
261 : done:
262 7 : NaClRichFileInfoDtor(&info);
263 7 : }
264 :
265 11 : void NaClAddCodeIdentity(uint8_t *data,
266 11 : size_t size,
267 11 : const struct NaClValidationMetadata *metadata,
268 11 : struct NaClValidationCache *cache,
269 11 : void *query) {
270 11 : NaClCodeIdentityType identity_type;
271 11 : if (NULL != metadata) {
272 5 : identity_type = metadata->identity_type;
273 5 : } else {
274 : /* Fallback: identity unknown, treat it as anonymous data. */
275 6 : identity_type = NaClCodeIdentityData;
276 : }
277 33 : CHECK(identity_type < NaClCodeIdentityMax);
278 :
279 : /*
280 : * Explicitly record the type of identity being used to prevent attacks
281 : * that confuse the payload of different identity types.
282 : */
283 11 : ADD_LITERAL(cache, query, identity_type);
284 :
285 11 : if (identity_type == NaClCodeIdentityFile) {
286 : /* Sanity checks. */
287 15 : CHECK(metadata->file_name);
288 15 : CHECK(metadata->file_name_length);
289 15 : CHECK(metadata->code_offset + (int64_t) size <= metadata->file_size);
290 :
291 : /* The location of the code in the file. */
292 5 : ADD_LITERAL(cache, query, metadata->code_offset);
293 5 : ADD_LITERAL(cache, query, size);
294 :
295 : /* The identity of the file. */
296 5 : ADD_LITERAL(cache, query, metadata->file_name_length);
297 5 : cache->AddData(query, (uint8_t *) metadata->file_name,
298 : metadata->file_name_length);
299 5 : ADD_LITERAL(cache, query, metadata->device_id);
300 5 : ADD_LITERAL(cache, query, metadata->file_id);
301 5 : ADD_LITERAL(cache, query, metadata->file_size);
302 5 : ADD_LITERAL(cache, query, metadata->mtime);
303 5 : ADD_LITERAL(cache, query, metadata->ctime);
304 5 : } else {
305 : /* Hash all the code. */
306 6 : cache->AddData(query, data, size);
307 : }
308 11 : }
|