blob: d715d24b0b71e96ce7091f87b80141f59dc079b3 [file] [log] [blame]
Xusong Wang96e68dc2019-01-18 17:28:26 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "neuralnetworks_hidl_hal_test"
18
19#include "VtsHalNeuralnetworks.h"
20
21#include "Callbacks.h"
22#include "GeneratedTestHarness.h"
23#include "TestHarness.h"
24#include "Utils.h"
25
26#include <android-base/logging.h>
27#include <android/hidl/memory/1.0/IMemory.h>
28#include <hidlmemory/mapping.h>
29#include <cstdio>
30#include <cstdlib>
31#include <random>
32
33#include <gtest/gtest.h>
34
35namespace android {
36namespace hardware {
37namespace neuralnetworks {
38namespace V1_2 {
39namespace vts {
40namespace functional {
41
42using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
43using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
44using ::android::nn::allocateSharedMemory;
45using ::test_helper::MixedTypedExample;
46
47namespace {
48
49// In frameworks/ml/nn/runtime/tests/generated/, creates a hidl model of mobilenet.
50#include "examples/mobilenet_224_gender_basic_fixed.example.cpp"
51#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp"
52
53// Prevent the compiler from complaining about an otherwise unused function.
54[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
55[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
56
57enum class AccessMode { READ_ONLY, WRITE_ONLY };
58
59void createCacheHandle(const std::vector<std::string>& files, AccessMode mode,
60 hidl_handle* handle) {
61 std::vector<int> fds;
62 for (const auto& file : files) {
63 int fd;
64 if (mode == AccessMode::READ_ONLY) {
65 fd = open(file.c_str(), O_RDONLY);
66 } else if (mode == AccessMode::WRITE_ONLY) {
67 fd = open(file.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
68 } else {
69 FAIL();
70 }
71 ASSERT_GE(fd, 0);
72 fds.push_back(fd);
73 }
74 native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0);
75 ASSERT_NE(cacheNativeHandle, nullptr);
76 for (uint32_t i = 0; i < fds.size(); i++) {
77 cacheNativeHandle->data[i] = fds[i];
78 }
79 handle->setTo(cacheNativeHandle, /*shouldOwn=*/true);
80}
81
82} // namespace
83
84// Tag for the compilation caching tests.
85class CompilationCachingTest : public NeuralnetworksHidlTest {
86 protected:
87 void SetUp() override {
88 NeuralnetworksHidlTest::SetUp();
Hervé Guihotac7ac522019-02-12 16:22:44 -080089 ASSERT_NE(device.get(), nullptr);
Xusong Wang96e68dc2019-01-18 17:28:26 -080090
91 // Create cache directory.
92 char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
93 char* cacheDir = mkdtemp(cacheDirTemp);
94 ASSERT_NE(cacheDir, nullptr);
95 mCache1 = cacheDir + mCache1;
96 mCache2 = cacheDir + mCache2;
97 mCache3 = cacheDir + mCache3;
98
99 // Check if caching is supported.
100 bool isCachingSupported;
101 Return<void> ret = device->isCachingSupported(
102 [&isCachingSupported](ErrorStatus status, bool supported) {
103 EXPECT_EQ(ErrorStatus::NONE, status);
104 isCachingSupported = supported;
105 });
106 EXPECT_TRUE(ret.isOk());
107 if (isCachingSupported) {
108 mIsCachingSupported = true;
109 } else {
110 LOG(INFO) << "NN VTS: Early termination of test because vendor service does not "
111 "support compilation caching.";
112 std::cout << "[ ] Early termination of test because vendor service does not "
113 "support compilation caching."
114 << std::endl;
115 mIsCachingSupported = false;
116 }
117
118 // Create empty cache files.
119 hidl_handle handle;
120 createCacheHandle({mCache1, mCache2, mCache3}, AccessMode::WRITE_ONLY, &handle);
121 }
122
123 void saveModelToCache(sp<IPreparedModel> preparedModel, const hidl_handle& cache1,
124 const hidl_handle& cache2, ErrorStatus* status) {
125 // Save IPreparedModel to cache.
126 hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
127 Return<ErrorStatus> saveToCacheStatus =
128 preparedModel->saveToCache(cache1, cache2, cacheToken);
129 ASSERT_TRUE(saveToCacheStatus.isOk());
130 *status = static_cast<ErrorStatus>(saveToCacheStatus);
131 }
132
133 bool checkEarlyTermination(ErrorStatus status) {
134 if (status == ErrorStatus::GENERAL_FAILURE) {
135 LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
136 "save the prepared model that it does not support.";
137 std::cout << "[ ] Early termination of test because vendor service cannot "
138 "save the prepared model that it does not support."
139 << std::endl;
140 return true;
141 }
142 return false;
143 }
144
145 void prepareModelFromCache(const hidl_handle& cache1, const hidl_handle& cache2,
146 sp<IPreparedModel>* preparedModel, ErrorStatus* status) {
147 // Launch prepare model from cache.
148 sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
149 ASSERT_NE(nullptr, preparedModelCallback.get());
150 hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
151 Return<ErrorStatus> prepareLaunchStatus =
152 device->prepareModelFromCache(cache1, cache2, cacheToken, preparedModelCallback);
153 ASSERT_TRUE(prepareLaunchStatus.isOk());
154 if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
155 *preparedModel = nullptr;
156 *status = static_cast<ErrorStatus>(prepareLaunchStatus);
157 return;
158 }
159
160 // Retrieve prepared model.
161 preparedModelCallback->wait();
162 *status = preparedModelCallback->getStatus();
163 *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
164 .withDefault(nullptr);
165 }
166
167 std::string mCache1 = "/cache1";
168 std::string mCache2 = "/cache2";
169 std::string mCache3 = "/cache3";
170 uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {};
171 bool mIsCachingSupported;
172};
173
174TEST_F(CompilationCachingTest, CacheSavingAndRetrieval) {
175 // Create test HIDL model and compile.
176 Model testModel = createTestModel();
177 sp<IPreparedModel> preparedModel = nullptr;
178 generated_tests::PrepareModel(device, testModel, &preparedModel);
179 // Terminate early if the driver cannot prepare the model.
180 if (preparedModel == nullptr) return;
181
182 // Save the compilation to cache.
183 {
184 ErrorStatus status;
185 hidl_handle cache1, cache2;
186 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
187 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
188 saveModelToCache(preparedModel, cache1, cache2, &status);
189 if (!mIsCachingSupported) {
190 EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
191 } else {
192 if (checkEarlyTermination(status)) return;
193 ASSERT_EQ(status, ErrorStatus::NONE);
194 }
195 }
196
197 // Retrieve preparedModel from cache.
198 {
199 preparedModel = nullptr;
200 ErrorStatus status;
201 hidl_handle cache1, cache2;
202 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
203 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
204 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
205 if (!mIsCachingSupported) {
206 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
207 ASSERT_EQ(preparedModel, nullptr);
208 return;
209 } else {
210 ASSERT_EQ(status, ErrorStatus::NONE);
211 ASSERT_NE(preparedModel, nullptr);
212 }
213 }
214
215 // Execute and verify results.
216 generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
217 testModel.relaxComputationFloat32toFloat16,
218 /*testDynamicOutputShape=*/false);
219}
220
221TEST_F(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
222 // Create test HIDL model and compile.
223 Model testModel = createTestModel();
224 sp<IPreparedModel> preparedModel = nullptr;
225 generated_tests::PrepareModel(device, testModel, &preparedModel);
226 // Terminate early if the driver cannot prepare the model.
227 if (preparedModel == nullptr) return;
228
229 // Save the compilation to cache.
230 {
231 ErrorStatus status;
232 hidl_handle cache1, cache2;
233 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
234 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
235 saveModelToCache(preparedModel, cache1, cache2, &status);
236 if (!mIsCachingSupported) {
237 EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
238 } else {
239 if (checkEarlyTermination(status)) return;
240 ASSERT_EQ(status, ErrorStatus::NONE);
241 }
242 }
243
244 // Retrieve preparedModel from cache.
245 {
246 preparedModel = nullptr;
247 ErrorStatus status;
248 hidl_handle cache1, cache2;
249 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
250 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
251 uint8_t dummyByte = 0;
252 // Advance offset by one byte.
253 ASSERT_GE(read(cache1.getNativeHandle()->data[0], &dummyByte, 1), 0);
254 ASSERT_GE(read(cache2.getNativeHandle()->data[0], &dummyByte, 1), 0);
255 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
256 if (!mIsCachingSupported) {
257 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
258 ASSERT_EQ(preparedModel, nullptr);
259 return;
260 } else {
261 ASSERT_EQ(status, ErrorStatus::NONE);
262 ASSERT_NE(preparedModel, nullptr);
263 }
264 }
265
266 // Execute and verify results.
267 generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
268 testModel.relaxComputationFloat32toFloat16,
269 /*testDynamicOutputShape=*/false);
270}
271
272TEST_F(CompilationCachingTest, SaveToCacheInvalidNumFd) {
273 // Create test HIDL model and compile.
274 Model testModel = createTestModel();
275 sp<IPreparedModel> preparedModel = nullptr;
276 generated_tests::PrepareModel(device, testModel, &preparedModel);
277 // Terminate early if the driver cannot prepare the model.
278 if (preparedModel == nullptr) return;
279
280 // cache1 with invalid NumFd.
281 {
282 ErrorStatus status;
283 hidl_handle cache1, cache2;
284 createCacheHandle({mCache1, mCache3}, AccessMode::WRITE_ONLY, &cache1);
285 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
286 saveModelToCache(preparedModel, cache1, cache2, &status);
287 if (status != ErrorStatus::GENERAL_FAILURE) {
288 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
289 }
290 }
291
292 // cache2 with invalid NumFd.
293 {
294 ErrorStatus status;
295 hidl_handle cache1, cache2;
296 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
297 createCacheHandle({mCache2, mCache3}, AccessMode::WRITE_ONLY, &cache2);
298 saveModelToCache(preparedModel, cache1, cache2, &status);
299 if (status != ErrorStatus::GENERAL_FAILURE) {
300 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
301 }
302 }
303}
304
305TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
306 // Create test HIDL model and compile.
307 Model testModel = createTestModel();
308 sp<IPreparedModel> preparedModel = nullptr;
309 generated_tests::PrepareModel(device, testModel, &preparedModel);
310 // Terminate early if the driver cannot prepare the model.
311 if (preparedModel == nullptr) return;
312
313 // Save the compilation to cache.
314 {
315 ErrorStatus status;
316 hidl_handle cache1, cache2;
317 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
318 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
319 saveModelToCache(preparedModel, cache1, cache2, &status);
320 if (status != ErrorStatus::GENERAL_FAILURE) {
321 ASSERT_EQ(status, ErrorStatus::NONE);
322 }
323 }
324
325 // cache1 with invalid NumFd.
326 {
327 preparedModel = nullptr;
328 ErrorStatus status;
329 hidl_handle cache1, cache2;
330 createCacheHandle({mCache1, mCache3}, AccessMode::READ_ONLY, &cache1);
331 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
332 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
333 if (status != ErrorStatus::GENERAL_FAILURE) {
334 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
335 ASSERT_EQ(preparedModel, nullptr);
336 }
337 }
338
339 // cache2 with invalid NumFd.
340 {
341 preparedModel = nullptr;
342 ErrorStatus status;
343 hidl_handle cache1, cache2;
344 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
345 createCacheHandle({mCache2, mCache3}, AccessMode::READ_ONLY, &cache2);
346 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
347 if (status != ErrorStatus::GENERAL_FAILURE) {
348 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
349 ASSERT_EQ(preparedModel, nullptr);
350 }
351 }
352}
353
354TEST_F(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
355 // Create test HIDL model and compile.
356 Model testModel = createTestModel();
357 sp<IPreparedModel> preparedModel = nullptr;
358 generated_tests::PrepareModel(device, testModel, &preparedModel);
359 // Terminate early if the driver cannot prepare the model.
360 if (preparedModel == nullptr) return;
361
362 // cache1 with invalid access mode.
363 {
364 ErrorStatus status;
365 hidl_handle cache1, cache2;
366 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
367 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
368 saveModelToCache(preparedModel, cache1, cache2, &status);
369 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
370 }
371
372 // cache2 with invalid access mode.
373 {
374 ErrorStatus status;
375 hidl_handle cache1, cache2;
376 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
377 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
378 saveModelToCache(preparedModel, cache1, cache2, &status);
379 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
380 }
381}
382
383TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
384 // Create test HIDL model and compile.
385 Model testModel = createTestModel();
386 sp<IPreparedModel> preparedModel = nullptr;
387 generated_tests::PrepareModel(device, testModel, &preparedModel);
388 // Terminate early if the driver cannot prepare the model.
389 if (preparedModel == nullptr) return;
390
391 // Save the compilation to cache.
392 {
393 ErrorStatus status;
394 hidl_handle cache1, cache2;
395 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
396 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
397 saveModelToCache(preparedModel, cache1, cache2, &status);
398 if (status != ErrorStatus::GENERAL_FAILURE) {
399 ASSERT_EQ(status, ErrorStatus::NONE);
400 }
401 }
402
403 // cache1 with invalid access mode.
404 {
405 preparedModel = nullptr;
406 ErrorStatus status;
407 hidl_handle cache1, cache2;
408 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
409 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
410 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
411 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
412 ASSERT_EQ(preparedModel, nullptr);
413 }
414
415 // cache2 with invalid access mode.
416 {
417 preparedModel = nullptr;
418 ErrorStatus status;
419 hidl_handle cache1, cache2;
420 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
421 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
422 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
423 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
424 ASSERT_EQ(preparedModel, nullptr);
425 }
426}
427
428TEST_F(CompilationCachingTest, SaveToCacheInvalidOffset) {
429 // Create test HIDL model and compile.
430 Model testModel = createTestModel();
431 sp<IPreparedModel> preparedModel = nullptr;
432 generated_tests::PrepareModel(device, testModel, &preparedModel);
433 // Terminate early if the driver cannot prepare the model.
434 if (preparedModel == nullptr) return;
435
436 // cache1 with invalid file descriptor offset.
437 {
438 ErrorStatus status;
439 hidl_handle cache1, cache2;
440 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
441 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
442 uint8_t dummyByte = 0;
443 // Advance offset by one byte.
444 ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
445 saveModelToCache(preparedModel, cache1, cache2, &status);
446 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
447 }
448
449 // cache2 with invalid file descriptor offset.
450 {
451 ErrorStatus status;
452 hidl_handle cache1, cache2;
453 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
454 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
455 uint8_t dummyByte = 0;
456 // Advance offset by one byte.
457 ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
458 saveModelToCache(preparedModel, cache1, cache2, &status);
459 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
460 }
461}
462
463TEST_F(CompilationCachingTest, SaveToCacheInvalidFileSize) {
464 // Create test HIDL model and compile.
465 Model testModel = createTestModel();
466 sp<IPreparedModel> preparedModel = nullptr;
467 generated_tests::PrepareModel(device, testModel, &preparedModel);
468 // Terminate early if the driver cannot prepare the model.
469 if (preparedModel == nullptr) return;
470
471 // cache1 with invalid file size.
472 {
473 ErrorStatus status;
474 hidl_handle cache1, cache2;
475 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
476 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
477 uint8_t dummyByte = 0;
478 // Write one byte and seek back to the beginning.
479 ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
480 ASSERT_EQ(lseek(cache1.getNativeHandle()->data[0], 0, SEEK_SET), 0);
481 saveModelToCache(preparedModel, cache1, cache2, &status);
482 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
483 }
484
485 // cache2 with invalid file size.
486 {
487 ErrorStatus status;
488 hidl_handle cache1, cache2;
489 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
490 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
491 uint8_t dummyByte = 0;
492 // Write one byte and seek back to the beginning.
493 ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
494 ASSERT_EQ(lseek(cache2.getNativeHandle()->data[0], 0, SEEK_SET), 0);
495 saveModelToCache(preparedModel, cache1, cache2, &status);
496 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
497 }
498}
499
500class CompilationCachingSecurityTest : public CompilationCachingTest,
501 public ::testing::WithParamInterface<uint32_t> {
502 protected:
503 void SetUp() {
504 CompilationCachingTest::SetUp();
505 generator.seed(kSeed);
506 }
507
508 // Get a random integer within a closed range [lower, upper].
509 template <typename T>
510 T getRandomInt(T lower, T upper) {
511 std::uniform_int_distribution<T> dis(lower, upper);
512 return dis(generator);
513 }
514
515 const uint32_t kSeed = GetParam();
516 std::mt19937 generator;
517};
518
519TEST_P(CompilationCachingSecurityTest, CorruptedSecuritySensitiveCache) {
520 if (!mIsCachingSupported) return;
521
522 // Create test HIDL model and compile.
523 Model testModel = createTestModel();
524 sp<IPreparedModel> preparedModel = nullptr;
525 generated_tests::PrepareModel(device, testModel, &preparedModel);
526 // Terminate early if the driver cannot prepare the model.
527 if (preparedModel == nullptr) return;
528
529 // Save the compilation to cache.
530 {
531 ErrorStatus status;
532 hidl_handle cache1, cache2;
533 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
534 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
535 saveModelToCache(preparedModel, cache1, cache2, &status);
536 if (checkEarlyTermination(status)) return;
537 ASSERT_EQ(status, ErrorStatus::NONE);
538 }
539
540 // Randomly flip one single bit of the cache entry.
541 FILE* pFile = fopen(mCache1.c_str(), "r+");
542 ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0);
543 long int fileSize = ftell(pFile);
544 ASSERT_GT(fileSize, 0);
545 ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0);
546 int readByte = fgetc(pFile);
547 ASSERT_NE(readByte, EOF);
548 ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0);
549 ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF);
550 fclose(pFile);
551
552 // Retrieve preparedModel from cache, expect failure.
553 {
554 preparedModel = nullptr;
555 ErrorStatus status;
556 hidl_handle cache1, cache2;
557 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
558 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
559 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
560 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
561 ASSERT_EQ(preparedModel, nullptr);
562 }
563}
564
565TEST_P(CompilationCachingSecurityTest, WrongLengthSecuritySensitiveCache) {
566 if (!mIsCachingSupported) return;
567
568 // Create test HIDL model and compile.
569 Model testModel = createTestModel();
570 sp<IPreparedModel> preparedModel = nullptr;
571 generated_tests::PrepareModel(device, testModel, &preparedModel);
572 // Terminate early if the driver cannot prepare the model.
573 if (preparedModel == nullptr) return;
574
575 // Save the compilation to cache.
576 {
577 ErrorStatus status;
578 hidl_handle cache1, cache2;
579 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
580 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
581 saveModelToCache(preparedModel, cache1, cache2, &status);
582 if (checkEarlyTermination(status)) return;
583 ASSERT_EQ(status, ErrorStatus::NONE);
584 }
585
586 // Randomly append bytes to the cache entry.
587 FILE* pFile = fopen(mCache1.c_str(), "a");
588 uint32_t appendLength = getRandomInt(1, 256);
589 for (uint32_t i = 0; i < appendLength; i++) {
590 ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
591 }
592 fclose(pFile);
593
594 // Retrieve preparedModel from cache, expect failure.
595 {
596 preparedModel = nullptr;
597 ErrorStatus status;
598 hidl_handle cache1, cache2;
599 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
600 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
601 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
602 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
603 ASSERT_EQ(preparedModel, nullptr);
604 }
605}
606
607TEST_P(CompilationCachingSecurityTest, WrongToken) {
608 if (!mIsCachingSupported) return;
609
610 // Create test HIDL model and compile.
611 Model testModel = createTestModel();
612 sp<IPreparedModel> preparedModel = nullptr;
613 generated_tests::PrepareModel(device, testModel, &preparedModel);
614 // Terminate early if the driver cannot prepare the model.
615 if (preparedModel == nullptr) return;
616
617 // Save the compilation to cache.
618 {
619 ErrorStatus status;
620 hidl_handle cache1, cache2;
621 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
622 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
623 saveModelToCache(preparedModel, cache1, cache2, &status);
624 if (checkEarlyTermination(status)) return;
625 ASSERT_EQ(status, ErrorStatus::NONE);
626 }
627
628 // Randomly flip one single bit in mToken.
629 uint32_t ind = getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1);
630 mToken[ind] ^= (1U << getRandomInt(0, 7));
631
632 // Retrieve the preparedModel from cache, expect failure.
633 {
634 preparedModel = nullptr;
635 ErrorStatus status;
636 hidl_handle cache1, cache2;
637 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
638 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
639 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
640 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
641 ASSERT_EQ(preparedModel, nullptr);
642 }
643}
644
645INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
646 ::testing::Range(0U, 10U));
647
648} // namespace functional
649} // namespace vts
650} // namespace V1_2
651} // namespace neuralnetworks
652} // namespace hardware
653} // namespace android