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