All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dave Hansen <dave.hansen@intel.com>
To: speck@linutronix.de
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Subject: [MODERATED] [PATCH 2/5] SSB extra v2 2
Date: Mon,  7 May 2018 16:18:43 -0700	[thread overview]
Message-ID: <=?utf-8?q?=3C8e72615bb02e3b433c57659652e0f4c31555eb98=2E152573?= =?utf-8?q?4796=2Egit=2Edave=2Ehansen=40intel=2Ecom=3E?=> (raw)
In-Reply-To: <cover.1525734796.git.dave.hansen@intel.com>
In-Reply-To: <cover.1525734796.git.dave.hansen@intel.com>

From: Dave Hansen <dave.hansen@linux.intel.com>

BPF programs can potentially do bad things, especially where
side-channels are concerned.  This introduces some infrastructure to
help deal with them.

Each BPF program has a function pointer (->bpf_func) which either
points to an interpreter or to the actual JIT'd code.  We override it
when running untrusted programs (defined by having CAP_SYS_ADMIN at
program load time), but leave it in place for trusted ones.  This way,
the runtime overhead is basically zero for programs which receive no
mitigation: it just calls directly into the original code.

The function we override it to (bpf_untrusted_wrapper()) just turns
on mitigations when entering the program and turns them off before
returning.  Ideally, we would change the ->bpf_func call to actually
pass 'bpf_prog' itself instead of deriving it via container_of(),
but this means less churn for now.

Why not use the BPF machine itself to do the mitigation by patching
in instructions?

We could attempt to do the mitigation in the eBPF instructions
themselves, but that gets messy, fast.  We would need something like
bpf__gen_prologue(), which I ran away from in terror.  We would also
need to ensure that offloaded programs did not receive the mitigation
instructions.

eBPF programs can also "call" other programs, but those calls never
return, so they are more similar to execve().  That means that the
mitigations at the beginning of programs *have* to be conditional in
some way if implemented inside the eBPF machine.  It also means that
we do not get a nice, clean call/return pair.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
 include/linux/filter.h |  7 ++++++-
 kernel/bpf/core.c      |  9 +++++++++
 net/core/filter.c      | 25 +++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/include/linux/filter.h b/include/linux/filter.h
index fc4e8f9..ac10038 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -467,7 +467,8 @@ struct bpf_prog {
 				dst_needed:1,	/* Do we need dst entry? */
 				blinded:1,	/* Was blinded */
 				is_func:1,	/* program is a bpf function */
-				kprobe_override:1; /* Do we override a kprobe? */
+				kprobe_override:1, /* Do we override a kprobe? */
+				need_mitigation:1; /* Need speculation fixes? */
 	enum bpf_prog_type	type;		/* Type of BPF program */
 	enum bpf_attach_type	expected_attach_type; /* For some prog types */
 	u32			len;		/* Number of filter blocks */
@@ -477,6 +478,8 @@ struct bpf_prog {
 	struct sock_fprog_kern	*orig_prog;	/* Original BPF program */
 	unsigned int		(*bpf_func)(const void *ctx,
 					    const struct bpf_insn *insn);
+	unsigned int		(*bpf_orig_func)(const void *ctx,
+					    const struct bpf_insn *insn);
 	/* Instructions for interpreter */
 	union {
 		struct sock_filter	insns[0];
@@ -1051,4 +1054,6 @@ struct bpf_sock_ops_kern {
 					 */
 };
 
+unsigned int bpf_untrusted_wrapper(const void *ctx, const struct bpf_insn *insn);
+
 #endif /* __LINUX_FILTER_H__ */
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index dd7caa1..15e4865 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1501,6 +1501,15 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
 		if (*err)
 			return fp;
 	}
+
+	/* Must be done after JIT has set fp->bpf_func: */
+	if (fp->need_mitigation) {
+		/* Stash the original function: */
+		fp->bpf_orig_func = fp->bpf_func;
+		/* Replace it with the wrapper for untrusted programs: */
+		fp->bpf_func = bpf_untrusted_wrapper;
+	}
+
 	bpf_prog_lock_ro(fp);
 
 	/* The tail call compatibility check can only be done at
diff --git a/net/core/filter.c b/net/core/filter.c
index d31aff9..f8b8099 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -48,6 +48,7 @@
 #include <linux/filter.h>
 #include <linux/ratelimit.h>
 #include <linux/seccomp.h>
+#include <linux/nospec.h>
 #include <linux/if_vlan.h>
 #include <linux/bpf.h>
 #include <net/sch_generic.h>
@@ -5649,3 +5650,27 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,
 	release_sock(sk);
 	return ret;
 }
+
+/*
+ * This function is installed as the ->bpf_func in all bpf_prog's that
+ * are not trusted.  They might have been loaded by an untrusted user
+ * or call potentially untrusted code.  They might be doing something
+ * that reduces kernel hardening, so add mitigations while they are
+ * running.
+ *
+ * This is nice for things like offloaded BPF programs because they
+ * do not use ->bpf_func.
+ */
+unsigned int bpf_untrusted_wrapper(const void *ctx, const struct bpf_insn *insn)
+{
+	struct bpf_prog *prog = container_of(insn, struct bpf_prog, insnsi[0]);
+	unsigned int ret;
+
+	arch_bpf_spec_ctrl_enable();
+	ret = prog->bpf_orig_func(ctx, insn);
+	arch_bpf_spec_ctrl_disable();
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bpf_untrusted_wrapper);
+
-- 
2.9.5

  parent reply	other threads:[~2018-05-07 23:24 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-07 23:18 [MODERATED] [PATCH 0/5] SSB extra v2 0 Dave Hansen
2018-05-07 23:18 ` [MODERATED] [PATCH 1/5] SSB extra v2 1 Dave Hansen
2018-05-07 23:18 ` Dave Hansen [this message]
2018-05-07 23:18 ` [MODERATED] [PATCH 3/5] SSB extra v2 3 Dave Hansen
2018-05-07 23:18 ` [MODERATED] [PATCH 4/5] SSB extra v2 4 Dave Hansen
2018-05-07 23:18 ` [MODERATED] [PATCH 5/5] SSB extra v2 5 Dave Hansen
2018-05-08  0:36 ` [MODERATED] " Andi Kleen
2018-05-08  0:46   ` Dave Hansen
2018-05-09 15:36     ` Thomas Gleixner
2018-05-09 15:43       ` [MODERATED] " Dave Hansen
2018-05-09 15:55         ` Greg KH
2018-05-09 16:03           ` Dave Hansen
2018-05-09 16:05             ` Jiri Kosina
2018-05-09 16:36               ` Dave Hansen
2018-05-16 15:23                 ` Jon Masters
2018-05-09 21:04         ` Linus Torvalds

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='=?utf-8?q?=3C8e72615bb02e3b433c57659652e0f4c31555eb98=2E152573?= =?utf-8?q?4796=2Egit=2Edave=2Ehansen=40intel=2Ecom=3E?=' \
    --to=dave.hansen@intel.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=speck@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.