1 /**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
10 #define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
11 #define TRANSLATE_SIZE 256
12 #define MAX_COLLISIONS 2
14 static uint32_t *gator_crc32_table;
15 static unsigned int translate_buffer_mask;
17 static DEFINE_PER_CPU(char *, translate_text);
18 static DEFINE_PER_CPU(uint32_t, cookie_next_key);
19 static DEFINE_PER_CPU(uint64_t *, cookie_keys);
20 static DEFINE_PER_CPU(uint32_t *, cookie_values);
21 static DEFINE_PER_CPU(int, translate_buffer_read);
22 static DEFINE_PER_CPU(int, translate_buffer_write);
23 static DEFINE_PER_CPU(void **, translate_buffer);
25 static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
26 static void wq_cookie_handler(struct work_struct *unused);
27 DECLARE_WORK(cookie_work, wq_cookie_handler);
28 static struct timer_list app_process_wake_up_timer;
29 static void app_process_wake_up_handler(unsigned long unused_data);
31 static uint32_t cookiemap_code(uint64_t value64)
32 {
33 uint32_t value = (uint32_t)((value64 >> 32) + value64);
34 uint32_t cookiecode = (value >> 24) & 0xff;
35 cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
36 cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
37 cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
38 cookiecode &= (COOKIEMAP_ENTRIES - 1);
39 return cookiecode * MAX_COLLISIONS;
40 }
42 static uint32_t gator_chksum_crc32(const char *data)
43 {
44 register unsigned long crc;
45 const unsigned char *block = data;
46 int i, length = strlen(data);
48 crc = 0xFFFFFFFF;
49 for (i = 0; i < length; i++) {
50 crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
51 }
53 return (crc ^ 0xFFFFFFFF);
54 }
56 /*
57 * Exists
58 * Pre: [0][1][v][3]..[n-1]
59 * Post: [v][0][1][3]..[n-1]
60 */
61 static uint32_t cookiemap_exists(uint64_t key)
62 {
63 unsigned long x, flags, retval = 0;
64 int cpu = smp_processor_id();
65 uint32_t cookiecode = cookiemap_code(key);
66 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
67 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
69 // Can be called from interrupt handler or from work queue
70 local_irq_save(flags);
71 for (x = 0; x < MAX_COLLISIONS; x++) {
72 if (keys[x] == key) {
73 uint32_t value = values[x];
74 for (; x > 0; x--) {
75 keys[x] = keys[x - 1];
76 values[x] = values[x - 1];
77 }
78 keys[0] = key;
79 values[0] = value;
80 retval = value;
81 break;
82 }
83 }
84 local_irq_restore(flags);
86 return retval;
87 }
89 /*
90 * Add
91 * Pre: [0][1][2][3]..[n-1]
92 * Post: [v][0][1][2]..[n-2]
93 */
94 static void cookiemap_add(uint64_t key, uint32_t value)
95 {
96 int cpu = smp_processor_id();
97 int cookiecode = cookiemap_code(key);
98 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
99 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
100 int x;
102 for (x = MAX_COLLISIONS - 1; x > 0; x--) {
103 keys[x] = keys[x - 1];
104 values[x] = values[x - 1];
105 }
106 keys[0] = key;
107 values[0] = value;
108 }
110 static void translate_buffer_write_ptr(int cpu, void *x)
111 {
112 per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
113 per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
114 }
116 static void *translate_buffer_read_ptr(int cpu)
117 {
118 void *value = per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_read, cpu)++];
119 per_cpu(translate_buffer_read, cpu) &= translate_buffer_mask;
120 return value;
121 }
123 static void wq_cookie_handler(struct work_struct *unused)
124 {
125 struct task_struct *task;
126 char *text;
127 int cpu = smp_processor_id();
128 unsigned int commit;
130 mutex_lock(&start_mutex);
132 if (gator_started != 0) {
133 commit = per_cpu(translate_buffer_write, cpu);
134 while (per_cpu(translate_buffer_read, cpu) != commit) {
135 task = (struct task_struct *)translate_buffer_read_ptr(cpu);
136 text = (char *)translate_buffer_read_ptr(cpu);
137 get_cookie(cpu, task, text, true);
138 }
139 }
141 mutex_unlock(&start_mutex);
142 }
144 static void app_process_wake_up_handler(unsigned long unused_data)
145 {
146 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
147 schedule_work(&cookie_work);
148 }
150 // Retrieve full name from proc/pid/cmdline for java processes on Android
151 static int translate_app_process(const char **text, int cpu, struct task_struct *task, bool from_wq)
152 {
153 void *maddr;
154 unsigned int len;
155 unsigned long addr;
156 struct mm_struct *mm;
157 struct page *page = NULL;
158 struct vm_area_struct *page_vma;
159 int bytes, offset, retval = 0, ptr;
160 char *buf = per_cpu(translate_text, cpu);
162 // Push work into a work queue if in atomic context as the kernel functions below might sleep
163 // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems
164 // inconsistent during a context switch between android/linux versions
165 if (!from_wq) {
166 // Check if already in buffer
167 ptr = per_cpu(translate_buffer_read, cpu);
168 while (ptr != per_cpu(translate_buffer_write, cpu)) {
169 if (per_cpu(translate_buffer, cpu)[ptr] == (void *)task)
170 goto out;
171 ptr = (ptr + 2) & translate_buffer_mask;
172 }
174 translate_buffer_write_ptr(cpu, (void *)task);
175 translate_buffer_write_ptr(cpu, (void *)*text);
177 mod_timer(&app_process_wake_up_timer, jiffies + 1);
178 goto out;
179 }
181 mm = get_task_mm(task);
182 if (!mm)
183 goto out;
184 if (!mm->arg_end)
185 goto outmm;
186 addr = mm->arg_start;
187 len = mm->arg_end - mm->arg_start;
189 if (len > TRANSLATE_SIZE)
190 len = TRANSLATE_SIZE;
192 down_read(&mm->mmap_sem);
193 while (len) {
194 if (get_user_pages(task, mm, addr, 1, 0, 1, &page, &page_vma) <= 0)
195 goto outsem;
197 maddr = kmap(page);
198 offset = addr & (PAGE_SIZE - 1);
199 bytes = len;
200 if (bytes > PAGE_SIZE - offset)
201 bytes = PAGE_SIZE - offset;
203 copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
205 kunmap(page); // release page allocated by get_user_pages()
206 page_cache_release(page);
208 len -= bytes;
209 buf += bytes;
210 addr += bytes;
212 *text = per_cpu(translate_text, cpu);
213 retval = 1;
214 }
216 // On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
217 if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
218 retval = 0;
220 outsem:
221 up_read(&mm->mmap_sem);
222 outmm:
223 mmput(mm);
224 out:
225 return retval;
226 }
228 static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq)
229 {
230 unsigned long flags, cookie;
231 uint64_t key;
233 key = gator_chksum_crc32(text);
234 key = (key << 32) | (uint32_t)task->tgid;
236 cookie = cookiemap_exists(key);
237 if (cookie) {
238 return cookie;
239 }
241 if (strcmp(text, "app_process") == 0) {
242 if (!translate_app_process(&text, cpu, task, from_wq))
243 return INVALID_COOKIE;
244 }
246 // Can be called from interrupt handler or from work queue or from scheduler trace
247 local_irq_save(flags);
249 cookie = INVALID_COOKIE;
250 if (marshal_cookie_header(text)) {
251 cookie = per_cpu(cookie_next_key, cpu) += nr_cpu_ids;
252 cookiemap_add(key, cookie);
253 marshal_cookie(cookie, text);
254 }
256 local_irq_restore(flags);
258 return cookie;
259 }
261 static int get_exec_cookie(int cpu, struct task_struct *task)
262 {
263 struct mm_struct *mm = task->mm;
264 const char *text;
266 // kernel threads have no address space
267 if (!mm)
268 return NO_COOKIE;
270 if (task && task->mm && task->mm->exe_file) {
271 text = task->mm->exe_file->f_path.dentry->d_name.name;
272 return get_cookie(cpu, task, text, false);
273 }
275 return INVALID_COOKIE;
276 }
278 static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
279 {
280 unsigned long cookie = NO_COOKIE;
281 struct mm_struct *mm = task->mm;
282 struct vm_area_struct *vma;
283 const char *text;
285 if (!mm)
286 return cookie;
288 for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
289 if (addr < vma->vm_start || addr >= vma->vm_end)
290 continue;
292 if (vma->vm_file) {
293 text = vma->vm_file->f_path.dentry->d_name.name;
294 cookie = get_cookie(cpu, task, text, false);
295 *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
296 } else {
297 /* must be an anonymous map */
298 *offset = addr;
299 }
301 break;
302 }
304 if (!vma)
305 cookie = INVALID_COOKIE;
307 return cookie;
308 }
310 static int cookies_initialize(void)
311 {
312 uint32_t crc, poly;
313 int i, j, cpu, size, err = 0;
315 int translate_buffer_size = 512; // must be a power of 2
316 translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
318 for_each_present_cpu(cpu) {
319 per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
321 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
322 per_cpu(cookie_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
323 if (!per_cpu(cookie_keys, cpu)) {
324 err = -ENOMEM;
325 goto cookie_setup_error;
326 }
327 memset(per_cpu(cookie_keys, cpu), 0, size);
329 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
330 per_cpu(cookie_values, cpu) = (uint32_t *)kmalloc(size, GFP_KERNEL);
331 if (!per_cpu(cookie_values, cpu)) {
332 err = -ENOMEM;
333 goto cookie_setup_error;
334 }
335 memset(per_cpu(cookie_values, cpu), 0, size);
337 per_cpu(translate_buffer, cpu) = (void **)kmalloc(translate_buffer_size, GFP_KERNEL);
338 if (!per_cpu(translate_buffer, cpu)) {
339 err = -ENOMEM;
340 goto cookie_setup_error;
341 }
343 per_cpu(translate_buffer_write, cpu) = 0;
344 per_cpu(translate_buffer_read, cpu) = 0;
346 per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL);
347 if (!per_cpu(translate_text, cpu)) {
348 err = -ENOMEM;
349 goto cookie_setup_error;
350 }
351 }
353 // build CRC32 table
354 poly = 0x04c11db7;
355 gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
356 for (i = 0; i < 256; i++) {
357 crc = i;
358 for (j = 8; j > 0; j--) {
359 if (crc & 1) {
360 crc = (crc >> 1) ^ poly;
361 } else {
362 crc >>= 1;
363 }
364 }
365 gator_crc32_table[i] = crc;
366 }
368 setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
370 cookie_setup_error:
371 return err;
372 }
374 static void cookies_release(void)
375 {
376 int cpu;
378 for_each_present_cpu(cpu) {
379 kfree(per_cpu(cookie_keys, cpu));
380 per_cpu(cookie_keys, cpu) = NULL;
382 kfree(per_cpu(cookie_values, cpu));
383 per_cpu(cookie_values, cpu) = NULL;
385 kfree(per_cpu(translate_buffer, cpu));
386 per_cpu(translate_buffer, cpu) = NULL;
387 per_cpu(translate_buffer_read, cpu) = 0;
388 per_cpu(translate_buffer_write, cpu) = 0;
390 kfree(per_cpu(translate_text, cpu));
391 per_cpu(translate_text, cpu) = NULL;
392 }
394 del_timer_sync(&app_process_wake_up_timer);
395 kfree(gator_crc32_table);
396 gator_crc32_table = NULL;
397 }