From 9213428bd7860ca603d7c54a93cc1967c655be45 Mon Sep 17 00:00:00 2001 From: Alexander Aksenov Date: Tue, 14 Jan 2014 11:20:53 +0400 Subject: [PATCH] [IMPROVE] Ksyms: Implement searching symbols with kallsyms_on_each_symbol() Change-Id: I6e2211b6beca9d3b4b3ba4799009a87acf88c01b Signed-off-by: Alexander Aksenov --- Kbuild | 1 + ksyms/Kbuild | 11 +- ksyms/ksyms.c | 320 +++++-------------------------------------------- ksyms/ksyms.h | 2 + ksyms/no_ksyms.c | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ start.sh | 1 + stop.sh | 1 + 7 files changed, 399 insertions(+), 295 deletions(-) create mode 100644 ksyms/no_ksyms.c diff --git a/Kbuild b/Kbuild index 7deb5d8..e334a39 100644 --- a/Kbuild +++ b/Kbuild @@ -1,6 +1,7 @@ EXTRA_CFLAGS := $(extra_cflags) obj-m := buffer/ \ + ksyms/ \ driver/ \ writer/ \ kprobe/ \ diff --git a/ksyms/Kbuild b/ksyms/Kbuild index 317f398..70bb2c9 100644 --- a/ksyms/Kbuild +++ b/ksyms/Kbuild @@ -1,4 +1,9 @@ -ifneq ($(CONFIG_KALLSYMS),y) - obj-m := swap_ksyms.o +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_ksyms.o + +ifeq ($(CONFIG_KALLSYMS),y) swap_ksyms-y := ksyms.o -endif \ No newline at end of file +else + swap_ksyms-y := no_ksyms.o +endif diff --git a/ksyms/ksyms.c b/ksyms/ksyms.c index 6cf9ada..dca39eb 100644 --- a/ksyms/ksyms.c +++ b/ksyms/ksyms.c @@ -16,326 +16,63 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) Samsung Electronics, 2013 + * Copyright (C) Samsung Electronics, 2014 * - * 2013 Vyacheslav Cherkashin + * 2014 Alexander Aksenov * */ + #include "ksyms.h" +#include #include -#include -#include -#include -#include -#include -#include - - -#ifndef CONFIG_KALLSYMS - -#define KSYMS_ERR(format, args...) \ - do { \ - char *f = __FILE__; \ - char *n = strrchr(f, '/'); \ - printk("%s:%u \'%s\' ERROR: " format "\n" , (n) ? n+1 : f, __LINE__, __FUNCTION__, ##args); \ - } while(0) - - -struct sys_map_item { - struct list_head list; +#include +struct symbol_data { + const char *name; + size_t len; unsigned long addr; - char *name; }; -static char* sm_path = NULL; -module_param(sm_path, charp, 0); - -LIST_HEAD(smi_list); -static struct file *file = NULL; - -static int cnt_init_sm = 0; -DEFINE_SEMAPHORE(cnt_init_sm_lock); - -static int file_open(void) +static int symbol_cb(void *data, const char *sym, struct module *mod, + unsigned long addr) { - struct file *f = filp_open(sm_path, O_RDONLY, 0); + struct symbol_data *sym_data_p = (struct symbol_data *)data; - if (IS_ERR(f)) { - KSYMS_ERR("cannot open file \'%s\'", sm_path); - return PTR_ERR(f); + /* We expect that real symbol name should have at least the same length as + * symbol name we are looking for. */ + if (strncmp(sym_data_p->name, sym, sym_data_p->len) == 0) { + sym_data_p->addr = addr; + /* Return != 0 to stop loop over the symbols */ + return 1; } - file = f; - return 0; } -static void file_close(void) -{ - if (file) { - int ret = filp_close(file, NULL); - file = NULL; - - if (ret) { - KSYMS_ERR("while closing file \'%s\' err=%d", sm_path, ret); - } - } -} - -static int file_check(void) -{ - int ret = file_open(); - if (ret == 0) { - file_close(); - } - - return ret; -} - -static long file_size(struct file *file) -{ - struct kstat st; - if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) { - return -1; - } - - if (!S_ISREG(st.mode)) { - return -1; - } - - if (st.size != (long)st.size) { - return -1; - } - - return st.size; -} - -static struct sys_map_item *create_smi(unsigned long addr, const char *name) +unsigned long swap_ksyms_substr(const char *name) { - struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL); - - if (smi == NULL) { - KSYMS_ERR("not enough memory"); - return NULL; - } - - smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL); - if (smi->name == NULL) { - kfree(smi); - KSYMS_ERR("not enough memory"); - return NULL; - } - - INIT_LIST_HEAD(&smi->list); - smi->addr = addr; - strcpy(smi->name, name); - - return smi; -} - -static void free_smi(struct sys_map_item *smi) -{ - kfree(smi->name); - kfree(smi); -} - -static void add_smi(const struct sys_map_item *smi) -{ - list_add_tail(&smi->list, &smi_list); -} - -static int is_endline(char c) -{ - return c == '\n' || c == '\r' || c == '\0'; -} - -static int is_symbol_attr(char c) -{ - return c == 't' || c == 'T'; -} - -static struct sys_map_item *get_sys_map_item(char *begin, char *end) -{ - struct sys_map_item *smi = NULL; - int n, len = end - begin; - unsigned long addr; - char attr, name[128], *line; - - line = kmalloc(len + 1, GFP_KERNEL); - memcpy(line, begin, len); - line[len] = '\0'; - - n = sscanf(line, "%x %c %127s", &addr, &attr, &name); - name[127] = '\0'; - - if (n != 3) { - KSYMS_ERR("parsing line: \"%s\"", line); - attr = '\0'; - } - - kfree(line); - - if (is_symbol_attr(attr)) { - smi = create_smi(addr, name); - } + struct symbol_data sym_data = { + .name = name, + .len = strlen(name), + .addr = 0 + }; + kallsyms_on_each_symbol(symbol_cb, (void *)&sym_data); - return smi; + return sym_data.addr; } - - -static void parsing(char *buf, int size) -{ - struct sys_map_item *smi; - char *start, *end, *c; - - start = buf; - end = buf + size; - - for (c = start; c < end; ++c) { - if (is_endline(*c)) { - smi = get_sys_map_item(start, c); - if (smi) { - add_smi(smi); - } - - for (start = c; c < end; ++c) { - if (!is_endline(*c)) { - start = c; - break; - } - } - } - } -} - -static int create_sys_map(void) -{ - char *data; - long size; - int ret = file_open(); - - if (ret) { - return ret; - } - - size = file_size(file); - if (size < 0) { - KSYMS_ERR("cannot get file size"); - ret = size; - goto close; - } - - data = vmalloc(size); - if (data == NULL) { - KSYMS_ERR("not enough memory"); - ret = -1; - goto close; - } - - if (kernel_read(file, 0, data, size) != size) { - KSYMS_ERR("reading file %s", sm_path); - ret = -1; - goto free; - } - - parsing(data, size); - -free: - vfree(data); - -close: - file_close(); - - return 0; -} - -static void free_sys_map(void) -{ - struct sys_map_item *smi, *n; - list_for_each_entry_safe(smi, n, &smi_list, list) { - list_del(&smi->list); - free_smi(smi); - } -} - -int swap_get_ksyms(void) -{ - int ret = 0; - - down(&cnt_init_sm_lock); - if (cnt_init_sm == 0) { - ret = create_sys_map(); - } - - ++cnt_init_sm; - up(&cnt_init_sm_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(swap_get_ksyms); - -void swap_put_ksyms(void) -{ - down(&cnt_init_sm_lock); - --cnt_init_sm; - if (cnt_init_sm == 0) { - free_sys_map(); - } - - if (cnt_init_sm < 0) { - KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm); - cnt_init_sm = 0; - } - - up(&cnt_init_sm_lock); -} -EXPORT_SYMBOL_GPL(swap_put_ksyms); - -unsigned long swap_ksyms(const char *name) -{ - struct sys_map_item *smi; - - list_for_each_entry(smi, &smi_list, list) { - if (strcmp(name, smi->name) == 0) { - return smi->addr; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(swap_ksyms); +EXPORT_SYMBOL_GPL(swap_ksyms_substr); int __init swap_ksyms_init(void) { - int ret = 0; - - if (sm_path == NULL) { - KSYMS_ERR("sm_path=NULL"); - return -EINVAL; - } - - ret = file_check(); - if (ret) { - return -EINVAL; - } - - // TODO: calling func 'swap_get_ksyms' in module used func 'swap_ksyms' - swap_get_ksyms(); + printk("SWAP_KSYMS: Module initialized\n"); return 0; } void __exit swap_ksyms_exit(void) { - down(&cnt_init_sm_lock); - - if (cnt_init_sm > 0) { - free_sys_map(); - } - - up(&cnt_init_sm_lock); + printk("SWAP_KSYMS: Module uninitialized\n"); } module_init(swap_ksyms_init); @@ -345,4 +82,3 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SWAP ksyms module"); MODULE_AUTHOR("Vyacheslav Cherkashin "); -#endif /*CONFIG_KALLSYMS*/ diff --git a/ksyms/ksyms.h b/ksyms/ksyms.h index 7719e2e..723bb08 100644 --- a/ksyms/ksyms.h +++ b/ksyms/ksyms.h @@ -58,4 +58,6 @@ unsigned long swap_ksyms(const char *name); #endif /*CONFIG_KALLSYMS*/ +unsigned long swap_ksyms_substr(const char *name); + #endif /*__KSYMS_H__*/ diff --git a/ksyms/no_ksyms.c b/ksyms/no_ksyms.c new file mode 100644 index 0000000..a91eeb8 --- /dev/null +++ b/ksyms/no_ksyms.c @@ -0,0 +1,358 @@ +/* + * Dynamic Binary Instrumentation Module based on KProbes + * modules/ksyms/no_ksyms.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2013 + * + * 2013 Vyacheslav Cherkashin + * + */ + +#include "ksyms.h" +#include +#include +#include +#include +#include +#include +#include + + +#define KSYMS_ERR(format, args...) \ + do { \ + char *f = __FILE__; \ + char *n = strrchr(f, '/'); \ + printk("%s:%u \'%s\' ERROR: " format "\n" , (n) ? n+1 : f, __LINE__, __FUNCTION__, ##args); \ + } while(0) + + +struct sys_map_item { + struct list_head list; + + unsigned long addr; + char *name; +}; + +static char* sm_path = NULL; +module_param(sm_path, charp, 0); + +LIST_HEAD(smi_list); +static struct file *file = NULL; + +static int cnt_init_sm = 0; +DEFINE_SEMAPHORE(cnt_init_sm_lock); + +static int file_open(void) +{ + struct file *f = filp_open(sm_path, O_RDONLY, 0); + + if (IS_ERR(f)) { + KSYMS_ERR("cannot open file \'%s\'", sm_path); + return PTR_ERR(f); + } + + file = f; + + return 0; +} + +static void file_close(void) +{ + if (file) { + int ret = filp_close(file, NULL); + file = NULL; + + if (ret) { + KSYMS_ERR("while closing file \'%s\' err=%d", sm_path, ret); + } + } +} + +static int file_check(void) +{ + int ret = file_open(); + if (ret == 0) { + file_close(); + } + + return ret; +} + +static long file_size(struct file *file) +{ + struct kstat st; + if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) { + return -1; + } + + if (!S_ISREG(st.mode)) { + return -1; + } + + if (st.size != (long)st.size) { + return -1; + } + + return st.size; +} + +static struct sys_map_item *create_smi(unsigned long addr, const char *name) +{ + struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL); + + if (smi == NULL) { + KSYMS_ERR("not enough memory"); + return NULL; + } + + smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL); + if (smi->name == NULL) { + kfree(smi); + KSYMS_ERR("not enough memory"); + return NULL; + } + + INIT_LIST_HEAD(&smi->list); + smi->addr = addr; + strcpy(smi->name, name); + + return smi; +} + +static void free_smi(struct sys_map_item *smi) +{ + kfree(smi->name); + kfree(smi); +} + +static void add_smi(const struct sys_map_item *smi) +{ + list_add_tail(&smi->list, &smi_list); +} + +static int is_endline(char c) +{ + return c == '\n' || c == '\r' || c == '\0'; +} + +static int is_symbol_attr(char c) +{ + return c == 't' || c == 'T'; +} + +static struct sys_map_item *get_sys_map_item(char *begin, char *end) +{ + struct sys_map_item *smi = NULL; + int n, len = end - begin; + unsigned long addr; + char attr, name[128], *line; + + line = kmalloc(len + 1, GFP_KERNEL); + memcpy(line, begin, len); + line[len] = '\0'; + + n = sscanf(line, "%x %c %127s", &addr, &attr, &name); + name[127] = '\0'; + + if (n != 3) { + KSYMS_ERR("parsing line: \"%s\"", line); + attr = '\0'; + } + + kfree(line); + + if (is_symbol_attr(attr)) { + smi = create_smi(addr, name); + } + + return smi; +} + + +static void parsing(char *buf, int size) +{ + struct sys_map_item *smi; + char *start, *end, *c; + + start = buf; + end = buf + size; + + for (c = start; c < end; ++c) { + if (is_endline(*c)) { + smi = get_sys_map_item(start, c); + if (smi) { + add_smi(smi); + } + + for (start = c; c < end; ++c) { + if (!is_endline(*c)) { + start = c; + break; + } + } + } + } +} + +static int create_sys_map(void) +{ + char *data; + long size; + int ret = file_open(); + + if (ret) { + return ret; + } + + size = file_size(file); + if (size < 0) { + KSYMS_ERR("cannot get file size"); + ret = size; + goto close; + } + + data = vmalloc(size); + if (data == NULL) { + KSYMS_ERR("not enough memory"); + ret = -1; + goto close; + } + + if (kernel_read(file, 0, data, size) != size) { + KSYMS_ERR("reading file %s", sm_path); + ret = -1; + goto free; + } + + parsing(data, size); + +free: + vfree(data); + +close: + file_close(); + + return 0; +} + +static void free_sys_map(void) +{ + struct sys_map_item *smi, *n; + list_for_each_entry_safe(smi, n, &smi_list, list) { + list_del(&smi->list); + free_smi(smi); + } +} + +int swap_get_ksyms(void) +{ + int ret = 0; + + down(&cnt_init_sm_lock); + if (cnt_init_sm == 0) { + ret = create_sys_map(); + } + + ++cnt_init_sm; + up(&cnt_init_sm_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(swap_get_ksyms); + +void swap_put_ksyms(void) +{ + down(&cnt_init_sm_lock); + --cnt_init_sm; + if (cnt_init_sm == 0) { + free_sys_map(); + } + + if (cnt_init_sm < 0) { + KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm); + cnt_init_sm = 0; + } + + up(&cnt_init_sm_lock); +} +EXPORT_SYMBOL_GPL(swap_put_ksyms); + +unsigned long swap_ksyms(const char *name) +{ + struct sys_map_item *smi; + + list_for_each_entry(smi, &smi_list, list) { + if (strcmp(name, smi->name) == 0) { + return smi->addr; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(swap_ksyms); + +unsigned long swap_ksyms_substr(const char *name) +{ + struct sys_map_item *smi; + size_t len = strlen(name); + + list_for_each_entry(smi, &smi_list, list) { + if (strncmp(name, smi->name, len) == 0) + return smi->addr; + } + + return 0; +} +EXPORT_SYMBOL_GPL(swap_ksyms_substr); + +int __init swap_ksyms_init(void) +{ + int ret = 0; + + if (sm_path == NULL) { + KSYMS_ERR("sm_path=NULL"); + return -EINVAL; + } + + ret = file_check(); + if (ret) { + return -EINVAL; + } + + // TODO: calling func 'swap_get_ksyms' in module used func 'swap_ksyms' + swap_get_ksyms(); + + return 0; +} + +void __exit swap_ksyms_exit(void) +{ + down(&cnt_init_sm_lock); + + if (cnt_init_sm > 0) { + free_sys_map(); + } + + up(&cnt_init_sm_lock); +} + +module_init(swap_ksyms_init); +module_exit(swap_ksyms_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SWAP ksyms module"); +MODULE_AUTHOR("Vyacheslav Cherkashin "); diff --git a/start.sh b/start.sh index 5d0e6c9..41864b3 100755 --- a/start.sh +++ b/start.sh @@ -1,6 +1,7 @@ #!/bin/sh insmod swap_buffer.ko || exit 1 # buffer is loaded +insmod swap_ksyms.ko || exit 1 insmod swap_driver.ko || exit 1 # driver is loaded insmod swap_writer.ko || exit 1 insmod swap_kprobe.ko || exit 1 # kprobe is loaded diff --git a/stop.sh b/stop.sh index 12d1406..dcb4706 100755 --- a/stop.sh +++ b/stop.sh @@ -10,6 +10,7 @@ rmmod swap_ks_manager rmmod swap_kprobe rmmod swap_writer rmmod swap_driver +rmmod swap_ksyms rmmod swap_buffer -- 2.7.4