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