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