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/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"
27 #define ADD_LITERAL(cache, query, data) \
28 ((cache)->AddData((query), (uint8_t*)&(data), sizeof(data)))
30 int NaClCachingIsInexpensive(struct NaClValidationCache *cache,
31 const struct NaClValidationMetadata *metadata) {
32 if (cache->CachingIsInexpensive != NULL) {
33 return cache->CachingIsInexpensive(metadata);
35 return NULL != metadata && metadata->identity_type == NaClCodeIdentityFile;
39 void NaClMetadataFromFDCtor(struct NaClValidationMetadata *metadata,
41 const char* file_name,
42 size_t file_name_length) {
43 struct NaClHostDesc wrapper;
44 nacl_host_stat_t stat;
46 BY_HANDLE_FILE_INFORMATION file_info;
49 memset(metadata, 0, sizeof(*metadata));
50 /* If we early out, identity_type will be 0 / NaClCodeIdentityData. */
52 wrapper.d = file_desc;
53 if(NaClHostDescFstat(&wrapper, &stat))
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.
66 if (!GetFileInformationByHandle((HANDLE) _get_osfhandle(file_desc),
69 metadata->device_id = file_info.dwVolumeSerialNumber;
70 metadata->file_id = ((((uint64_t)file_info.nFileIndexHigh) << 32) |
71 file_info.nFileIndexLow);
73 /* st_dev is not actually a property of the device, so skip it. */
74 metadata->file_id = stat.st_ino;
77 metadata->file_size = stat.st_size;
78 metadata->mtime = stat.st_mtime;
79 metadata->ctime = stat.st_ctime;
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;
87 /* We have all the identity information we need. */
88 metadata->identity_type = NaClCodeIdentityFile;
91 void NaClMetadataDtor(struct NaClValidationMetadata *metadata) {
92 free(metadata->file_name);
93 /* Prevent use after free. */
94 memset(metadata, 0, sizeof(*metadata));
97 static void Serialize(uint8_t *buffer, const void *value, size_t size,
100 memcpy(&buffer[*offset], value, size);
101 *offset += (uint32_t) size;
104 static void SerializeNaClDescMetadataInternal(
105 const struct NaClRichFileInfo *info,
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),
113 Serialize(buffer, info->file_path, info->file_path_length, offset);
117 int NaClSerializeNaClDescMetadata(
118 const struct NaClRichFileInfo *info,
120 uint32_t *buffer_length) {
124 /* Calculate the buffer size. */
125 SerializeNaClDescMetadataInternal(info, NULL, buffer_length);
127 /* Allocate the buffer. */
128 *buffer = malloc(*buffer_length);
132 /* Fill the buffer. */
133 SerializeNaClDescMetadataInternal(info, *buffer, buffer_length);
137 int NaClSetFileOriginInfo(struct NaClDesc *desc,
138 struct NaClRichFileInfo *info) {
139 uint8_t *buffer = NULL;
140 uint32_t buffer_length = 0;
142 if (NaClSerializeNaClDescMetadata(info, &buffer, &buffer_length)) {
145 status = NACL_VTBL(NaClDesc, desc)->SetMetadata(
147 NACL_DESC_METADATA_ORIGIN_INFO_TYPE,
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)
158 memcpy(value, &buffer[*offset], size);
159 *offset += (uint32_t) size;
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;
170 NaClRichFileInfoCtor(info);
172 if (Deserialize(buffer, buffer_length, &info->known_file,
173 sizeof(info->known_file), &offset))
176 if (info->known_file) {
177 if (Deserialize(buffer, buffer_length, &info->file_path_length,
178 sizeof(info->file_path_length), &offset))
180 file_path = malloc(info->file_path_length);
181 if (NULL == file_path)
183 if (Deserialize(buffer, buffer_length, file_path, info->file_path_length,
186 info->file_path = file_path;
190 /* Entire buffer consumed? */
191 if (offset != buffer_length)
197 NaClRichFileInfoDtor(info);
201 void NaClRichFileInfoCtor(struct NaClRichFileInfo *info) {
202 memset(info, 0, sizeof(*info));
205 void NaClRichFileInfoDtor(struct NaClRichFileInfo *info) {
207 * file_path is "const" to express intent, we need to cast away the const to
210 free((void *) info->file_path);
211 /* Prevent use after Dtor. */
212 memset(info, 0, sizeof(*info));
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;
222 /* Get the buffer length. */
223 metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
227 if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
230 buffer = (uint8_t *) malloc(buffer_length);
234 metadata_type = NACL_VTBL(NaClDesc, desc)->GetMetadata(
238 if (metadata_type != NACL_DESC_METADATA_ORIGIN_INFO_TYPE)
241 status = NaClDeserializeNaClDescMetadata(buffer, buffer_length, info);
246 void NaClMetadataFromNaClDescCtor(struct NaClValidationMetadata *metadata,
247 struct NaClDesc *desc) {
248 struct NaClRichFileInfo info;
251 NaClRichFileInfoCtor(&info);
252 memset(metadata, 0, sizeof(*metadata));
254 if (NACL_VTBL(NaClDesc, desc)->typeTag != NACL_DESC_HOST_IO)
256 fd = ((struct NaClDescIoDesc *) desc)->hd->d;
257 if (NaClGetFileOriginInfo(desc, &info))
259 if (!info.known_file || info.file_path == NULL || info.file_path_length <= 0)
261 NaClMetadataFromFDCtor(metadata, fd, info.file_path, info.file_path_length);
263 NaClRichFileInfoDtor(&info);
266 void NaClAddCodeIdentity(uint8_t *data,
268 const struct NaClValidationMetadata *metadata,
269 struct NaClValidationCache *cache,
271 NaClCodeIdentityType identity_type;
272 if (NULL != metadata) {
273 identity_type = metadata->identity_type;
275 /* Fallback: identity unknown, treat it as anonymous data. */
276 identity_type = NaClCodeIdentityData;
278 CHECK(identity_type < NaClCodeIdentityMax);
281 * Explicitly record the type of identity being used to prevent attacks
282 * that confuse the payload of different identity types.
284 ADD_LITERAL(cache, query, identity_type);
286 if (identity_type == NaClCodeIdentityFile) {
288 CHECK(metadata->file_name);
289 CHECK(metadata->file_name_length);
290 CHECK(metadata->code_offset + (int64_t) size <= metadata->file_size);
292 /* The location of the code in the file. */
293 ADD_LITERAL(cache, query, metadata->code_offset);
294 ADD_LITERAL(cache, query, size);
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);
306 /* Hash all the code. */
307 cache->AddData(query, data, size);
311 struct NaClDesc *NaClDescCreateWithFilePathMetadata(NaClHandle handle,
312 const char *file_path) {
313 struct NaClDesc *desc = NaClDescIoDescFromHandleAllocCtor(handle,
315 char *alloc_file_path;
316 size_t file_path_length = strlen(file_path);
318 struct NaClRichFileInfo info;
324 * If there is no file path metadata, just return the created NaClDesc
325 * without adding rich file info.
327 if (file_path_length == 0)
330 /* Mark the desc as OK for mmapping. */
331 NaClDescMarkSafeForMmap(desc);
333 alloc_file_path = (char *) malloc(file_path_length + 1);
334 if (alloc_file_path == NULL) {
338 memcpy(alloc_file_path, file_path, file_path_length + 1);
340 /* Provide metadata for validation. */
341 NaClRichFileInfoCtor(&info);
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);