427 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			427 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * 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
 |