96902940031084b094c3786548ffe94b94bdb5f7
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / kernel / swap / fbiprobe / fbiprobe.c
1 /*
2  * @file fbiprobe/fbi_probe.c
3  *
4  * @author Alexander Aksenov <a.aksenov@samsung.com>
5  * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
6  *
7  * @section LICENSE
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * @section COPYRIGHT
24  *
25  * Copyright (C) Samsung Electronics, 2014
26  *
27  * 2014 Alexander Aksenov : FBI implement
28  * 2014 Vitaliy Cherepanov: FBI implement, portage
29  *
30  * @section DESCRIPTION
31  *
32  * Function body instrumetation
33  *
34  */
35
36 #include "fbiprobe.h"
37 #include "fbi_probe_module.h"
38 #include "fbi_msg.h"
39 #include "regs.h"
40
41 #include <us_manager/us_manager.h>
42 #include <us_manager/probes/probes.h>
43 #include <us_manager/probes/register_probes.h>
44
45 #include <uprobe/swap_uprobes.h>
46 #include <us_manager/sspt/ip.h>
47
48 #include <kprobe/swap_kprobes_deps.h>
49 #include <linux/module.h>
50
51 #include <linux/mm.h>
52 #include <linux/sched.h>
53 #include <linux/dcache.h>
54 #include <linux/mm_types.h>
55
56 #include <us_manager/sspt/sspt_page.h>
57 #include <us_manager/sspt/sspt_file.h>
58
59 #define DIRECT_ADDR (0xFF)
60 #define MAX_STRING_LEN (512)
61
62 /* on fails. return NULL, set size to 0 */
63 /* you shoud free allocated data buffer */
64 static char *fbi_probe_alloc_and_read_from_addr(const struct fbi_var_data *fbid,
65                                                 unsigned long addr,
66                                                 uint32_t *size)
67 {
68         uint8_t i, j;
69         char *buf = NULL;
70         struct fbi_step *step;
71
72         *size = 0;
73
74         /* get final variable address */
75         step = fbid->steps;
76         for (i = 0; i != fbid->steps_count; i++) {
77                 /* dereference */
78                 for (j = 0; j != step->ptr_order; j++) {
79                         unsigned long new_addr;
80                         /* equel to: addr = *addr */
81                         if (!read_proc_vm_atomic(current, addr, &new_addr,
82                                                  sizeof(new_addr))) {
83                                 print_warn("p = 0x%lx step #%d ptr_order #%d\n",
84                                            addr, i + 1, j + 1);
85                                 goto exit_fail;
86                         }
87                         addr = new_addr;
88                         print_debug("dereference addr = 0x%lx;\n", addr);
89                 }
90
91                 /* offset */
92                 addr += step->data_offset;
93                 print_debug("addr + offset = 0x%lx;\n", addr);
94                 step++;
95         }
96
97         /* calculate data size */
98         if (fbid->data_size == 0) {
99                 /*
100                  * that mean variable is string and
101                  * we need to calculate string length
102                  */
103
104                 *size = strnlen_user((const char __user *)addr, MAX_STRING_LEN);
105                 if (*size == 0) {
106                         print_warn("Cannot get string from 0x%lx\n", addr);
107                         goto exit_fail;
108                 }
109         } else {
110                 /* else use size from fbi struct */
111                 *size = fbid->data_size;
112         }
113
114         buf = kmalloc(*size, GFP_KERNEL);
115         if (buf == NULL) {
116                 print_warn("Not enough memory\n");
117                 goto exit_fail_size_0;
118         }
119
120         if (!read_proc_vm_atomic(current, addr, buf, *size)) {
121                 print_warn("Error reading data at 0x%lx, task %d\n",
122                            addr, current->pid);
123                 goto exit_fail_free_buf;
124         }
125
126         if (fbid->data_size == 0) {
127                 /*
128                  * that mean variable is string and
129                  * we need to add terminate '\0'
130                  */
131                 buf[*size - 1] = '\0';
132         }
133
134         return buf;
135
136 exit_fail_free_buf:
137         kfree(buf);
138         buf = NULL;
139 exit_fail_size_0:
140         *size = 0;
141 exit_fail:
142         return NULL;
143
144 }
145
146 static int fbi_probe_get_data_from_reg(const struct fbi_var_data *fbi_i,
147                                        struct pt_regs *regs)
148 {
149         unsigned long *reg_ptr;
150
151         reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
152         if (reg_ptr == NULL) {
153                 print_err("fbi_probe_get_data_from_reg: Wrong register number!\n");
154                 return 0;
155         }
156
157         fbi_msg(fbi_i->var_id, fbi_i->data_size, (char *)reg_ptr);
158
159         return 0;
160 }
161
162 static int fbi_probe_get_data_from_ptrs(const struct fbi_var_data *fbi_i,
163                                         struct pt_regs *regs)
164 {
165         unsigned long *reg_ptr;
166         unsigned long addr;
167         uint32_t size = 0;
168         void *buf = NULL;
169
170         reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
171         if (reg_ptr == NULL) {
172                 print_err("fbi_probe_get_data_from_ptrs: Wrong register number!\n");
173                 goto send_msg;
174         }
175
176         addr = *reg_ptr + fbi_i->reg_offset;
177         print_warn("reg = %p; off = 0x%llx; addr = 0x%lx!\n", reg_ptr,
178                    fbi_i->reg_offset, addr);
179
180         buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
181
182 send_msg:
183         /* If buf is NULL size will be 0.
184          * That mean we cannot get data for this probe.
185          * But we should send probe message with packed data size 0
186          * as error message.
187          */
188         fbi_msg(fbi_i->var_id, size, buf);
189
190         if (buf != NULL)
191                 kfree(buf);
192         else
193                 print_err("cannot get data from ptrs\n");
194
195         return 0;
196 }
197
198 static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm,
199                                                      struct dentry *dentry)
200 {
201         struct vm_area_struct *vma;
202
203         /* FIXME: down_write(&mm->mmap_sem); up_write(&mm->mmap_sem); */
204         /* TODO FILTER vma */
205         for (vma = mm->mmap; vma; vma = vma->vm_next) {
206                 if (vma->vm_file &&
207                    (vma->vm_file->f_dentry == dentry))
208                         /* found */
209                         goto exit;
210         }
211
212         /* not found */
213         vma = NULL;
214 exit:
215         return vma;
216 }
217
218 static int fbi_probe_get_data_from_direct_addr(const struct fbi_var_data *fbi_i,
219                                                struct us_ip *ip,
220                                                struct pt_regs *regs)
221 {
222         struct vm_area_struct *vma;
223         unsigned long addr;
224         uint32_t size = 0;
225         char *buf;
226
227         /* register offset is global address */
228         vma = find_vma_exe_by_dentry(current->mm, ip->page->file->dentry);
229         if (vma == NULL) {
230                 print_warn("cannot locate dentry\n");
231                 goto exit;
232         }
233
234         addr = vma->vm_start + fbi_i->reg_offset;
235
236         print_debug("DIRECT_ADDR reg_offset = %llx\n", fbi_i->reg_offset);
237         print_debug("DIRECT_ADDR vm_start   = %lx\n", vma->vm_start);
238         print_debug("DIRECT_ADDR res_addr   = %lx\n", addr);
239
240         buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
241         /* If buf is NULL size will be 0.
242          * That mean we cannot get data for this probe.
243          * But we should send probe message with packed data size 0
244          * as error message.
245          */
246         fbi_msg(fbi_i->var_id, size, buf);
247
248         if (buf != NULL) {
249                 kfree(buf);
250         } else {
251                 print_warn("get data by direct addr failed (0x%lx :0x%llx)\n",
252                            addr, fbi_i->reg_offset);
253         }
254 exit:
255         return 0;
256 }
257
258 static int fbi_probe_handler(struct kprobe *p, struct pt_regs *regs)
259 {
260         struct uprobe *up = container_of(p, struct uprobe, kp);
261         struct us_ip *ip = container_of(up, struct us_ip, uprobe);
262         struct fbi_info *fbi_i = &ip->info->fbi_i;
263         struct fbi_var_data *fbi_d = NULL;
264         uint8_t i;
265
266         if (ip->info->probe_type != SWAP_FBIPROBE) {
267                 /* How this can occure? Doesn't matter, just print and go */
268                 print_err("Not FBI probe in FBI handler!\n");
269                 return 0;
270         }
271
272         for (i = 0; i != fbi_i->var_count; i++) {
273                 fbi_d = &fbi_i->vars[i];
274                 if (fbi_d->reg_n == DIRECT_ADDR) {
275                         if (0 != fbi_probe_get_data_from_direct_addr(fbi_d, ip,
276                                                                      regs))
277                                 print_err("fbi_probe_get_data_from_direct_addr error\n");
278                 } else if (fbi_d->steps_count == 0) {
279                         if (0 != fbi_probe_get_data_from_reg(fbi_d, regs))
280                                 print_err("fbi_probe_get_data_from_reg error\n");
281                 } else {
282                         if (0 != fbi_probe_get_data_from_ptrs(fbi_d, regs))
283                                 print_err("fbi_probe_get_data_from_ptrs error\n");
284                 }
285         }
286
287         return 0;
288 }
289
290 /* FBI probe interfaces */
291 void fbi_probe_cleanup(struct probe_info *probe_i)
292 {
293         uint8_t i;
294         struct fbi_info *fbi_i = &(probe_i->fbi_i);
295
296         for (i = 0; i != fbi_i->var_count; i++) {
297                 if (fbi_i->vars[i].steps != NULL) {
298                         if (fbi_i->vars[i].steps != NULL)
299                                 kfree(fbi_i->vars[i].steps);
300                         fbi_i->vars[i].steps = NULL;
301                         fbi_i->vars[i].steps_count = 0;
302                 }
303         }
304
305         kfree(fbi_i->vars);
306         fbi_i->vars = NULL;
307 }
308
309 void fbi_probe_init(struct us_ip *ip)
310 {
311         ip->uprobe.kp.pre_handler = (kprobe_pre_handler_t)fbi_probe_handler;
312 }
313
314 void fbi_probe_uninit(struct us_ip *ip)
315 {
316         if (ip != NULL)
317                 fbi_probe_cleanup(ip->info);
318 }
319
320 static int fbi_probe_register_probe(struct us_ip *ip)
321 {
322         return swap_register_uprobe(&ip->uprobe);
323 }
324
325 static void fbi_probe_unregister_probe(struct us_ip *ip, int disarm)
326 {
327         __swap_unregister_uprobe(&ip->uprobe, disarm);
328 }
329
330 static struct uprobe *fbi_probe_get_uprobe(struct us_ip *ip)
331 {
332         return &ip->uprobe;
333 }
334
335 int fbi_probe_copy(struct probe_info *dest, const struct probe_info *source)
336 {
337         uint8_t steps_count;
338         size_t steps_size;
339         size_t vars_size;
340         struct fbi_var_data *vars;
341         struct fbi_step *steps_source;
342         struct fbi_step *steps_dest = NULL;
343         uint8_t i, n;
344         int ret = 0;
345
346         memcpy(dest, source, sizeof(*source));
347
348         vars_size = source->fbi_i.var_count * sizeof(*source->fbi_i.vars);
349         vars = kmalloc(vars_size, GFP_KERNEL);
350         if (vars == NULL)
351                 return -ENOMEM;
352
353         memcpy(vars, source->fbi_i.vars, vars_size);
354
355         for (i = 0; i != source->fbi_i.var_count; i++) {
356                 steps_dest = NULL;
357                 steps_count = vars[i].steps_count;
358                 steps_size = sizeof(*steps_source) * steps_count;
359                 steps_source = vars[i].steps;
360
361                 if (steps_size != 0 && steps_source != NULL) {
362                         steps_dest = kmalloc(steps_size, GFP_KERNEL);
363                         if (steps_dest == NULL) {
364                                 print_err("can not alloc data\n");
365                                 n = i;
366                                 ret = -ENOMEM;
367                                 goto err;
368                         }
369
370                         memcpy(steps_dest, steps_source, steps_size);
371                 }
372                 vars[i].steps = steps_dest;
373         }
374
375         dest->fbi_i.vars = vars;
376
377         return ret;
378 err:
379         for (i = 0; i < n; i++)
380                 kfree(vars[i].steps);
381         kfree(vars);
382         return ret;
383 }
384
385 /* Register */
386 static struct probe_iface fbi_probe_iface = {
387         .init = fbi_probe_init,
388         .uninit = fbi_probe_uninit,
389         .reg = fbi_probe_register_probe,
390         .unreg = fbi_probe_unregister_probe,
391         .get_uprobe = fbi_probe_get_uprobe,
392         .copy = fbi_probe_copy,
393         .cleanup = fbi_probe_cleanup
394 };
395
396 static int __init fbiprobe_module_init(void)
397 {
398         int ret = 0;
399         ret = swap_register_probe_type(SWAP_FBIPROBE, &fbi_probe_iface);
400         print_debug("Init done. Result=%d\n", ret);
401         return ret;
402 }
403
404 static void __exit fbiprobe_module_exit(void)
405 {
406         swap_unregister_probe_type(SWAP_FBIPROBE);
407 }
408
409 module_init(fbiprobe_module_init);
410 module_exit(fbiprobe_module_exit);
411
412 MODULE_LICENSE("GPL");
413 MODULE_DESCRIPTION("SWAP fbiprobe");
414 MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>; Vitaliy Cherepanov <v.cherepanov@samsung.com>");
415