[Devel,RHEL7,COMMIT] ve/seccomp, ptrace: Save original BPF program when setting the filer

Submitted by Konstantin Khorenko on Dec. 8, 2016, 1:30 p.m.

Details

Message ID 201612081330.uB8DU3AR003241@finist_cl7.x64_64.work.ct
State New
Series "seccomp, ptrace: Save original BPF program when setting the filer"
Headers show

Commit Message

Konstantin Khorenko Dec. 8, 2016, 1:30 p.m.
The commit is pushed to "branch-rh7-3.10.0-327.36.1.vz7.20.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.36.1.vz7.20.12
------>
commit 185e8e4a2979bd98a935095fc19bdfefcabc78a5
Author: Cyrill Gorcunov <gorcunov@virtuozzo.com>
Date:   Thu Dec 8 17:30:03 2016 +0400

    ve/seccomp, ptrace: Save original BPF program when setting the filer
    
    The vanilla kernel is quite reworked in filter management, in particular
    the filters passed into sockets or seccomp are saved in the userspace form
    as struct bpf_prog::orig_prog. We can't port all the patches right now,
    lets rather do a trick for seccomp sake and simply carry a copy inside
    struct seccomp_filter. The socket filters are decoded into userspace form
    anyway so this area is safe.
    
    https://jira.sw.ru/browse/PSBM-55593
    
    CC: Andrey Vagin <avagin@openvz.org>
    Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
 kernel/seccomp.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

Patch hide | download patch | download mbox

diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index b5f6d50..2d0927b 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -54,6 +54,9 @@ 
 struct seccomp_filter {
 	atomic_t usage;
 	struct seccomp_filter *prev;
+#if CONFIG_VE
+	struct sock_fprog orig_prog;
+#endif
 	unsigned short len;  /* Instruction count */
 	struct sock_filter insns[];
 };
@@ -265,6 +268,16 @@  static long seccomp_attach_filter(struct sock_fprog *fprog)
 	if (copy_from_user(filter->insns, fprog->filter, fp_size))
 		goto fail;
 
+#if CONFIG_VE
+	filter->orig_prog.len = fprog->len;
+	filter->orig_prog.filter = kmemdup(filter->insns, fp_size,
+					   GFP_KERNEL|__GFP_NOWARN);
+	if (!filter->orig_prog.filter) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+#endif
+
 	/* Check and rewrite the fprog via the skb checker */
 	ret = sk_chk_filter(filter->insns, filter->len);
 	if (ret)
@@ -283,6 +296,9 @@  static long seccomp_attach_filter(struct sock_fprog *fprog)
 	current->seccomp.filter = filter;
 	return 0;
 fail:
+#if CONFIG_VE
+	kfree(filter->orig_prog.filter);
+#endif
 	kfree(filter);
 	return ret;
 }
@@ -332,6 +348,9 @@  void put_seccomp_filter(struct task_struct *tsk)
 	while (orig && atomic_dec_and_test(&orig->usage)) {
 		struct seccomp_filter *freeme = orig;
 		orig = orig->prev;
+#if CONFIG_VE
+		kfree(freeme->orig_prog.filter);
+#endif
 		kfree(freeme);
 	}
 }
@@ -566,8 +585,14 @@  long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
 	get_seccomp_filter(task);
 	spin_unlock_irq(&task->sighand->siglock);
 
+#if CONFIG_VE
+	if (copy_to_user(data, filter->orig_prog.filter,
+			 filter->orig_prog.len * sizeof(filter->orig_prog.filter[0])))
+		ret = -EFAULT;
+#else
 	if (copy_to_user(data, filter->insns, filter->len * sizeof(filter->insns[0])))
 		ret = -EFAULT;
+#endif
 
 	put_seccomp_filter(task);
 	return ret;