1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "accesstokenid_test.h"
17#include <cstdio>
18#include <cstdlib>
19#include <fcntl.h>
20#include <cerrno>
21#include <unistd.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <sys/mman.h>
25#include <sys/wait.h>
26#include <sys/ioctl.h>
27#include <ctime>
28#include <climits>
29#include <pthread.h>
30#include <sys/syscall.h>
31#include <grp.h>
32
33constexpr unsigned char ACCESS_TOKEN_ID_IOCTL_BASE = 'A';
34constexpr unsigned int GET_TOKEN_ID = 1;
35constexpr unsigned int SET_TOKEN_ID = 2;
36constexpr unsigned int GET_FTOKEN_ID = 3;
37constexpr unsigned int SET_FTOKEN_ID = 4;
38constexpr unsigned int ACCESS_TOKENID_MAX_NR = 5;
39#define	ACCESS_TOKENID_GET_TOKENID \
40    _IOR(ACCESS_TOKEN_ID_IOCTL_BASE, GET_TOKEN_ID, unsigned long long)
41#define	ACCESS_TOKENID_SET_TOKENID \
42    _IOW(ACCESS_TOKEN_ID_IOCTL_BASE, SET_TOKEN_ID, unsigned long long)
43#define	ACCESS_TOKENID_GET_FTOKENID \
44    _IOR(ACCESS_TOKEN_ID_IOCTL_BASE, GET_FTOKEN_ID, unsigned long long)
45#define	ACCESS_TOKENID_SET_FTOKENID \
46    _IOW(ACCESS_TOKEN_ID_IOCTL_BASE, SET_FTOKEN_ID, unsigned long long)
47#define	ACCESS_TOKENID_ILLEGAL1 \
48    _IOW(ACCESS_TOKEN_ID_IOCTL_BASE, 0, unsigned long long)
49#define	ACCESS_TOKENID_ILLEGAL2 \
50    _IOW(ACCESS_TOKEN_ID_IOCTL_BASE, ACCESS_TOKENID_MAX_NR, unsigned long long)
51
52constexpr unsigned long long INVAL_TOKEN = 0xffffffffffffffff;
53
54#define CHILDREN_NUM			    3
55#define WAIT_FOR_SHELL_OP_TIME		1
56#define FATHER_WAIT_TIME		    (WAIT_FOR_SHELL_OP_TIME * (CHILDREN_NUM + 1))
57
58constexpr unsigned int ACCESS_TOKEN_GRPID = 3020;
59constexpr unsigned int ACCESS_TOKEN_OTHER_UID = 1234;
60constexpr unsigned int ACCESS_TOKEN_OTHER_GRPID = 1234;
61
62const char dev_accesstokenid[] = "/dev/access_token_id";
63
64struct tokeninfo {
65    pid_t               pid;
66    pid_t               tid;
67    unsigned long long  tokenid;
68    unsigned long long  ftokenid;
69};
70
71namespace {
72static unsigned long long GenRand64(void)
73{
74    struct timespec time = {0, 0};
75    unsigned long long randvalue = 0;
76    int fd;
77
78    fd = open("/dev/random", O_RDONLY);
79    if (fd > 0) {
80        read(fd, &randvalue, sizeof(unsigned long long));
81    }
82    close(fd);
83
84    sleep(1);
85    clock_gettime(CLOCK_REALTIME, &time);
86
87    return randvalue + time.tv_nsec;
88}
89
90static int GetTokenid(unsigned long long *token)
91{
92    int fd = open(dev_accesstokenid, O_RDWR);
93    if (fd < 0) {
94        printf("open %s failed\r\n", dev_accesstokenid);
95        return -1;
96    }
97
98    int ret = ioctl(fd, ACCESS_TOKENID_GET_TOKENID, token);
99    if (ret) {
100        printf("ioctl ACCESS_TOKENID_GET_TOKENID failed\r\n");
101        close(fd);
102        return -1;
103    }
104
105    close(fd);
106    return 0;
107}
108
109static int SetTokenid(unsigned long long *token)
110{
111    int fd = open(dev_accesstokenid, O_RDWR);
112    if (fd < 0) {
113        printf("open %s failed\r\n", dev_accesstokenid);
114        return -1;
115    }
116
117    int ret = ioctl(fd, ACCESS_TOKENID_SET_TOKENID, token);
118    if (ret) {
119        printf("ioctl ACCESS_TOKENID_SET_TOKENID failed\r\n");
120        close(fd);
121        return -1;
122    }
123
124    close(fd);
125    return 0;
126}
127
128static int GetfTokenid(unsigned long long *ftoken)
129{
130    int fd = open(dev_accesstokenid, O_RDWR);
131    if (fd < 0) {
132        printf("open %s failed\r\n", dev_accesstokenid);
133        return -1;
134    }
135
136    int ret = ioctl(fd, ACCESS_TOKENID_GET_FTOKENID, ftoken);
137    if (ret) {
138        printf("ioctl ACCESS_TOKENID_GET_FTOKENID failed\r\n");
139        close(fd);
140        return -1;
141    }
142
143    close(fd);
144    return 0;
145}
146
147static int SetfTokenid(unsigned long long *ftoken)
148{
149    int fd = open(dev_accesstokenid, O_RDWR);
150    if (fd < 0) {
151        printf("open %s failed\r\n", dev_accesstokenid);
152        return -1;
153    }
154
155    int ret = ioctl(fd, ACCESS_TOKENID_SET_FTOKENID, ftoken);
156    if (ret) {
157        printf("ioctl ACCESS_TOKENID_SET_FTOKENID failed\r\n");
158        close(fd);
159        return -1;
160    }
161
162    close(fd);
163    return 0;
164}
165
166static void GetCurToken(unsigned long long *token, unsigned long long *ftoken)
167{
168    GetTokenid(token);
169    GetfTokenid(ftoken);
170
171    return;
172}
173
174static void *CheckChildThreadInheritance(void *args)
175{
176    struct tokeninfo *tinfo = (struct tokeninfo *) args;
177
178    tinfo->pid = getpid();
179    tinfo->tid = gettid();
180    GetTokenid(&(tinfo->tokenid));
181    GetfTokenid(&(tinfo->ftokenid));
182
183    pthread_exit(nullptr);
184    return nullptr;
185}
186
187static void *CheckChildThreadSetIndepent(void *args)
188{
189    struct tokeninfo *tinfo = (struct tokeninfo *) args;
190    unsigned long long tokenSet = GenRand64();
191    unsigned long long ftokenSet = GenRand64();
192    unsigned long long tokenidGet = INVAL_TOKEN;
193    unsigned long long ftokenidGet = INVAL_TOKEN;
194
195    tinfo->pid = getpid();
196    tinfo->tid = gettid();
197
198    GetTokenid(&tokenidGet);
199    GetfTokenid(&ftokenidGet);
200    SetTokenid(&tokenSet);
201    SetfTokenid(&ftokenSet);
202    GetTokenid(&(tinfo->tokenid));
203    GetfTokenid(&(tinfo->ftokenid));
204
205    /* Indicate that the tokenid setting of each child thread does not met requirements. */
206    if (ftokenidGet == 0 && tinfo->tokenid == tokenSet && tinfo->ftokenid == ftokenSet && tinfo->ftokenid != 0) {
207        tinfo->ftokenid = INVAL_TOKEN;
208    }
209
210    pthread_exit(nullptr);
211    return nullptr;
212}
213}
214
215using namespace testing::ext;
216using namespace std;
217
218void AccesstokenidTest::SetUp() {}
219
220void AccesstokenidTest::TearDown() {}
221
222void AccesstokenidTest::SetUpTestCase() {}
223
224void AccesstokenidTest::TearDownTestCase() {}
225
226/**
227 * @tc.name: CheckInitToken
228 * @tc.desc: Test init value of tokenid and ftokenid
229 * @tc.desc: tokenid equals to the father(hdcd) and ftokenid equals to 0
230 * @tc.type: FUNC
231 */
232HWTEST_F(AccesstokenidTest, CheckInitToken, Function | MediumTest | Level1)
233{
234    unsigned long long token = INVAL_TOKEN;
235    unsigned long long ftoken = INVAL_TOKEN;
236
237    GetCurToken(&token, &ftoken);
238
239    /* /data/service/el0/access_token/nativetoken.json
240       {"processName":"hdcd","APL":3,"version":1,"tokenId":680034571,"tokenAttr":0,"dcaps":[]}
241    */
242    ASSERT_NE(0, token);
243    ASSERT_EQ(0, ftoken);
244}
245
246/**
247 * @tc.name: CheckSetTokenid
248 * @tc.desc: Test setting of tokenid
249 * @tc.desc: tokenid equals to the setting value
250 * @tc.type: FUNC
251 */
252HWTEST_F(AccesstokenidTest, CheckSetTokenid, Function | MediumTest | Level1)
253{
254    unsigned long long token = INVAL_TOKEN;
255    unsigned long long tokenSet = GenRand64();
256
257    SetTokenid(&tokenSet);
258    GetTokenid(&token);
259
260    ASSERT_EQ(tokenSet, token);
261}
262
263/**
264 * @tc.name: CheckSetfTokenid
265 * @tc.desc: Test setting of ftokenid
266 * @tc.desc: ftokenid equals to the setting value
267 * @tc.type: FUNC
268 */
269HWTEST_F(AccesstokenidTest, CheckSetfTokenid, Function | MediumTest | Level1)
270{
271    unsigned long long ftoken = INVAL_TOKEN;
272    unsigned long long ftokenSet = GenRand64();
273
274    SetfTokenid(&ftokenSet);
275    GetfTokenid(&ftoken);
276
277    ASSERT_EQ(ftokenSet, ftoken);
278}
279
280/**
281 * @tc.name: CheckChildThreadInheritance
282 * @tc.desc: Test each child thread tokenid equals to father process while ftokenid not equals
283 * @tc.desc: The ftokenid of each child thread equals to 0
284 * @tc.type: FUNC
285 */
286HWTEST_F(AccesstokenidTest, CheckChildThreadInheritance, Function | MediumTest | Level1)
287{
288    pthread_t cid[10];
289
290    unsigned long long token = INVAL_TOKEN;
291    unsigned long long ftoken = INVAL_TOKEN;
292    unsigned long long tokenSet = GenRand64();
293    unsigned long long ftokenSet = GenRand64();
294
295    struct tokeninfo tinfo;
296    tinfo.pid = getpid();
297    tinfo.tid = gettid();
298    tinfo.tokenid = INVAL_TOKEN;
299    tinfo.ftokenid = INVAL_TOKEN;
300
301    GetTokenid(&token);
302    GetfTokenid(&ftoken);
303
304    SetTokenid(&tokenSet);
305    SetfTokenid(&ftokenSet);
306
307    for (int i = 0; i < 10; i++) {
308        if (pthread_create(&cid[i], nullptr, CheckChildThreadInheritance, &tinfo) != 0) {
309            printf("thread %d (ID %ld) pthread_create error\n", i, cid[i]);
310        }
311
312        if (pthread_join(cid[i], nullptr) != 0) {
313            printf("thread %d (ID %ld) pthread_join error\n", i, cid[i]);
314        }
315
316        ASSERT_EQ(tinfo.tokenid, tokenSet);
317        ASSERT_NE(tinfo.ftokenid, ftokenSet);
318        ASSERT_EQ(0, tinfo.ftokenid);
319    }
320}
321
322/**
323 * @tc.name: CheckChildThreadSetIndepent
324 * @tc.desc: Test each child thread tokenid and ftokenid is indepent
325 * @tc.desc: The tokenid and ftokenid of each child thread not equal to father process
326 * @tc.type: FUNC
327 */
328HWTEST_F(AccesstokenidTest, CheckChildThreadSetIndepent, Function | MediumTest | Level1)
329{
330    pthread_t cid[10];
331
332    unsigned long long token = INVAL_TOKEN;
333    unsigned long long ftoken = INVAL_TOKEN;
334    unsigned long long tokenSet = GenRand64();
335    unsigned long long ftokenSet = GenRand64();
336
337    struct tokeninfo tinfo;
338    tinfo.pid = getpid();
339    tinfo.tid = gettid();
340    tinfo.tokenid = INVAL_TOKEN;
341    tinfo.ftokenid = INVAL_TOKEN;
342
343    GetTokenid(&token);
344    GetfTokenid(&ftoken);
345
346    SetTokenid(&tokenSet);
347    SetfTokenid(&ftokenSet);
348
349    for (int i = 0; i < 10; i++) {
350        if (pthread_create(&cid[i], nullptr, CheckChildThreadSetIndepent, &tinfo) != 0) {
351            printf("thread %d (ID %ld) pthread_create error\n", i, cid[i]);
352        }
353
354        if (pthread_join(cid[i], nullptr) != 0) {
355            printf("thread %d (ID %ld) pthread_join error\n", i, cid[i]);
356        }
357
358        ASSERT_NE(tinfo.tokenid, tokenSet);
359        ASSERT_NE(tinfo.ftokenid, ftokenSet);
360        ASSERT_NE(0, tinfo.ftokenid);
361    }
362}
363
364/**
365 * @tc.name: AbnormalGetTokenid
366 * @tc.desc: Test abnormal ioctl cmd of ACCESS_TOKENID_GET_TOKENID
367 * @tc.desc: using nullptr instead of the address of tokenid to ioctl
368 * @tc.type: FUNC
369 */
370HWTEST_F(AccesstokenidTest, AbnormalGetTokenid, Function | MediumTest | Level1)
371{
372    int fd = open(dev_accesstokenid, O_RDWR);
373    if (fd < 0) {
374        printf("open %s failed\r\n", dev_accesstokenid);
375        return;
376    }
377
378    int ret = ioctl(fd, ACCESS_TOKENID_GET_TOKENID, nullptr);
379    close(fd);
380
381    ASSERT_NE(0, ret);
382}
383
384/**
385 * @tc.name: AbnormalSetTokenid
386 * @tc.desc: Test abnormal ioctl cmd of ACCESS_TOKENID_SET_TOKENID
387 * @tc.desc: using nullptr instead of the address of tokenid to ioctl
388 * @tc.type: FUNC
389 */
390HWTEST_F(AccesstokenidTest, AbnormalSetTokenid, Function | MediumTest | Level1)
391{
392    int fd = open(dev_accesstokenid, O_RDWR);
393    if (fd < 0) {
394        printf("open %s failed\r\n", dev_accesstokenid);
395        return;
396    }
397
398    int ret = ioctl(fd, ACCESS_TOKENID_SET_TOKENID, nullptr);
399    close(fd);
400
401    ASSERT_NE(0, ret);
402}
403
404/**
405 * @tc.name: AbnormalGetfTokenid
406 * @tc.desc: Test abnormal ioctl cmd of ACCESS_TOKENID_GET_FTOKENID
407 * @tc.desc: using nullptr instead of the address of ftokenid to ioctl
408 * @tc.type: FUNC
409 */
410HWTEST_F(AccesstokenidTest, AbnormalGetfTokenid, Function | MediumTest | Level1)
411{
412    int fd = open(dev_accesstokenid, O_RDWR);
413    if (fd < 0) {
414        printf("open %s failed\r\n", dev_accesstokenid);
415        return;
416    }
417
418    int ret = ioctl(fd, ACCESS_TOKENID_GET_FTOKENID, nullptr);
419    close(fd);
420
421    ASSERT_NE(0, ret);
422}
423
424/**
425 * @tc.name: AbnormalSetfTokenid
426 * @tc.desc: Test abnormal ioctl cmd of ACCESS_TOKENID_SET_FTOKENID
427 * @tc.desc: using nullptr instead of the address of ftokenid to ioctl
428 * @tc.type: FUNC
429 */
430HWTEST_F(AccesstokenidTest, AbnormalSetfTokenid, Function | MediumTest | Level1)
431{
432    int fd = open(dev_accesstokenid, O_RDWR);
433    if (fd < 0) {
434        printf("open %s failed\r\n", dev_accesstokenid);
435        return;
436    }
437
438    int ret = ioctl(fd, ACCESS_TOKENID_SET_FTOKENID, nullptr);
439    close(fd);
440
441    ASSERT_NE(0, ret);
442}
443
444/**
445 * @tc.name: AbnormalIoctlCmd
446 * @tc.desc: Test abnormal ioctl cmd of ACCESS_TOKENID_ILLEGAL1 and ACCESS_TOKENID_ILLEGAL1
447 * @tc.desc: using illegal cmd instead of accesstokenid to ioctl
448 * @tc.type: FUNC
449 */
450HWTEST_F(AccesstokenidTest, AbnormalIoctlCmd, Function | MediumTest | Level1)
451{
452    unsigned long long token;
453
454    int fd = open(dev_accesstokenid, O_RDWR);
455    if (fd < 0) {
456        printf("open %s failed\r\n", dev_accesstokenid);
457        return;
458    }
459
460    int ret1 = ioctl(fd, ACCESS_TOKENID_ILLEGAL1, &token);
461    int ret2 = ioctl(fd, ACCESS_TOKENID_ILLEGAL2, &token);
462    close(fd);
463
464    ASSERT_NE(0, ret1);
465    ASSERT_NE(0, ret2);
466}
467
468/**
469 * @tc.name: OtherUidSetTokenid
470 * @tc.desc: Test ACCESS_TOKEN_OTHER_UID can not set tokenid
471 * @tc.desc: tokenid can be only set by uid 3020
472 * @tc.type: FUNC
473 */
474HWTEST_F(AccesstokenidTest, OtherUidSetTokenid, Function | MediumTest | Level1)
475{
476    unsigned long long tokenSet = GenRand64();
477    int ret;
478
479    ret = setuid(ACCESS_TOKEN_OTHER_UID);
480    if (ret != 0) {
481        printf("setuid error %d \r\n", ret);
482    }
483
484    int fd = open(dev_accesstokenid, O_RDWR);
485    if (fd < 0) {
486        printf("open %s failed\r\n", dev_accesstokenid);
487        return;
488    }
489
490    ret = ioctl(fd, ACCESS_TOKENID_SET_TOKENID, &tokenSet);
491    close(fd);
492
493    ASSERT_NE(0, ret);
494}
495
496/**
497 * @tc.name: OtherUidGetTokenid
498 * @tc.desc: Test ACCESS_TOKEN_OTHER_UID can get tokenid
499 * @tc.desc: tokenid can get not only by uid 3020
500 * @tc.type: FUNC
501 */
502HWTEST_F(AccesstokenidTest, OtherUidGetTokenid, Function | MediumTest | Level1)
503{
504    unsigned long long token = INVAL_TOKEN;
505    int ret;
506
507    ret = setuid(ACCESS_TOKEN_OTHER_UID);
508    if (ret != 0) {
509        printf("setuid error %d \r\n", ret);
510    }
511
512    int fd = open(dev_accesstokenid, O_RDWR);
513    if (fd < 0) {
514        printf("open %s failed\r\n", dev_accesstokenid);
515        return;
516    }
517
518    ret = ioctl(fd, ACCESS_TOKENID_GET_TOKENID, &token);
519    close(fd);
520
521    ASSERT_EQ(0, ret);
522}
523
524/**
525 * @tc.name: WithoutGrpSetfTokenid
526 * @tc.desc: Test ACCESS_TOKEN_OTHER_GRPID can not set ftokenid
527 * @tc.desc: ftokenid can not set by groups without grpid 3020
528 * @tc.type: FUNC
529 */
530HWTEST_F(AccesstokenidTest, WithoutGrpSetfTokenid, Function | MediumTest | Level1)
531{
532    int ret;
533    size_t size = 1;
534    gid_t list[1] = {ACCESS_TOKEN_OTHER_GRPID};
535    unsigned long long ftokenSet = GenRand64();
536
537    ret = setgroups(size, list);
538    if (ret != 0) {
539        printf("setgroups error %d \r\n", ret);
540    }
541
542    int fd = open(dev_accesstokenid, O_RDWR);
543    if (fd < 0) {
544        printf("open %s failed\r\n", dev_accesstokenid);
545        return;
546    }
547
548    ret = ioctl(fd, ACCESS_TOKENID_SET_FTOKENID, &ftokenSet);
549    close(fd);
550
551    ASSERT_NE(0, ret);
552}
553
554/**
555 * @tc.name: WithoutGrpGetfTokenid
556 * @tc.desc: Test ACCESS_TOKEN_OTHER_GRPID can not get ftokenid
557 * @tc.desc: ftokenid can not get by groups without grpid 3020
558 * @tc.type: FUNC
559 */
560HWTEST_F(AccesstokenidTest, WithoutGrpGetfTokenid, Function | MediumTest | Level1)
561{
562    int ret;
563    size_t size = 1;
564    gid_t list[1] = {ACCESS_TOKEN_OTHER_GRPID};
565    unsigned long long ftoken = INVAL_TOKEN;
566
567    ret = setgroups(size, list);
568    if (ret != 0) {
569        printf("setgroups error %d \r\n", ret);
570    }
571
572    int fd = open(dev_accesstokenid, O_RDWR);
573    if (fd < 0) {
574        printf("open %s failed\r\n", dev_accesstokenid);
575        return;
576    }
577
578    ret = ioctl(fd, ACCESS_TOKENID_GET_FTOKENID, &ftoken);
579    close(fd);
580
581    ASSERT_NE(0, ret);
582}
583
584/**
585 * @tc.name: WithGrpSetfTokenid
586 * @tc.desc: Test ACCESS_TOKEN_OTHER_GRPID and ACCESS_TOKEN_GRPID can set ftokenid
587 * @tc.desc: ftokenid can set by groups with grpid 3020
588 * @tc.type: FUNC
589 */
590HWTEST_F(AccesstokenidTest, WithGrpSetfTokenid, Function | MediumTest | Level1)
591{
592    int ret;
593    size_t size = 2;
594    gid_t list[2] = {ACCESS_TOKEN_OTHER_GRPID, ACCESS_TOKEN_GRPID};
595    unsigned long long ftokenSet = GenRand64();
596
597    ret = setgroups(size, list);
598    if (ret != 0) {
599        printf("setgroups error %d \r\n", ret);
600    }
601
602    int fd = open(dev_accesstokenid, O_RDWR);
603    if (fd < 0) {
604        printf("open %s failed\r\n", dev_accesstokenid);
605        return;
606    }
607
608    ret = ioctl(fd, ACCESS_TOKENID_SET_FTOKENID, &ftokenSet);
609    close(fd);
610
611    ASSERT_EQ(0, ret);
612}
613
614/**
615 * @tc.name: WithGrpGetfTokenid
616 * @tc.desc: Test ACCESS_TOKEN_OTHER_GRPID and ACCESS_TOKEN_GRPID can set ftokenid
617 * @tc.desc: ftokenid can set by groups with grpid 3020
618 * @tc.type: FUNC
619 */
620HWTEST_F(AccesstokenidTest, WithGrpGetfTokenid, Function | MediumTest | Level1)
621{
622    int ret;
623    size_t size = 2;
624    gid_t list[2] = {ACCESS_TOKEN_OTHER_GRPID, ACCESS_TOKEN_GRPID};
625    unsigned long long ftoken = INVAL_TOKEN;
626
627    ret = setgroups(size, list);
628    if (ret != 0) {
629        printf("setgroups error %d \r\n", ret);
630    }
631
632    int fd = open(dev_accesstokenid, O_RDWR);
633    if (fd < 0) {
634        printf("open %s failed\r\n", dev_accesstokenid);
635        return;
636    }
637
638    ret = ioctl(fd, ACCESS_TOKENID_GET_FTOKENID, &ftoken);
639    close(fd);
640
641    ASSERT_EQ(0, ret);
642}
643
644