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
20 #include <dlfcn.h>
21 #include <sys/syscall.h>
22 #include <unistd.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <linux/audit.h>
27 #include <linux/seccomp.h>
28 #include <linux/filter.h>
29 #include <limits.h>
30
31 #ifndef SECCOMP_SET_MODE_FILTER
32 #define SECCOMP_SET_MODE_FILTER (1)
33 #endif
34
35 #ifdef __aarch64__
36 #define FILTER_LIB_PATH_FORMAT "/system/lib64/lib%s_filter.z.so"
37 #define FILTER_LIB_PATH_HEAD "/system/lib64/lib"
38 #else
39 #define FILTER_LIB_PATH_FORMAT "/system/lib/lib%s_filter.z.so"
40 #define FILTER_LIB_PATH_HEAD "/system/lib/lib"
41 #endif
42 #define FILTER_NAME_FORMAT "g_%sSeccompFilter"
43 #define FILTER_SIZE_STRING "Size"
44
45 typedef enum {
46 SECCOMP_SUCCESS,
47 INPUT_ERROR,
48 RETURN_NULL,
49 RETURN_ERROR
50 } SeccompErrorCode;
51
IsSupportFilterFlag(unsigned int filterFlag)52 static bool IsSupportFilterFlag(unsigned int filterFlag)
53 {
54 errno = 0;
55 long ret = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, filterFlag, NULL);
56 if (ret != -1 || errno != EFAULT) {
57 PLUGIN_LOGE("not support seccomp flag %u", filterFlag);
58 return false;
59 }
60
61 return true;
62 }
63
InstallSeccompPolicy(const struct sock_filter * filter,size_t filterSize,unsigned int filterFlag)64 static bool InstallSeccompPolicy(const struct sock_filter* filter, size_t filterSize, unsigned int filterFlag)
65 {
66 if (filter == NULL) {
67 return false;
68 }
69
70 unsigned int flag = 0;
71 struct sock_fprog prog = {
72 (unsigned short)filterSize,
73 (struct sock_filter*)filter
74 };
75
76 if (IsSupportFilterFlag(SECCOMP_FILTER_FLAG_TSYNC) && (filterFlag & SECCOMP_FILTER_FLAG_TSYNC)) {
77 flag |= SECCOMP_FILTER_FLAG_TSYNC;
78 }
79
80 if (IsSupportFilterFlag(SECCOMP_FILTER_FLAG_LOG) && (filterFlag & SECCOMP_FILTER_FLAG_LOG)) {
81 flag |= SECCOMP_FILTER_FLAG_LOG;
82 }
83
84 if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flag, &prog) != 0) {
85 PLUGIN_LOGE("SetSeccompFilter failed");
86 return false;
87 }
88
89 return true;
90 }
91
GetFilterFileByName(const char * filterName)92 static char *GetFilterFileByName(const char *filterName)
93 {
94 size_t maxFilterNameLen = PATH_MAX - strlen(FILTER_LIB_PATH_FORMAT) + strlen("%s") - 1;
95 if (filterName == NULL || strlen(filterName) > maxFilterNameLen) {
96 return NULL;
97 }
98
99 char filterLibPath[PATH_MAX] = {0};
100
101 int rc = snprintf_s(filterLibPath, sizeof(filterLibPath), \
102 strlen(filterName) + strlen(FILTER_LIB_PATH_FORMAT) - strlen("%s"), \
103 FILTER_LIB_PATH_FORMAT, filterName);
104 if (rc == -1) {
105 return NULL;
106 }
107
108 return realpath(filterLibPath, NULL);
109 }
110
GetSeccompPolicy(const char * filterName,int ** handler,char * filterLibRealPath,struct sock_fprog * prog)111 static int GetSeccompPolicy(const char *filterName, int **handler,
112 char *filterLibRealPath, struct sock_fprog *prog)
113 {
114 if (filterName == NULL || filterLibRealPath == NULL || \
115 handler == NULL || prog == NULL) {
116 return INPUT_ERROR;
117 }
118
119 if (strncmp(filterLibRealPath, FILTER_LIB_PATH_HEAD, strlen(FILTER_LIB_PATH_HEAD))) {
120 return INPUT_ERROR;
121 }
122
123 char filterVaribleName[PATH_MAX] = {0};
124 struct sock_filter *filter = NULL;
125 size_t *filterSize = NULL;
126 void *policyHanlder = NULL;
127 int ret = SECCOMP_SUCCESS;
128 do {
129 int rc = snprintf_s(filterVaribleName, sizeof(filterVaribleName), \
130 strlen(filterName) + strlen(FILTER_NAME_FORMAT) - strlen("%s"), \
131 FILTER_NAME_FORMAT, filterName);
132 if (rc == -1) {
133 ret = RETURN_ERROR;
134 break;
135 }
136
137 policyHanlder = dlopen(filterLibRealPath, RTLD_LAZY);
138 if (policyHanlder == NULL) {
139 ret = RETURN_NULL;
140 break;
141 }
142
143 filter = (struct sock_filter *)dlsym(policyHanlder, filterVaribleName);
144 if (filter == NULL) {
145 ret = RETURN_NULL;
146 break;
147 }
148
149 rc = strcat_s(filterVaribleName, strlen(filterVaribleName) + \
150 strlen(FILTER_SIZE_STRING) + 1, FILTER_SIZE_STRING);
151 if (rc != 0) {
152 ret = RETURN_ERROR;
153 break;
154 }
155
156 filterSize = (size_t *)dlsym(policyHanlder, filterVaribleName);
157 if (filterSize == NULL) {
158 ret = RETURN_NULL;
159 break;
160 }
161 } while (0);
162
163 *handler = (int *)policyHanlder;
164 prog->filter = filter;
165 if (filterSize != NULL) {
166 prog->len = (unsigned short)(*filterSize);
167 }
168
169 return ret;
170 }
171
SetSeccompPolicyWithName(const char * filterName)172 bool SetSeccompPolicyWithName(const char *filterName)
173 {
174 if (filterName == NULL) {
175 return false;
176 }
177
178 void *handler = NULL;
179 char *filterLibRealPath = NULL;
180 struct sock_fprog prog;
181 bool ret = false;
182
183 filterLibRealPath = GetFilterFileByName(filterName);
184 PLUGIN_CHECK(filterLibRealPath != NULL, return false, "get filter file name faield");
185
186 int retCode = GetSeccompPolicy(filterName, (int **)&handler, filterLibRealPath, &prog);
187 if (retCode == SECCOMP_SUCCESS) {
188 ret = InstallSeccompPolicy(prog.filter, prog.len, SECCOMP_FILTER_FLAG_LOG);
189 } else {
190 PLUGIN_LOGE("GetSeccompPolicy failed return is %d", retCode);
191 }
192
193 if (handler != NULL) {
194 dlclose(handler);
195 }
196
197 if (filterLibRealPath != NULL) {
198 free(filterLibRealPath);
199 }
200
201 return ret;
202 }
203