blob: 454aa1f92192ca546331b4c43fe413a72c940d9a [file] [log] [blame]
Xusong Wang34058782019-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();
89
90 // Create cache directory.
91 char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
92 char* cacheDir = mkdtemp(cacheDirTemp);
93 ASSERT_NE(cacheDir, nullptr);
94 mCache1 = cacheDir + mCache1;
95 mCache2 = cacheDir + mCache2;
96 mCache3 = cacheDir + mCache3;
97
98 // Check if caching is supported.
99 bool isCachingSupported;
100 Return<void> ret = device->isCachingSupported(
101 [&isCachingSupported](ErrorStatus status, bool supported) {
102 EXPECT_EQ(ErrorStatus::NONE, status);
103 isCachingSupported = supported;
104 });
105 EXPECT_TRUE(ret.isOk());
106 if (isCachingSupported) {
107 mIsCachingSupported = true;
108 } else {
109 LOG(INFO) << "NN VTS: Early termination of test because vendor service does not "
110 "support compilation caching.";
111 std::cout << "[ ] Early termination of test because vendor service does not "
112 "support compilation caching."
113 << std::endl;
114 mIsCachingSupported = false;
115 }
116
117 // Create empty cache files.
118 hidl_handle handle;
119 createCacheHandle({mCache1, mCache2, mCache3}, AccessMode::WRITE_ONLY, &handle);
120 }
121
122 void saveModelToCache(sp<IPreparedModel> preparedModel, const hidl_handle& cache1,
123 const hidl_handle& cache2, ErrorStatus* status) {
124 // Save IPreparedModel to cache.
125 hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
126 Return<ErrorStatus> saveToCacheStatus =
127 preparedModel->saveToCache(cache1, cache2, cacheToken);
128 ASSERT_TRUE(saveToCacheStatus.isOk());
129 *status = static_cast<ErrorStatus>(saveToCacheStatus);
130 }
131
132 bool checkEarlyTermination(ErrorStatus status) {
133 if (status == ErrorStatus::GENERAL_FAILURE) {
134 LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
135 "save the prepared model that it does not support.";
136 std::cout << "[ ] Early termination of test because vendor service cannot "
137 "save the prepared model that it does not support."
138 << std::endl;
139 return true;
140 }
141 return false;
142 }
143
144 void prepareModelFromCache(const hidl_handle& cache1, const hidl_handle& cache2,
145 sp<IPreparedModel>* preparedModel, ErrorStatus* status) {
146 // Launch prepare model from cache.
147 sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
148 ASSERT_NE(nullptr, preparedModelCallback.get());
149 hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
150 Return<ErrorStatus> prepareLaunchStatus =
151 device->prepareModelFromCache(cache1, cache2, cacheToken, preparedModelCallback);
152 ASSERT_TRUE(prepareLaunchStatus.isOk());
153 if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
154 *preparedModel = nullptr;
155 *status = static_cast<ErrorStatus>(prepareLaunchStatus);
156 return;
157 }
158
159 // Retrieve prepared model.
160 preparedModelCallback->wait();
161 *status = preparedModelCallback->getStatus();
162 *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
163 .withDefault(nullptr);
164 }
165
166 std::string mCache1 = "/cache1";
167 std::string mCache2 = "/cache2";
168 std::string mCache3 = "/cache3";
169 uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {};
170 bool mIsCachingSupported;
171};
172
173TEST_F(CompilationCachingTest, CacheSavingAndRetrieval) {
174 // Create test HIDL model and compile.
175 Model testModel = createTestModel();
176 sp<IPreparedModel> preparedModel = nullptr;
177 generated_tests::PrepareModel(device, testModel, &preparedModel);
178 // Terminate early if the driver cannot prepare the model.
179 if (preparedModel == nullptr) return;
180
181 // Save the compilation to cache.
182 {
183 ErrorStatus status;
184 hidl_handle cache1, cache2;
185 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
186 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
187 saveModelToCache(preparedModel, cache1, cache2, &status);
188 if (!mIsCachingSupported) {
189 EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
190 } else {
191 if (checkEarlyTermination(status)) return;
192 ASSERT_EQ(status, ErrorStatus::NONE);
193 }
194 }
195
196 // Retrieve preparedModel from cache.
197 {
198 preparedModel = nullptr;
199 ErrorStatus status;
200 hidl_handle cache1, cache2;
201 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
202 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
203 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
204 if (!mIsCachingSupported) {
205 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
206 ASSERT_EQ(preparedModel, nullptr);
207 return;
208 } else {
209 ASSERT_EQ(status, ErrorStatus::NONE);
210 ASSERT_NE(preparedModel, nullptr);
211 }
212 }
213
214 // Execute and verify results.
215 generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
216 testModel.relaxComputationFloat32toFloat16,
217 /*testDynamicOutputShape=*/false);
218}
219
220TEST_F(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
221 // Create test HIDL model and compile.
222 Model testModel = createTestModel();
223 sp<IPreparedModel> preparedModel = nullptr;
224 generated_tests::PrepareModel(device, testModel, &preparedModel);
225 // Terminate early if the driver cannot prepare the model.
226 if (preparedModel == nullptr) return;
227
228 // Save the compilation to cache.
229 {
230 ErrorStatus status;
231 hidl_handle cache1, cache2;
232 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
233 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
234 saveModelToCache(preparedModel, cache1, cache2, &status);
235 if (!mIsCachingSupported) {
236 EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
237 } else {
238 if (checkEarlyTermination(status)) return;
239 ASSERT_EQ(status, ErrorStatus::NONE);
240 }
241 }
242
243 // Retrieve preparedModel from cache.
244 {
245 preparedModel = nullptr;
246 ErrorStatus status;
247 hidl_handle cache1, cache2;
248 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
249 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
250 uint8_t dummyByte = 0;
251 // Advance offset by one byte.
252 ASSERT_GE(read(cache1.getNativeHandle()->data[0], &dummyByte, 1), 0);
253 ASSERT_GE(read(cache2.getNativeHandle()->data[0], &dummyByte, 1), 0);
254 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
255 if (!mIsCachingSupported) {
256 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
257 ASSERT_EQ(preparedModel, nullptr);
258 return;
259 } else {
260 ASSERT_EQ(status, ErrorStatus::NONE);
261 ASSERT_NE(preparedModel, nullptr);
262 }
263 }
264
265 // Execute and verify results.
266 generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
267 testModel.relaxComputationFloat32toFloat16,
268 /*testDynamicOutputShape=*/false);
269}
270
271TEST_F(CompilationCachingTest, SaveToCacheInvalidNumFd) {
272 // Create test HIDL model and compile.
273 Model testModel = createTestModel();
274 sp<IPreparedModel> preparedModel = nullptr;
275 generated_tests::PrepareModel(device, testModel, &preparedModel);
276 // Terminate early if the driver cannot prepare the model.
277 if (preparedModel == nullptr) return;
278
279 // cache1 with invalid NumFd.
280 {
281 ErrorStatus status;
282 hidl_handle cache1, cache2;
283 createCacheHandle({mCache1, mCache3}, AccessMode::WRITE_ONLY, &cache1);
284 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
285 saveModelToCache(preparedModel, cache1, cache2, &status);
286 if (status != ErrorStatus::GENERAL_FAILURE) {
287 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
288 }
289 }
290
291 // cache2 with invalid NumFd.
292 {
293 ErrorStatus status;
294 hidl_handle cache1, cache2;
295 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
296 createCacheHandle({mCache2, mCache3}, AccessMode::WRITE_ONLY, &cache2);
297 saveModelToCache(preparedModel, cache1, cache2, &status);
298 if (status != ErrorStatus::GENERAL_FAILURE) {
299 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
300 }
301 }
302}
303
304TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
305 // Create test HIDL model and compile.
306 Model testModel = createTestModel();
307 sp<IPreparedModel> preparedModel = nullptr;
308 generated_tests::PrepareModel(device, testModel, &preparedModel);
309 // Terminate early if the driver cannot prepare the model.
310 if (preparedModel == nullptr) return;
311
312 // Save the compilation to cache.
313 {
314 ErrorStatus status;
315 hidl_handle cache1, cache2;
316 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
317 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
318 saveModelToCache(preparedModel, cache1, cache2, &status);
319 if (status != ErrorStatus::GENERAL_FAILURE) {
320 ASSERT_EQ(status, ErrorStatus::NONE);
321 }
322 }
323
324 // cache1 with invalid NumFd.
325 {
326 preparedModel = nullptr;
327 ErrorStatus status;
328 hidl_handle cache1, cache2;
329 createCacheHandle({mCache1, mCache3}, AccessMode::READ_ONLY, &cache1);
330 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
331 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
332 if (status != ErrorStatus::GENERAL_FAILURE) {
333 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
334 ASSERT_EQ(preparedModel, nullptr);
335 }
336 }
337
338 // cache2 with invalid NumFd.
339 {
340 preparedModel = nullptr;
341 ErrorStatus status;
342 hidl_handle cache1, cache2;
343 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
344 createCacheHandle({mCache2, mCache3}, AccessMode::READ_ONLY, &cache2);
345 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
346 if (status != ErrorStatus::GENERAL_FAILURE) {
347 ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
348 ASSERT_EQ(preparedModel, nullptr);
349 }
350 }
351}
352
353TEST_F(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
354 // Create test HIDL model and compile.
355 Model testModel = createTestModel();
356 sp<IPreparedModel> preparedModel = nullptr;
357 generated_tests::PrepareModel(device, testModel, &preparedModel);
358 // Terminate early if the driver cannot prepare the model.
359 if (preparedModel == nullptr) return;
360
361 // cache1 with invalid access mode.
362 {
363 ErrorStatus status;
364 hidl_handle cache1, cache2;
365 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
366 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
367 saveModelToCache(preparedModel, cache1, cache2, &status);
368 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
369 }
370
371 // cache2 with invalid access mode.
372 {
373 ErrorStatus status;
374 hidl_handle cache1, cache2;
375 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
376 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
377 saveModelToCache(preparedModel, cache1, cache2, &status);
378 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
379 }
380}
381
382TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
383 // Create test HIDL model and compile.
384 Model testModel = createTestModel();
385 sp<IPreparedModel> preparedModel = nullptr;
386 generated_tests::PrepareModel(device, testModel, &preparedModel);
387 // Terminate early if the driver cannot prepare the model.
388 if (preparedModel == nullptr) return;
389
390 // Save the compilation to cache.
391 {
392 ErrorStatus status;
393 hidl_handle cache1, cache2;
394 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
395 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
396 saveModelToCache(preparedModel, cache1, cache2, &status);
397 if (status != ErrorStatus::GENERAL_FAILURE) {
398 ASSERT_EQ(status, ErrorStatus::NONE);
399 }
400 }
401
402 // cache1 with invalid access mode.
403 {
404 preparedModel = nullptr;
405 ErrorStatus status;
406 hidl_handle cache1, cache2;
407 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
408 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
409 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
410 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
411 ASSERT_EQ(preparedModel, nullptr);
412 }
413
414 // cache2 with invalid access mode.
415 {
416 preparedModel = nullptr;
417 ErrorStatus status;
418 hidl_handle cache1, cache2;
419 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
420 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
421 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
422 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
423 ASSERT_EQ(preparedModel, nullptr);
424 }
425}
426
427TEST_F(CompilationCachingTest, SaveToCacheInvalidOffset) {
428 // Create test HIDL model and compile.
429 Model testModel = createTestModel();
430 sp<IPreparedModel> preparedModel = nullptr;
431 generated_tests::PrepareModel(device, testModel, &preparedModel);
432 // Terminate early if the driver cannot prepare the model.
433 if (preparedModel == nullptr) return;
434
435 // cache1 with invalid file descriptor offset.
436 {
437 ErrorStatus status;
438 hidl_handle cache1, cache2;
439 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
440 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
441 uint8_t dummyByte = 0;
442 // Advance offset by one byte.
443 ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
444 saveModelToCache(preparedModel, cache1, cache2, &status);
445 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
446 }
447
448 // cache2 with invalid file descriptor offset.
449 {
450 ErrorStatus status;
451 hidl_handle cache1, cache2;
452 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
453 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
454 uint8_t dummyByte = 0;
455 // Advance offset by one byte.
456 ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
457 saveModelToCache(preparedModel, cache1, cache2, &status);
458 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
459 }
460}
461
462TEST_F(CompilationCachingTest, SaveToCacheInvalidFileSize) {
463 // Create test HIDL model and compile.
464 Model testModel = createTestModel();
465 sp<IPreparedModel> preparedModel = nullptr;
466 generated_tests::PrepareModel(device, testModel, &preparedModel);
467 // Terminate early if the driver cannot prepare the model.
468 if (preparedModel == nullptr) return;
469
470 // cache1 with invalid file size.
471 {
472 ErrorStatus status;
473 hidl_handle cache1, cache2;
474 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
475 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
476 uint8_t dummyByte = 0;
477 // Write one byte and seek back to the beginning.
478 ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
479 ASSERT_EQ(lseek(cache1.getNativeHandle()->data[0], 0, SEEK_SET), 0);
480 saveModelToCache(preparedModel, cache1, cache2, &status);
481 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
482 }
483
484 // cache2 with invalid file size.
485 {
486 ErrorStatus status;
487 hidl_handle cache1, cache2;
488 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
489 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
490 uint8_t dummyByte = 0;
491 // Write one byte and seek back to the beginning.
492 ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
493 ASSERT_EQ(lseek(cache2.getNativeHandle()->data[0], 0, SEEK_SET), 0);
494 saveModelToCache(preparedModel, cache1, cache2, &status);
495 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
496 }
497}
498
499class CompilationCachingSecurityTest : public CompilationCachingTest,
500 public ::testing::WithParamInterface<uint32_t> {
501 protected:
502 void SetUp() {
503 CompilationCachingTest::SetUp();
504 generator.seed(kSeed);
505 }
506
507 // Get a random integer within a closed range [lower, upper].
508 template <typename T>
509 T getRandomInt(T lower, T upper) {
510 std::uniform_int_distribution<T> dis(lower, upper);
511 return dis(generator);
512 }
513
514 const uint32_t kSeed = GetParam();
515 std::mt19937 generator;
516};
517
518TEST_P(CompilationCachingSecurityTest, CorruptedSecuritySensitiveCache) {
519 if (!mIsCachingSupported) return;
520
521 // Create test HIDL model and compile.
522 Model testModel = createTestModel();
523 sp<IPreparedModel> preparedModel = nullptr;
524 generated_tests::PrepareModel(device, testModel, &preparedModel);
525 // Terminate early if the driver cannot prepare the model.
526 if (preparedModel == nullptr) return;
527
528 // Save the compilation to cache.
529 {
530 ErrorStatus status;
531 hidl_handle cache1, cache2;
532 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
533 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
534 saveModelToCache(preparedModel, cache1, cache2, &status);
535 if (checkEarlyTermination(status)) return;
536 ASSERT_EQ(status, ErrorStatus::NONE);
537 }
538
539 // Randomly flip one single bit of the cache entry.
540 FILE* pFile = fopen(mCache1.c_str(), "r+");
541 ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0);
542 long int fileSize = ftell(pFile);
543 ASSERT_GT(fileSize, 0);
544 ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0);
545 int readByte = fgetc(pFile);
546 ASSERT_NE(readByte, EOF);
547 ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0);
548 ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF);
549 fclose(pFile);
550
551 // Retrieve preparedModel from cache, expect failure.
552 {
553 preparedModel = nullptr;
554 ErrorStatus status;
555 hidl_handle cache1, cache2;
556 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
557 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
558 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
559 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
560 ASSERT_EQ(preparedModel, nullptr);
561 }
562}
563
564TEST_P(CompilationCachingSecurityTest, WrongLengthSecuritySensitiveCache) {
565 if (!mIsCachingSupported) return;
566
567 // Create test HIDL model and compile.
568 Model testModel = createTestModel();
569 sp<IPreparedModel> preparedModel = nullptr;
570 generated_tests::PrepareModel(device, testModel, &preparedModel);
571 // Terminate early if the driver cannot prepare the model.
572 if (preparedModel == nullptr) return;
573
574 // Save the compilation to cache.
575 {
576 ErrorStatus status;
577 hidl_handle cache1, cache2;
578 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
579 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
580 saveModelToCache(preparedModel, cache1, cache2, &status);
581 if (checkEarlyTermination(status)) return;
582 ASSERT_EQ(status, ErrorStatus::NONE);
583 }
584
585 // Randomly append bytes to the cache entry.
586 FILE* pFile = fopen(mCache1.c_str(), "a");
587 uint32_t appendLength = getRandomInt(1, 256);
588 for (uint32_t i = 0; i < appendLength; i++) {
589 ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
590 }
591 fclose(pFile);
592
593 // Retrieve preparedModel from cache, expect failure.
594 {
595 preparedModel = nullptr;
596 ErrorStatus status;
597 hidl_handle cache1, cache2;
598 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
599 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
600 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
601 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
602 ASSERT_EQ(preparedModel, nullptr);
603 }
604}
605
606TEST_P(CompilationCachingSecurityTest, WrongToken) {
607 if (!mIsCachingSupported) return;
608
609 // Create test HIDL model and compile.
610 Model testModel = createTestModel();
611 sp<IPreparedModel> preparedModel = nullptr;
612 generated_tests::PrepareModel(device, testModel, &preparedModel);
613 // Terminate early if the driver cannot prepare the model.
614 if (preparedModel == nullptr) return;
615
616 // Save the compilation to cache.
617 {
618 ErrorStatus status;
619 hidl_handle cache1, cache2;
620 createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
621 createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
622 saveModelToCache(preparedModel, cache1, cache2, &status);
623 if (checkEarlyTermination(status)) return;
624 ASSERT_EQ(status, ErrorStatus::NONE);
625 }
626
627 // Randomly flip one single bit in mToken.
628 uint32_t ind = getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1);
629 mToken[ind] ^= (1U << getRandomInt(0, 7));
630
631 // Retrieve the preparedModel from cache, expect failure.
632 {
633 preparedModel = nullptr;
634 ErrorStatus status;
635 hidl_handle cache1, cache2;
636 createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
637 createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
638 prepareModelFromCache(cache1, cache2, &preparedModel, &status);
639 ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
640 ASSERT_EQ(preparedModel, nullptr);
641 }
642}
643
644INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
645 ::testing::Range(0U, 10U));
646
647} // namespace functional
648} // namespace vts
649} // namespace V1_2
650} // namespace neuralnetworks
651} // namespace hardware
652} // namespace android