1 /*
2 * Copyright (c) 2022 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 "seccomp_policy.h"
17 #include "plugin_adapter.h"
18 #include "securec.h"
19 #include "config_policy_utils.h"
20
21 #ifdef WITH_SECCOMP_DEBUG
22 #include "init_utils.h"
23 #include "init_param.h"
24 #endif
25
26 #include <dlfcn.h>
27 #include <sys/syscall.h>
28 #include <unistd.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <linux/audit.h>
33 #include <linux/seccomp.h>
34 #include <linux/filter.h>
35 #include <limits.h>
36
37 #ifndef SECCOMP_SET_MODE_FILTER
38 #define SECCOMP_SET_MODE_FILTER (1)
39 #endif
40
41 #ifdef __aarch64__
42 #define FILTER_LIB_PATH_FORMAT "lib64/seccomp/lib%s_filter.z.so"
43 #define FILTER_LIB_PATH_PART "lib64/seccomp/lib"
44 #else
45 #define FILTER_LIB_PATH_FORMAT "lib/seccomp/lib%s_filter.z.so"
46 #define FILTER_LIB_PATH_PART "lib/seccomp/lib"
47 #endif
48 #define FILTER_NAME_FORMAT "g_%sSeccompFilter"
49 #define FILTER_SIZE_STRING "Size"
50
51 typedef enum {
52 SECCOMP_SUCCESS,
53 INPUT_ERROR,
54 RETURN_NULL,
55 RETURN_ERROR,
56 RETURN_LENGTH_CHECK
57 } SeccompErrorCode;
58
IsSupportFilterFlag(unsigned int filterFlag)59 static bool IsSupportFilterFlag(unsigned int filterFlag)
60 {
61 errno = 0;
62 long ret = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, filterFlag, NULL);
63 if (ret != -1 || errno != EFAULT) {
64 PLUGIN_LOGE("not support seccomp flag %u", filterFlag);
65 return false;
66 }
67
68 return true;
69 }
70
InstallSeccompPolicy(const struct sock_filter * filter,size_t filterSize,unsigned int filterFlag)71 static bool InstallSeccompPolicy(const struct sock_filter* filter, size_t filterSize, unsigned int filterFlag)
72 {
73 if (filter == NULL) {
74 return false;
75 }
76
77 unsigned int flag = 0;
78 struct sock_fprog prog = {
79 (unsigned short)filterSize,
80 (struct sock_filter*)filter
81 };
82
83 if (IsSupportFilterFlag(SECCOMP_FILTER_FLAG_TSYNC) && (filterFlag & SECCOMP_FILTER_FLAG_TSYNC)) {
84 flag |= SECCOMP_FILTER_FLAG_TSYNC;
85 }
86
87 if (IsSupportFilterFlag(SECCOMP_FILTER_FLAG_LOG) && (filterFlag & SECCOMP_FILTER_FLAG_LOG)) {
88 flag |= SECCOMP_FILTER_FLAG_LOG;
89 }
90
91 if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flag, &prog) != 0) {
92 PLUGIN_LOGE("SetSeccompFilter failed");
93 return false;
94 }
95
96 return true;
97 }
98
GetFilterFileByName(const char * filterName,char * filterLibRealPath,unsigned int pathSize)99 static bool GetFilterFileByName(const char *filterName, char *filterLibRealPath, unsigned int pathSize)
100 {
101 size_t maxFilterNameLen = PATH_MAX - strlen(FILTER_LIB_PATH_FORMAT) + strlen("%s") - 1;
102 if (filterName == NULL || strlen(filterName) > maxFilterNameLen) {
103 return false;
104 }
105
106 bool flag = false;
107 char filterLibPath[PATH_MAX] = {0};
108
109 int rc = snprintf_s(filterLibPath, sizeof(filterLibPath), \
110 strlen(filterName) + strlen(FILTER_LIB_PATH_FORMAT) - strlen("%s"), \
111 FILTER_LIB_PATH_FORMAT, filterName);
112 if (rc == -1) {
113 return false;
114 }
115
116 int seccompPathNum = 0;
117 CfgFiles *files = GetCfgFiles(filterLibPath);
118 for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
119 if (files->paths[i]) {
120 seccompPathNum++;
121 }
122 }
123
124 // allow only one path to a seccomp shared library to avoid shared library replaced
125 if (seccompPathNum == 1 && files && files->paths[0]) {
126 if (memcpy_s(filterLibRealPath, pathSize, files->paths[0], strlen(files->paths[0]) + 1) == EOK) {
127 flag = true;
128 }
129 }
130 FreeCfgFiles(files);
131
132 return flag;
133 }
134
GetSeccompPolicy(const char * filterName,int ** handler,const char * filterLibRealPath,struct sock_fprog * prog)135 static int GetSeccompPolicy(const char *filterName, int **handler,
136 const char *filterLibRealPath, struct sock_fprog *prog)
137 {
138 if (filterName == NULL || filterLibRealPath == NULL || handler == NULL || prog == NULL) {
139 return INPUT_ERROR;
140 }
141
142 if (strstr(filterLibRealPath, FILTER_LIB_PATH_PART) == NULL) {
143 return INPUT_ERROR;
144 }
145
146 char filterVaribleName[PATH_MAX] = {0};
147 struct sock_filter *filter = NULL;
148 size_t *filterSize = NULL;
149 void *policyHanlder = NULL;
150 int ret = SECCOMP_SUCCESS;
151 do {
152 int rc = snprintf_s(filterVaribleName, sizeof(filterVaribleName), \
153 strlen(filterName) + strlen(FILTER_NAME_FORMAT) - strlen("%s"), FILTER_NAME_FORMAT, filterName);
154 if (rc == -1) {
155 return RETURN_ERROR;
156 }
157 char realPath[PATH_MAX] = { 0 };
158 realpath(filterLibRealPath, realPath);
159 policyHanlder = dlopen(realPath, RTLD_LAZY);
160 PLUGIN_CHECK(policyHanlder != NULL, return RETURN_ERROR, "dlopen error policyHanlder:NULL");
161
162 filter = (struct sock_filter *)dlsym(policyHanlder, filterVaribleName);
163 if (filter == NULL) {
164 ret = RETURN_NULL;
165 break;
166 }
167
168 size_t filterVaribleNameLen = strlen(filterVaribleName) + strlen(FILTER_SIZE_STRING) + 1;
169 if (filterVaribleNameLen > sizeof(filterVaribleName)) {
170 ret = RETURN_LENGTH_CHECK;
171 break;
172 }
173 rc = strcat_s(filterVaribleName, filterVaribleNameLen, FILTER_SIZE_STRING);
174 if (rc != 0) {
175 ret = RETURN_ERROR;
176 break;
177 }
178
179 filterSize = (size_t *)dlsym(policyHanlder, filterVaribleName);
180 if (filterSize == NULL) {
181 ret = RETURN_NULL;
182 break;
183 }
184 } while (0);
185
186 *handler = (int *)policyHanlder;
187 prog->filter = filter;
188 if (filterSize != NULL) {
189 prog->len = (unsigned short)(*filterSize);
190 }
191
192 return ret;
193 }
194
195
IsEnableSeccomp(void)196 bool IsEnableSeccomp(void)
197 {
198 bool isEnableSeccompFlag = true;
199 #ifdef WITH_SECCOMP_DEBUG
200 char value[MAX_BUFFER_LEN] = {0};
201 unsigned int len = MAX_BUFFER_LEN;
202 if (SystemReadParam("persist.init.debug.seccomp.enable", value, &len) == 0) {
203 if (strncmp(value, "0", len) == 0) {
204 isEnableSeccompFlag = false;
205 }
206 }
207 #endif
208 return isEnableSeccompFlag;
209 }
210
SetSeccompPolicyWithName(SeccompFilterType type,const char * filterName)211 bool SetSeccompPolicyWithName(SeccompFilterType type, const char *filterName)
212 {
213 if (filterName == NULL) {
214 return false;
215 }
216
217 #ifdef WITH_SECCOMP_DEBUG
218 if (!IsEnableSeccomp()) {
219 return true;
220 }
221 #endif
222
223 void *handler = NULL;
224 char filterLibRealPath[PATH_MAX] = {0};
225 struct sock_fprog prog;
226 bool ret = false;
227 const char *filterNamePtr = filterName;
228
229 bool flag = GetFilterFileByName(filterNamePtr, filterLibRealPath, sizeof(filterLibRealPath));
230 if (!flag) {
231 if (type == SYSTEM_SA) {
232 filterNamePtr = SYSTEM_NAME;
233 flag = GetFilterFileByName(filterNamePtr, filterLibRealPath, sizeof(filterLibRealPath));
234 PLUGIN_CHECK(flag == true, return ret, "get filter name failed");
235 } else if (type == SYSTEM_OTHERS) {
236 return true;
237 } else {
238 PLUGIN_LOGE("get filter name failed");
239 return ret;
240 }
241 }
242
243 int retCode = GetSeccompPolicy(filterNamePtr, (int **)&handler, filterLibRealPath, &prog);
244 if (retCode == SECCOMP_SUCCESS) {
245 ret = InstallSeccompPolicy(prog.filter, prog.len, SECCOMP_FILTER_FLAG_LOG);
246 } else {
247 PLUGIN_LOGE("get seccomp policy failed return is %d and path is %s", retCode, filterLibRealPath);
248 }
249 #ifndef COVERAGE_TEST
250 if (handler != NULL) {
251 dlclose(handler);
252 }
253 #endif
254 return ret;
255 }
256