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 51typedef enum { 52 SECCOMP_SUCCESS, 53 INPUT_ERROR, 54 RETURN_NULL, 55 RETURN_ERROR, 56 RETURN_LENGTH_CHECK 57} SeccompErrorCode; 58 59static 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 71static 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 99static 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 135static 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 196bool 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 211bool 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