diff --git a/BUILD.gn b/BUILD.gn index 075a9553..e36ea3dc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -250,6 +250,7 @@ config("container_config") { "-DLOSCFG_CHROOT", "-DLOSCFG_IPC_CONTAINER", "-DLOSCFG_TIME_CONTAINER", + "-DLOSCFG_USER_CONTAINER", "-DLOSCFG_PROC_PROCESS_DIR", ] } diff --git a/fs/proc/os_adapt/process_proc.c b/fs/proc/os_adapt/process_proc.c index d3958024..9adfa6b3 100644 --- a/fs/proc/os_adapt/process_proc.c +++ b/fs/proc/os_adapt/process_proc.c @@ -46,6 +46,11 @@ typedef enum { #ifdef LOSCFG_KERNEL_CPUP PROC_PID_CPUP, #endif +#ifdef LOSCFG_USER_CONTAINER + PROC_UID_MAP, + PROC_GID_MAP, +#endif + PROC_P_TYPE_MAX, } ProcessDataType; struct ProcProcess { @@ -84,6 +89,8 @@ static ssize_t ProcessContainerLink(unsigned int containerID, ContainerType type count = snprintf_s(buffer, bufLen, bufLen - 1, "'ipc:[%u]'", containerID); } else if ((type == TIME_CONTAINER) || (type == TIME_CHILD_CONTAINER)) { count = snprintf_s(buffer, bufLen, bufLen - 1, "'time:[%u]'", containerID); + } else if (type == USER_CONTAINER) { + count = snprintf_s(buffer, bufLen, bufLen - 1, "'user:[%u]'", containerID); } if (count < 0) { @@ -105,7 +112,7 @@ static ssize_t ProcessContainerReadLink(struct ProcDirEntry *entry, char *buffer } LosProcessCB *processCB = ProcGetProcessCB(data); SCHEDULER_LOCK(intSave); - UINT32 containerID = OsGetContainerID(processCB->container, (ContainerType)data->type); + UINT32 containerID = OsGetContainerID(processCB, (ContainerType)data->type); SCHEDULER_UNLOCK(intSave); if (containerID != OS_INVALID_VALUE) { return ProcessContainerLink(containerID, (ContainerType)data->type, buffer, bufLen); @@ -320,6 +327,121 @@ static const struct ProcFileOperations TIME_CONTAINER_FOPS = { }; #endif +#ifdef LOSCFG_USER_CONTAINER + +static void *MemdupUserNul(const void *src, size_t len) +{ + char *des = NULL; + if (len <= 0) { + return NULL; + } + des = LOS_MemAlloc(OS_SYS_MEM_ADDR, len + 1); + if (des == NULL) { + return NULL; + } + + if (LOS_ArchCopyFromUser(des, src, len) != 0) { + (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, des); + return NULL; + } + + des[len] = '\0'; + return des; +} + +static LosProcessCB *ProcUidGidMapWriteCheck(struct ProcFile *pf, const char *buf, size_t size, + char **kbuf, ProcessDataType *type) +{ + if ((pf == NULL) || (size <= 0) || (size >= PAGE_SIZE)) { + return NULL; + } + + struct ProcDirEntry *entry = pf->pPDE; + if (entry == NULL) { + return NULL; + } + + struct ProcessData *data = (struct ProcessData *)entry->data; + if (data == NULL) { + return NULL; + } + + *kbuf = MemdupUserNul(buf, size); + if (*kbuf == NULL) { + return NULL; + } + *type = (ProcessDataType)data->type; + return ProcGetProcessCB(data); +} + +static ssize_t ProcIDMapWrite(struct ProcFile *file, const char *buf, size_t size, loff_t *ppos) +{ + (void)ppos; + char *kbuf = NULL; + int ret; + unsigned int intSave; + ProcessDataType type = PROC_P_TYPE_MAX; + LosProcessCB *processCB = ProcUidGidMapWriteCheck(file, buf, size, &kbuf, &type); + if (processCB == NULL) { + return -EINVAL; + } + + SCHEDULER_LOCK(intSave); + if ((processCB->credentials == NULL) || (processCB->credentials->userContainer == NULL)) { + SCHEDULER_UNLOCK(intSave); + (void)LOS_MemFree(m_aucSysMem1, kbuf); + return -EINVAL; + } + UserContainer *userContainer = processCB->credentials->userContainer; + if (userContainer->parent == NULL) { + SCHEDULER_UNLOCK(intSave); + (void)LOS_MemFree(m_aucSysMem1, kbuf); + return -EPERM; + } + if (type == PROC_UID_MAP) { + ret = OsUserContainerMapWrite(file, kbuf, size, CAP_SETUID, + &userContainer->uidMap, &userContainer->parent->uidMap); + } else { + ret = OsUserContainerMapWrite(file, kbuf, size, CAP_SETGID, + &userContainer->gidMap, &userContainer->parent->gidMap); + } + SCHEDULER_UNLOCK(intSave); + (void)LOS_MemFree(m_aucSysMem1, kbuf); + return ret; +} + +static int ProcIDMapRead(struct SeqBuf *seqBuf, void *v) +{ + unsigned int intSave; + if ((seqBuf == NULL) || (v == NULL)) { + return -EINVAL; + } + struct ProcessData *data = (struct ProcessData *)v; + LosProcessCB *processCB = ProcGetProcessCB(data); + + SCHEDULER_LOCK(intSave); + if ((processCB->credentials == NULL) || (processCB->credentials->userContainer == NULL)) { + SCHEDULER_UNLOCK(intSave); + return -EINVAL; + } + UserContainer *userContainer = processCB->credentials->userContainer; + if ((userContainer != NULL) && (userContainer->parent == NULL)) { + UidGidExtent uidGidExtent = userContainer->uidMap.extent[0]; + SCHEDULER_UNLOCK(intSave); + (void)LosBufPrintf(seqBuf, "%d %d %u\n", uidGidExtent.first, uidGidExtent.lowerFirst, + uidGidExtent.count); + return 0; + } + SCHEDULER_LOCK(intSave); + return 0; +} + +static const struct ProcFileOperations UID_GID_MAP_FOPS = { + .read = ProcIDMapRead, + .write = ProcIDMapWrite, +}; +#endif + static int ProcProcessRead(struct SeqBuf *m, void *v) { if ((m == NULL) || (v == NULL)) { @@ -432,6 +554,26 @@ static struct ProcProcess g_procProcess[] = { .fileOps = &TIME_CONTAINER_FOPS }, #endif +#ifdef LOSCFG_IPC_CONTAINER + { + .name = "container/user", + .mode = S_IFLNK, + .type = USER_CONTAINER, + .fileOps = &PID_CONTAINER_FOPS + }, + { + .name = "uid_map", + .mode = 0, + .type = PROC_UID_MAP, + .fileOps = &UID_GID_MAP_FOPS + }, + { + .name = "gid_map", + .mode = 0, + .type = PROC_GID_MAP, + .fileOps = &UID_GID_MAP_FOPS + }, +#endif #endif }; diff --git a/kernel/Kconfig b/kernel/Kconfig index 7653b945..4fcd60f7 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -103,6 +103,11 @@ config TIME_CONTAINER default n depends on KERNEL_CONTAINER +config USER_CONTAINER + bool "Enable user container" + default n + depends on KERNEL_CONTAINER + ######################### config options of extended ##################### source "kernel/extended/Kconfig" diff --git a/kernel/base/BUILD.gn b/kernel/base/BUILD.gn index 3371b054..cd87af0c 100644 --- a/kernel/base/BUILD.gn +++ b/kernel/base/BUILD.gn @@ -33,10 +33,12 @@ module_name = get_path_info(rebase_path("."), "name") kernel_module(module_name) { sources = [ "container/los_container.c", + "container/los_credentials.c", "container/los_ipc_container.c", "container/los_mnt_container.c", "container/los_pid_container.c", "container/los_time_container.c", + "container/los_user_container.c", "container/los_uts_container.c", "core/los_bitmap.c", "core/los_info.c", diff --git a/kernel/base/container/los_container.c b/kernel/base/container/los_container.c index da091158..7f374016 100644 --- a/kernel/base/container/los_container.c +++ b/kernel/base/container/los_container.c @@ -34,6 +34,9 @@ STATIC Container g_rootContainer; STATIC Atomic g_containerCount = 0xF0000000U; +#ifdef LOSCFG_USER_CONTAINER +STATIC Credentials *g_rootCredentials = NULL; +#endif UINT32 OsAllocContainerID(VOID) { @@ -43,6 +46,9 @@ UINT32 OsAllocContainerID(VOID) VOID OsContainerInitSystemProcess(LosProcessCB *processCB) { processCB->container = &g_rootContainer; +#ifdef LOSCFG_USER_CONTAINER + processCB->credentials = g_rootCredentials; +#endif LOS_AtomicInc(&processCB->container->rc); #ifdef LOSCFG_PID_CONTAINER (VOID)OsAllocSpecifiedVpidUnsafe(processCB->processID, processCB->container->pidContainer, processCB, NULL); @@ -52,6 +58,9 @@ VOID OsContainerInitSystemProcess(LosProcessCB *processCB) VOID OsInitRootContainer(VOID) { +#ifdef LOSCFG_USER_CONTAINER + OsInitRootUserCredentials(&g_rootCredentials); +#endif #ifdef LOSCFG_PID_CONTAINER (VOID)OsInitRootPidContainer(&g_rootContainer.pidContainer); g_rootContainer.pidForChildContainer = g_rootContainer.pidContainer; @@ -95,6 +104,12 @@ STATIC UINT32 CopyContainers(UINTPTR flags, LosProcessCB *child, LosProcessCB *p return ret; } #endif +#ifdef LOSCFG_USER_CONTAINER + ret = OsCopyCredentials(flags, child, parent); + if (ret != LOS_OK) { + return ret; + } +#endif #ifdef LOSCFG_UTS_CONTAINER ret = OsCopyUtsContainer(flags, child, parent); if (ret != LOS_OK) { @@ -182,6 +197,10 @@ VOID OsContainersDestroy(LosProcessCB *processCB) } #endif +#ifdef LOSCFG_USER_CONTAINER + OsUserContainerDestroy(processCB); +#endif + #ifdef LOSCFG_UTS_CONTAINER OsUtsContainerDestroy(processCB->container); #endif @@ -245,8 +264,9 @@ STATIC VOID DeInitContainers(UINT32 flags, Container *container, LosProcessCB *p SCHEDULER_UNLOCK(intSave); } -UINT32 OsGetContainerID(Container *container, ContainerType type) +UINT32 OsGetContainerID(LosProcessCB *processCB, ContainerType type) { + Container *container = processCB->container; if (container == NULL) { return OS_INVALID_VALUE; } @@ -258,6 +278,10 @@ UINT32 OsGetContainerID(Container *container, ContainerType type) case PID_CHILD_CONTAINER: return OsGetPidContainerID(container->pidForChildContainer); #endif +#ifdef LOSCFG_USER_CONTAINER + case USER_CONTAINER: + return OsGetUserContainerID(processCB->credentials); +#endif #ifdef LOSCFG_UTS_CONTAINER case UTS_CONTAINER: return OsGetUtsContainerID(container->utsContainer); @@ -324,12 +348,22 @@ INT32 OsUnshare(UINT32 flags) UINT32 intSave; LosProcessCB *curr = OsCurrProcessGet(); Container *oldContainer = curr->container; - UINT32 unshareFlags = CLONE_NEWPID | CLONE_NEWTIME | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWIPC; + UINT32 unshareFlags = CLONE_NEWPID | CLONE_NEWTIME | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUSER; if (!(flags & unshareFlags) || ((flags & (~unshareFlags)) != 0)) { return -EINVAL; } +#ifdef LOSCFG_USER_CONTAINER + ret = OsUnshareUserCredentials(flags, curr); + if (ret != LOS_OK) { + return ret; + } + if (flags == CLONE_NEWUSER) { + return LOS_OK; + } +#endif + Container *newContainer = CreateContainer(); if (newContainer == NULL) { return -ENOMEM; @@ -363,6 +397,8 @@ STATIC UINT32 SetNsGetFlagByContainerType(UINT32 containerType) case PID_CONTAINER: case PID_CHILD_CONTAINER: return CLONE_NEWPID; + case USER_CONTAINER: + return CLONE_NEWUSER; case UTS_CONTAINER: return CLONE_NEWUTS; case MNT_CONTAINER: @@ -414,27 +450,65 @@ STATIC UINT32 SetNsCreateNewContainers(UINT32 flags, Container *newContainer, Co return LOS_OK; } -INT32 OsSetNs(INT32 fd, INT32 type) +STATIC UINT32 SetNsParamCheck(INT32 fd, INT32 type, UINT32 *flag, LosProcessCB **target) { - UINT32 intSave; - UINT32 typeMask = CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWTIME; + UINT32 typeMask = CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWTIME | CLONE_NEWUSER; + *flag = (UINT32)(type & typeMask); UINT32 containerType = 0; - UINT32 flag = (UINT32)(type & typeMask); - LosProcessCB *curr = OsCurrProcessGet(); if (((type & (~typeMask)) != 0)) { - return -EINVAL; - } - - Container *newContainer = CreateContainer(); - if (newContainer == NULL) { - return -ENOMEM; + return EINVAL; } LosProcessCB *processCB = (LosProcessCB *)ProcfsContainerGet(fd, &containerType); if (processCB == NULL) { - (VOID)LOS_MemFree(m_aucSysMem1, newContainer); - return -EBADF; + return EBADF; + } + + if (*flag == 0) { + *flag = SetNsGetFlagByContainerType(containerType); + } + + if ((*flag == 0) || (*flag != SetNsGetFlagByContainerType(containerType))) { + return EINVAL; + } + + if (processCB == OsCurrProcessGet()) { + return EINVAL; + } + *target = processCB; + return LOS_OK; +} + +INT32 OsSetNs(INT32 fd, INT32 type) +{ + UINT32 intSave, ret; + UINT32 flag = 0; + LosProcessCB *curr = OsCurrProcessGet(); + LosProcessCB *processCB = NULL; + + ret = SetNsParamCheck(fd, type, &flag, &processCB); + if (ret != LOS_OK) { + return -ret; + } + +#ifdef LOSCFG_USER_CONTAINER + if (flag == CLONE_NEWUSER) { + SCHEDULER_LOCK(intSave); + if ((processCB->credentials == NULL) || (processCB->credentials->userContainer == NULL)) { + SCHEDULER_UNLOCK(intSave); + return -EBADF; + } + UserContainer *userContainer = processCB->credentials->userContainer; + ret = OsSetNsUserContainer(userContainer, curr); + SCHEDULER_UNLOCK(intSave); + return ret; + } +#endif + + Container *newContainer = CreateContainer(); + if (newContainer == NULL) { + return -ENOMEM; } SCHEDULER_LOCK(intSave); @@ -444,16 +518,7 @@ INT32 OsSetNs(INT32 fd, INT32 type) return -EBADF; } - if (flag == 0) { - flag = SetNsGetFlagByContainerType(containerType); - } - - if ((flag == 0) || (flag != SetNsGetFlagByContainerType(containerType)) || (targetContainer == curr->container)) { - SCHEDULER_UNLOCK(intSave); - return -EBADF; - } - - UINT32 ret = SetNsCreateNewContainers(flag, newContainer, targetContainer); + ret = SetNsCreateNewContainers(flag, newContainer, targetContainer); if (ret != LOS_OK) { SCHEDULER_UNLOCK(intSave); goto EXIT; diff --git a/kernel/base/container/los_credentials.c b/kernel/base/container/los_credentials.c new file mode 100644 index 00000000..0a7c3a66 --- /dev/null +++ b/kernel/base/container/los_credentials.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "los_credentials_pri.h" +#include "los_user_container_pri.h" +#include "los_config.h" +#include "los_memory.h" +#include "los_process_pri.h" + +#ifdef LOSCFG_USER_CONTAINER +STATIC Credentials *CreateNewCredential(LosProcessCB *parent) +{ + UINT32 size = sizeof(Credentials); + Credentials *newCredentials = LOS_MemAlloc(m_aucSysMem1, size); + if (newCredentials == NULL) { + return NULL; + } + + if (parent != NULL) { + const Credentials *oldCredentials = parent->credentials; + (VOID)memcpy_s(newCredentials, sizeof(Credentials), oldCredentials, sizeof(Credentials)); + LOS_AtomicSet(&newCredentials->rc, 1); + } else { + (VOID)memset_s(newCredentials, sizeof(Credentials), 0, sizeof(Credentials)); + LOS_AtomicSet(&newCredentials->rc, 3); /* 3: Three system processes */ + } + newCredentials->userContainer = NULL; + return newCredentials; +} + +Credentials *PrepareCredential(LosProcessCB *runProcessCB) +{ + Credentials *newCredentials = CreateNewCredential(runProcessCB); + if (newCredentials == NULL) { + return NULL; + } + + newCredentials->userContainer = runProcessCB->credentials->userContainer; + LOS_AtomicInc(&newCredentials->userContainer->rc); + return newCredentials; +} + +VOID FreeCredential(Credentials *credentials) +{ + if (credentials == NULL) { + return; + } + + if (credentials->userContainer != NULL) { + LOS_AtomicDec(&credentials->userContainer->rc); + if (LOS_AtomicRead(&credentials->userContainer->rc) <= 0) { + FreeUserContainer(credentials->userContainer); + credentials->userContainer = NULL; + } + } + + LOS_AtomicDec(&credentials->rc); + if (LOS_AtomicRead(&credentials->rc) <= 0) { + (VOID)LOS_MemFree(m_aucSysMem1, credentials); + } +} + +VOID OsUserContainerDestroy(LosProcessCB *curr) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + FreeCredential(curr->credentials); + curr->credentials = NULL; + SCHEDULER_UNLOCK(intSave); + return; +} + +STATIC Credentials *CreateCredentials(unsigned long flags, LosProcessCB *parent) +{ + UINT32 ret; + Credentials *newCredentials = CreateNewCredential(parent); + if (newCredentials == NULL) { + return NULL; + } + + if (!(flags & CLONE_NEWUSER)) { + newCredentials->userContainer = parent->credentials->userContainer; + LOS_AtomicInc(&newCredentials->userContainer->rc); + return newCredentials; + } + + if (parent != NULL) { + ret = OsCreateUserContainer(newCredentials, parent->credentials->userContainer); + } else { + ret = OsCreateUserContainer(newCredentials, NULL); + } + if (ret != LOS_OK) { + FreeCredential(newCredentials); + return NULL; + } + return newCredentials; +} + +UINT32 OsCopyCredentials(unsigned long flags, LosProcessCB *child, LosProcessCB *parent) +{ + UINT32 intSave; + + SCHEDULER_LOCK(intSave); + child->credentials = CreateCredentials(flags, parent); + SCHEDULER_UNLOCK(intSave); + if (child->credentials == NULL) { + return ENOMEM; + } + return LOS_OK; +} + +UINT32 OsInitRootUserCredentials(Credentials **credentials) +{ + *credentials = CreateCredentials(CLONE_NEWUSER, NULL); + if (*credentials == NULL) { + return ENOMEM; + } + return LOS_OK; +} + +UINT32 OsUnshareUserCredentials(UINTPTR flags, LosProcessCB *curr) +{ + UINT32 intSave; + if (!(flags & CLONE_NEWUSER)) { + return LOS_OK; + } + + SCHEDULER_LOCK(intSave); + UINT32 ret = OsCreateUserContainer(curr->credentials, curr->credentials->userContainer); + SCHEDULER_UNLOCK(intSave); + return ret; +} + +UINT32 OsSetNsUserContainer(struct UserContainer *targetContainer, LosProcessCB *runProcess) +{ + Credentials *oldCredentials = runProcess->credentials; + Credentials *newCredentials = CreateNewCredential(runProcess); + if (newCredentials == NULL) { + return ENOMEM; + } + + runProcess->credentials = newCredentials; + newCredentials->userContainer = targetContainer; + LOS_AtomicInc(&targetContainer->rc); + FreeCredential(oldCredentials); + return LOS_OK; +} + +UINT32 OsGetUserContainerID(Credentials *credentials) +{ + if ((credentials == NULL) || (credentials->userContainer == NULL)) { + return OS_INVALID_VALUE; + } + + return credentials->userContainer->containerID; +} + +INT32 CommitCredentials(Credentials *newCredentials) +{ + Credentials *oldCredentials = OsCurrProcessGet()->credentials; + + if (LOS_AtomicRead(&newCredentials->rc) < 1) { + return -EINVAL; + } + + OsCurrProcessGet()->credentials = newCredentials; + FreeCredential(oldCredentials); + return 0; +} + +Credentials *CurrentCredentials(VOID) +{ + return OsCurrProcessGet()->credentials; +} + +UserContainer *OsCurrentUserContainer(VOID) +{ + UserContainer *userContainer = OsCurrProcessGet()->credentials->userContainer; + return userContainer; +} +#endif diff --git a/kernel/base/container/los_user_container.c b/kernel/base/container/los_user_container.c new file mode 100644 index 00000000..5101171a --- /dev/null +++ b/kernel/base/container/los_user_container.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "los_user_container_pri.h" +#include "errno.h" +#include "ctype.h" +#include "los_config.h" +#include "los_memory.h" +#include "proc_fs.h" +#include "user_copy.h" +#include "los_seq_buf.h" +#include "capability_type.h" +#include "capability_api.h" +#include "internal.h" + +#define DEFAULT_OVERFLOWUID 65534 +#define DEFAULT_OVERFLOWGID 65534 +#define LEVEL_MAX 3 +#define HEX 16 +#define OCT 8 +#define DEC 10 + +#ifdef LOSCFG_USER_CONTAINER +UINT32 g_currentUserContainerNum = 1; + +UINT32 OsCreateUserContainer(Credentials *newCredentials, UserContainer *parentUserContainer) +{ + if ((parentUserContainer != NULL) && (parentUserContainer->level >= LEVEL_MAX)) { + return EINVAL; + } + + if ((newCredentials->euid < 0) || (newCredentials->egid < 0)) { + return EINVAL; + } + + UserContainer *userContainer = LOS_MemAlloc(m_aucSysMem1, sizeof(UserContainer)); + if (userContainer == NULL) { + return ENOMEM; + } + (VOID)memset_s(userContainer, sizeof(UserContainer), 0, sizeof(UserContainer)); + + g_currentUserContainerNum++; + userContainer->containerID = OsAllocContainerID(); + userContainer->parent = parentUserContainer; + newCredentials->userContainer = userContainer; + if (parentUserContainer != NULL) { + LOS_AtomicInc(&parentUserContainer->rc); + LOS_AtomicSet(&userContainer->rc, 1); + userContainer->level = parentUserContainer->level + 1; + userContainer->owner = newCredentials->euid; + userContainer->group = newCredentials->egid; + } else { + LOS_AtomicSet(&userContainer->rc, 3); /* 3: Three system processes */ + userContainer->uidMap.extentCount = 1; + userContainer->uidMap.extent[0].count = 4294967295U; + userContainer->gidMap.extentCount = 1; + userContainer->gidMap.extent[0].count = 4294967295U; + } + return LOS_OK; +} + +VOID FreeUserContainer(UserContainer *userContainer) +{ + UserContainer *parent = NULL; + do { + parent = userContainer->parent; + (VOID)LOS_MemFree(m_aucSysMem1, userContainer); + userContainer->parent = NULL; + userContainer = parent; + g_currentUserContainerNum--; + } while ((userContainer != NULL) && (LOS_AtomicRead(&userContainer->rc) <= 0)); +} + +STATIC UidGidExtent *MapIdUpBase(UINT32 extents, UidGidMap *map, UINT32 id) +{ + UINT32 idx; + UINT32 first; + UINT32 last; + + for (idx = 0; idx < extents; idx++) { + first = map->extent[idx].lowerFirst; + last = first + map->extent[idx].count - 1; + if ((id >= first) && (id <= last)) { + return &map->extent[idx]; + } + } + return NULL; +} + +STATIC UINT32 MapIdUp(UidGidMap *map, UINT32 id) +{ + UINT32 extents = map->extentCount; + if (extents > UID_GID_MAP_MAX_EXTENTS) { + return (UINT32)-1; + } + + UidGidExtent *extent = MapIdUpBase(extents, map, id); + if (extent != NULL) { + return ((id - extent->lowerFirst) + extent->first); + } + + return (UINT32)-1; +} + +UINT32 FromKuid(UserContainer *userContainer, UINT32 kuid) +{ + return MapIdUp(&userContainer->uidMap, kuid); +} + +UINT32 FromKgid(UserContainer *userContainer, UINT32 kgid) +{ + return MapIdUp(&userContainer->gidMap, kgid); +} + +UINT32 OsFromKuidMunged(UserContainer *userContainer, UINT32 kuid) +{ + UINT32 uid = FromKuid(userContainer, kuid); + if (uid == (UINT32)-1) { + uid = DEFAULT_OVERFLOWUID; + } + return uid; +} + +UINT32 OsFromKgidMunged(UserContainer *userContainer, UINT32 kgid) +{ + UINT32 gid = FromKgid(userContainer, kgid); + if (gid == (UINT32)-1) { + gid = DEFAULT_OVERFLOWGID; + } + return gid; +} + +STATIC UidGidExtent *MapIdRangeDownBase(UINT32 extents, UidGidMap *map, UINT32 id, UINT32 count) +{ + UINT32 idx; + UINT32 first; + UINT32 last; + UINT32 id2; + + id2 = id + count - 1; + for (idx = 0; idx < extents; idx++) { + first = map->extent[idx].first; + last = first + map->extent[idx].count - 1; + if ((id >= first && id <= last) && (id2 >= first && id2 <= last)) { + return &map->extent[idx]; + } + } + return NULL; +} + +STATIC UINT32 MapIdRangeDown(UidGidMap *map, UINT32 id, UINT32 count) +{ + UINT32 extents = map->extentCount; + if (extents > UID_GID_MAP_MAX_EXTENTS) { + return (UINT32)-1; + } + + UidGidExtent *extent = MapIdRangeDownBase(extents, map, id, count); + if (extent != NULL) { + return ((id - extent->first) + extent->lowerFirst); + } + + return (UINT32)-1; +} + +STATIC UINT32 MapIdDown(UidGidMap *map, UINT32 id) +{ + return MapIdRangeDown(map, id, 1); +} + +UINT32 OsMakeKuid(UserContainer *userContainer, UINT32 uid) +{ + return MapIdDown(&userContainer->uidMap, uid); +} + +UINT32 OsMakeKgid(UserContainer *userContainer, UINT32 gid) +{ + return MapIdDown(&userContainer->gidMap, gid); +} + +STATIC INT32 InsertExtent(UidGidMap *idMap, UidGidExtent *extent) +{ + if (idMap->extentCount > UID_GID_MAP_MAX_EXTENTS) { + return -EINVAL; + } + + UidGidExtent *dest = &idMap->extent[idMap->extentCount]; + *dest = *extent; + idMap->extentCount++; + + return 0; +} + +STATIC BOOL MappingsOverlap(UidGidMap *idMap, UidGidExtent *extent) +{ + UINT32 upperFirst = extent->first; + UINT32 lowerFirst = extent->lowerFirst; + UINT32 upperLast = upperFirst + extent->count - 1; + UINT32 lowerLast = lowerFirst + extent->count - 1; + INT32 idx; + + for (idx = 0; idx < idMap->extentCount; idx++) { + if (idMap->extentCount > UID_GID_MAP_MAX_EXTENTS) { + return TRUE; + } + UidGidExtent *prev = &idMap->extent[idx]; + UINT32 prevUpperFirst = prev->first; + UINT32 prevLowerFirst = prev->lowerFirst; + UINT32 prevUpperLast = prevUpperFirst + prev->count - 1; + UINT32 prevLowerLast = prevLowerFirst + prev->count - 1; + + if ((prevUpperFirst <= upperLast) && (prevUpperLast >= upperFirst)) { + return TRUE; + } + + if ((prevLowerFirst <= lowerLast) && (prevLowerLast >= lowerFirst)) { + return TRUE; + } + } + return FALSE; +} + +STATIC CHAR *SkipSpaces(const CHAR *str) +{ + while (isspace(*str)) { + ++str; + } + + return (CHAR *)str; +} + +STATIC UINTPTR StrToUInt(const CHAR *str, CHAR **endp, UINT32 base) +{ + unsigned long result = 0; + unsigned long value; + + if (*str == '0') { + str++; + if ((*str == 'x') && isxdigit(str[1])) { + base = HEX; + str++; + } + if (!base) { + base = OCT; + } + } + if (!base) { + base = DEC; + } + while (isxdigit(*str) && (value = isdigit(*str) ? *str - '0' : (islower(*str) ? + toupper(*str) : *str) - 'A' + DEC) < base) { + result = result * base + value; + str++; + } + if (endp != NULL) { + *endp = (CHAR *)str; + } + return result; +} + +STATIC INT32 ParsePosData(CHAR *pos, UidGidExtent *extent) +{ + INT32 ret = -EINVAL; + pos = SkipSpaces(pos); + extent->first = StrToUInt(pos, &pos, DEC); + if (!isspace(*pos)) { + return ret; + } + + pos = SkipSpaces(pos); + extent->lowerFirst = StrToUInt(pos, &pos, DEC); + if (!isspace(*pos)) { + return ret; + } + + pos = SkipSpaces(pos); + extent->count = StrToUInt(pos, &pos, DEC); + if (*pos && !isspace(*pos)) { + return ret; + } + + pos = SkipSpaces(pos); + if (*pos != '\0') { + return ret; + } + return LOS_OK; +} + +STATIC INT32 ParseUserData(CHAR *kbuf, UidGidExtent *extent, UidGidMap *newMap) +{ + INT32 ret = -EINVAL; + CHAR *pos = NULL; + CHAR *nextLine = NULL; + + for (pos = kbuf; pos != NULL; pos = nextLine) { + nextLine = strchr(pos, '\n'); + if (nextLine != NULL) { + *nextLine = '\0'; + nextLine++; + if (*nextLine == '\0') { + nextLine = NULL; + } + } + + if (ParsePosData(pos, extent) != LOS_OK) { + return ret; + } + + if ((extent->first == (UINT32)-1) || (extent->lowerFirst == (UINT32)-1)) { + return ret; + } + + if ((extent->first + extent->count) <= extent->first) { + return ret; + } + + if ((extent->lowerFirst + extent->count) <= extent->lowerFirst) { + return ret; + } + + if (MappingsOverlap(newMap, extent)) { + return ret; + } + + if ((newMap->extentCount + 1) == UID_GID_MAP_MAX_EXTENTS && (nextLine != NULL)) { + return ret; + } + + ret = InsertExtent(newMap, extent); + if (ret < 0) { + return ret; + } + ret = 0; + } + + if (newMap->extentCount == 0) { + return -EINVAL; + } + + return ret; +} + +STATIC INT32 ParentMapIdRange(UidGidMap *newMap, UidGidMap *parentMap) +{ + UINT32 idx; + INT32 ret = -EPERM; + for (idx = 0; idx < newMap->extentCount; idx++) { + if (newMap->extentCount > UID_GID_MAP_MAX_EXTENTS) { + return ret; + } + + UidGidExtent *extent = &newMap->extent[idx]; + UINT32 lowerFirst = MapIdRangeDown(parentMap, extent->lowerFirst, extent->count); + if (lowerFirst == (UINT32) -1) { + return ret; + } + + extent->lowerFirst = lowerFirst; + } + return 0; +} + +INT32 OsUserContainerMapWrite(struct ProcFile *fp, CHAR *kbuf, size_t count, + INT32 capSetid, UidGidMap *map, UidGidMap *parentMap) +{ + UidGidMap newMap = {0}; + UidGidExtent extent; + INT32 ret; + + if (map->extentCount != 0) { + return -EPERM; + } + + if (!IsCapPermit(capSetid)) { + return -EPERM; + } + + ret = ParseUserData(kbuf, &extent, &newMap); + if (ret < 0) { + return -EPERM; + } + + ret = ParentMapIdRange(&newMap, parentMap); + if (ret < 0) { + return -EPERM; + } + + if (newMap.extentCount <= UID_GID_MAP_MAX_EXTENTS) { + size_t mapSize = newMap.extentCount * sizeof(newMap.extent[0]); + ret = memcpy_s(map->extent, sizeof(map->extent), newMap.extent, mapSize); + if (ret != EOK) { + return -EPERM; + } + } + + map->extentCount = newMap.extentCount; + return count; +} +#endif diff --git a/kernel/base/core/los_process.c b/kernel/base/core/los_process.c index 016da592..cddf2b51 100644 --- a/kernel/base/core/los_process.c +++ b/kernel/base/core/los_process.c @@ -822,7 +822,11 @@ LITE_OS_SEC_TEXT INT32 LOS_GetUserID(VOID) INT32 uid; SCHEDULER_LOCK(intSave); +#ifdef LOSCFG_USER_CONTAINER + uid = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->uid); +#else uid = (INT32)OsCurrUserGet()->userID; +#endif SCHEDULER_UNLOCK(intSave); return uid; #else @@ -837,7 +841,11 @@ LITE_OS_SEC_TEXT INT32 LOS_GetGroupID(VOID) INT32 gid; SCHEDULER_LOCK(intSave); +#ifdef LOSCFG_USER_CONTAINER + gid = OsFromKgidMunged(OsCurrentUserContainer(), CurrentCredentials()->gid); +#else gid = (INT32)OsCurrUserGet()->gid; +#endif SCHEDULER_UNLOCK(intSave); return gid; @@ -2123,6 +2131,9 @@ LITE_OS_SEC_TEXT INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size) #ifdef LOSCFG_TIME_CONTAINER cloneFlag |= CLONE_NEWTIME; #endif +#ifdef LOSCFG_USER_CONTAINER + cloneFlag |= CLONE_NEWUSER; +#endif #endif if (flags & (~cloneFlag)) { diff --git a/kernel/base/include/los_container_pri.h b/kernel/base/include/los_container_pri.h index 68e166f1..7e8ebd8a 100644 --- a/kernel/base/include/los_container_pri.h +++ b/kernel/base/include/los_container_pri.h @@ -45,6 +45,9 @@ #ifdef LOSCFG_IPC_CONTAINER #include "los_ipc_container_pri.h" #endif +#ifdef LOSCFG_USER_CONTAINER +#include "los_user_container_pri.h" +#endif #ifdef LOSCFG_TIME_CONTAINER #include "los_time_container_pri.h" #endif @@ -56,6 +59,7 @@ typedef enum { UTS_CONTAINER, MNT_CONTAINER, IPC_CONTAINER, + USER_CONTAINER, TIME_CONTAINER, TIME_CHILD_CONTAINER, CONTAINER_MAX, @@ -94,7 +98,7 @@ VOID OsContainerFree(LosProcessCB *processCB); UINT32 OsAllocContainerID(VOID); -UINT32 OsGetContainerID(Container *container, ContainerType type); +UINT32 OsGetContainerID(LosProcessCB *processCB, ContainerType type); INT32 OsUnshare(UINT32 flags); diff --git a/kernel/base/include/los_credentials_pri.h b/kernel/base/include/los_credentials_pri.h new file mode 100644 index 00000000..bbdc49fb --- /dev/null +++ b/kernel/base/include/los_credentials_pri.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LOS_CREDENTIALS_PRI_H +#define _LOS_CREDENTIALS_PRI_H + +#include "los_atomic.h" +#include "los_list.h" + +#ifdef LOSCFG_USER_CONTAINER +struct Container; +struct UserContainer; +typedef struct ProcessCB LosProcessCB; + +typedef struct Credentials { + Atomic rc; + UINT32 uid; + UINT32 gid; + UINT32 euid; + UINT32 egid; + struct UserContainer *userContainer; +} Credentials; + +UINT32 OsCopyCredentials(unsigned long flags, LosProcessCB *child, LosProcessCB *parent); + +UINT32 OsInitRootUserCredentials(Credentials **credentials); + +UINT32 OsUnshareUserCredentials(UINTPTR flags, LosProcessCB *curr); + +UINT32 OsSetNsUserContainer(struct UserContainer *targetContainer, LosProcessCB *runProcess); + +VOID FreeCredential(Credentials *credentials); + +VOID OsUserContainerDestroy(LosProcessCB *curr); + +UINT32 OsGetUserContainerID(Credentials *credentials); + +Credentials *PrepareCredential(LosProcessCB *runProcessCB); + +INT32 CommitCredentials(Credentials *newCredentials); + +Credentials *CurrentCredentials(VOID); + +struct UserContainer *OsCurrentUserContainer(VOID); +#endif +#endif /* _LOS_CREDENTIALS_PRI_H */ diff --git a/kernel/base/include/los_process_pri.h b/kernel/base/include/los_process_pri.h index ecf2d049..a75836a6 100644 --- a/kernel/base/include/los_process_pri.h +++ b/kernel/base/include/los_process_pri.h @@ -132,6 +132,9 @@ typedef struct ProcessCB { struct rlimit *resourceLimit; #ifdef LOSCFG_KERNEL_CONTAINER Container *container; +#ifdef LOSCFG_USER_CONTAINER + struct Credentials *credentials; +#endif #endif #ifdef LOSCFG_PROC_PROCESS_DIR struct ProcDirEntry *procDir; diff --git a/kernel/base/include/los_user_container_pri.h b/kernel/base/include/los_user_container_pri.h new file mode 100644 index 00000000..bdc38904 --- /dev/null +++ b/kernel/base/include/los_user_container_pri.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LOS_USER_CONTAINER_PRI_H +#define _LOS_USER_CONTAINER_PRI_H + +#include "los_atomic.h" +#include "los_credentials_pri.h" + +#define UID_GID_MAP_MAX_EXTENTS 5 + +#ifdef LOSCFG_USER_CONTAINER +struct ProcFile; + +typedef struct UidGidExtent { + UINT32 first; + UINT32 lowerFirst; + UINT32 count; +} UidGidExtent; + +typedef struct UidGidMap { + UINT32 extentCount; + union { + UidGidExtent extent[UID_GID_MAP_MAX_EXTENTS]; + }; +} UidGidMap; + +typedef struct UserContainer { + Atomic rc; + INT32 level; + UINT32 owner; + UINT32 group; + struct UserContainer *parent; + UidGidMap uidMap; + UidGidMap gidMap; + UINT32 containerID; +} UserContainer; + +UINT32 OsCreateUserContainer(Credentials *newCredentials, UserContainer *parentUserContainer); + +VOID FreeUserContainer(UserContainer *userContainer); + +UINT32 OsFromKuidMunged(UserContainer *userContainer, UINT32 kuid); + +UINT32 OsFromKgidMunged(UserContainer *userContainer, UINT32 kgid); + +UINT32 OsMakeKuid(UserContainer *userContainer, UINT32 uid); + +UINT32 OsMakeKgid(UserContainer *userContainer, UINT32 gid); + +INT32 OsUserContainerMapWrite(struct ProcFile *fp, CHAR *buf, size_t count, + INT32 capSetid, UidGidMap *map, UidGidMap *parentMap); +#endif +#endif diff --git a/syscall/process_syscall.c b/syscall/process_syscall.c index af7c73fd..491f608f 100644 --- a/syscall/process_syscall.c +++ b/syscall/process_syscall.c @@ -448,7 +448,11 @@ int SysGetEffUserID(void) int euid; SCHEDULER_LOCK(intSave); +#ifdef LOSCFG_USER_CONTAINER + euid = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->euid); +#else euid = (int)OsCurrUserGet()->effUserID; +#endif SCHEDULER_UNLOCK(intSave); return euid; #else @@ -463,7 +467,11 @@ int SysGetEffGID(void) int egid; SCHEDULER_LOCK(intSave); +#ifdef LOSCFG_USER_CONTAINER + egid = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->egid); +#else egid = (int)OsCurrUserGet()->effGid; +#endif SCHEDULER_UNLOCK(intSave); return egid; #else @@ -479,9 +487,15 @@ int SysGetRealEffSaveUserID(int *ruid, int *euid, int *suid) unsigned int intSave; SCHEDULER_LOCK(intSave); +#ifdef LOSCFG_USER_CONTAINER + realUserID = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->uid); + effUserID = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->euid); + saveUserID = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->euid); +#else realUserID = OsCurrUserGet()->userID; effUserID = OsCurrUserGet()->effUserID; saveUserID = OsCurrUserGet()->effUserID; +#endif SCHEDULER_UNLOCK(intSave); #else realUserID = 0; @@ -507,6 +521,58 @@ int SysGetRealEffSaveUserID(int *ruid, int *euid, int *suid) return 0; } +#ifdef LOSCFG_USER_CONTAINER +long SysSetUserID(int uid) +{ +#ifdef LOSCFG_SECURITY_CAPABILITY + UserContainer *userContainer = CurrentCredentials()->userContainer; + int retval = -EPERM; + unsigned int intSave; + + UINT32 kuid = OsMakeKuid(userContainer, uid); + if (kuid == (UINT32)-1) { + return -EINVAL; + } + + Credentials *newCredentials = PrepareCredential(OsCurrProcessGet()); + if (newCredentials == NULL) { + return -ENOMEM; + } + + Credentials *oldCredentials = CurrentCredentials(); + + SCHEDULER_LOCK(intSave); + User *user = OsCurrUserGet(); + if (IsCapPermit(CAP_SETUID)) { + newCredentials->uid = kuid; + if (kuid != oldCredentials->uid) { + user->userID = kuid; + user->effUserID = kuid; + } + retval = LOS_OK; + } else if (kuid != oldCredentials->uid) { + goto ERROR; + } + newCredentials->euid = kuid; + + retval = CommitCredentials(newCredentials); + SCHEDULER_UNLOCK(intSave); + return retval; + +ERROR: + FreeCredential(newCredentials); + SCHEDULER_UNLOCK(intSave); + return retval; +#else + if (uid != 0) { + return -EPERM; + } + return 0; +#endif +} + +#else + int SysSetUserID(int uid) { #ifdef LOSCFG_SECURITY_CAPABILITY @@ -540,6 +606,7 @@ EXIT: return 0; #endif } +#endif #ifdef LOSCFG_SECURITY_CAPABILITY static int SetRealEffSaveUserIDCheck(int ruid, int euid, int suid) @@ -607,6 +674,62 @@ int SysSetRealEffUserID(int ruid, int euid) #endif } +#ifdef LOSCFG_USER_CONTAINER +int SysSetGroupID(int gid) +{ +#ifdef LOSCFG_SECURITY_CAPABILITY + UserContainer *userContainer = CurrentCredentials()->userContainer; + int retval = -EPERM; + unsigned int oldGid; + unsigned int intSave; + int count; + + unsigned int kgid = OsMakeKgid(userContainer, gid); + if (kgid == (UINT32)-1) { + return -EINVAL; + } + + Credentials *newCredentials = PrepareCredential(OsCurrProcessGet()); + if (newCredentials == NULL) { + return -ENOMEM; + } + + SCHEDULER_LOCK(intSave); + User *user = OsCurrUserGet(); + if (IsCapPermit(CAP_SETGID)) { + newCredentials->gid = kgid; + newCredentials->egid = kgid; + oldGid = user->gid; + user->gid = kgid; + user->effGid = kgid; + for (count = 0; count < user->groupNumber; count++) { + if (user->groups[count] == oldGid) { + user->groups[count] = kgid; + retval = LOS_OK; + break; + } + } + } else if (user->gid != kgid) { + goto ERROR; + } + + retval = CommitCredentials(newCredentials); + SCHEDULER_UNLOCK(intSave); + return retval; + +ERROR: + FreeCredential(newCredentials); + SCHEDULER_UNLOCK(intSave); + return retval; + +#else + if (gid != 0) { + return -EPERM; + } + return 0; +#endif +} +#else int SysSetGroupID(int gid) { #ifdef LOSCFG_SECURITY_CAPABILITY @@ -651,6 +774,7 @@ EXIT: return 0; #endif } +#endif int SysGetRealEffSaveGroupID(int *rgid, int *egid, int *sgid) { @@ -660,9 +784,15 @@ int SysGetRealEffSaveGroupID(int *rgid, int *egid, int *sgid) unsigned int intSave; SCHEDULER_LOCK(intSave); +#ifdef LOSCFG_USER_CONTAINER + realGroupID = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->gid); + effGroupID = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->egid); + saveGroupID = OsFromKuidMunged(OsCurrentUserContainer(), CurrentCredentials()->egid); +#else realGroupID = OsCurrUserGet()->gid; effGroupID = OsCurrUserGet()->effGid; saveGroupID = OsCurrUserGet()->effGid; +#endif SCHEDULER_UNLOCK(intSave); #else realGroupID = 0; diff --git a/testsuites/unittest/config.gni b/testsuites/unittest/config.gni index cf6c5842..d659f216 100644 --- a/testsuites/unittest/config.gni +++ b/testsuites/unittest/config.gni @@ -142,6 +142,7 @@ LOSCFG_USER_TEST_UTS_CONTAINER = false LOSCFG_USER_TEST_MNT_CONTAINER = false LOSCFG_USER_TEST_IPC_CONTAINER = false LOSCFG_USER_TEST_TIME_CONTAINER = false +LOSCFG_USER_TEST_USER_CONTAINER = false if (defined(LOSCFG_KERNEL_CONTAINER) || liteos_container_test_enable == true) { LOSCFG_USER_TEST_CONTAINER = true if (defined(LOSCFG_PID_CONTAINER) || liteos_container_test_enable == true) { @@ -159,6 +160,9 @@ if (defined(LOSCFG_KERNEL_CONTAINER) || liteos_container_test_enable == true) { if (defined(LOSCFG_TIME_CONTAINER) || liteos_container_test_enable == true) { LOSCFG_USER_TEST_TIME_CONTAINER = true } + if (defined(LOSCFG_USER_CONTAINER) || liteos_container_test_enable == true) { + LOSCFG_USER_TEST_USER_CONTAINER = true + } } ########## fuzz test ########## diff --git a/testsuites/unittest/container/BUILD.gn b/testsuites/unittest/container/BUILD.gn index d517d203..032e9e97 100644 --- a/testsuites/unittest/container/BUILD.gn +++ b/testsuites/unittest/container/BUILD.gn @@ -47,6 +47,9 @@ config("container_config") { if (defined(LOSCFG_USER_TEST_TIME_CONTAINER)) { cflags += [ "-DLOSCFG_USER_TEST_TIME_CONTAINER" ] } + if (defined(LOSCFG_USER_TEST_USER_CONTAINER)) { + cflags += [ "-DLOSCFG_USER_TEST_USER_CONTAINER" ] + } cflags_cc = cflags } diff --git a/testsuites/unittest/container/It_container_test.cpp b/testsuites/unittest/container/It_container_test.cpp index c0af9453..296228b6 100644 --- a/testsuites/unittest/container/It_container_test.cpp +++ b/testsuites/unittest/container/It_container_test.cpp @@ -589,6 +589,55 @@ HWTEST_F(ContainerTest, ItTimeContainer010, TestSize.Level0) ItTimeContainer010(); } #endif +#if defined(LOSCFG_USER_TEST_USER_CONTAINER) +/** +* @tc.name: Container_UTS_Test_001 +* @tc.desc: uts container function test case +* @tc.type: FUNC +* @tc.require: issueI6EC0A +* @tc.author: +*/ +HWTEST_F(ContainerTest, ItUserContainer001, TestSize.Level0) +{ + ItUserContainer001(); +} + +/** +* @tc.name: Container_UTS_Test_002 +* @tc.desc: uts container function test case +* @tc.type: FUNC +* @tc.require: issueI6EC0A +* @tc.author: +*/ +HWTEST_F(ContainerTest, ItUserContainer002, TestSize.Level0) +{ + ItUserContainer002(); +} + +/** +* @tc.name: Container_UTS_Test_003 +* @tc.desc: uts container function test case +* @tc.type: FUNC +* @tc.require: issueI6EC0A +* @tc.author: +*/ +HWTEST_F(ContainerTest, ItUserContainer003, TestSize.Level0) +{ + ItUserContainer003(); +} + +/** +* @tc.name: Container_UTS_Test_004 +* @tc.desc: uts container function test case +* @tc.type: FUNC +* @tc.require: issueI6EC0A +* @tc.author: +*/ +HWTEST_F(ContainerTest, ItUserContainer004, TestSize.Level0) +{ + ItUserContainer004(); +} +#endif #endif /* LOSCFG_USER_TEST_SMOKE */ #if defined(LOSCFG_USER_TEST_FULL) @@ -884,6 +933,19 @@ HWTEST_F(ContainerTest, ItUtsContainer003, TestSize.Level0) ItUtsContainer003(); } #endif +#if defined(LOSCFG_USER_TEST_USER_CONTAINER) +/** +* @tc.name: Container_UTS_Test_005 +* @tc.desc: uts container function test case +* @tc.type: FUNC +* @tc.require: issueI6EC0A +* @tc.author: +*/ +HWTEST_F(ContainerTest, ItUserContainer005, TestSize.Level0) +{ + ItUserContainer005(); +} +#endif #endif } // namespace OHOS diff --git a/testsuites/unittest/container/It_container_test.h b/testsuites/unittest/container/It_container_test.h index 526bbc8d..49e40414 100644 --- a/testsuites/unittest/container/It_container_test.h +++ b/testsuites/unittest/container/It_container_test.h @@ -137,6 +137,11 @@ private: int m_shmid; }; +void ItUserContainer001(void); +void ItUserContainer002(void); +void ItUserContainer003(void); +void ItUserContainer004(void); +void ItUserContainer005(void); #if defined(LOSCFG_USER_TEST_SMOKE) void ItContainer001(void); void ItContainerChroot001(void); diff --git a/testsuites/unittest/container/config.gni b/testsuites/unittest/container/config.gni index a43f6dce..a0b0cba1 100644 --- a/testsuites/unittest/container/config.gni +++ b/testsuites/unittest/container/config.gni @@ -128,3 +128,14 @@ if (defined(LOSCFG_USER_TEST_TIME_CONTAINER)) { "$TEST_UNITTEST_DIR/container/smoke/It_time_container_010.cpp", ] } + +if (defined(LOSCFG_USER_TEST_USER_CONTAINER)) { + sources_smoke += [ + "$TEST_UNITTEST_DIR/container/smoke/It_user_container_001.cpp", + "$TEST_UNITTEST_DIR/container/smoke/It_user_container_002.cpp", + "$TEST_UNITTEST_DIR/container/smoke/It_user_container_003.cpp", + "$TEST_UNITTEST_DIR/container/smoke/It_user_container_004.cpp", + ] + sources_full += + [ "$TEST_UNITTEST_DIR/container/full/It_user_container_005.cpp" ] +} diff --git a/testsuites/unittest/container/full/It_user_container_005.cpp b/testsuites/unittest/container/full/It_user_container_005.cpp new file mode 100644 index 00000000..e3e91087 --- /dev/null +++ b/testsuites/unittest/container/full/It_user_container_005.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "It_container_test.h" +#include "sys/resource.h" +#include "sys/wait.h" +#include "pthread.h" +#include "sched.h" + +const int EXIT_TRUE_CODE = 255; +const int MAX_PID_RANGE = 100000; +const int SLEEP_TIME_US = 1000; +const int LOOP_NUM = 1000; + +static int childFunc(void *arg) +{ + (void)arg; + usleep(SLEEP_TIME_US); + exit(EXIT_TRUE_CODE); +} + +static int GroupProcess(void *arg) +{ + (void)arg; + int ret; + int status = 0; + + for (int i = 0; i < LOOP_NUM; i++) { + int arg_child = CHILD_FUNC_ARG; + auto pid = CloneWrapper(childFunc, CLONE_NEWUSER, &arg_child); + if (pid == -1) { + return EXIT_CODE_ERRNO_1; + } + + ret = waitpid(pid, &status, 0); + if (ret != pid) { + return EXIT_CODE_ERRNO_2; + } + + status = WEXITSTATUS(status); + if (status != EXIT_TRUE_CODE) { + return EXIT_CODE_ERRNO_3; + } + } + + exit(EXIT_TRUE_CODE); +} + +void ItUserContainer005(void) +{ + int ret; + int status = 0; + int arg = CHILD_FUNC_ARG; + auto pid = CloneWrapper(GroupProcess, CLONE_NEWUSER, &arg); + ASSERT_NE(pid, -1); + + ret = waitpid(pid, &status, 0); + ASSERT_EQ(ret, pid); + + status = WEXITSTATUS(status); + ASSERT_EQ(status, EXIT_TRUE_CODE); +} diff --git a/testsuites/unittest/container/smoke/It_user_container_001.cpp b/testsuites/unittest/container/smoke/It_user_container_001.cpp new file mode 100644 index 00000000..78d3d900 --- /dev/null +++ b/testsuites/unittest/container/smoke/It_user_container_001.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "It_container_test.h" +using namespace std; + +const int RETURN_CODE = 2; + +static int childFunc(void *arg) +{ + int value = *((int*)arg); + if (value != CHILD_FUNC_ARG) { + return EXIT_CODE_ERRNO_1; + } + + sleep(1); + return RETURN_CODE; +} + +void ItUserContainer001(void) +{ + int ret; + int arg = CHILD_FUNC_ARG; + auto pid = CloneWrapper(childFunc, CLONE_NEWUSER, &arg); + ASSERT_NE(pid, -1); + + int status; + ret = waitpid(pid, &status, 0); + ASSERT_EQ(ret, pid); + + ret = WIFEXITED(status); + ASSERT_NE(ret, 0); + + int exitCode = WEXITSTATUS(status); + ASSERT_EQ(exitCode, RETURN_CODE); +} + diff --git a/testsuites/unittest/container/smoke/It_user_container_002.cpp b/testsuites/unittest/container/smoke/It_user_container_002.cpp new file mode 100644 index 00000000..add03c26 --- /dev/null +++ b/testsuites/unittest/container/smoke/It_user_container_002.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "It_container_test.h" +#include "sys/utsname.h" + +const int EXIT_TRUE_CODE = 255; +const int TEST_SET_OLD_ID = 1001; +const int TEST_SET_NEW_ID = 4; +static const int SLEEP_TIME = 3; + +std::string GetIdMapPath(int pid, const std::string& mapType) +{ + std::ostringstream buf; + buf << "/proc/" << pid << "/" << mapType; + return buf.str(); +} + +int WriteIdMap(int pid) +{ + std::string uidMapPath = GetIdMapPath(pid, "uid_map"); + std::string gidMapPath = GetIdMapPath(pid, "gid_map"); + + const char* idMapStr = "0 1000 1\n1 1001 1\n2 1002 1\n3 1003 1\n4 1004 1\n"; + int strLen = strlen(idMapStr); + int uidMap = open(uidMapPath.c_str(), O_WRONLY); + if (uidMap == -1) { + return EXIT_CODE_ERRNO_1; + } + + int ret = write(uidMap, idMapStr, strLen); + if (ret != strLen) { + close(uidMap); + return EXIT_CODE_ERRNO_2; + } + close(uidMap); + + int gidMap = open(gidMapPath.c_str(), O_WRONLY); + if (gidMap == -1) { + close(gidMap); + return EXIT_CODE_ERRNO_3; + } + + ret = write(gidMap, idMapStr, strLen); + if (ret != strLen) { + close(gidMap); + return EXIT_CODE_ERRNO_4; + } + + close(gidMap); + return 0; +} + +static int childFunc(void *arg) +{ + (void)arg; + sleep(SLEEP_TIME); + + int newUid = getuid(); + if (newUid != 1) { + return EXIT_CODE_ERRNO_1; + } + + int newGid = getgid(); + if (newGid != 1) { + return EXIT_CODE_ERRNO_2; + } + + int ret = setuid(TEST_SET_NEW_ID); + if (ret != 0) { + return EXIT_CODE_ERRNO_3; + } + + ret = setgid(TEST_SET_NEW_ID); + if (ret != 0) { + return EXIT_CODE_ERRNO_4; + } + + newUid = getuid(); + if (newUid != TEST_SET_NEW_ID) { + return EXIT_CODE_ERRNO_5; + } + + newGid = getgid(); + if (newGid != TEST_SET_NEW_ID) { + return EXIT_CODE_ERRNO_6; + } + + exit(EXIT_TRUE_CODE); +} + +void ItUserContainer002(void) +{ + int ret = setuid(TEST_SET_OLD_ID); + ASSERT_EQ(ret, 0); + + int oldUid = getuid(); + ASSERT_EQ(oldUid, TEST_SET_OLD_ID); + + ret = setgid(TEST_SET_OLD_ID); + ASSERT_EQ(ret, 0); + + int oldGid = getgid(); + ASSERT_EQ(oldGid, TEST_SET_OLD_ID); + + int arg = CHILD_FUNC_ARG; + auto pid = CloneWrapper(childFunc, CLONE_NEWUSER, &arg); + ASSERT_NE(pid, -1); + + ret = WriteIdMap(pid); + ASSERT_EQ(ret, 0); + + int status; + ret = waitpid(pid, &status, 0); + ASSERT_EQ(ret, pid); + + status = WEXITSTATUS(status); + ASSERT_EQ(status, EXIT_TRUE_CODE); + + int oldUid1 = getuid(); + ASSERT_EQ(oldUid1, TEST_SET_OLD_ID); + + int oldGid1 = getgid(); + ASSERT_EQ(oldGid1, TEST_SET_OLD_ID); + + ASSERT_EQ(oldUid, oldUid1); + ASSERT_EQ(oldGid, oldGid1); +} diff --git a/testsuites/unittest/container/smoke/It_user_container_003.cpp b/testsuites/unittest/container/smoke/It_user_container_003.cpp new file mode 100644 index 00000000..e46a15bb --- /dev/null +++ b/testsuites/unittest/container/smoke/It_user_container_003.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "It_container_test.h" +#include "sys/utsname.h" + +const int EXIT_TRUE_CODE = 255; +const int MAX_PID_RANGE = 100000; +const int TEST_SET_OLD_ID = 1001; +const int TEST_SET_NEW_ID = 4; + +std::string GetIdMapPath(int pid, const std::string& mapType); +int WriteIdMap(int pid); + +static int TestMap(int oldUid, int oldGid) +{ + pid_t pid = getpid(); + int ret = WriteIdMap(pid); + if (ret != 0) { + return EXIT_CODE_ERRNO_6; + } + + int newUid = getuid(); + if (newUid != 1) { + return EXIT_CODE_ERRNO_7; + } + + int newGid = getgid(); + if (newGid != 1) { + return EXIT_CODE_ERRNO_8; + } + + ret = setuid(TEST_SET_NEW_ID); + if (ret != 0) { + return EXIT_CODE_ERRNO_9; + } + + ret = setgid(TEST_SET_NEW_ID); + if (ret != 0) { + return EXIT_CODE_ERRNO_10; + } + + newUid = getuid(); + if (newUid != TEST_SET_NEW_ID) { + return EXIT_CODE_ERRNO_11; + } + + newGid = getgid(); + if (newGid != TEST_SET_NEW_ID) { + exit(1); + } + + if (oldUid == newUid) { + return EXIT_CODE_ERRNO_12; + } + + if (oldGid == newGid) { + return EXIT_CODE_ERRNO_13; + } + return 0; +} + +static int childFunc(void *arg) +{ + (void)arg; + int ret; + int oldUid; + int oldGid; + + ret = setuid(TEST_SET_OLD_ID); + if (ret != 0) { + return EXIT_CODE_ERRNO_1; + } + + oldUid = getuid(); + if (oldUid != TEST_SET_OLD_ID) { + return EXIT_CODE_ERRNO_2; + } + + ret = setgid(TEST_SET_OLD_ID); + if (ret != 0) { + return EXIT_CODE_ERRNO_3; + } + + oldGid = getgid(); + if (oldGid != TEST_SET_OLD_ID) { + return EXIT_CODE_ERRNO_4; + } + + ret = unshare(CLONE_NEWUSER); + if (ret == -1) { + return EXIT_CODE_ERRNO_5; + } + + ret = TestMap(oldUid, oldGid); + if (ret != 0) { + return ret; + } + + exit(EXIT_TRUE_CODE); +} + +void ItUserContainer003(void) +{ + int ret; + int status = 0; + int arg = CHILD_FUNC_ARG; + auto pid = CloneWrapper(childFunc, SIGCHLD, &arg); + ASSERT_NE(pid, -1); + + ret = waitpid(pid, &status, 0); + ASSERT_EQ(ret, pid); + + status = WEXITSTATUS(status); + ASSERT_EQ(status, EXIT_TRUE_CODE); +} diff --git a/testsuites/unittest/container/smoke/It_user_container_004.cpp b/testsuites/unittest/container/smoke/It_user_container_004.cpp new file mode 100644 index 00000000..846667ce --- /dev/null +++ b/testsuites/unittest/container/smoke/It_user_container_004.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "It_container_test.h" + +const int EXIT_TRUE_CODE = 255; +const int MAX_PID_RANGE = 100000; + +static int childFunc(void *arg) +{ + (void)arg; + std::string containerType = "user"; + std::string childlink; + std::string filePath; + std::string parentlink1; + int fd; + int ret; + int status; + int parentPid = getpid(); + + auto parentlink = ReadlinkContainer(parentPid, containerType); + int childsPid = CloneWrapper(ChildFunction, CLONE_NEWUSER, NULL); + if (childsPid == -1) { + return EXIT_CODE_ERRNO_1; + } + + childlink = ReadlinkContainer(childsPid, containerType); + filePath = GenContainerLinkPath(childsPid, containerType); + fd = open(filePath.c_str(), O_RDONLY); + if (fd == -1) { + return EXIT_CODE_ERRNO_2; + } + + ret = setns(fd, CLONE_NEWUSER); + if (ret == -1) { + close(fd); + return EXIT_CODE_ERRNO_3; + } + + parentlink1 = ReadlinkContainer(parentPid, containerType); + + close(fd); + + ret = waitpid(childsPid, &status, 0); + if (ret != childsPid) { + return EXIT_CODE_ERRNO_4; + } + + ret = parentlink.compare(parentlink1); + if (ret == 0) { + return EXIT_CODE_ERRNO_5; + } + + ret = parentlink1.compare(childlink); + if (ret != 0) { + return EXIT_CODE_ERRNO_6; + } + + exit(EXIT_TRUE_CODE); +} + +void ItUserContainer004(void) +{ + + int ret; + int status = 0; + int arg = CHILD_FUNC_ARG; + auto pid = CloneWrapper(childFunc, SIGCHLD, &arg); + ASSERT_NE(pid, -1); + + ret = waitpid(pid, &status, 0); + ASSERT_EQ(ret, pid); + + status = WEXITSTATUS(status); + ASSERT_EQ(status, EXIT_TRUE_CODE); +}