1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <arpa/inet.h>
18 #include <error.h>
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <sys/socket.h>
24 
25 #include <gtest/gtest.h>
26 #include <qtaguid/qtaguid.h>
27 
canAccessQtaguidFile()28 int canAccessQtaguidFile() {
29     int fd = open("/proc/net/xt_qtaguid/ctrl", O_RDONLY | O_CLOEXEC);
30     close(fd);
31     return fd != -1;
32 }
33 
34 #define SKIP_IF_QTAGUID_NOT_SUPPORTED()                                                       \
35   do {                                                                                        \
36     int res = canAccessQtaguidFile();                                                      \
37     ASSERT_LE(0, res);                                                                        \
38     if (!res) {                                                                               \
39           GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n";  \
40           return;                                                                             \
41     }                                                                                         \
42   } while (0)
43 
getCtrlSkInfo(int tag,uid_t uid,uint64_t * sk_addr,int * ref_cnt)44 int getCtrlSkInfo(int tag, uid_t uid, uint64_t* sk_addr, int* ref_cnt) {
45     FILE *fp;
46     fp = fopen("/proc/net/xt_qtaguid/ctrl", "r");
47     if (!fp)
48         return -ENOENT;
49     uint64_t full_tag = (uint64_t)tag << 32 | uid;
50     char pattern[40];
51     snprintf(pattern, sizeof(pattern), " tag=0x%" PRIx64 " (uid=%" PRIu32 ")", full_tag, uid);
52 
53     size_t len;
54     char *line_buffer = NULL;
55     while(getline(&line_buffer, &len, fp) != -1) {
56         if (strstr(line_buffer, pattern) == NULL)
57             continue;
58         int res;
59         pid_t dummy_pid;
60         uint64_t k_tag;
61         uint32_t k_uid;
62         const int TOTAL_PARAM = 5;
63         res = sscanf(line_buffer, "sock=%" PRIx64 " tag=0x%" PRIx64 " (uid=%" PRIu32 ") "
64                      "pid=%u f_count=%u", sk_addr, &k_tag, &k_uid,
65                      &dummy_pid, ref_cnt);
66         if (!(res == TOTAL_PARAM && k_tag == full_tag && k_uid == uid))
67             return -EINVAL;
68         free(line_buffer);
69         return 0;
70     }
71     free(line_buffer);
72     return -ENOENT;
73 }
74 
checkNoSocketPointerLeaks(int family)75 void checkNoSocketPointerLeaks(int family) {
76     int sockfd = socket(family, SOCK_STREAM, 0);
77     uid_t uid = getuid();
78     int tag = arc4random();
79     int ref_cnt;
80     uint64_t sk_addr;
81     uint64_t expect_addr = 0;
82 
83     EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
84     EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt));
85     EXPECT_EQ(expect_addr, sk_addr);
86     close(sockfd);
87     EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt));
88 }
89 
TEST(NativeQtaguidTest,close_socket_without_untag)90 TEST (NativeQtaguidTest, close_socket_without_untag) {
91     SKIP_IF_QTAGUID_NOT_SUPPORTED();
92 
93     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
94     uid_t uid = getuid();
95     int tag = arc4random();
96     int ref_cnt;
97     uint64_t dummy_sk;
98     EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
99     EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
100     EXPECT_EQ(2, ref_cnt);
101     close(sockfd);
102     EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
103 }
104 
TEST(NativeQtaguidTest,close_socket_without_untag_ipv6)105 TEST (NativeQtaguidTest, close_socket_without_untag_ipv6) {
106     SKIP_IF_QTAGUID_NOT_SUPPORTED();
107 
108     int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
109     uid_t uid = getuid();
110     int tag = arc4random();
111     int ref_cnt;
112     uint64_t dummy_sk;
113     EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
114     EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
115     EXPECT_EQ(2, ref_cnt);
116     close(sockfd);
117     EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
118 }
119 
TEST(NativeQtaguidTest,no_socket_addr_leak)120 TEST (NativeQtaguidTest, no_socket_addr_leak) {
121   SKIP_IF_QTAGUID_NOT_SUPPORTED();
122 
123   checkNoSocketPointerLeaks(AF_INET);
124   checkNoSocketPointerLeaks(AF_INET6);
125 }
126 
main(int argc,char ** argv)127 int main(int argc, char **argv) {
128       testing::InitGoogleTest(&argc, argv);
129       return RUN_ALL_TESTS();
130 }
131