aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Arapov <anton@redhat.com>2013-04-03 12:00:37 -0400
committerOleg Nesterov <oleg@redhat.com>2013-04-13 09:31:58 -0400
commitded49c55309a37129dc30a5f0e85b8a64e5c1716 (patch)
tree7734bd75b1b95c22457c0671c6d9968b131fb5b1
parentfec8898d86ad0fb4d2161fc89885fa52da1e8b72 (diff)
uretprobes: Limit the depth of return probe nestedness
Unlike the kretprobes we can't trust userspace, thus must have protection from user space attacks. User-space have "unlimited" stack, and this patch limits the return probes nestedness as a simple remedy for it. Note that this implementation leaks return_instance on siglongjmp until exit()/exec(). The intention is to have KISS and bare minimum solution for the initial implementation in order to not complicate the uretprobes code. In the future we may come up with more sophisticated solution that remove this depth limitation. It is not easy task and lays beyond this patchset. Signed-off-by: Anton Arapov <anton@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
-rw-r--r--include/linux/uprobes.h3
-rw-r--r--kernel/events/uprobes.c11
2 files changed, 14 insertions, 0 deletions
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index b0507f24eeb0..06f28beed7c2 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -38,6 +38,8 @@ struct inode;
38#define UPROBE_HANDLER_REMOVE 1 38#define UPROBE_HANDLER_REMOVE 1
39#define UPROBE_HANDLER_MASK 1 39#define UPROBE_HANDLER_MASK 1
40 40
41#define MAX_URETPROBE_DEPTH 64
42
41enum uprobe_filter_ctx { 43enum uprobe_filter_ctx {
42 UPROBE_FILTER_REGISTER, 44 UPROBE_FILTER_REGISTER,
43 UPROBE_FILTER_UNREGISTER, 45 UPROBE_FILTER_UNREGISTER,
@@ -72,6 +74,7 @@ struct uprobe_task {
72 struct arch_uprobe_task autask; 74 struct arch_uprobe_task autask;
73 75
74 struct return_instance *return_instances; 76 struct return_instance *return_instances;
77 unsigned int depth;
75 struct uprobe *active_uprobe; 78 struct uprobe *active_uprobe;
76 79
77 unsigned long xol_vaddr; 80 unsigned long xol_vaddr;
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 65429ad2ce51..6ab00e090c87 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1404,6 +1404,13 @@ static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
1404 if (!utask) 1404 if (!utask)
1405 return; 1405 return;
1406 1406
1407 if (utask->depth >= MAX_URETPROBE_DEPTH) {
1408 printk_ratelimited(KERN_INFO "uprobe: omit uretprobe due to"
1409 " nestedness limit pid/tgid=%d/%d\n",
1410 current->pid, current->tgid);
1411 return;
1412 }
1413
1407 ri = kzalloc(sizeof(struct return_instance), GFP_KERNEL); 1414 ri = kzalloc(sizeof(struct return_instance), GFP_KERNEL);
1408 if (!ri) 1415 if (!ri)
1409 goto fail; 1416 goto fail;
@@ -1439,6 +1446,8 @@ static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
1439 ri->orig_ret_vaddr = orig_ret_vaddr; 1446 ri->orig_ret_vaddr = orig_ret_vaddr;
1440 ri->chained = chained; 1447 ri->chained = chained;
1441 1448
1449 utask->depth++;
1450
1442 /* add instance to the stack */ 1451 /* add instance to the stack */
1443 ri->next = utask->return_instances; 1452 ri->next = utask->return_instances;
1444 utask->return_instances = ri; 1453 utask->return_instances = ri;
@@ -1681,6 +1690,8 @@ static bool handle_trampoline(struct pt_regs *regs)
1681 if (!chained) 1690 if (!chained)
1682 break; 1691 break;
1683 1692
1693 utask->depth--;
1694
1684 BUG_ON(!ri); 1695 BUG_ON(!ri);
1685 } 1696 }
1686 1697