1 /*
2 * Copyright (C) 2025 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 #include <dlfcn.h>
16 #include <link.h>
17 #include <pthread.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <sys/wait.h>
25 #include <sys/prctl.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
28
29 #include "test.h"
30 #define MAX_BUF 256
31 #define HEX_TERM 16
32 #define RELRO_INDEX 3
33 #define RELRO_NUM 1
34 #define BUFFER_SIZE 1024
35 #define PID_BUFFER_SIZE 128
36
37 const char *g_libPath = "/system/lib64/libc++.so";
38 const char *g_keylog = "ro_seal report: provition_type: 1, reason: 2, filename: /system/lib64/libc++.so";
39
dlclose_check(unsigned long start,unsigned long end,const char * so)40 int dlclose_check(unsigned long start, unsigned long end, const char *so)
41 {
42 if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE) == 0) {
43 t_error("the relro segment of %s should be readonly and cannot be changed\n", so);
44 return 0;
45 }
46 int fd = open(so, O_RDONLY);
47 if (fd < 0) {
48 t_error("open file %s should be success but failed, errno %d\n", so, errno);
49 return 0;
50 }
51 if (mmap((void *)start, end - start, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0) != MAP_FAILED) {
52 t_error("mmap to the fixed region of so %s, start: %zu, end: %zu should fail but success\n",
53 so, start, end);
54 close(fd);
55 munmap((void *)start, end - start);
56 return 0;
57 }
58 close(fd);
59 return 1;
60 }
61
check_load_permission(const char * so,int is_dlclose)62 int check_load_permission(const char *so, int is_dlclose)
63 {
64 int pid = getpid();
65 const char *so_name = NULL;
66 char path[MAX_BUF] = { 0 };
67 if (sprintf(path, "/proc/%d/maps", pid) < 0) {
68 t_error("Failed in sprintf: %s\n", strerror(errno));
69 }
70 FILE* fp = fopen(path, "r");
71 if (fp == NULL) {
72 return 0;
73 }
74 if (strchr(so, '/')) {
75 so_name = strrchr(so, '/') + 1;
76 }
77 char buffer[MAX_BUF] = { 0 };
78 unsigned long start = 0;
79 unsigned long end = 0;
80 int seg_num = 0;
81 while (fgets(buffer, MAX_BUF, fp) != NULL) {
82 if (strstr(buffer, so_name) != NULL) {
83 char *end_ptr;
84 seg_num++;
85 if (is_dlclose && seg_num == RELRO_NUM) {
86 start = strtoul(buffer, &end_ptr, HEX_TERM);
87 end = strtoul(end_ptr + 1, &end_ptr, HEX_TERM);
88 }
89 if (!is_dlclose && seg_num == RELRO_INDEX) {
90 start = strtoul(buffer, &end_ptr, HEX_TERM);
91 end = strtoul(end_ptr + 1, &end_ptr, HEX_TERM);
92 }
93 }
94 }
95 fclose(fp);
96 if (start != 0 && end != 0 && is_dlclose && seg_num == RELRO_NUM) {
97 return dlclose_check(start, end, so);
98 } else if (start != 0 && end != 0 && !is_dlclose && seg_num >= RELRO_INDEX) {
99 mprotect((void*)start, end - start, PROT_READ | PROT_WRITE);
100 return 1;
101 }
102 return 0;
103 }
104
test_lib(void)105 void test_lib(void)
106 {
107 void *handle = dlopen(g_libPath, RTLD_LAZY);
108 if (!handle) {
109 t_error("dlopen(name=%s, mode=%d) failed: %s\n", g_libPath, RTLD_LAZY, dlerror());
110 }
111
112 if (!check_load_permission(g_libPath, 0)) {
113 t_error("check_load_permission failed for so %s\n", g_libPath);
114 }
115 dlclose(handle);
116 }
117
main(int argc,char * argv[])118 int main(int argc, char* argv[])
119 {
120 int pipe_fd[2];
121 pid_t pid;
122 test_lib();
123
124 if (pipe(pipe_fd) == -1) {
125 t_error("create pipe failed\n");
126 return t_status;
127 }
128 pid = fork();
129 if (pid == -1) {
130 close(pipe_fd[0]);
131 close(pipe_fd[1]);
132 t_error("fork failed\n");
133 return t_status;
134 }
135
136 if (pid == 0) {
137 close(pipe_fd[0]);
138 dup2(pipe_fd[1], STDOUT_FILENO);
139 close(pipe_fd[1]);
140
141 execlp("dmesg", "dmesg", NULL);
142 _exit(0);
143 } else {
144 close(pipe_fd[1]);
145 FILE *pipe_read = fdopen(pipe_fd[0], "r");
146 if (pipe_read == NULL) {
147 t_error("Failed to open read pipe fd, errno %d\n", errno);
148 close(pipe_fd[0]);
149 return t_status;
150 }
151 char buffer[BUFFER_SIZE];
152 char pid_buffer[PID_BUFFER_SIZE] = { 0 };
153 int check_success = 0;
154 if (sprintf(pid_buffer, "pid=%d", getpid()) < 0) {
155 t_error("Failed in sprintf: %s\n", strerror(errno));
156 }
157 while (fgets(buffer, BUFFER_SIZE, pipe_read) != NULL) {
158 if (strstr(buffer, g_keylog) && strstr(buffer, pid_buffer)) {
159 check_success = 1;
160 break;
161 }
162 }
163 if (!check_success) {
164 t_error("don't find correct log in dmesg: %s\n", g_keylog);
165 }
166 waitpid(pid, NULL, 0);
167 fclose(pipe_read);
168 }
169 return t_status;
170 }
171
172