Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator / validation_cache.c
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 int NaClCachingIsInexpensive(struct NaClValidationCache *cache,
30                              const struct NaClValidationMetadata *metadata) {
31   if (cache->CachingIsInexpensive != NULL) {
32     return cache->CachingIsInexpensive(metadata);
33   } else {
34     return NULL != metadata && metadata->identity_type == NaClCodeIdentityFile;
35   }
36 }
37
38 void NaClMetadataFromFDCtor(struct NaClValidationMetadata *metadata,
39                             int file_desc,
40                             const char* file_name,
41                             size_t file_name_length) {
42   struct NaClHostDesc wrapper;
43   nacl_host_stat_t stat;
44 #if NACL_WINDOWS
45   BY_HANDLE_FILE_INFORMATION file_info;
46 #endif
47
48   memset(metadata, 0, sizeof(*metadata));
49   /* If we early out, identity_type will be 0 / NaClCodeIdentityData. */
50
51   wrapper.d = file_desc;
52   if(NaClHostDescFstat(&wrapper, &stat))
53     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   metadata->file_id = stat.st_ino;
74 #endif
75
76   metadata->file_size = stat.st_size;
77   metadata->mtime = stat.st_mtime;
78   metadata->ctime = stat.st_ctime;
79
80   CHECK(0 < file_name_length);
81   metadata->file_name = malloc(file_name_length);
82   CHECK(NULL != metadata->file_name);
83   memcpy(metadata->file_name, file_name, file_name_length);
84   metadata->file_name_length = file_name_length;
85
86   /* We have all the identity information we need. */
87   metadata->identity_type = NaClCodeIdentityFile;
88 }
89
90 void NaClMetadataDtor(struct NaClValidationMetadata *metadata) {
91   free(metadata->file_name);
92   /* Prevent use after free. */
93   memset(metadata, 0, sizeof(*metadata));
94 }
95
96 static void Serialize(uint8_t *buffer, const void *value, size_t size,
97                       uint32_t *offset) {
98   if (buffer != NULL)
99     memcpy(&buffer[*offset], value, size);
100   *offset += (uint32_t) size;
101 }
102
103 static void SerializeNaClDescMetadataInternal(
104     const struct NaClRichFileInfo *info,
105     uint8_t *buffer,
106     uint32_t *offset) {
107   *offset = 0;
108   Serialize(buffer, &info->known_file, sizeof(info->known_file), offset);
109   if (info->known_file) {
110     Serialize(buffer, &info->file_path_length, sizeof(info->file_path_length),
111               offset);
112     Serialize(buffer, info->file_path, info->file_path_length, offset);
113   }
114 }
115
116 int NaClSerializeNaClDescMetadata(
117     const struct NaClRichFileInfo *info,
118     uint8_t **buffer,
119     uint32_t *buffer_length) {
120
121   *buffer = NULL;
122
123   /* Calculate the buffer size. */
124   SerializeNaClDescMetadataInternal(info, NULL, buffer_length);
125
126   /* Allocate the buffer. */
127   *buffer = malloc(*buffer_length);
128   if (NULL == *buffer)
129     return 1;
130
131   /* Fill the buffer. */
132   SerializeNaClDescMetadataInternal(info, *buffer, buffer_length);
133   return 0;
134 }
135
136 int NaClSetFileOriginInfo(struct NaClDesc *desc,
137                           struct NaClRichFileInfo *info) {
138   uint8_t *buffer = NULL;
139   uint32_t buffer_length = 0;
140   int status;
141   if (NaClSerializeNaClDescMetadata(info, &buffer, &buffer_length)) {
142     return 1;
143   }
144   status = NACL_VTBL(NaClDesc, desc)->SetMetadata(
145       desc,
146       NACL_DESC_METADATA_ORIGIN_INFO_TYPE,
147       buffer_length,
148       (uint8_t *) buffer);
149   free(buffer);
150   return status;
151 }
152
153 static int Deserialize(const uint8_t *buffer, uint32_t buffer_length,
154                        void *value, size_t size, uint32_t *offset) {
155   if (*offset + size > buffer_length)
156     return 1;
157   memcpy(value, &buffer[*offset], size);
158   *offset += (uint32_t) size;
159   return 0;
160 }
161
162 int NaClDeserializeNaClDescMetadata(
163     const uint8_t *buffer,
164     uint32_t buffer_length,
165     struct NaClRichFileInfo *info) {
166   /* Work around const issues. */
167   char *file_path = NULL;
168   uint32_t offset = 0;
169   NaClRichFileInfoCtor(info);
170
171   if (Deserialize(buffer, buffer_length, &info->known_file,
172                   sizeof(info->known_file), &offset))
173     goto on_error;
174
175   if (info->known_file) {
176     if (Deserialize(buffer, buffer_length, &info->file_path_length,
177                     sizeof(info->file_path_length), &offset))
178       goto on_error;
179     file_path = malloc(info->file_path_length);
180     if (NULL == file_path)
181       goto on_error;
182     if (Deserialize(buffer, buffer_length, file_path, info->file_path_length,
183                     &offset))
184       goto on_error;
185     info->file_path = file_path;
186     file_path = NULL;
187   }
188
189   /* Entire buffer consumed? */
190   if (offset != buffer_length)
191     goto on_error;
192   return 0;
193
194  on_error:
195   free(file_path);
196   NaClRichFileInfoDtor(info);
197   return 1;
198 }
199
200 void NaClRichFileInfoCtor(struct NaClRichFileInfo *info) {
201   memset(info, 0, sizeof(*info));
202 }
203
204 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   free((void *) info->file_path);
210   /* Prevent use after Dtor. */
211   memset(info, 0, sizeof(*info));
212 }
213
214 int NaClGetFileOriginInfo(struct NaClDesc *desc,
215                           struct NaClRichFileInfo *info) {
216   int32_t metadata_type;
217   uint8_t *buffer = NULL;
218   uint32_t buffer_length = 0;
219   int status;
220
221   /* Get the buffer length. */
222   metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
223       desc,
224       &buffer_length,
225       NULL);
226   if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
227     return 1;
228
229   buffer = (uint8_t *) malloc(buffer_length);
230   if (NULL == buffer)
231     return 1;
232
233   metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
234       desc,
235       &buffer_length,
236       buffer);
237   if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
238     return 1;
239
240   status = NaClDeserializeNaClDescMetadata(buffer, buffer_length, info);
241   free(buffer);
242   return status;
243 }
244
245 void NaClMetadataFromNaClDescCtor(struct NaClValidationMetadata *metadata,
246                                   struct NaClDesc *desc) {
247   struct NaClRichFileInfo info;
248   int32_t fd = -1;
249
250   NaClRichFileInfoCtor(&info);
251   memset(metadata, 0, sizeof(*metadata));
252
253   if (NACL_VTBL(NaClDesc, desc)->typeTag != NACL_DESC_HOST_IO)
254     goto done;
255   fd = ((struct NaClDescIoDesc *) desc)->hd->d;
256   if (NaClGetFileOriginInfo(desc, &info))
257     goto done;
258   if (!info.known_file || info.file_path == NULL || info.file_path_length <= 0)
259     goto done;
260   NaClMetadataFromFDCtor(metadata, fd, info.file_path, info.file_path_length);
261  done:
262   NaClRichFileInfoDtor(&info);
263 }
264
265 void NaClAddCodeIdentity(uint8_t *data,
266                          size_t size,
267                          const struct NaClValidationMetadata *metadata,
268                          struct NaClValidationCache *cache,
269                          void *query) {
270   NaClCodeIdentityType identity_type;
271   if (NULL != metadata) {
272     identity_type = metadata->identity_type;
273   } else {
274     /* Fallback: identity unknown, treat it as anonymous data. */
275     identity_type = NaClCodeIdentityData;
276   }
277   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   ADD_LITERAL(cache, query, identity_type);
284
285   if (identity_type == NaClCodeIdentityFile) {
286     /* Sanity checks. */
287     CHECK(metadata->file_name);
288     CHECK(metadata->file_name_length);
289     CHECK(metadata->code_offset + (int64_t) size <= metadata->file_size);
290
291     /* The location of the code in the file. */
292     ADD_LITERAL(cache, query, metadata->code_offset);
293     ADD_LITERAL(cache, query, size);
294
295     /* The identity of the file. */
296     ADD_LITERAL(cache, query, metadata->file_name_length);
297     cache->AddData(query, (uint8_t *) metadata->file_name,
298                    metadata->file_name_length);
299     ADD_LITERAL(cache, query, metadata->device_id);
300     ADD_LITERAL(cache, query, metadata->file_id);
301     ADD_LITERAL(cache, query, metadata->file_size);
302     ADD_LITERAL(cache, query, metadata->mtime);
303     ADD_LITERAL(cache, query, metadata->ctime);
304   } else {
305     /* Hash all the code. */
306     cache->AddData(query, data, size);
307   }
308 }