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.
7 #include "native_client/src/trusted/validator/validation_cache.h"
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"
26 #define ADD_LITERAL(cache, query, data) \
27 ((cache)->AddData((query), (uint8_t*)&(data), sizeof(data)))
29 int NaClCachingIsInexpensive(struct NaClValidationCache *cache,
30 const struct NaClValidationMetadata *metadata) {
31 if (cache->CachingIsInexpensive != NULL) {
32 return cache->CachingIsInexpensive(metadata);
34 return NULL != metadata && metadata->identity_type == NaClCodeIdentityFile;
38 void NaClMetadataFromFDCtor(struct NaClValidationMetadata *metadata,
40 const char* file_name,
41 size_t file_name_length) {
42 struct NaClHostDesc wrapper;
43 nacl_host_stat_t stat;
45 BY_HANDLE_FILE_INFORMATION file_info;
48 memset(metadata, 0, sizeof(*metadata));
49 /* If we early out, identity_type will be 0 / NaClCodeIdentityData. */
51 wrapper.d = file_desc;
52 if(NaClHostDescFstat(&wrapper, &stat))
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.
65 if (!GetFileInformationByHandle((HANDLE) _get_osfhandle(file_desc),
68 metadata->device_id = file_info.dwVolumeSerialNumber;
69 metadata->file_id = ((((uint64_t)file_info.nFileIndexHigh) << 32) |
70 file_info.nFileIndexLow);
72 /* st_dev is not actually a property of the device, so skip it. */
73 metadata->file_id = stat.st_ino;
76 metadata->file_size = stat.st_size;
77 metadata->mtime = stat.st_mtime;
78 metadata->ctime = stat.st_ctime;
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;
86 /* We have all the identity information we need. */
87 metadata->identity_type = NaClCodeIdentityFile;
90 void NaClMetadataDtor(struct NaClValidationMetadata *metadata) {
91 free(metadata->file_name);
92 /* Prevent use after free. */
93 memset(metadata, 0, sizeof(*metadata));
96 static void Serialize(uint8_t *buffer, const void *value, size_t size,
99 memcpy(&buffer[*offset], value, size);
100 *offset += (uint32_t) size;
103 static void SerializeNaClDescMetadataInternal(
104 const struct NaClRichFileInfo *info,
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),
112 Serialize(buffer, info->file_path, info->file_path_length, offset);
116 int NaClSerializeNaClDescMetadata(
117 const struct NaClRichFileInfo *info,
119 uint32_t *buffer_length) {
123 /* Calculate the buffer size. */
124 SerializeNaClDescMetadataInternal(info, NULL, buffer_length);
126 /* Allocate the buffer. */
127 *buffer = malloc(*buffer_length);
131 /* Fill the buffer. */
132 SerializeNaClDescMetadataInternal(info, *buffer, buffer_length);
136 int NaClSetFileOriginInfo(struct NaClDesc *desc,
137 struct NaClRichFileInfo *info) {
138 uint8_t *buffer = NULL;
139 uint32_t buffer_length = 0;
141 if (NaClSerializeNaClDescMetadata(info, &buffer, &buffer_length)) {
144 status = NACL_VTBL(NaClDesc, desc)->SetMetadata(
146 NACL_DESC_METADATA_ORIGIN_INFO_TYPE,
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)
157 memcpy(value, &buffer[*offset], size);
158 *offset += (uint32_t) size;
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;
169 NaClRichFileInfoCtor(info);
171 if (Deserialize(buffer, buffer_length, &info->known_file,
172 sizeof(info->known_file), &offset))
175 if (info->known_file) {
176 if (Deserialize(buffer, buffer_length, &info->file_path_length,
177 sizeof(info->file_path_length), &offset))
179 file_path = malloc(info->file_path_length);
180 if (NULL == file_path)
182 if (Deserialize(buffer, buffer_length, file_path, info->file_path_length,
185 info->file_path = file_path;
189 /* Entire buffer consumed? */
190 if (offset != buffer_length)
196 NaClRichFileInfoDtor(info);
200 void NaClRichFileInfoCtor(struct NaClRichFileInfo *info) {
201 memset(info, 0, sizeof(*info));
204 void NaClRichFileInfoDtor(struct NaClRichFileInfo *info) {
206 * file_path is "const" to express intent, we need to cast away the const to
209 free((void *) info->file_path);
210 /* Prevent use after Dtor. */
211 memset(info, 0, sizeof(*info));
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;
221 /* Get the buffer length. */
222 metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
226 if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
229 buffer = (uint8_t *) malloc(buffer_length);
233 metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
237 if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
240 status = NaClDeserializeNaClDescMetadata(buffer, buffer_length, info);
245 void NaClMetadataFromNaClDescCtor(struct NaClValidationMetadata *metadata,
246 struct NaClDesc *desc) {
247 struct NaClRichFileInfo info;
250 NaClRichFileInfoCtor(&info);
251 memset(metadata, 0, sizeof(*metadata));
253 if (NACL_VTBL(NaClDesc, desc)->typeTag != NACL_DESC_HOST_IO)
255 fd = ((struct NaClDescIoDesc *) desc)->hd->d;
256 if (NaClGetFileOriginInfo(desc, &info))
258 if (!info.known_file || info.file_path == NULL || info.file_path_length <= 0)
260 NaClMetadataFromFDCtor(metadata, fd, info.file_path, info.file_path_length);
262 NaClRichFileInfoDtor(&info);
265 void NaClAddCodeIdentity(uint8_t *data,
267 const struct NaClValidationMetadata *metadata,
268 struct NaClValidationCache *cache,
270 NaClCodeIdentityType identity_type;
271 if (NULL != metadata) {
272 identity_type = metadata->identity_type;
274 /* Fallback: identity unknown, treat it as anonymous data. */
275 identity_type = NaClCodeIdentityData;
277 CHECK(identity_type < NaClCodeIdentityMax);
280 * Explicitly record the type of identity being used to prevent attacks
281 * that confuse the payload of different identity types.
283 ADD_LITERAL(cache, query, identity_type);
285 if (identity_type == NaClCodeIdentityFile) {
287 CHECK(metadata->file_name);
288 CHECK(metadata->file_name_length);
289 CHECK(metadata->code_offset + (int64_t) size <= metadata->file_size);
291 /* The location of the code in the file. */
292 ADD_LITERAL(cache, query, metadata->code_offset);
293 ADD_LITERAL(cache, query, size);
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);
305 /* Hash all the code. */
306 cache->AddData(query, data, size);