1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci#include <errno.h>
16d9f0492fSopenharmony_ci#include <dlfcn.h>
17d9f0492fSopenharmony_ci#include <sys/socket.h>
18d9f0492fSopenharmony_ci
19d9f0492fSopenharmony_ci#include "init_utils.h"
20d9f0492fSopenharmony_ci#include "param_manager.h"
21d9f0492fSopenharmony_ci#include "param_security.h"
22d9f0492fSopenharmony_ci#include "param_utils.h"
23d9f0492fSopenharmony_ci#include "param_base.h"
24d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
25d9f0492fSopenharmony_ci#include "selinux_parameter.h"
26d9f0492fSopenharmony_ci#endif
27d9f0492fSopenharmony_ci
28d9f0492fSopenharmony_ci#if defined (__aarch64__) || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64)
29d9f0492fSopenharmony_ci#define CHECKER_LIB_NAME "/system/lib64/libparaperm_checker.z.so"
30d9f0492fSopenharmony_ci#define CHECKER_UPDATER_LIB "/lib64/libparaperm_checker.z.so"
31d9f0492fSopenharmony_ci#else
32d9f0492fSopenharmony_ci#define CHECKER_LIB_NAME "/system/lib/libparaperm_checker.z.so"
33d9f0492fSopenharmony_ci#define CHECKER_UPDATER_LIB "/lib/libparaperm_checker.z.so"
34d9f0492fSopenharmony_ci#endif
35d9f0492fSopenharmony_citypedef int (*SelinuxSetParamCheck)(const char *paraName, const char *destContext, const SrcInfo *info);
36d9f0492fSopenharmony_ci
37d9f0492fSopenharmony_cistatic int InitSelinuxOpsForInit(SelinuxSpace *selinuxSpace)
38d9f0492fSopenharmony_ci{
39d9f0492fSopenharmony_ci    if (selinuxSpace->selinuxHandle == NULL) {
40d9f0492fSopenharmony_ci        const char *libname = (GetParamWorkSpace()->ops.updaterMode == 1) ? CHECKER_UPDATER_LIB : CHECKER_LIB_NAME;
41d9f0492fSopenharmony_ci        selinuxSpace->selinuxHandle = dlopen(libname, RTLD_LAZY);
42d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->selinuxHandle != NULL,
43d9f0492fSopenharmony_ci            return 0, "Failed to dlsym selinuxHandle, %s", dlerror());
44d9f0492fSopenharmony_ci    }
45d9f0492fSopenharmony_ci    void *handle = selinuxSpace->selinuxHandle;
46d9f0492fSopenharmony_ci    if (selinuxSpace->setParamCheck == NULL) {
47d9f0492fSopenharmony_ci        selinuxSpace->setParamCheck = (SelinuxSetParamCheck)dlsym(handle, "SetParamCheck");
48d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->setParamCheck != NULL, return -1, "Failed to dlsym setParamCheck %s", dlerror());
49d9f0492fSopenharmony_ci    }
50d9f0492fSopenharmony_ci    if (selinuxSpace->getParamList == NULL) {
51d9f0492fSopenharmony_ci        selinuxSpace->getParamList = (ParamContextsList *(*)()) dlsym(handle, "GetParamList");
52d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->getParamList != NULL, return -1, "Failed to dlsym getParamList %s", dlerror());
53d9f0492fSopenharmony_ci    }
54d9f0492fSopenharmony_ci    if (selinuxSpace->getParamLabel == NULL) {
55d9f0492fSopenharmony_ci        selinuxSpace->getParamLabel = (const char *(*)(const char *))dlsym(handle, "GetParamLabel");
56d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->getParamLabel != NULL, return -1, "Failed to dlsym getParamLabel %s", dlerror());
57d9f0492fSopenharmony_ci    }
58d9f0492fSopenharmony_ci    if (selinuxSpace->initParamSelinux == NULL) {
59d9f0492fSopenharmony_ci        selinuxSpace->initParamSelinux = (int (*)(int))dlsym(handle, "InitParamSelinux");
60d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->initParamSelinux != NULL, return -1, "Failed to dlsym initParamSelinux ");
61d9f0492fSopenharmony_ci    }
62d9f0492fSopenharmony_ci    if (selinuxSpace->getParamLabelIndex == NULL) {
63d9f0492fSopenharmony_ci        selinuxSpace->getParamLabelIndex = (int (*)(const char *))dlsym(handle, "GetParamLabelIndex");
64d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->getParamLabelIndex != NULL, return -1, "Failed to dlsym getParamLabelIndex ");
65d9f0492fSopenharmony_ci    }
66d9f0492fSopenharmony_ci    if (selinuxSpace->setSelinuxLogCallback == NULL) {
67d9f0492fSopenharmony_ci        selinuxSpace->setSelinuxLogCallback = (void (*)())dlsym(handle, "SetInitSelinuxLog");
68d9f0492fSopenharmony_ci    }
69d9f0492fSopenharmony_ci    if (selinuxSpace->destroyParamList == NULL) {
70d9f0492fSopenharmony_ci        selinuxSpace->destroyParamList =
71d9f0492fSopenharmony_ci            (void (*)(ParamContextsList **))dlsym(handle, "DestroyParamList");
72d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->destroyParamList != NULL,
73d9f0492fSopenharmony_ci            return -1, "Failed to dlsym destroyParamList %s", dlerror());
74d9f0492fSopenharmony_ci    }
75d9f0492fSopenharmony_ci
76d9f0492fSopenharmony_ci    // init and open avc log
77d9f0492fSopenharmony_ci    int ret = selinuxSpace->initParamSelinux(1);
78d9f0492fSopenharmony_ci    if (selinuxSpace->setSelinuxLogCallback != NULL) {
79d9f0492fSopenharmony_ci        selinuxSpace->setSelinuxLogCallback();
80d9f0492fSopenharmony_ci    }
81d9f0492fSopenharmony_ci    return ret;
82d9f0492fSopenharmony_ci}
83d9f0492fSopenharmony_ci
84d9f0492fSopenharmony_cistatic int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
85d9f0492fSopenharmony_ci{
86d9f0492fSopenharmony_ci    PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace");
87d9f0492fSopenharmony_ci    UNUSED(isInit);
88d9f0492fSopenharmony_ci    PARAM_CHECK(security != NULL, return -1, "Invalid security");
89d9f0492fSopenharmony_ci    security->cred.pid = getpid();
90d9f0492fSopenharmony_ci    security->cred.uid = geteuid();
91d9f0492fSopenharmony_ci    security->cred.gid = getegid();
92d9f0492fSopenharmony_ci    security->flags[PARAM_SECURITY_SELINUX] = 0;
93d9f0492fSopenharmony_ci    PARAM_LOGV("InitLocalSecurityLabel");
94d9f0492fSopenharmony_ci#if !(defined STARTUP_INIT_TEST || defined LOCAL_TEST)
95d9f0492fSopenharmony_ci    if ((bool)isInit) {
96d9f0492fSopenharmony_ci        int ret = InitSelinuxOpsForInit(&GetParamWorkSpace()->selinuxSpace);
97d9f0492fSopenharmony_ci        PARAM_CHECK(ret == 0, return -1, "Failed to init selinux ops");
98d9f0492fSopenharmony_ci    } else {
99d9f0492fSopenharmony_ci        SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
100d9f0492fSopenharmony_ci        selinuxSpace->initParamSelinux = InitParamSelinux;
101d9f0492fSopenharmony_ci        selinuxSpace->getParamList = GetParamList;
102d9f0492fSopenharmony_ci        selinuxSpace->getParamLabel = GetParamLabel;
103d9f0492fSopenharmony_ci        selinuxSpace->destroyParamList = DestroyParamList;
104d9f0492fSopenharmony_ci        selinuxSpace->getParamLabelIndex = GetParamLabelIndex;
105d9f0492fSopenharmony_ci        // init
106d9f0492fSopenharmony_ci        selinuxSpace->initParamSelinux(isInit);
107d9f0492fSopenharmony_ci    }
108d9f0492fSopenharmony_ci#endif
109d9f0492fSopenharmony_ci    PARAM_LOGV("Load selinux lib success.");
110d9f0492fSopenharmony_ci    return 0;
111d9f0492fSopenharmony_ci}
112d9f0492fSopenharmony_ci
113d9f0492fSopenharmony_cistatic int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
114d9f0492fSopenharmony_ci{
115d9f0492fSopenharmony_ci    return 0;
116d9f0492fSopenharmony_ci}
117d9f0492fSopenharmony_ci
118d9f0492fSopenharmony_cistatic void SetSelinuxFileCon(const char *name, const char *context)
119d9f0492fSopenharmony_ci{
120d9f0492fSopenharmony_ci    PARAM_CHECK(GetParamWorkSpace() != NULL && GetParamWorkSpace()->ops.setfilecon != NULL,
121d9f0492fSopenharmony_ci        return, "Invalid workspace or setfilecon");
122d9f0492fSopenharmony_ci    static char buffer[FILENAME_LEN_MAX] = {0};
123d9f0492fSopenharmony_ci    int len = PARAM_SPRINTF(buffer, sizeof(buffer), "%s/%s", PARAM_STORAGE_PATH, context);
124d9f0492fSopenharmony_ci    if (len > 0) {
125d9f0492fSopenharmony_ci        buffer[len] = '\0';
126d9f0492fSopenharmony_ci        PARAM_LOGV("setfilecon name %s path: %s %s ", name, context, buffer);
127d9f0492fSopenharmony_ci        if (GetParamWorkSpace()->ops.setfilecon(buffer, context) < 0) {
128d9f0492fSopenharmony_ci            PARAM_LOGE("Failed to setfilecon %s ", context);
129d9f0492fSopenharmony_ci        }
130d9f0492fSopenharmony_ci    }
131d9f0492fSopenharmony_ci}
132d9f0492fSopenharmony_ci
133d9f0492fSopenharmony_cistatic void HandleSelinuxLabelForOpen(const ParameterNode *paramNode, int readOnly)
134d9f0492fSopenharmony_ci{
135d9f0492fSopenharmony_ci    uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE;
136d9f0492fSopenharmony_ci    int ret = OpenWorkSpace(labelIndex, readOnly);
137d9f0492fSopenharmony_ci    if (ret != 0) {
138d9f0492fSopenharmony_ci        PARAM_LOGE("Forbid to add selinux workspace %s %s", paramNode->paraName, paramNode->paraContext);
139d9f0492fSopenharmony_ci        return;
140d9f0492fSopenharmony_ci    }
141d9f0492fSopenharmony_ci    if (!readOnly) {
142d9f0492fSopenharmony_ci        // set selinux label
143d9f0492fSopenharmony_ci        SetSelinuxFileCon(paramNode->paraName, paramNode->paraContext);
144d9f0492fSopenharmony_ci    }
145d9f0492fSopenharmony_ci}
146d9f0492fSopenharmony_ci
147d9f0492fSopenharmony_cistatic void HandleSelinuxLabelForInit(const ParameterNode *paramNode, int readOnly)
148d9f0492fSopenharmony_ci{
149d9f0492fSopenharmony_ci    uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE;
150d9f0492fSopenharmony_ci    int ret = AddWorkSpace(paramNode->paraContext, labelIndex, readOnly, 0);
151d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return, "Not enough memory for %s", paramNode->paraContext);
152d9f0492fSopenharmony_ci
153d9f0492fSopenharmony_ci    ParamWorkSpace *paramSpace = GetParamWorkSpace();
154d9f0492fSopenharmony_ci    PARAM_CHECK(paramSpace != NULL, return, "Invalid workspace");
155d9f0492fSopenharmony_ci    if (paramSpace->maxLabelIndex < labelIndex) {
156d9f0492fSopenharmony_ci        paramSpace->maxLabelIndex = labelIndex;
157d9f0492fSopenharmony_ci    }
158d9f0492fSopenharmony_ci}
159d9f0492fSopenharmony_ci
160d9f0492fSopenharmony_ciint SelinuxGetAllLabel(int readOnly,
161d9f0492fSopenharmony_ci    void (*handleSelinuxLabel)(const ParameterNode *paramNode, int readOnly))
162d9f0492fSopenharmony_ci{
163d9f0492fSopenharmony_ci    SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
164d9f0492fSopenharmony_ci    PARAM_CHECK(selinuxSpace->getParamList != NULL, return DAC_RESULT_FORBIDED, "Invalid getParamList");
165d9f0492fSopenharmony_ci    ParamContextsList *node = selinuxSpace->getParamList();
166d9f0492fSopenharmony_ci    int count = 0;
167d9f0492fSopenharmony_ci    while (node != NULL) {
168d9f0492fSopenharmony_ci        PARAM_LOGV("SelinuxGetAllLabel index %d name %s content %s",
169d9f0492fSopenharmony_ci            node->info.index, node->info.paraName, node->info.paraContext);
170d9f0492fSopenharmony_ci        if (node->info.paraContext == NULL || node->info.paraName == NULL) {
171d9f0492fSopenharmony_ci            node = node->next;
172d9f0492fSopenharmony_ci            continue;
173d9f0492fSopenharmony_ci        }
174d9f0492fSopenharmony_ci        handleSelinuxLabel(&node->info, readOnly);
175d9f0492fSopenharmony_ci        count++;
176d9f0492fSopenharmony_ci        node = node->next;
177d9f0492fSopenharmony_ci    }
178d9f0492fSopenharmony_ci    ParameterNode tmpNode = {WORKSPACE_NAME_DEF_SELINUX, WORKSPACE_NAME_DEF_SELINUX, 0};
179d9f0492fSopenharmony_ci    handleSelinuxLabel(&tmpNode, readOnly);
180d9f0492fSopenharmony_ci    PARAM_LOGV("Selinux get all label counts %d.", count);
181d9f0492fSopenharmony_ci    return 0;
182d9f0492fSopenharmony_ci}
183d9f0492fSopenharmony_ci
184d9f0492fSopenharmony_cistatic void HandleSelinuxLabelForPermission(const ParameterNode *paramNode, int readOnly)
185d9f0492fSopenharmony_ci{
186d9f0492fSopenharmony_ci    uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE;
187d9f0492fSopenharmony_ci    if (labelIndex == WORKSPACE_INDEX_BASE) {
188d9f0492fSopenharmony_ci        return;
189d9f0492fSopenharmony_ci    }
190d9f0492fSopenharmony_ci    if (*(paramNode->paraName + strlen(paramNode->paraName) - 1) != '.') {
191d9f0492fSopenharmony_ci        return;
192d9f0492fSopenharmony_ci    }
193d9f0492fSopenharmony_ci    // save selinux index
194d9f0492fSopenharmony_ci    ParamWorkSpace *paramWorkspace = GetParamWorkSpace();
195d9f0492fSopenharmony_ci    PARAM_CHECK(paramWorkspace != NULL && paramWorkspace->workSpace != NULL, return, "Invalid workspace");
196d9f0492fSopenharmony_ci    WorkSpace *space = paramWorkspace->workSpace[WORKSPACE_INDEX_DAC];
197d9f0492fSopenharmony_ci    PARAM_CHECK(space != NULL && space->area != NULL, return, "Failed to get dac space %s", paramNode->paraName);
198d9f0492fSopenharmony_ci    uint32_t index = 0;
199d9f0492fSopenharmony_ci    (void)FindTrieNode(space, paramNode->paraName, strlen(paramNode->paraName), &index);
200d9f0492fSopenharmony_ci    ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, index);
201d9f0492fSopenharmony_ci    PARAM_CHECK(node != NULL, return, "Can not get security label for %s", paramNode->paraName);
202d9f0492fSopenharmony_ci    PARAM_LOGV("HandleSelinuxLabelForPermission %s selinuxIndex [ %u %u] dac %u %s ",
203d9f0492fSopenharmony_ci        paramNode->paraName, labelIndex, node->selinuxIndex, index, paramNode->paraContext);
204d9f0492fSopenharmony_ci    ParamAuditData auditData = {0};
205d9f0492fSopenharmony_ci    auditData.dacData.gid = node->gid;
206d9f0492fSopenharmony_ci    auditData.dacData.uid = node->uid;
207d9f0492fSopenharmony_ci    auditData.dacData.mode = node->mode;
208d9f0492fSopenharmony_ci    auditData.dacData.paramType = node->type;
209d9f0492fSopenharmony_ci    auditData.selinuxIndex = labelIndex;
210d9f0492fSopenharmony_ci    auditData.name = paramNode->paraName;
211d9f0492fSopenharmony_ci    auditData.memberNum = 1;
212d9f0492fSopenharmony_ci    auditData.members[0] = node->gid;
213d9f0492fSopenharmony_ci    AddSecurityLabel(&auditData);
214d9f0492fSopenharmony_ci}
215d9f0492fSopenharmony_ci
216d9f0492fSopenharmony_cistatic int SelinuxGetParamSecurityLabel(const char *cmd, int readOnly)
217d9f0492fSopenharmony_ci{
218d9f0492fSopenharmony_ci    if (cmd == NULL || strcmp(cmd, "create") == 0) { // for init and other processor
219d9f0492fSopenharmony_ci        return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForInit);
220d9f0492fSopenharmony_ci    }
221d9f0492fSopenharmony_ci    if ((strcmp(cmd, "init") == 0) && (!readOnly)) { // only for init
222d9f0492fSopenharmony_ci        return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForOpen);
223d9f0492fSopenharmony_ci    }
224d9f0492fSopenharmony_ci    if ((strcmp(cmd, "permission") == 0) && (!readOnly)) { // only for init
225d9f0492fSopenharmony_ci        return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForPermission);
226d9f0492fSopenharmony_ci    }
227d9f0492fSopenharmony_ci    if ((strcmp(cmd, "open") == 0) && readOnly) { // for read only
228d9f0492fSopenharmony_ci        static int loadLabels = 0;
229d9f0492fSopenharmony_ci        if (loadLabels) {
230d9f0492fSopenharmony_ci            return 0;
231d9f0492fSopenharmony_ci        }
232d9f0492fSopenharmony_ci        loadLabels = 1;
233d9f0492fSopenharmony_ci        return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForOpen);
234d9f0492fSopenharmony_ci    }
235d9f0492fSopenharmony_ci    return 0;
236d9f0492fSopenharmony_ci}
237d9f0492fSopenharmony_ci
238d9f0492fSopenharmony_cistatic int SelinuxGetParamSecurityLabelForInit(const char *path)
239d9f0492fSopenharmony_ci{
240d9f0492fSopenharmony_ci    return SelinuxGetParamSecurityLabel(path, 0);
241d9f0492fSopenharmony_ci}
242d9f0492fSopenharmony_ci
243d9f0492fSopenharmony_cistatic int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
244d9f0492fSopenharmony_ci{
245d9f0492fSopenharmony_ci    UNUSED(flags);
246d9f0492fSopenharmony_ci    UNUSED(localLabel);
247d9f0492fSopenharmony_ci    UNUSED(fileName);
248d9f0492fSopenharmony_ci    return 0;
249d9f0492fSopenharmony_ci}
250d9f0492fSopenharmony_ci
251d9f0492fSopenharmony_cistatic int UpdaterCheckParamPermission(const ParamLabelIndex *labelIndex,
252d9f0492fSopenharmony_ci    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
253d9f0492fSopenharmony_ci{
254d9f0492fSopenharmony_ci    return DAC_RESULT_PERMISSION;
255d9f0492fSopenharmony_ci}
256d9f0492fSopenharmony_ci
257d9f0492fSopenharmony_cistatic int SelinuxGetParamSecurityLabelForOther(const char *path)
258d9f0492fSopenharmony_ci{
259d9f0492fSopenharmony_ci    return SelinuxGetParamSecurityLabel(path, 1);
260d9f0492fSopenharmony_ci}
261d9f0492fSopenharmony_ci
262d9f0492fSopenharmony_ciINIT_LOCAL_API int RegisterSecuritySelinuxOps(ParamSecurityOps *ops, int isInit)
263d9f0492fSopenharmony_ci{
264d9f0492fSopenharmony_ci    PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace");
265d9f0492fSopenharmony_ci    PARAM_CHECK(ops != NULL, return -1, "Invalid param");
266d9f0492fSopenharmony_ci    int ret = PARAM_STRCPY(ops->name, sizeof(ops->name), "selinux");
267d9f0492fSopenharmony_ci    ops->securityGetLabel = NULL;
268d9f0492fSopenharmony_ci    ops->securityInitLabel = InitLocalSecurityLabel;
269d9f0492fSopenharmony_ci    ops->securityCheckFilePermission = CheckFilePermission;
270d9f0492fSopenharmony_ci    if (GetParamWorkSpace()->ops.updaterMode == 1) {
271d9f0492fSopenharmony_ci        ops->securityCheckParamPermission = UpdaterCheckParamPermission;
272d9f0492fSopenharmony_ci    } else {
273d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST
274d9f0492fSopenharmony_ci        ops->securityCheckParamPermission = SelinuxCheckParamPermission;
275d9f0492fSopenharmony_ci#endif
276d9f0492fSopenharmony_ci    }
277d9f0492fSopenharmony_ci    ops->securityFreeLabel = FreeLocalSecurityLabel;
278d9f0492fSopenharmony_ci    if (isInit != 0) {
279d9f0492fSopenharmony_ci        ops->securityGetLabel = SelinuxGetParamSecurityLabelForInit;
280d9f0492fSopenharmony_ci    } else {
281d9f0492fSopenharmony_ci        ops->securityGetLabel = SelinuxGetParamSecurityLabelForOther;
282d9f0492fSopenharmony_ci    }
283d9f0492fSopenharmony_ci    return ret;
284d9f0492fSopenharmony_ci}
285