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