1 /*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <asm/unistd.h>
17 #include <cstdint>
18 #include <cstdlib>
19 #include <gtest/gtest.h>
20 #include <fcntl.h>
21 #include <iostream>
22 #include <cstdio>
23 #include <cstring>
24 #include <string>
25 #include <sys/mman.h>
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
28 #include <sys/utsname.h>
29 #include <linux/fs.h>
30 #include <linux/fsverity.h>
31 #include <linux/types.h>
32 #include <linux/ioctl.h>
33
34 #include "byte_buffer.h"
35 #include "directory_ex.h"
36 #include "enable_key_utils.h"
37 #include "log.h"
38 #include "xpm_common.h"
39 #include "code_sign_attr_utils.h"
40 #include "selinux/selinux.h"
41
42 using namespace testing::ext;
43
44 namespace OHOS {
45 namespace Security {
46 namespace CodeSign {
47 constexpr uint32_t HASH_PAGE_SIZE = 4096;
48 constexpr uint32_t BUFFER_LENGTH = 4096;
49
50 const std::string TEST_FILES_DIR = "/data/test/tmp/";
51 const std::string TEST_FILES_LIST[] = {
52 "file_4K/file_4K",
53 "file_4K_greater/file_4K_greater",
54 "file_4K_less/file_4K_less",
55 "file_4M/file_4M",
56 "file_4M_greater/file_4M_greater",
57 "file_4M_less/file_4M_less"
58 };
59 const int TEST_FILE_NUM = sizeof(TEST_FILES_LIST) / sizeof(TEST_FILES_LIST[0]);
60 const std::string TEST_DEFAULT_FILE = TEST_FILES_DIR + "file_4M_greater/file_4M_greater";
61 const std::string FAKE_STRING = "AAAAA";
62
63 const std::string TEST_SUBJECT = "OpenHarmony Application Release";
64 const std::string TEST_ISSUER = "OpenHarmony Application CA";
65
66 const std::string DROP_CACHE_PROC_PATH = "/proc/sys/vm/drop_caches";
67 const std::string DROP_ALL_CACHE_LEVEL = "3";
68
69 static bool g_isXpmOn;
70 static bool g_isKernelLinux = false;
71
72 class EnableVerityTest : public testing::Test {
73 public:
EnableVerityTest()74 EnableVerityTest() {};
~EnableVerityTest()75 virtual ~EnableVerityTest() {};
SetUpTestCase()76 static void SetUpTestCase()
77 {
78 EXPECT_EQ(EnableTestKey(TEST_SUBJECT.c_str(), TEST_ISSUER.c_str()), 0);
79 EXPECT_EQ(SetXpmOwnerId(PROCESS_OWNERID_COMPAT, NULL), 0);
80 g_isXpmOn = AllocXpmRegion();
81 SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE);
82 SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, ENFORCE_MODE);
83 if (g_isXpmOn) {
84 std::string realPath;
85 g_isXpmOn = OHOS::PathToRealPath(XPM_DEBUG_FS_MODE_PATH, realPath);
86 }
87 struct utsname uts;
88 if (uname(&uts) == 0 && strcmp(uts.sysname, "Linux") == 0) {
89 g_isKernelLinux = true;
90 }
91 };
TearDownTestCase()92 static void TearDownTestCase()
93 {
94 SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, PERMISSIVE_MODE);
95 };
SetUp()96 void SetUp() {};
TearDown()97 void TearDown() {};
98 };
99
100 class SELinuxContextSetter {
101 public:
SELinuxContextSetter()102 SELinuxContextSetter()
103 {
104 getcon(&curContext);
105 setcon(BLOCKED_LABEL.c_str());
106 }
107
~SELinuxContextSetter()108 ~SELinuxContextSetter()
109 {
110 setcon(curContext);
111 freecon(curContext);
112 }
113
114 private:
115 const std::string BLOCKED_LABEL = "u:r:key_enable:s0";
116 char *curContext;
117 };
118
GetFileSize(const std::string &path)119 static size_t GetFileSize(const std::string &path)
120 {
121 FILE *file = fopen(path.c_str(), "rb");
122 if (file == nullptr) {
123 return false;
124 }
125 if (fseek(file, 0L, SEEK_END) != 0) {
126 (void)fclose(file);
127 return false;
128 }
129 size_t fileSize = ftell(file);
130 (void)fclose(file);
131 return fileSize;
132 }
133
ReadDataFromFile(const std::string &path, ByteBuffer &data)134 static bool ReadDataFromFile(const std::string &path, ByteBuffer &data)
135 {
136 FILE *file = fopen(path.c_str(), "rb");
137 if (file == nullptr) {
138 return false;
139 }
140 if (fseek(file, 0L, SEEK_END) != 0) {
141 (void)fclose(file);
142 return false;
143 }
144
145 size_t fileSize = ftell(file);
146 if (fileSize == 0) {
147 (void)fclose(file);
148 return true;
149 }
150 rewind(file);
151 if (!data.Resize(fileSize)) {
152 (void)fclose(file);
153 return false;
154 }
155 size_t ret = fread(data.GetBuffer(), 1, fileSize, file);
156 (void)fclose(file);
157 if (ret < fileSize) {
158 LOG_ERROR("Read size (%{public}zu) < file size", ret);
159 return false;
160 }
161 return true;
162 }
163
CopyData(const std::string &srcPath, FILE *fout)164 static void CopyData(const std::string &srcPath, FILE *fout)
165 {
166 ByteBuffer data;
167 EXPECT_EQ(ReadDataFromFile(srcPath, data), true);
168 if (data.GetSize() > 0) {
169 int32_t ret = fwrite(data.GetBuffer(), 1, data.GetSize(), fout);
170 EXPECT_EQ(static_cast<uint32_t>(ret), data.GetSize());
171 }
172 }
173
CopyFile(const std::string &srcPath, const std::string &dstPath)174 static bool CopyFile(const std::string &srcPath, const std::string &dstPath)
175 {
176 FILE *fout = fopen(dstPath.c_str(), "wb");
177 if (fout == nullptr) {
178 return false;
179 }
180 CopyData(srcPath, fout);
181 (void)fclose(fout);
182 return true;
183 }
184
CleanFile(const std::string &filePath)185 static void CleanFile(const std::string &filePath)
186 {
187 EXPECT_EQ(OHOS::RemoveFile(filePath), true);
188 }
189
ExpandFile(const std::string &srcPath, const std::string &expandDataFile, size_t gapSize, const std::string &dstPath)190 static bool ExpandFile(const std::string &srcPath, const std::string &expandDataFile,
191 size_t gapSize, const std::string &dstPath)
192 {
193 FILE *fout = fopen(dstPath.c_str(), "wb");
194 if (fout == nullptr) {
195 return false;
196 }
197 CopyData(srcPath, fout);
198 uint8_t buffer[BUFFER_LENGTH];
199 (void)memset_s(buffer, BUFFER_LENGTH, 0, BUFFER_LENGTH);
200 size_t writeSize = BUFFER_LENGTH;
201 size_t totalSize = 0;
202 size_t ret;
203 while (totalSize < gapSize) {
204 if (gapSize - totalSize < BUFFER_LENGTH) {
205 writeSize = gapSize - totalSize;
206 }
207 ret = fwrite(buffer, 1, writeSize, fout);
208 if (ret != writeSize) {
209 (void)fclose(fout);
210 return false;
211 }
212 LOG_ERROR("write padding = %{public}zu", writeSize);
213 totalSize += writeSize;
214 }
215 CopyData(expandDataFile, fout);
216 (void)fclose(fout);
217 return true;
218 }
219
CheckEnableSuccess(const std::string &filePath)220 static void CheckEnableSuccess(const std::string &filePath)
221 {
222 // drop all caches
223 SaveStringToFile(DROP_CACHE_PROC_PATH, DROP_ALL_CACHE_LEVEL);
224 FILE *fout = fopen(filePath.c_str(), "wb");
225 EXPECT_EQ(fout, nullptr);
226
227 ByteBuffer tmp;
228 EXPECT_EQ(ReadDataFromFile(filePath, tmp), true);
229 }
230
GetRoundUp(size_t fileSize)231 static inline size_t GetRoundUp(size_t fileSize)
232 {
233 return ceil(static_cast<double>(fileSize) / HASH_PAGE_SIZE) *
234 HASH_PAGE_SIZE;
235 }
236
TamperFileTail(const std::string &filePath)237 static bool TamperFileTail(const std::string &filePath)
238 {
239 FILE *file = fopen(filePath.c_str(), "ab");
240 if (file == nullptr) {
241 return false;
242 }
243 if (fseek(file, 0L, SEEK_END) != 0) {
244 (void)fclose(file);
245 return false;
246 }
247
248 size_t fileSize = ftell(file);
249 if (fseek(file, fileSize - FAKE_STRING.size(), SEEK_SET)) {
250 (void)fclose(file);
251 return false;
252 }
253 int32_t ret = fwrite(FAKE_STRING.c_str(), 1, FAKE_STRING.size(), file);
254 EXPECT_EQ(ret, FAKE_STRING.size());
255 (void)fclose(file);
256 return true;
257 }
258
TamperFileHead(const std::string &filePath)259 static bool TamperFileHead(const std::string &filePath)
260 {
261 FILE *file = fopen(filePath.c_str(), "ab");
262 if (file == nullptr) {
263 return false;
264 }
265 if (fseek(file, 0L, SEEK_SET) != 0) {
266 (void)fclose(file);
267 return false;
268 }
269
270 int32_t ret = fwrite(FAKE_STRING.c_str(), 1, FAKE_STRING.size(), file);
271 EXPECT_EQ(ret, FAKE_STRING.size());
272 (void)fclose(file);
273 return true;
274 }
275
EnableVerityOnOneFile(const std::string filePath, struct code_sign_enable_arg *arg)276 int32_t EnableVerityOnOneFile(const std::string filePath,
277 struct code_sign_enable_arg *arg)
278 {
279 int fd = open(filePath.c_str(), O_RDONLY);
280 int ret = 0;
281
282 int error = ioctl(fd, FS_IOC_ENABLE_CODE_SIGN, arg);
283 if (error < 0) {
284 LOG_ERROR("Enable fs-verity failed, errno = <%{public}d, %{public}s>",
285 errno, strerror(errno));
286 ret = errno;
287 }
288 close(fd);
289 return ret;
290 }
291
MakeExpandTreeFile(const std::string &filePath, struct code_sign_enable_arg *arg)292 static std::string MakeExpandTreeFile(const std::string &filePath,
293 struct code_sign_enable_arg *arg)
294 {
295 size_t treeOffset = GetRoundUp(arg->data_size);
296 std::string expandFilePath = filePath + "_expand_tree";
297 EXPECT_EQ(ExpandFile(filePath, filePath + ".tree",
298 treeOffset - arg->data_size, expandFilePath), true);
299 return expandFilePath;
300 }
301
FillCommonArgs(const std::string &filePath, bool isInsideTree, struct code_sign_enable_arg *arg, ByteBuffer &signature)302 static void FillCommonArgs(const std::string &filePath, bool isInsideTree,
303 struct code_sign_enable_arg *arg, ByteBuffer &signature)
304 {
305 bool ret;
306
307 if (isInsideTree) {
308 ret = ReadDataFromFile(filePath + "_inside_tree.sig", signature);
309 } else {
310 ret = ReadDataFromFile(filePath + "_no_tree.sig", signature);
311 }
312 EXPECT_EQ(ret, true);
313
314 size_t fileSize = GetFileSize(filePath);
315 arg->version = 1;
316 arg->cs_version = 1; // version of code signing features
317 arg->hash_algorithm = 1;
318 arg->block_size = HASH_PAGE_SIZE;
319 arg->salt_ptr = 0;
320 arg->salt_size = 0;
321 arg->data_size = fileSize;
322 arg->sig_size = signature.GetSize();
323 arg->sig_ptr = reinterpret_cast<uintptr_t>(signature.GetBuffer());
324 }
325
FillOptional(const std::string &filePath, struct code_sign_enable_arg *arg, ByteBuffer &rootHash)326 static void FillOptional(const std::string &filePath, struct code_sign_enable_arg *arg,
327 ByteBuffer &rootHash)
328 {
329 EXPECT_EQ(ReadDataFromFile(filePath + ".hash", rootHash), true);
330 arg->flags = 1;
331 arg->tree_offset = GetRoundUp(arg->data_size);
332 arg->root_hash_ptr = reinterpret_cast<uintptr_t>(rootHash.GetBuffer());
333 }
334
EnableExpandedTamperFile(const std::string &filePath, bool (*tamperFileFunc)(const std::string &filePath))335 static void EnableExpandedTamperFile(const std::string &filePath,
336 bool (*tamperFileFunc)(const std::string &filePath))
337 {
338 struct code_sign_enable_arg arg = {};
339 ByteBuffer signature;
340 ByteBuffer rootHash;
341 FillCommonArgs(filePath, true, &arg, signature);
342 FillOptional(filePath, &arg, rootHash);
343
344 // tamper file
345 std::string tmpFilePath = filePath + "_tmp";
346 EXPECT_EQ(CopyFile(filePath, tmpFilePath), true);
347 EXPECT_EQ(tamperFileFunc(tmpFilePath), true);
348
349 // expand tampered file
350 std::string treeFile = filePath + ".tree";
351 std::string expandFilePath = filePath + "_expand_tree";
352 size_t treeOffset = GetRoundUp(arg.data_size);
353 EXPECT_EQ(ExpandFile(tmpFilePath, treeFile,
354 treeOffset - arg.data_size, expandFilePath), true);
355
356 if (g_isKernelLinux) {
357 // Enable successully but cannot read
358 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
359 SaveStringToFile(DROP_CACHE_PROC_PATH, DROP_ALL_CACHE_LEVEL);
360 ByteBuffer tmp;
361 EXPECT_EQ(ReadDataFromFile(expandFilePath, tmp), false);
362 } else {
363 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EKEYREJECTED);
364 }
365
366 CleanFile(expandFilePath);
367 CleanFile(tmpFilePath);
368 }
369
370 /**
371 * @tc.name: EnableVerityTest_0001
372 * @tc.desc: enable all data in file successfully
373 * @tc.type: Func
374 * @tc.require:I8DH28
375 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0001, TestSize.Level0)376 HWTEST_F(EnableVerityTest, EnableVerityTest_0001, TestSize.Level0)
377 {
378 for (int i = 0; i < TEST_FILE_NUM; i++) {
379 std::string filePath = TEST_FILES_DIR + TEST_FILES_LIST[i];
380 LOG_INFO("Test on file path = %{public}s", filePath.c_str());
381 struct code_sign_enable_arg arg = {};
382 ByteBuffer signature;
383 FillCommonArgs(filePath, false, &arg, signature);
384 std::string copiedFile = filePath + "_copy";
385 EXPECT_EQ(CopyFile(filePath, copiedFile), true);
386 EXPECT_EQ(EnableVerityOnOneFile(copiedFile, &arg), 0);
387 CheckEnableSuccess(copiedFile);
388 CleanFile(copiedFile);
389 }
390 }
391
392 /**
393 * @tc.name: EnableVerityTest_0002
394 * @tc.desc: enable orignial file with wrong file size
395 * @tc.type: Func
396 * @tc.require:I8DH28
397 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0002, TestSize.Level0)398 HWTEST_F(EnableVerityTest, EnableVerityTest_0002, TestSize.Level0)
399 {
400 std::string filePath = TEST_DEFAULT_FILE;
401
402 struct code_sign_enable_arg arg = {};
403 ByteBuffer signature;
404 FillCommonArgs(filePath, false, &arg, signature);
405
406 std::string copiedFile = filePath + "_copy";
407 EXPECT_EQ(CopyFile(filePath, copiedFile), true);
408
409 uint32_t fileSize = arg.data_size;
410 // size is set to less than file size
411 // descriptor is unmatched, signature verification failed.
412 arg.data_size = fileSize - 1;
413 EXPECT_EQ(EnableVerityOnOneFile(copiedFile, &arg), EKEYREJECTED);
414
415 // size is set to greater than file size
416 // unable to pass parameter check
417 arg.data_size = fileSize + 1;
418 EXPECT_EQ(EnableVerityOnOneFile(copiedFile, &arg), EINVAL);
419
420 CleanFile(copiedFile);
421 }
422
423 /**
424 * @tc.name: EnableVerityTest_0003
425 * @tc.desc: enable expanded file successfully
426 * @tc.type: Func
427 * @tc.require:I8DH28
428 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0003, TestSize.Level0)429 HWTEST_F(EnableVerityTest, EnableVerityTest_0003, TestSize.Level0)
430 {
431 for (int i = 0; i < TEST_FILE_NUM; i++) {
432 std::string filePath = TEST_FILES_DIR + TEST_FILES_LIST[i];
433 struct code_sign_enable_arg arg = {};
434 ByteBuffer signature;
435 FillCommonArgs(filePath, false, &arg, signature);
436
437 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
438 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
439 CheckEnableSuccess(expandFilePath);
440 CleanFile(expandFilePath);
441 }
442 }
443
444 /**
445 * @tc.name: EnableVerityTest_0004
446 * @tc.desc: enable expanded file with inside tree successfully
447 * @tc.type: Func
448 * @tc.require:I8DH28
449 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0004, TestSize.Level0)450 HWTEST_F(EnableVerityTest, EnableVerityTest_0004, TestSize.Level0)
451 {
452 for (int i = 0; i < TEST_FILE_NUM; i++) {
453 std::string filePath = TEST_FILES_DIR + TEST_FILES_LIST[i];
454 LOG_INFO("Test on file path = %{public}s", filePath.c_str());
455
456 struct code_sign_enable_arg arg = {};
457 ByteBuffer signature;
458 ByteBuffer rootHash;
459 FillCommonArgs(filePath, true, &arg, signature);
460 FillOptional(filePath, &arg, rootHash);
461 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
462 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
463 CheckEnableSuccess(expandFilePath);
464 CleanFile(expandFilePath);
465 }
466 }
467
468 /**
469 * @tc.name: EnableVerityTest_0005
470 * @tc.desc: enable expanded file with wrong tree offset
471 * @tc.type: Func
472 * @tc.require:I8DH28
473 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0005, TestSize.Level0)474 HWTEST_F(EnableVerityTest, EnableVerityTest_0005, TestSize.Level0)
475 {
476 std::string filePath = TEST_DEFAULT_FILE;
477 struct code_sign_enable_arg arg = {};
478 ByteBuffer signature;
479 ByteBuffer rootHash;
480 FillCommonArgs(filePath, true, &arg, signature);
481 FillOptional(filePath, &arg, rootHash);
482 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
483
484 uint32_t treeOffset = arg.tree_offset;
485 // byte alignment check failed
486 arg.tree_offset = treeOffset + 1;
487 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EINVAL);
488
489 // unmatched fsverity descriptor
490 arg.tree_offset = treeOffset - HASH_PAGE_SIZE;
491 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EKEYREJECTED);
492
493 CleanFile(expandFilePath);
494 }
495
496 /**
497 * @tc.name: EnableVerityTest_0006
498 * @tc.desc: enable expanded file with wrong root hash
499 * @tc.type: Func
500 * @tc.require:I8DH28
501 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0006, TestSize.Level0)502 HWTEST_F(EnableVerityTest, EnableVerityTest_0006, TestSize.Level0)
503 {
504 std::string filePath = TEST_DEFAULT_FILE;
505 struct code_sign_enable_arg arg = {};
506 ByteBuffer signature;
507 ByteBuffer rootHash;
508 FillCommonArgs(filePath, true, &arg, signature);
509 FillOptional(filePath, &arg, rootHash);
510 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
511
512 (void)memcpy_s(reinterpret_cast<void *>(arg.root_hash_ptr),
513 FAKE_STRING.size(), FAKE_STRING.c_str(), FAKE_STRING.size());
514
515 if (g_isKernelLinux) {
516 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EKEYREJECTED);
517 } else {
518 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
519 }
520 CleanFile(expandFilePath);
521 }
522
523 /**
524 * @tc.name: EnableVerityTest_0007
525 * @tc.desc: enable expanded file with wrong file
526 * @tc.type: Func
527 * @tc.require:I8DH28
528 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0007, TestSize.Level0)529 HWTEST_F(EnableVerityTest, EnableVerityTest_0007, TestSize.Level0)
530 {
531 std::string filePath = TEST_DEFAULT_FILE;
532 EnableExpandedTamperFile(filePath, TamperFileHead);
533
534 EnableExpandedTamperFile(filePath, TamperFileTail);
535 }
536
537 /**
538 * @tc.name: EnableVerityTest_0008
539 * @tc.desc: mmap signed data in xpm region success
540 * @tc.type: Func
541 * @tc.require:
542 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0008, TestSize.Level0)543 HWTEST_F(EnableVerityTest, EnableVerityTest_0008, TestSize.Level0)
544 {
545 if (!g_isXpmOn) {
546 return;
547 }
548
549 std::string filePath = TEST_DEFAULT_FILE;
550 struct code_sign_enable_arg arg = {};
551 ByteBuffer signature;
552 ByteBuffer rootHash;
553 FillCommonArgs(filePath, true, &arg, signature);
554 FillOptional(filePath, &arg, rootHash);
555 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
556 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
557
558 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
559 int fd = open(expandFilePath.c_str(), O_RDONLY);
560 // mmap with MAP_XPM flag, success
561 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM,
562 fd, 0);
563 EXPECT_NE(MAP_FAILED, addr);
564
565 // release resource
566 munmap(addr, PAGE_SIZE);
567 close(fd);
568 CleanFile(expandFilePath);
569 }
570
571 /**
572 * @tc.name: EnableVerityTest_0009
573 * @tc.desc: mmap unsigned data in xpm region failed
574 * @tc.type: Func
575 * @tc.require:
576 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0009, TestSize.Level0)577 HWTEST_F(EnableVerityTest, EnableVerityTest_0009, TestSize.Level0)
578 {
579 if (!g_isXpmOn) {
580 return;
581 }
582 std::string filePath = TEST_DEFAULT_FILE;
583 struct code_sign_enable_arg arg = {};
584 ByteBuffer signature;
585 ByteBuffer rootHash;
586 FillCommonArgs(filePath, true, &arg, signature);
587 FillOptional(filePath, &arg, rootHash);
588 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
589 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
590
591 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
592 int fd = open(expandFilePath.c_str(), O_RDONLY);
593 // mmap with MAP_XPM flag, over verity range
594 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM,
595 fd, arg.tree_offset & PAGE_MASK);
596 EXPECT_EQ(MAP_FAILED, addr);
597
598 close(fd);
599 CleanFile(expandFilePath);
600 }
601
602 /**
603 * @tc.name: EnableVerityTest_0010
604 * @tc.desc: mmap signed data as executable success
605 * @tc.type: Func
606 * @tc.require:
607 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0010, TestSize.Level0)608 HWTEST_F(EnableVerityTest, EnableVerityTest_0010, TestSize.Level0)
609 {
610 if (!g_isXpmOn) {
611 return;
612 }
613 std::string filePath = TEST_FILES_DIR + "elf/elf";
614 struct code_sign_enable_arg arg = {};
615 ByteBuffer signature;
616 ByteBuffer rootHash;
617 FillCommonArgs(filePath, true, &arg, signature);
618 FillOptional(filePath, &arg, rootHash);
619 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
620 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
621
622 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
623 int fd = open(expandFilePath.c_str(), O_RDONLY);
624 // readelf from elf
625 // [19] .text PROGBITS 000063ec 0053ec 002168 00 AX 0 0 4
626 int codeOffset = 0x53ec;
627 // mmap success at enforce mode
628 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE,
629 fd, codeOffset & PAGE_MASK);
630 EXPECT_NE(MAP_FAILED, addr);
631
632 // release resource
633 munmap(addr, PAGE_SIZE);
634
635 close(fd);
636 CleanFile(expandFilePath);
637 }
638
639 /**
640 * @tc.name: EnableVerityTest_00011
641 * @tc.desc: mmap unsigned data as executable failed
642 * @tc.type: Func
643 * @tc.require
644 */
HWTEST_F(EnableVerityTest, EnableVerityTest_0011, TestSize.Level0)645 HWTEST_F(EnableVerityTest, EnableVerityTest_0011, TestSize.Level0)
646 {
647 if (!g_isXpmOn) {
648 return;
649 }
650 std::string filePath = TEST_FILES_DIR + "elf/elf";
651 struct code_sign_enable_arg arg = {};
652 ByteBuffer signature;
653 ByteBuffer rootHash;
654 FillCommonArgs(filePath, true, &arg, signature);
655 FillOptional(filePath, &arg, rootHash);
656 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
657 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
658
659 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
660 int fd = open(expandFilePath.c_str(), O_RDONLY);
661 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE,
662 fd, arg.tree_offset & PAGE_MASK);
663 EXPECT_EQ(MAP_FAILED, addr);
664
665 close(fd);
666 CleanFile(expandFilePath);
667 }
668 } // namespace CodeSign
669 } // namespace Security
670 } // namespace OHOS
671