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