summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>2015-08-18 12:32:24 +0300
committerDmitry Kovalenko <d.kovalenko@samsung.com>2015-08-27 22:53:43 -0700
commit2b6aa26aa59dace9e60cf25cc97d315382b2f8a6 (patch)
tree74b658f196a512035dc73b49dd607fed408f52a6
parent49f33cdd88ccc2158a97d9e8e3e4a720d49eb0c8 (diff)
downloadswap-modules-2b6aa26aa59dace9e60cf25cc97d315382b2f8a6.tar.gz
swap-modules-2b6aa26aa59dace9e60cf25cc97d315382b2f8a6.tar.bz2
swap-modules-2b6aa26aa59dace9e60cf25cc97d315382b2f8a6.zip
[FIX] probes disarming in fork'ed process
Disarming is now moved out of atomic context. Change-Id: I723b11e25dc377a7caea5efb54ed42b34db68868 Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
-rw-r--r--kprobe/swap_kprobes.h3
-rw-r--r--uprobe/arch/arm/swap-asm/swap_uprobes.c38
-rw-r--r--uprobe/arch/arm/swap-asm/swap_uprobes.h3
-rw-r--r--uprobe/arch/x86/swap-asm/swap_uprobes.c15
-rw-r--r--uprobe/arch/x86/swap-asm/swap_uprobes.h3
-rw-r--r--uprobe/swap_uprobes.c158
-rw-r--r--uprobe/swap_uprobes.h27
-rw-r--r--us_manager/helper.c78
-rw-r--r--us_manager/sspt/sspt_file.c16
-rw-r--r--us_manager/sspt/sspt_file.h3
-rw-r--r--us_manager/sspt/sspt_page.c12
-rw-r--r--us_manager/sspt/sspt_page.h3
-rw-r--r--us_manager/sspt/sspt_proc.c9
-rw-r--r--us_manager/sspt/sspt_proc.h4
14 files changed, 310 insertions, 62 deletions
diff --git a/kprobe/swap_kprobes.h b/kprobe/swap_kprobes.h
index 5153e8eb..5ad80813 100644
--- a/kprobe/swap_kprobes.h
+++ b/kprobe/swap_kprobes.h
@@ -294,9 +294,6 @@ void swap_unregister_kretprobe_bottom(struct kretprobe *rp);
void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size);
-int swap_disarm_urp_inst_for_task(struct task_struct *parent,
- struct task_struct *task);
-
int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs);
diff --git a/uprobe/arch/arm/swap-asm/swap_uprobes.c b/uprobe/arch/arm/swap-asm/swap_uprobes.c
index 13697856..bba8d98e 100644
--- a/uprobe/arch/arm/swap-asm/swap_uprobes.c
+++ b/uprobe/arch/arm/swap-asm/swap_uprobes.c
@@ -698,6 +698,15 @@ int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
return 0;
}
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
+{
+ /* Understand function mode */
+ return ((unsigned long)ri->sp & 1) ?
+ ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b) :
+ (unsigned long)(ri->rp->up.kp.ainsn.insn +
+ UPROBES_TRAMP_RET_BREAK_IDX);
+}
+
/**
* @brief Disarms uretprobe instance.
*
@@ -707,7 +716,7 @@ int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
* negative error code on error.
*/
int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task)
+ struct task_struct *task, unsigned long tr)
{
struct pt_regs *uregs = task_pt_regs(ri->task);
unsigned long ra = swap_get_ret_addr(uregs);
@@ -716,15 +725,16 @@ int arch_disarm_urp_inst(struct uretprobe_instance *ri,
unsigned long *stack = sp - RETPROBE_STACK_DEPTH + 1;
unsigned long *found = NULL;
unsigned long *buf[RETPROBE_STACK_DEPTH];
+ unsigned long vaddr;
int i, retval;
- /* Understand function mode */
- if ((long)ri->sp & 1) {
- tramp = (unsigned long *)
- ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b);
+ if (tr == 0) {
+ vaddr = (unsigned long)ri->rp->up.kp.addr;
+ tramp = (unsigned long *)arch_tramp_by_ri(ri);
} else {
- tramp = (unsigned long *)(ri->rp->up.kp.ainsn.insn +
- UPROBES_TRAMP_RET_BREAK_IDX);
+ /* ri - invalid */
+ vaddr = 0;
+ tramp = (unsigned long *)tr;
}
/* check stack */
@@ -752,10 +762,10 @@ int arch_disarm_urp_inst(struct uretprobe_instance *ri,
}
printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
- "%08lx (%08lx /%+d) - %p\n",
+ "%08lx (%08lx /%+d) - %lx, set ret_addr=%p\n",
task->comm, task->tgid, task->pid,
(unsigned long)found, (unsigned long)sp,
- found - sp, ri->rp->up.kp.addr);
+ found - sp, vaddr, ri->ret_addr);
retval = write_proc_vm_atomic(task, (unsigned long)found,
&ri->ret_addr,
sizeof(ri->ret_addr));
@@ -771,16 +781,16 @@ int arch_disarm_urp_inst(struct uretprobe_instance *ri,
check_lr: /* check lr anyway */
if (ra == (unsigned long)tramp) {
printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
- "lr = %08lx - %p\n",
- task->comm, task->tgid, task->pid,
- ra, ri->rp->up.kp.addr);
+ "lr = %08lx - %lx, set ret_addr=%p\n",
+ task->comm, task->tgid, task->pid, ra, vaddr, ri->ret_addr);
+
swap_set_ret_addr(uregs, (unsigned long)ri->ret_addr);
retval = 0;
} else if (retval) {
printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at "
- "sp = %08lx, lr = %08lx - %p\n",
+ "sp = %08lx, lr = %08lx - %lx, ret_addr=%p\n",
task->comm, task->tgid, task->pid,
- (unsigned long)sp, ra, ri->rp->up.kp.addr);
+ (unsigned long)sp, ra, vaddr, ri->ret_addr);
}
return retval;
diff --git a/uprobe/arch/arm/swap-asm/swap_uprobes.h b/uprobe/arch/arm/swap-asm/swap_uprobes.h
index 885f227d..d0ba89b0 100644
--- a/uprobe/arch/arm/swap-asm/swap_uprobes.h
+++ b/uprobe/arch/arm/swap-asm/swap_uprobes.h
@@ -82,7 +82,8 @@ static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task);
+ struct task_struct *task, unsigned long tr);
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri);
unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
diff --git a/uprobe/arch/x86/swap-asm/swap_uprobes.c b/uprobe/arch/x86/swap-asm/swap_uprobes.c
index 84de6e4f..9a336c22 100644
--- a/uprobe/arch/x86/swap-asm/swap_uprobes.c
+++ b/uprobe/arch/x86/swap-asm/swap_uprobes.c
@@ -54,6 +54,11 @@ static unsigned long trampoline_addr(struct uprobe *up)
UPROBES_TRAMP_RET_BREAK_IDX);
}
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
+{
+ return trampoline_addr(&ri->rp->up);
+}
+
static struct uprobe_ctlblk *current_ucb(void)
{
/* FIXME hardcoded offset */
@@ -211,12 +216,18 @@ int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
* negative error code on error.
*/
int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task)
+ struct task_struct *task, unsigned long tr)
{
int len;
unsigned long ret_addr;
unsigned long sp = (unsigned long)ri->sp;
- unsigned long tramp_addr = trampoline_addr(&ri->rp->up);
+ unsigned long tramp_addr;
+
+ if (tr == 0)
+ tramp_addr = arch_tramp_by_ri(ri);
+ else
+ tramp_addr = tr; /* ri - invalid */
+
len = read_proc_vm_atomic(task, sp, &ret_addr, sizeof(ret_addr));
if (len != sizeof(ret_addr)) {
printk(KERN_INFO "---> %s (%d/%d): failed to read stack from %08lx\n",
diff --git a/uprobe/arch/x86/swap-asm/swap_uprobes.h b/uprobe/arch/x86/swap-asm/swap_uprobes.h
index faef033d..70336803 100644
--- a/uprobe/arch/x86/swap-asm/swap_uprobes.h
+++ b/uprobe/arch/x86/swap-asm/swap_uprobes.h
@@ -86,7 +86,8 @@ static inline int arch_opcode_analysis_uretprobe(struct uretprobe *rp)
int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task);
+ struct task_struct *task, unsigned long tr);
+unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri);
unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
void arch_remove_uprobe(struct uprobe *up);
diff --git a/uprobe/swap_uprobes.c b/uprobe/swap_uprobes.c
index 82e64c8f..838820e1 100644
--- a/uprobe/swap_uprobes.c
+++ b/uprobe/swap_uprobes.c
@@ -78,6 +78,42 @@ void print_uprobe_hash_table(void)
}
#endif
+
+struct uinst_info *uinst_info_create(unsigned long vaddr,
+ kprobe_opcode_t opcode)
+{
+ struct uinst_info *uinst;
+
+ uinst = kmalloc(sizeof(*uinst), GFP_ATOMIC);
+ if (uinst) {
+ INIT_HLIST_NODE(&uinst->hlist);
+ uinst->vaddr = vaddr;
+ uinst->opcode = opcode;
+ } else {
+ pr_err("Cannot allocate memory for uinst\n");
+ }
+
+ return uinst;
+}
+EXPORT_SYMBOL_GPL(uinst_info_create);
+
+void uinst_info_destroy(struct uinst_info *uinst)
+{
+ kfree(uinst);
+}
+EXPORT_SYMBOL_GPL(uinst_info_destroy);
+
+void uinst_info_disarm(struct uinst_info *uinst, struct task_struct *task)
+{
+ int ret = write_proc_vm_atomic(task, uinst->vaddr,
+ &uinst->opcode, sizeof(uinst->opcode));
+ if (!ret) {
+ printk("uinst_info_disarm: failed to write memory "
+ "tgid=%u, vaddr=%08lx!\n", task->tgid, uinst->vaddr);
+ }
+}
+EXPORT_SYMBOL_GPL(uinst_info_disarm);
+
/*
* Keep all fields in the uprobe consistent
*/
@@ -858,36 +894,6 @@ int swap_register_uretprobe(struct uretprobe *rp)
EXPORT_SYMBOL_GPL(swap_register_uretprobe);
/**
- * @brief Disarms uretprobe instances for the specified child task.
- *
- * @param parent Pointer to the parent task struct.
- * @param task Pointer to the child task struct.
- * @return 0
- */
-int swap_disarm_urp_inst_for_task(struct task_struct *parent,
- struct task_struct *task)
-{
- unsigned long flags;
- struct uretprobe_instance *ri;
- struct hlist_head *head;
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- spin_lock_irqsave(&uretprobe_lock, flags);
-
- head = uretprobe_inst_table_head(parent->mm);
- swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (parent == ri->task)
- arch_disarm_urp_inst(ri, task);
- }
-
- spin_unlock_irqrestore(&uretprobe_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_disarm_urp_inst_for_task);
-
-/**
* @brief Disarms uretprobes for specified task.
*
* @param task Pointer to the task_struct.
@@ -909,7 +915,7 @@ void swap_discard_pending_uretprobes(struct task_struct *task)
printk(KERN_INFO "%s (%d/%d): pending urp inst: %08lx\n",
task->comm, task->tgid, task->pid,
(unsigned long)ri->rp->up.kp.addr);
- arch_disarm_urp_inst(ri, task);
+ arch_disarm_urp_inst(ri, task, 0);
recycle_urp_inst(ri);
}
}
@@ -934,7 +940,7 @@ void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm)
spin_lock_irqsave(&uretprobe_lock, flags);
while ((ri = get_used_urp_inst(rp)) != NULL) {
- if (arch_disarm_urp_inst(ri, ri->task) != 0)
+ if (arch_disarm_urp_inst(ri, ri->task, 0) != 0)
printk(KERN_INFO "%s (%d/%d): "
"cannot disarm urp instance (%08lx)\n",
ri->task->comm, ri->task->tgid, ri->task->pid,
@@ -1007,6 +1013,94 @@ void swap_ujprobe_return(void)
}
EXPORT_SYMBOL_GPL(swap_ujprobe_return);
+
+static struct urinst_info *urinst_info_create(struct uretprobe_instance *ri)
+{
+ struct urinst_info *urinst;
+
+ urinst = kmalloc(sizeof(*urinst), GFP_ATOMIC);
+ if (urinst) {
+ INIT_HLIST_NODE(&urinst->hlist);
+ urinst->task = ri->task;
+ urinst->sp = (unsigned long)ri->sp;
+ urinst->tramp = arch_tramp_by_ri(ri);
+ urinst->ret_addr = (unsigned long)ri->ret_addr;
+ } else {
+ pr_err("Cannot allocate memory for urinst\n");
+ }
+
+ return urinst;
+}
+
+static void urinst_info_destroy(struct urinst_info *urinst)
+{
+ kfree(urinst);
+}
+
+static void urinst_info_disarm(struct urinst_info *urinst, struct task_struct *task)
+{
+ struct uretprobe_instance ri;
+ unsigned long tramp = urinst->tramp;
+
+ /* set necessary data*/
+ ri.task = urinst->task;
+ ri.sp = (kprobe_opcode_t *)urinst->sp;
+ ri.ret_addr = (kprobe_opcode_t *)urinst->ret_addr;
+
+ arch_disarm_urp_inst(&ri, task, tramp);
+}
+
+void urinst_info_get_current_hlist(struct hlist_head *head)
+{
+ unsigned long flags;
+ struct task_struct *task = current;
+ struct uretprobe_instance *ri;
+ struct hlist_head *hhead;
+ struct hlist_node *n;
+ struct hlist_node *last = NULL;
+ DECLARE_NODE_PTR_FOR_HLIST(node);
+
+ spin_lock_irqsave(&uretprobe_lock, flags);
+ hhead = uretprobe_inst_table_head(task->mm);
+ swap_hlist_for_each_entry_safe(ri, node, n, hhead, hlist) {
+ if (task == ri->task) {
+ struct urinst_info *urinst;
+
+ urinst = urinst_info_create(ri);
+ if (urinst) {
+ if (last)
+ hlist_add_after(last, &urinst->hlist);
+ else
+ hlist_add_head(&urinst->hlist, head);
+
+ last = &urinst->hlist;
+ }
+
+ }
+ }
+ spin_unlock_irqrestore(&uretprobe_lock, flags);
+}
+EXPORT_SYMBOL_GPL(urinst_info_get_current_hlist);
+
+void urinst_info_put_current_hlist(struct hlist_head *head,
+ struct task_struct *task)
+{
+ struct urinst_info *urinst;
+ struct hlist_node *tmp;
+ DECLARE_NODE_PTR_FOR_HLIST(node);
+
+ swap_hlist_for_each_entry_safe(urinst, node, tmp, head, hlist) {
+ /* check on disarm */
+ if (task)
+ urinst_info_disarm(urinst, task);
+
+ hlist_del(&urinst->hlist);
+ urinst_info_destroy(urinst);
+ }
+}
+EXPORT_SYMBOL_GPL(urinst_info_put_current_hlist);
+
+
static int once(void)
{
init_uprobe_table();
diff --git a/uprobe/swap_uprobes.h b/uprobe/swap_uprobes.h
index 1e3a9fdb..cbee7068 100644
--- a/uprobe/swap_uprobes.h
+++ b/uprobe/swap_uprobes.h
@@ -50,6 +50,33 @@ struct uprobe {
struct arch_specific_tramp atramp; /**< Stores trampoline */
};
+struct uinst_info {
+ struct hlist_node hlist;
+
+ unsigned long vaddr;
+ kprobe_opcode_t opcode;
+};
+
+struct urinst_info {
+ struct hlist_node hlist;
+
+ struct task_struct *task;
+ unsigned long sp;
+ unsigned long tramp;
+ unsigned long ret_addr;
+};
+
+struct uinst_info *uinst_info_create(unsigned long vaddr,
+ kprobe_opcode_t opcode);
+void uinst_info_destroy(struct uinst_info *uinst);
+void uinst_info_disarm(struct uinst_info *uinst, struct task_struct *task);
+
+
+void urinst_info_get_current_hlist(struct hlist_head *head);
+void urinst_info_put_current_hlist(struct hlist_head *head,
+ struct task_struct *task);
+
+
/**
* @brief Uprobe pre-entry handler.
*/
diff --git a/us_manager/helper.c b/us_manager/helper.c
index b3a93957..8d9882f8 100644
--- a/us_manager/helper.c
+++ b/us_manager/helper.c
@@ -178,28 +178,88 @@ static void unregister_ctx_task(void)
* copy_process() *
******************************************************************************
*/
-static atomic_t copy_process_cnt = ATOMIC_INIT(0);
+static void func_uinst_creare(struct us_ip *ip, void *data)
+{
+ struct hlist_head *head = (struct hlist_head *)data;
+ struct uprobe *up;
+
+ up = probe_info_get_uprobe(ip->info, ip);
+ if (up) {
+ struct uinst_info *uinst;
+ unsigned long vaddr = (unsigned long)up->kp.addr;
+
+ uinst = uinst_info_create(vaddr, up->kp.opcode);
+ if (uinst)
+ hlist_add_head(&uinst->hlist, head);
+ }
+}
+
+static void disarm_for_task(struct task_struct *child, struct hlist_head *head)
+{
+ struct uinst_info *uinst;
+ struct hlist_node *tmp;
+ DECLARE_NODE_PTR_FOR_HLIST(node);
+
+ swap_hlist_for_each_entry_safe(uinst, node, tmp, head, hlist) {
+ uinst_info_disarm(uinst, child);
+ hlist_del(&uinst->hlist);
+ uinst_info_destroy(uinst);
+ }
+}
+
+struct clean_data {
+ struct task_struct *task;
+
+ struct hlist_head head;
+ struct hlist_head rhead;
+};
-static void recover_child(struct task_struct *child_task,
- struct sspt_proc *proc)
+/* FIXME: sync with stop */
+static unsigned long cb_clean_child(void *data)
{
- sspt_proc_uninstall(proc, child_task, US_DISARM);
- swap_disarm_urp_inst_for_task(current, child_task);
+ struct clean_data *cdata = (struct clean_data *)data;
+ struct task_struct *child = cdata->task;
+
+ /* disarm up for child */
+ disarm_for_task(child, &cdata->head);
+
+ /* disarm urp for child */
+ urinst_info_put_current_hlist(&cdata->rhead, child);
+
+ return 0;
}
-static void rm_uprobes_child(struct task_struct *task)
+static void rm_uprobes_child(struct kretprobe_instance *ri,
+ struct pt_regs *regs, struct task_struct *child)
{
+ int ret;
struct sspt_proc *proc;
+ struct clean_data cdata = {
+ .task = child,
+ .head = HLIST_HEAD_INIT,
+ .rhead = HLIST_HEAD_INIT
+ };
sspt_proc_write_lock();
proc = sspt_proc_get_by_task(current);
- if (proc)
- recover_child(task, proc);
+ if (proc) {
+ sspt_proc_on_each_ip(proc, func_uinst_creare, (void *)&cdata.head);
+ urinst_info_get_current_hlist(&cdata.rhead);
+ }
sspt_proc_write_unlock();
+
+ /* set jumper */
+ ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_clean_child,
+ &cdata, sizeof(cdata));
+ if (ret == 0)
+ ri->ret_addr = (unsigned long *)get_jump_addr();
}
+
+static atomic_t copy_process_cnt = ATOMIC_INIT(0);
+
static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
{
atomic_inc(&copy_process_cnt);
@@ -220,7 +280,7 @@ static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
goto out;
if (task->mm != current->mm) { /* check flags CLONE_VM */
- rm_uprobes_child(task);
+ rm_uprobes_child(ri, regs, task);
}
out:
atomic_dec(&copy_process_cnt);
diff --git a/us_manager/sspt/sspt_file.c b/us_manager/sspt/sspt_file.c
index 917335ad..9a1c318c 100644
--- a/us_manager/sspt/sspt_file.c
+++ b/us_manager/sspt/sspt_file.c
@@ -198,6 +198,22 @@ void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
sspt_add_ip(page, ip);
}
+void sspt_file_on_each_ip(struct sspt_file *file,
+ void (*func)(struct us_ip *, void *), void *data)
+{
+ int i;
+ const int table_size = (1 << file->page_probes_hash_bits);
+ struct sspt_page *page;
+ struct hlist_head *head;
+ DECLARE_NODE_PTR_FOR_HLIST(node);
+
+ for (i = 0; i < table_size; ++i) {
+ head = &file->page_probes_table[i];
+ swap_hlist_for_each_entry(page, node, head, hlist)
+ sspt_page_on_each_ip(page, func, data);
+ }
+}
+
/**
* @brief Get sspt_page from sspt_file (look)
*
diff --git a/us_manager/sspt/sspt_file.h b/us_manager/sspt/sspt_file.h
index 11e8f427..3024a8fc 100644
--- a/us_manager/sspt/sspt_file.h
+++ b/us_manager/sspt/sspt_file.h
@@ -56,6 +56,9 @@ struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
struct probe_info *probe_i);
+void sspt_file_on_each_ip(struct sspt_file *file,
+ void (*func)(struct us_ip *, void *), void *data);
+
struct sspt_page *sspt_get_page(struct sspt_file *file,
unsigned long offset_addr);
void sspt_put_page(struct sspt_page *page);
diff --git a/us_manager/sspt/sspt_page.c b/us_manager/sspt/sspt_page.c
index a701ecfe..6edf27a6 100644
--- a/us_manager/sspt/sspt_page.c
+++ b/us_manager/sspt/sspt_page.c
@@ -223,3 +223,15 @@ int sspt_unregister_page(struct sspt_page *page,
return err;
}
+
+void sspt_page_on_each_ip(struct sspt_page *page,
+ void (*func)(struct us_ip *, void *), void *data)
+{
+ struct us_ip *ip;
+
+ spin_lock(&page->lock);
+ list_for_each_entry(ip, &page->ip_list_inst, list)
+ func(ip, data);
+
+ spin_unlock(&page->lock);
+}
diff --git a/us_manager/sspt/sspt_page.h b/us_manager/sspt/sspt_page.h
index b3a94fcc..f06e5369 100644
--- a/us_manager/sspt/sspt_page.h
+++ b/us_manager/sspt/sspt_page.h
@@ -60,4 +60,7 @@ int sspt_unregister_page(struct sspt_page *page,
enum US_FLAGS flag,
struct task_struct *task);
+void sspt_page_on_each_ip(struct sspt_page *page,
+ void (*func)(struct us_ip *, void *), void *data);
+
#endif /* __SSPT_PAGE__ */
diff --git a/us_manager/sspt/sspt_proc.c b/us_manager/sspt/sspt_proc.c
index fff5d165..ce1e024c 100644
--- a/us_manager/sspt/sspt_proc.c
+++ b/us_manager/sspt/sspt_proc.c
@@ -499,6 +499,15 @@ void sspt_proc_on_each_filter(struct sspt_proc *proc,
func(fl, data);
}
+void sspt_proc_on_each_ip(struct sspt_proc *proc,
+ void (*func)(struct us_ip *, void *), void *data)
+{
+ struct sspt_file *file;
+
+ list_for_each_entry(file, &proc->file_list, list)
+ sspt_file_on_each_ip(file, func, data);
+}
+
static void is_send_event(struct sspt_filter *f, void *data)
{
bool *is_send = (bool *)data;
diff --git a/us_manager/sspt/sspt_proc.h b/us_manager/sspt/sspt_proc.h
index 85973222..0f4318c0 100644
--- a/us_manager/sspt/sspt_proc.h
+++ b/us_manager/sspt/sspt_proc.h
@@ -31,6 +31,7 @@ struct slot_manager;
struct task_struct;
struct pf_group;
struct sspt_filter;
+struct us_ip;
/** Flags for sspt_*_uninstall() */
enum US_FLAGS {
@@ -105,6 +106,9 @@ void sspt_proc_on_each_filter(struct sspt_proc *proc,
void (*func)(struct sspt_filter *, void *),
void *data);
+void sspt_proc_on_each_ip(struct sspt_proc *proc,
+ void (*func)(struct us_ip *, void *), void *data);
+
bool sspt_proc_is_send_event(struct sspt_proc *proc);
int sspt_proc_cb_set(struct sspt_proc_cb *cb);