• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  *    conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *    of conditions and the following disclaimer in the documentation and/or other materials
12  *    provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15  *    to endorse or promote products derived from this software without specific prior written
16  *    permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifdef LOSCFG_USER_CONTAINER
32 #include "los_user_container_pri.h"
33 #include "errno.h"
34 #include "ctype.h"
35 #include "los_config.h"
36 #include "los_memory.h"
37 #include "proc_fs.h"
38 #include "user_copy.h"
39 #include "los_seq_buf.h"
40 #include "capability_type.h"
41 #include "capability_api.h"
42 #include "internal.h"
43 
44 #define DEFAULT_OVERFLOWUID    65534
45 #define DEFAULT_OVERFLOWGID    65534
46 #define LEVEL_MAX 3
47 #define HEX 16
48 #define OCT 8
49 #define DEC 10
50 
51 UINT32 g_currentUserContainerNum = 0;
52 
OsCreateUserContainer(Credentials * newCredentials,UserContainer * parentUserContainer)53 UINT32 OsCreateUserContainer(Credentials *newCredentials, UserContainer *parentUserContainer)
54 {
55     if (g_currentUserContainerNum >= OsGetContainerLimit(USER_CONTAINER)) {
56         return EPERM;
57     }
58 
59     if ((parentUserContainer != NULL) && (parentUserContainer->level >= LEVEL_MAX)) {
60         return EINVAL;
61     }
62 
63     if ((newCredentials->euid < 0) || (newCredentials->egid < 0)) {
64         return EINVAL;
65     }
66 
67     UserContainer *userContainer = LOS_MemAlloc(m_aucSysMem1, sizeof(UserContainer));
68     if (userContainer == NULL) {
69         return ENOMEM;
70     }
71     (VOID)memset_s(userContainer, sizeof(UserContainer), 0, sizeof(UserContainer));
72 
73     g_currentUserContainerNum++;
74     userContainer->containerID = OsAllocContainerID();
75     userContainer->parent = parentUserContainer;
76     newCredentials->userContainer = userContainer;
77     if (parentUserContainer != NULL) {
78         LOS_AtomicInc(&parentUserContainer->rc);
79         LOS_AtomicSet(&userContainer->rc, 1);
80         userContainer->level = parentUserContainer->level + 1;
81         userContainer->owner = newCredentials->euid;
82         userContainer->group = newCredentials->egid;
83     } else {
84         LOS_AtomicSet(&userContainer->rc, 3); /* 3: Three system processes */
85         userContainer->uidMap.extentCount = 1;
86         userContainer->uidMap.extent[0].count = 4294967295U;
87         userContainer->gidMap.extentCount = 1;
88         userContainer->gidMap.extent[0].count = 4294967295U;
89     }
90     return LOS_OK;
91 }
92 
FreeUserContainer(UserContainer * userContainer)93 VOID FreeUserContainer(UserContainer *userContainer)
94 {
95     UserContainer *parent = NULL;
96     do {
97         parent = userContainer->parent;
98         (VOID)LOS_MemFree(m_aucSysMem1, userContainer);
99         userContainer->parent = NULL;
100         userContainer = parent;
101         g_currentUserContainerNum--;
102         if (userContainer == NULL) {
103             break;
104         }
105         LOS_AtomicDec(&userContainer->rc);
106     } while (LOS_AtomicRead(&userContainer->rc) <= 0);
107 }
108 
MapIdUpBase(UINT32 extents,UidGidMap * map,UINT32 id)109 STATIC UidGidExtent *MapIdUpBase(UINT32 extents, UidGidMap *map, UINT32 id)
110 {
111     UINT32 idx;
112     UINT32 first;
113     UINT32 last;
114 
115     for (idx = 0; idx < extents; idx++) {
116         first = map->extent[idx].lowerFirst;
117         last = first + map->extent[idx].count - 1;
118         if ((id >= first) && (id <= last)) {
119             return &map->extent[idx];
120         }
121     }
122     return NULL;
123 }
124 
MapIdUp(UidGidMap * map,UINT32 id)125 STATIC UINT32 MapIdUp(UidGidMap *map, UINT32 id)
126 {
127     UINT32 extents = map->extentCount;
128     if (extents > UID_GID_MAP_MAX_EXTENTS) {
129         return (UINT32)-1;
130     }
131 
132     UidGidExtent *extent = MapIdUpBase(extents, map, id);
133     if (extent != NULL) {
134         return ((id - extent->lowerFirst) + extent->first);
135     }
136 
137     return (UINT32)-1;
138 }
139 
FromKuid(UserContainer * userContainer,UINT32 kuid)140 UINT32 FromKuid(UserContainer *userContainer, UINT32 kuid)
141 {
142     return MapIdUp(&userContainer->uidMap, kuid);
143 }
144 
FromKgid(UserContainer * userContainer,UINT32 kgid)145 UINT32 FromKgid(UserContainer *userContainer, UINT32 kgid)
146 {
147     return MapIdUp(&userContainer->gidMap, kgid);
148 }
149 
OsFromKuidMunged(UserContainer * userContainer,UINT32 kuid)150 UINT32 OsFromKuidMunged(UserContainer *userContainer, UINT32 kuid)
151 {
152     UINT32 uid = FromKuid(userContainer, kuid);
153     if (uid == (UINT32)-1) {
154         uid = DEFAULT_OVERFLOWUID;
155     }
156     return uid;
157 }
158 
OsFromKgidMunged(UserContainer * userContainer,UINT32 kgid)159 UINT32 OsFromKgidMunged(UserContainer *userContainer, UINT32 kgid)
160 {
161     UINT32 gid = FromKgid(userContainer, kgid);
162     if (gid == (UINT32)-1) {
163         gid = DEFAULT_OVERFLOWGID;
164     }
165     return gid;
166 }
167 
MapIdRangeDownBase(UINT32 extents,UidGidMap * map,UINT32 id,UINT32 count)168 STATIC UidGidExtent *MapIdRangeDownBase(UINT32 extents, UidGidMap *map, UINT32 id, UINT32 count)
169 {
170     UINT32 idx;
171     UINT32 first;
172     UINT32 last;
173     UINT32 id2;
174 
175     id2 = id + count - 1;
176     for (idx = 0; idx < extents; idx++) {
177         first = map->extent[idx].first;
178         last = first + map->extent[idx].count - 1;
179         if ((id >= first && id <= last) && (id2 >= first && id2 <= last)) {
180             return &map->extent[idx];
181         }
182     }
183     return NULL;
184 }
185 
MapIdRangeDown(UidGidMap * map,UINT32 id,UINT32 count)186 STATIC UINT32 MapIdRangeDown(UidGidMap *map, UINT32 id, UINT32 count)
187 {
188     UINT32 extents = map->extentCount;
189     if (extents > UID_GID_MAP_MAX_EXTENTS) {
190         return (UINT32)-1;
191     }
192 
193     UidGidExtent *extent = MapIdRangeDownBase(extents, map, id, count);
194     if (extent != NULL) {
195         return ((id - extent->first) + extent->lowerFirst);
196     }
197 
198     return (UINT32)-1;
199 }
200 
MapIdDown(UidGidMap * map,UINT32 id)201 STATIC UINT32 MapIdDown(UidGidMap *map, UINT32 id)
202 {
203     return MapIdRangeDown(map, id, 1);
204 }
205 
OsMakeKuid(UserContainer * userContainer,UINT32 uid)206 UINT32 OsMakeKuid(UserContainer *userContainer, UINT32 uid)
207 {
208     return MapIdDown(&userContainer->uidMap, uid);
209 }
210 
OsMakeKgid(UserContainer * userContainer,UINT32 gid)211 UINT32 OsMakeKgid(UserContainer *userContainer, UINT32 gid)
212 {
213     return MapIdDown(&userContainer->gidMap, gid);
214 }
215 
InsertExtent(UidGidMap * idMap,UidGidExtent * extent)216 STATIC INT32 InsertExtent(UidGidMap *idMap, UidGidExtent *extent)
217 {
218     if (idMap->extentCount > UID_GID_MAP_MAX_EXTENTS) {
219         return -EINVAL;
220     }
221 
222     UidGidExtent *dest = &idMap->extent[idMap->extentCount];
223     *dest = *extent;
224     idMap->extentCount++;
225 
226     return 0;
227 }
228 
MappingsOverlap(UidGidMap * idMap,UidGidExtent * extent)229 STATIC BOOL MappingsOverlap(UidGidMap *idMap, UidGidExtent *extent)
230 {
231     UINT32 upperFirst = extent->first;
232     UINT32 lowerFirst = extent->lowerFirst;
233     UINT32 upperLast = upperFirst + extent->count - 1;
234     UINT32 lowerLast = lowerFirst + extent->count - 1;
235     INT32 idx;
236 
237     for (idx = 0; idx < idMap->extentCount; idx++) {
238         if (idMap->extentCount > UID_GID_MAP_MAX_EXTENTS) {
239             return TRUE;
240         }
241         UidGidExtent *prev = &idMap->extent[idx];
242         UINT32 prevUpperFirst = prev->first;
243         UINT32 prevLowerFirst = prev->lowerFirst;
244         UINT32 prevUpperLast = prevUpperFirst + prev->count - 1;
245         UINT32 prevLowerLast = prevLowerFirst + prev->count - 1;
246 
247         if ((prevUpperFirst <= upperLast) && (prevUpperLast >= upperFirst)) {
248             return TRUE;
249         }
250 
251         if ((prevLowerFirst <= lowerLast) && (prevLowerLast >= lowerFirst)) {
252             return TRUE;
253         }
254     }
255     return FALSE;
256 }
257 
SkipSpaces(const CHAR * str)258 STATIC CHAR *SkipSpaces(const CHAR *str)
259 {
260     while (isspace(*str)) {
261         ++str;
262     }
263 
264     return (CHAR *)str;
265 }
266 
StrToUInt(const CHAR * str,CHAR ** endp,UINT32 base)267 STATIC UINTPTR StrToUInt(const CHAR *str, CHAR **endp, UINT32 base)
268 {
269     unsigned long result = 0;
270     unsigned long value;
271 
272     if (*str == '0') {
273         str++;
274         if ((*str == 'x') && isxdigit(str[1])) {
275             base = HEX;
276             str++;
277         }
278         if (!base) {
279             base = OCT;
280         }
281     }
282     if (!base) {
283         base = DEC;
284     }
285     while (isxdigit(*str) && (value = isdigit(*str) ? *str - '0' : (islower(*str) ?
286         toupper(*str) : *str) - 'A' + DEC) < base) {
287         result = result * base + value;
288         str++;
289     }
290     if (endp != NULL) {
291         *endp = (CHAR *)str;
292     }
293     return result;
294 }
295 
ParsePosData(CHAR * pos,UidGidExtent * extent)296 STATIC INT32 ParsePosData(CHAR *pos, UidGidExtent *extent)
297 {
298     INT32 ret = -EINVAL;
299     pos = SkipSpaces(pos);
300     extent->first = StrToUInt(pos, &pos, DEC);
301     if (!isspace(*pos)) {
302         return ret;
303     }
304 
305     pos = SkipSpaces(pos);
306     extent->lowerFirst = StrToUInt(pos, &pos, DEC);
307     if (!isspace(*pos)) {
308         return ret;
309     }
310 
311     pos = SkipSpaces(pos);
312     extent->count = StrToUInt(pos, &pos, DEC);
313     if (*pos && !isspace(*pos)) {
314         return ret;
315     }
316 
317     pos = SkipSpaces(pos);
318     if (*pos != '\0') {
319         return ret;
320     }
321     return LOS_OK;
322 }
323 
ParseUserData(CHAR * kbuf,UidGidExtent * extent,UidGidMap * newMap)324 STATIC INT32 ParseUserData(CHAR *kbuf, UidGidExtent *extent, UidGidMap *newMap)
325 {
326     INT32 ret = -EINVAL;
327     CHAR *pos = NULL;
328     CHAR *nextLine = NULL;
329 
330     for (pos = kbuf; pos != NULL; pos = nextLine) {
331         nextLine = strchr(pos, '\n');
332         if (nextLine != NULL) {
333             *nextLine = '\0';
334             nextLine++;
335             if (*nextLine == '\0') {
336                 nextLine = NULL;
337             }
338         }
339 
340         if (ParsePosData(pos, extent) != LOS_OK) {
341             return ret;
342         }
343 
344         if ((extent->first == (UINT32)-1) || (extent->lowerFirst == (UINT32)-1)) {
345             return ret;
346         }
347 
348         if ((extent->first + extent->count) <= extent->first) {
349             return ret;
350         }
351 
352         if ((extent->lowerFirst + extent->count) <= extent->lowerFirst) {
353             return ret;
354         }
355 
356         if (MappingsOverlap(newMap, extent)) {
357             return ret;
358         }
359 
360         if ((newMap->extentCount + 1) == UID_GID_MAP_MAX_EXTENTS && (nextLine != NULL)) {
361             return ret;
362         }
363 
364         ret = InsertExtent(newMap, extent);
365         if (ret < 0) {
366             return ret;
367         }
368         ret = 0;
369     }
370 
371     if (newMap->extentCount == 0) {
372         return -EINVAL;
373     }
374 
375     return ret;
376 }
377 
ParentMapIdRange(UidGidMap * newMap,UidGidMap * parentMap)378 STATIC INT32 ParentMapIdRange(UidGidMap *newMap, UidGidMap *parentMap)
379 {
380     UINT32 idx;
381     INT32 ret = -EPERM;
382     for (idx = 0; idx < newMap->extentCount; idx++) {
383         if (newMap->extentCount > UID_GID_MAP_MAX_EXTENTS) {
384             return ret;
385         }
386 
387         UidGidExtent *extent = &newMap->extent[idx];
388         UINT32 lowerFirst = MapIdRangeDown(parentMap, extent->lowerFirst, extent->count);
389         if (lowerFirst == (UINT32) -1) {
390             return ret;
391         }
392 
393         extent->lowerFirst = lowerFirst;
394     }
395     return 0;
396 }
397 
OsUserContainerMapWrite(struct ProcFile * fp,CHAR * kbuf,size_t count,INT32 capSetid,UidGidMap * map,UidGidMap * parentMap)398 INT32 OsUserContainerMapWrite(struct ProcFile *fp, CHAR *kbuf, size_t count,
399                               INT32 capSetid, UidGidMap *map, UidGidMap *parentMap)
400 {
401     UidGidMap newMap = {0};
402     UidGidExtent extent;
403     INT32 ret;
404 
405     if (map->extentCount != 0) {
406         return -EPERM;
407     }
408 
409     if (!IsCapPermit(capSetid)) {
410         return -EPERM;
411     }
412 
413     ret = ParseUserData(kbuf, &extent, &newMap);
414     if (ret < 0) {
415         return -EPERM;
416     }
417 
418     ret = ParentMapIdRange(&newMap, parentMap);
419     if (ret < 0) {
420         return -EPERM;
421     }
422 
423     if (newMap.extentCount <= UID_GID_MAP_MAX_EXTENTS) {
424         size_t mapSize = newMap.extentCount * sizeof(newMap.extent[0]);
425         ret = memcpy_s(map->extent, sizeof(map->extent), newMap.extent, mapSize);
426         if (ret != EOK) {
427             return -EPERM;
428         }
429     }
430 
431     map->extentCount = newMap.extentCount;
432     return count;
433 }
434 
OsGetUserContainerCount(VOID)435 UINT32 OsGetUserContainerCount(VOID)
436 {
437     return g_currentUserContainerNum;
438 }
439 #endif
440