• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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