1 /*
2 * Copyright (c) 2023 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/utsname.h>
28 #include <sys/ioctl.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(LABEL, "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(LABEL, "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(LABEL, "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 // Enable successully but cannot read
357 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
358 SaveStringToFile(DROP_CACHE_PROC_PATH, DROP_ALL_CACHE_LEVEL);
359 ByteBuffer tmp;
360 EXPECT_EQ(ReadDataFromFile(expandFilePath, tmp), false);
361
362 CleanFile(expandFilePath);
363 CleanFile(tmpFilePath);
364 }
365
366 /**
367 * @tc.name: EnableVerityTest_0001
368 * @tc.desc: enable all data in file successfully
369 * @tc.type: Func
370 * @tc.require:I8DH28
371 */
372 HWTEST_F(EnableVerityTest, EnableVerityTest_0001, TestSize.Level0)
373 {
374 for (int i = 0; i < TEST_FILE_NUM; i++) {
375 std::string filePath = TEST_FILES_DIR + TEST_FILES_LIST[i];
376 LOG_INFO(LABEL, "Test on file path = %{public}s", filePath.c_str());
377 struct code_sign_enable_arg arg = {};
378 ByteBuffer signature;
379 FillCommonArgs(filePath, false, &arg, signature);
380 std::string copiedFile = filePath + "_copy";
381 EXPECT_EQ(CopyFile(filePath, copiedFile), true);
382 EXPECT_EQ(EnableVerityOnOneFile(copiedFile, &arg), 0);
383 CheckEnableSuccess(copiedFile);
384 CleanFile(copiedFile);
385 }
386 }
387
388 /**
389 * @tc.name: EnableVerityTest_0002
390 * @tc.desc: enable orignial file with wrong file size
391 * @tc.type: Func
392 * @tc.require:I8DH28
393 */
394 HWTEST_F(EnableVerityTest, EnableVerityTest_0002, TestSize.Level0)
395 {
396 if (!g_isKernelLinux) {
397 return;
398 }
399 std::string filePath = TEST_DEFAULT_FILE;
400
401 struct code_sign_enable_arg arg = {};
402 ByteBuffer signature;
403 FillCommonArgs(filePath, false, &arg, signature);
404
405 std::string copiedFile = filePath + "_copy";
406 EXPECT_EQ(CopyFile(filePath, copiedFile), true);
407
408 uint32_t fileSize = arg.data_size;
409 // size is set to less than file size
410 // descriptor is unmatched, signature verification failed.
411 arg.data_size = fileSize - 1;
412 EXPECT_EQ(EnableVerityOnOneFile(copiedFile, &arg), EKEYREJECTED);
413
414 // size is set to greater than file size
415 // unable to pass parameter check
416 arg.data_size = fileSize + 1;
417 EXPECT_EQ(EnableVerityOnOneFile(copiedFile, &arg), EINVAL);
418
419 CleanFile(copiedFile);
420 }
421
422 /**
423 * @tc.name: EnableVerityTest_0003
424 * @tc.desc: enable expanded file successfully
425 * @tc.type: Func
426 * @tc.require:I8DH28
427 */
428 HWTEST_F(EnableVerityTest, EnableVerityTest_0003, TestSize.Level0)
429 {
430 for (int i = 0; i < TEST_FILE_NUM; i++) {
431 std::string filePath = TEST_FILES_DIR + TEST_FILES_LIST[i];
432 struct code_sign_enable_arg arg = {};
433 ByteBuffer signature;
434 FillCommonArgs(filePath, false, &arg, signature);
435
436 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
437 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
438 CheckEnableSuccess(expandFilePath);
439 CleanFile(expandFilePath);
440 }
441 }
442
443 /**
444 * @tc.name: EnableVerityTest_0004
445 * @tc.desc: enable expanded file with inside tree successfully
446 * @tc.type: Func
447 * @tc.require:I8DH28
448 */
449 HWTEST_F(EnableVerityTest, EnableVerityTest_0004, TestSize.Level0)
450 {
451 for (int i = 0; i < TEST_FILE_NUM; i++) {
452 std::string filePath = TEST_FILES_DIR + TEST_FILES_LIST[i];
453 LOG_INFO(LABEL, "Test on file path = %{public}s", filePath.c_str());
454
455 struct code_sign_enable_arg arg = {};
456 ByteBuffer signature;
457 ByteBuffer rootHash;
458 FillCommonArgs(filePath, true, &arg, signature);
459 FillOptional(filePath, &arg, rootHash);
460 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
461 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
462 CheckEnableSuccess(expandFilePath);
463 CleanFile(expandFilePath);
464 }
465 }
466
467 /**
468 * @tc.name: EnableVerityTest_0005
469 * @tc.desc: enable expanded file with wrong tree offset
470 * @tc.type: Func
471 * @tc.require:I8DH28
472 */
473 HWTEST_F(EnableVerityTest, EnableVerityTest_0005, TestSize.Level0)
474 {
475 if (!g_isKernelLinux) {
476 return;
477 }
478 std::string filePath = TEST_DEFAULT_FILE;
479 struct code_sign_enable_arg arg = {};
480 ByteBuffer signature;
481 ByteBuffer rootHash;
482 FillCommonArgs(filePath, true, &arg, signature);
483 FillOptional(filePath, &arg, rootHash);
484 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
485
486 uint32_t treeOffset = arg.tree_offset;
487 // byte alignment check failed
488 arg.tree_offset = treeOffset + 1;
489 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EINVAL);
490
491 // unmatched fsverity descriptor
492 arg.tree_offset = treeOffset - HASH_PAGE_SIZE;
493 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EKEYREJECTED);
494
495 CleanFile(expandFilePath);
496 }
497
498 /**
499 * @tc.name: EnableVerityTest_0006
500 * @tc.desc: enable expanded file with wrong root hash
501 * @tc.type: Func
502 * @tc.require:I8DH28
503 */
504 HWTEST_F(EnableVerityTest, EnableVerityTest_0006, TestSize.Level0)
505 {
506 if (!g_isKernelLinux) {
507 return;
508 }
509 std::string filePath = TEST_DEFAULT_FILE;
510 struct code_sign_enable_arg arg = {};
511 ByteBuffer signature;
512 ByteBuffer rootHash;
513 FillCommonArgs(filePath, true, &arg, signature);
514 FillOptional(filePath, &arg, rootHash);
515 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
516
517 (void)memcpy_s(reinterpret_cast<void *>(arg.root_hash_ptr),
518 FAKE_STRING.size(), FAKE_STRING.c_str(), FAKE_STRING.size());
519
520 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), EKEYREJECTED);
521
522 CleanFile(expandFilePath);
523 }
524
525 /**
526 * @tc.name: EnableVerityTest_0007
527 * @tc.desc: enable expanded file with wrong file
528 * @tc.type: Func
529 * @tc.require:I8DH28
530 */
531 HWTEST_F(EnableVerityTest, EnableVerityTest_0007, TestSize.Level0)
532 {
533 std::string filePath = TEST_DEFAULT_FILE;
534 EnableExpandedTamperFile(filePath, TamperFileHead);
535
536 EnableExpandedTamperFile(filePath, TamperFileTail);
537 }
538
539 /**
540 * @tc.name: EnableVerityTest_0008
541 * @tc.desc: mmap signed data in xpm region success
542 * @tc.type: Func
543 * @tc.require:
544 */
545 HWTEST_F(EnableVerityTest, EnableVerityTest_0008, TestSize.Level0)
546 {
547 if (!g_isXpmOn) {
548 return;
549 }
550
551 std::string filePath = TEST_DEFAULT_FILE;
552 struct code_sign_enable_arg arg = {};
553 ByteBuffer signature;
554 ByteBuffer rootHash;
555 FillCommonArgs(filePath, true, &arg, signature);
556 FillOptional(filePath, &arg, rootHash);
557 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
558 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
559
560 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
561 int fd = open(expandFilePath.c_str(), O_RDONLY);
562 // mmap with MAP_XPM flag, success
563 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM,
564 fd, 0);
565 EXPECT_NE(MAP_FAILED, addr);
566
567 // release resource
568 munmap(addr, PAGE_SIZE);
569 close(fd);
570 CleanFile(expandFilePath);
571 }
572
573 /**
574 * @tc.name: EnableVerityTest_0009
575 * @tc.desc: mmap unsigned data in xpm region failed
576 * @tc.type: Func
577 * @tc.require:
578 */
579 HWTEST_F(EnableVerityTest, EnableVerityTest_0009, TestSize.Level0)
580 {
581 if (!g_isXpmOn || !g_isKernelLinux) {
582 return;
583 }
584 std::string filePath = TEST_DEFAULT_FILE;
585 struct code_sign_enable_arg arg = {};
586 ByteBuffer signature;
587 ByteBuffer rootHash;
588 FillCommonArgs(filePath, true, &arg, signature);
589 FillOptional(filePath, &arg, rootHash);
590 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
591 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
592
593 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
594 int fd = open(expandFilePath.c_str(), O_RDONLY);
595 // mmap with MAP_XPM flag, over verity range
596 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM,
597 fd, arg.tree_offset & PAGE_MASK);
598 EXPECT_EQ(MAP_FAILED, addr);
599
600 close(fd);
601 CleanFile(expandFilePath);
602 }
603
604 /**
605 * @tc.name: EnableVerityTest_0010
606 * @tc.desc: mmap signed data as executable success
607 * @tc.type: Func
608 * @tc.require:
609 */
610 HWTEST_F(EnableVerityTest, EnableVerityTest_0010, TestSize.Level0)
611 {
612 if (!g_isXpmOn) {
613 return;
614 }
615 std::string filePath = TEST_FILES_DIR + "elf/elf";
616 struct code_sign_enable_arg arg = {};
617 ByteBuffer signature;
618 ByteBuffer rootHash;
619 FillCommonArgs(filePath, true, &arg, signature);
620 FillOptional(filePath, &arg, rootHash);
621 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
622 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
623
624 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
625 int fd = open(expandFilePath.c_str(), O_RDONLY);
626 // readelf from elf
627 // [19] .text PROGBITS 000063ec 0053ec 002168 00 AX 0 0 4
628 int codeOffset = 0x53ec;
629 // mmap success at enforce mode
630 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE,
631 fd, codeOffset & PAGE_MASK);
632 EXPECT_NE(MAP_FAILED, addr);
633
634 // release resource
635 munmap(addr, PAGE_SIZE);
636
637 close(fd);
638 CleanFile(expandFilePath);
639 }
640
641 /**
642 * @tc.name: EnableVerityTest_00011
643 * @tc.desc: mmap unsigned data as executable failed
644 * @tc.type: Func
645 * @tc.require
646 */
647 HWTEST_F(EnableVerityTest, EnableVerityTest_0011, TestSize.Level0)
648 {
649 if (!g_isXpmOn || !g_isKernelLinux) {
650 return;
651 }
652 std::string filePath = TEST_FILES_DIR + "elf/elf";
653 struct code_sign_enable_arg arg = {};
654 ByteBuffer signature;
655 ByteBuffer rootHash;
656 FillCommonArgs(filePath, true, &arg, signature);
657 FillOptional(filePath, &arg, rootHash);
658 std::string expandFilePath = MakeExpandTreeFile(filePath, &arg);
659 EXPECT_EQ(EnableVerityOnOneFile(expandFilePath, &arg), 0);
660
661 std::unique_ptr<SELinuxContextSetter> setter = std::make_unique<SELinuxContextSetter>();
662 int fd = open(expandFilePath.c_str(), O_RDONLY);
663 void *addr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE,
664 fd, arg.tree_offset & PAGE_MASK);
665 EXPECT_EQ(MAP_FAILED, addr);
666
667 close(fd);
668 CleanFile(expandFilePath);
669 }
670 } // namespace CodeSign
671 } // namespace Security
672 } // namespace OHOS
673