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 } SeccompErrorCode;
57
IsSupportFilterFlag(unsigned int filterFlag)58 static bool IsSupportFilterFlag(unsigned int filterFlag)
59 {
60 errno = 0;
61 long ret = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, filterFlag, NULL);
62 if (ret != -1 || errno != EFAULT) {
63 PLUGIN_LOGE("not support seccomp flag %u", filterFlag);
64 return false;
65 }
66
67 return true;
68 }
69
InstallSeccompPolicy(const struct sock_filter * filter,size_t filterSize,unsigned int filterFlag)70 static bool InstallSeccompPolicy(const struct sock_filter* filter, size_t filterSize, unsigned int filterFlag)
71 {
72 if (filter == NULL) {
73 return false;
74 }
75
76 unsigned int flag = 0;
77 struct sock_fprog prog = {
78 (unsigned short)filterSize,
79 (struct sock_filter*)filter
80 };
81
82 if (IsSupportFilterFlag(SECCOMP_FILTER_FLAG_TSYNC) && (filterFlag & SECCOMP_FILTER_FLAG_TSYNC)) {
83 flag |= SECCOMP_FILTER_FLAG_TSYNC;
84 }
85
86 if (IsSupportFilterFlag(SECCOMP_FILTER_FLAG_LOG) && (filterFlag & SECCOMP_FILTER_FLAG_LOG)) {
87 flag |= SECCOMP_FILTER_FLAG_LOG;
88 }
89
90 if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flag, &prog) != 0) {
91 PLUGIN_LOGE("SetSeccompFilter failed");
92 return false;
93 }
94
95 return true;
96 }
97
GetFilterFileByName(const char * filterName,char * filterLibRealPath,unsigned int pathSize)98 static bool GetFilterFileByName(const char *filterName, char *filterLibRealPath, unsigned int pathSize)
99 {
100 size_t maxFilterNameLen = PATH_MAX - strlen(FILTER_LIB_PATH_FORMAT) + strlen("%s") - 1;
101 if (filterName == NULL || strlen(filterName) > maxFilterNameLen) {
102 return false;
103 }
104
105 bool flag = false;
106 char filterLibPath[PATH_MAX] = {0};
107
108 int rc = snprintf_s(filterLibPath, sizeof(filterLibPath), \
109 strlen(filterName) + strlen(FILTER_LIB_PATH_FORMAT) - strlen("%s"), \
110 FILTER_LIB_PATH_FORMAT, filterName);
111 if (rc == -1) {
112 return false;
113 }
114
115 int seccompPathNum = 0;
116 CfgFiles *files = GetCfgFiles(filterLibPath);
117 for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
118 if (files->paths[i]) {
119 seccompPathNum++;
120 }
121 }
122
123 // allow only one path to a seccomp shared library to avoid shared library replaced
124 if (seccompPathNum == 1 && files && files->paths[0]) {
125 if (memcpy_s(filterLibRealPath, pathSize, files->paths[0], strlen(files->paths[0]) + 1) == EOK) {
126 flag = true;
127 }
128 }
129 FreeCfgFiles(files);
130
131 return flag;
132 }
133
GetSeccompPolicy(const char * filterName,int ** handler,const char * filterLibRealPath,struct sock_fprog * prog)134 static int GetSeccompPolicy(const char *filterName, int **handler,
135 const char *filterLibRealPath, struct sock_fprog *prog)
136 {
137 if (filterName == NULL || filterLibRealPath == NULL || handler == NULL || prog == NULL) {
138 return INPUT_ERROR;
139 }
140
141 if (strstr(filterLibRealPath, FILTER_LIB_PATH_PART) == NULL) {
142 return INPUT_ERROR;
143 }
144
145 char filterVaribleName[PATH_MAX] = {0};
146 struct sock_filter *filter = NULL;
147 size_t *filterSize = NULL;
148 void *policyHanlder = NULL;
149 int ret = SECCOMP_SUCCESS;
150 do {
151 int rc = snprintf_s(filterVaribleName, sizeof(filterVaribleName), \
152 strlen(filterName) + strlen(FILTER_NAME_FORMAT) - strlen("%s"), \
153 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 if (policyHanlder == NULL) {
161 return RETURN_NULL;
162 }
163
164 filter = (struct sock_filter *)dlsym(policyHanlder, filterVaribleName);
165 if (filter == NULL) {
166 ret = RETURN_NULL;
167 break;
168 }
169
170 rc = strcat_s(filterVaribleName, strlen(filterVaribleName) + \
171 strlen(FILTER_SIZE_STRING) + 1, FILTER_SIZE_STRING);
172 if (rc != 0) {
173 ret = RETURN_ERROR;
174 break;
175 }
176
177 filterSize = (size_t *)dlsym(policyHanlder, filterVaribleName);
178 if (filterSize == NULL) {
179 ret = RETURN_NULL;
180 break;
181 }
182 } while (0);
183
184 *handler = (int *)policyHanlder;
185 prog->filter = filter;
186 if (filterSize != NULL) {
187 prog->len = (unsigned short)(*filterSize);
188 }
189
190 return ret;
191 }
192
193 #ifdef WITH_SECCOMP_DEBUG
IsEnableSeccomp(void)194 static bool IsEnableSeccomp(void)
195 {
196 char value[MAX_BUFFER_LEN] = {0};
197 unsigned int len = MAX_BUFFER_LEN;
198 bool isEnableSeccompFlag = true;
199 if (SystemReadParam("persist.init.debug.seccomp.enable", value, &len) == 0) {
200 if (strncmp(value, "0", len) == 0) {
201 isEnableSeccompFlag = false;
202 }
203 }
204
205 return isEnableSeccompFlag;
206 }
207 #endif
208
SetSeccompPolicyWithName(SeccompFilterType type,const char * filterName)209 bool SetSeccompPolicyWithName(SeccompFilterType type, const char *filterName)
210 {
211 if (filterName == NULL) {
212 return false;
213 }
214
215 #ifdef WITH_SECCOMP_DEBUG
216 if (!IsEnableSeccomp()) {
217 return true;
218 }
219 #endif
220
221 void *handler = NULL;
222 char filterLibRealPath[PATH_MAX] = {0};
223 struct sock_fprog prog;
224 bool ret = false;
225 const char *filterNamePtr = filterName;
226
227 bool flag = GetFilterFileByName(filterNamePtr, filterLibRealPath, sizeof(filterLibRealPath));
228 if (!flag) {
229 if (type == SYSTEM_SA) {
230 filterNamePtr = SYSTEM_NAME;
231 flag = GetFilterFileByName(filterNamePtr, filterLibRealPath, sizeof(filterLibRealPath));
232 PLUGIN_CHECK(flag == true, return ret, "get filter name failed");
233 } else if (type == SYSTEM_OTHERS) {
234 return true;
235 } else {
236 PLUGIN_LOGE("get filter name failed");
237 return ret;
238 }
239 }
240
241 int retCode = GetSeccompPolicy(filterNamePtr, (int **)&handler, filterLibRealPath, &prog);
242 if (retCode == SECCOMP_SUCCESS) {
243 ret = InstallSeccompPolicy(prog.filter, prog.len, SECCOMP_FILTER_FLAG_LOG);
244 } else {
245 PLUGIN_LOGE("get seccomp policy failed return is %d and path is %s", retCode, filterLibRealPath);
246 }
247 #ifndef COVERAGE_TEST
248 if (handler != NULL) {
249 dlclose(handler);
250 }
251 #endif
252 return ret;
253 }
254