mirror of
https://github.com/clearlinux/graphene.git
synced 2026-09-06 22:01:29 +00:00
- Bugfixes in PAL and SHIM - Improvement of migration scheme in SHIM, which largely speed up forking - Upgrade glibc to 2.19 - FreeBSD port - Support OpenJDK, python and R
749 lines
23 KiB
Diff
749 lines
23 KiB
Diff
diff --git a/Kconfig b/Kconfig
|
|
index c13f48d..e18713e 100644
|
|
--- a/Kconfig
|
|
+++ b/Kconfig
|
|
@@ -9,3 +9,4 @@ config SRCARCH
|
|
option env="SRCARCH"
|
|
|
|
source "arch/$SRCARCH/Kconfig"
|
|
+source "graphene/Kconfig"
|
|
diff --git a/Makefile b/Makefile
|
|
index e5ac8a6..116ac82 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -779,7 +779,7 @@ export mod_sign_cmd
|
|
|
|
|
|
ifeq ($(KBUILD_EXTMOD),)
|
|
-core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
|
|
+core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ graphene/
|
|
|
|
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
|
|
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
|
|
diff --git a/arch/Kconfig b/arch/Kconfig
|
|
index 80bbb8c..ca9f9e7 100644
|
|
--- a/arch/Kconfig
|
|
+++ b/arch/Kconfig
|
|
@@ -336,6 +336,10 @@ config SECCOMP_FILTER
|
|
|
|
See Documentation/prctl/seccomp_filter.txt for details.
|
|
|
|
+# Used by archs to tell that they support SECCOMP_FILTER_JIT
|
|
+config HAVE_SECCOMP_FILTER_JIT
|
|
+ bool
|
|
+
|
|
config HAVE_CC_STACKPROTECTOR
|
|
bool
|
|
help
|
|
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
|
index 0af5250..0c4dfea 100644
|
|
--- a/arch/x86/Kconfig
|
|
+++ b/arch/x86/Kconfig
|
|
@@ -94,6 +94,7 @@ config X86
|
|
select GENERIC_CLOCKEVENTS_MIN_ADJUST
|
|
select IRQ_FORCED_THREADING
|
|
select HAVE_BPF_JIT if X86_64
|
|
+ select HAVE_SECCOMP_FILTER_JIT if X86_64
|
|
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
|
select CLKEVT_I8253
|
|
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
|
@@ -1601,6 +1602,16 @@ config SECCOMP
|
|
|
|
If unsure, say Y. Only embedded should say N here.
|
|
|
|
+if SECCOMP
|
|
+config SECCOMP_FILTER_JIT
|
|
+ bool "Enable seccomp filter Just In Time compiler"
|
|
+ depends on HAVE_SECCOMP_FILTER_JIT
|
|
+ depends on MODULES
|
|
+ ---help---
|
|
+ Like Berkeley Packet Filter, This option allows kernel to generate a
|
|
+ native code when seccomp filter is loaded in memory.
|
|
+endif
|
|
+
|
|
source kernel/Kconfig.hz
|
|
|
|
config KEXEC
|
|
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
|
|
index 4ed75dd..5768520 100644
|
|
--- a/arch/x86/net/bpf_jit_comp.c
|
|
+++ b/arch/x86/net/bpf_jit_comp.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/filter.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/random.h>
|
|
+#include <asm/syscall.h>
|
|
|
|
/*
|
|
* Conventions :
|
|
@@ -108,9 +109,13 @@ do { \
|
|
goto cond_branch
|
|
|
|
|
|
-#define SEEN_DATAREF 1 /* might call external helpers */
|
|
-#define SEEN_XREG 2 /* ebx is used */
|
|
-#define SEEN_MEM 4 /* use mem[] for temporary storage */
|
|
+#define SEEN_DATAREF (1 << 0) /* might call external skb helpers */
|
|
+#define SEEN_XREG (1 << 1) /* ebx is used */
|
|
+#define SEEN_MEM (1 << 2) /* use mem[] for temporary storage */
|
|
+#define SEEN_SKBREF (1 << 3) /* use pointer to skb */
|
|
+#define SEEN_SECCOMP (1 << 4) /* seccomp filters */
|
|
+
|
|
+#define NEED_PERILOGUE(_seen) ((_seen) & (SEEN_XREG | SEEN_MEM | SEEN_DATAREF))
|
|
|
|
static inline void bpf_flush_icache(void *start, void *end)
|
|
{
|
|
@@ -122,6 +127,25 @@ static inline void bpf_flush_icache(void *start, void *end)
|
|
set_fs(old_fs);
|
|
}
|
|
|
|
+/* helper to find the offset in struct seccomp_data */
|
|
+#define BPF_DATA(_name) offsetof(struct seccomp_data, _name)
|
|
+
|
|
+/* helper to find the negative offset from the end of struct pt_regs */
|
|
+#define roffsetof(_type, _member) ((int)(offsetof(_type, _member) - sizeof(_type)))
|
|
+#define PT_REGS(_name) roffsetof(struct pt_regs, _name)
|
|
+
|
|
+#define EMIT_REGS_LOAD(offset) \
|
|
+do { \
|
|
+ if (is_imm8(offset)) { \
|
|
+ /* mov off8(%r8),%eax */ \
|
|
+ EMIT4(0x41, 0x8b, 0x40, offset); \
|
|
+ } else { \
|
|
+ /* mov off32(%r8),%eax */ \
|
|
+ EMIT3(0x41, 0x8b, 0x80); \
|
|
+ EMIT(offset, 4); \
|
|
+ } \
|
|
+} while (0)
|
|
+
|
|
#define CHOOSE_LOAD_FUNC(K, func) \
|
|
((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
|
|
|
|
@@ -178,7 +202,7 @@ static struct bpf_binary_header *bpf_alloc_binary(unsigned int proglen,
|
|
return header;
|
|
}
|
|
|
|
-void bpf_jit_compile(struct sk_filter *fp)
|
|
+static void *__bpf_jit_compile(struct sock_filter *filter, unsigned int flen, u8 seen_all)
|
|
{
|
|
u8 temp[64];
|
|
u8 *prog;
|
|
@@ -192,15 +216,14 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */
|
|
unsigned int cleanup_addr; /* epilogue code offset */
|
|
unsigned int *addrs;
|
|
- const struct sock_filter *filter = fp->insns;
|
|
- int flen = fp->len;
|
|
+ void *bpf_func = NULL;
|
|
|
|
if (!bpf_jit_enable)
|
|
- return;
|
|
+ return bpf_func;
|
|
|
|
addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL);
|
|
if (addrs == NULL)
|
|
- return;
|
|
+ return NULL;
|
|
|
|
/* Before first pass, make a rough estimation of addrs[]
|
|
* each bpf instruction is translated to less than 64 bytes
|
|
@@ -212,12 +235,12 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
cleanup_addr = proglen; /* epilogue address */
|
|
|
|
for (pass = 0; pass < 10; pass++) {
|
|
- u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen;
|
|
+ u8 seen_or_pass0 = (pass == 0) ? seen_all : seen;
|
|
/* no prologue/epilogue for trivial filters (RET something) */
|
|
proglen = 0;
|
|
prog = temp;
|
|
|
|
- if (seen_or_pass0) {
|
|
+ if (NEED_PERILOGUE(seen_or_pass0)) {
|
|
EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */
|
|
EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */
|
|
/* note : must save %rbx in case bpf_error is hit */
|
|
@@ -260,6 +283,47 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
}
|
|
}
|
|
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+ /* For seccomp filters, load :
|
|
+ * r9 = current
|
|
+ * r8 = current->thread.sp0
|
|
+ * edi = task_thread_info(current)->status & TS_COMPAT
|
|
+ *
|
|
+ * r8 points to the end of struct pt_regs, task_pt_regs(current) + 1
|
|
+ */
|
|
+ if (seen_or_pass0 & SEEN_SECCOMP) {
|
|
+ /* seccomp filters: skb must be NULL */
|
|
+ if (seen_or_pass0 & (SEEN_SKBREF | SEEN_DATAREF)) {
|
|
+ pr_err_once("seccomp filters shouldn't use skb");
|
|
+ goto out;
|
|
+ }
|
|
+ /* r9 = current */
|
|
+ EMIT1(0x65);EMIT4(0x4c, 0x8b, 0x0c, 0x25); /* mov %gs:imm32,%r9 */
|
|
+ EMIT((u32)(unsigned long)¤t_task, 4);
|
|
+
|
|
+ /* r8 = current->thread.sp0 */
|
|
+ EMIT3(0x4d, 0x8b, 0x81); /* mov off32(%r9),%r8 */
|
|
+ EMIT(offsetof(struct task_struct, thread.sp0), 4);
|
|
+
|
|
+ /* edi = task_thread_info(current)->status & TS_COMPAT */
|
|
+#ifdef CONFIG_IA32_EMULATION
|
|
+ /* task_thread_info(current): current->stack */
|
|
+ BUILD_BUG_ON(!is_imm8(offsetof(struct task_struct, stack)));
|
|
+ /* mov off8(%r9),%rdi */
|
|
+ EMIT4(0x49, 0x8b, 0x79, offsetof(struct task_struct, stack));
|
|
+ /* task_thread_info(current)->status */
|
|
+ BUILD_BUG_ON(!is_imm8(offsetof(struct thread_info, status)));
|
|
+ BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, status) != 4);
|
|
+ /* mov off8(%rdi),%edi */
|
|
+ EMIT3(0x8b, 0x7f, offsetof(struct thread_info, status));
|
|
+ /* task_thread_info(current)->status & TS_COMPAT */
|
|
+ BUILD_BUG_ON(!is_imm8(TS_COMPAT));
|
|
+ /* and imm8,%edi */
|
|
+ EMIT3(0x83, 0xe7, TS_COMPAT);
|
|
+#endif /* CONFIG_IA32_EMULATION */
|
|
+ }
|
|
+#endif /* CONFIG_SECCOMP_FILTER_JIT */
|
|
+
|
|
switch (filter[0].code) {
|
|
case BPF_S_RET_K:
|
|
case BPF_S_LD_W_LEN:
|
|
@@ -272,6 +336,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
case BPF_S_ANC_VLAN_TAG_PRESENT:
|
|
case BPF_S_ANC_QUEUE:
|
|
case BPF_S_ANC_PKTTYPE:
|
|
+ case BPF_S_ANC_SECCOMP_LD_W:
|
|
case BPF_S_LD_W_ABS:
|
|
case BPF_S_LD_H_ABS:
|
|
case BPF_S_LD_B_ABS:
|
|
@@ -449,7 +514,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
}
|
|
/* fallinto */
|
|
case BPF_S_RET_A:
|
|
- if (seen_or_pass0) {
|
|
+ if (NEED_PERILOGUE(seen_or_pass0)) {
|
|
if (i != flen - 1) {
|
|
EMIT_JMP(cleanup_addr - addrs[i]);
|
|
break;
|
|
@@ -499,6 +564,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
break;
|
|
case BPF_S_LD_W_LEN: /* A = skb->len; */
|
|
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, len)))
|
|
/* mov off8(%rdi),%eax */
|
|
EMIT3(0x8b, 0x47, offsetof(struct sk_buff, len));
|
|
@@ -508,7 +574,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
}
|
|
break;
|
|
case BPF_S_LDX_W_LEN: /* X = skb->len; */
|
|
- seen |= SEEN_XREG;
|
|
+ seen |= SEEN_XREG | SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, len)))
|
|
/* mov off8(%rdi),%ebx */
|
|
EMIT3(0x8b, 0x5f, offsetof(struct sk_buff, len));
|
|
@@ -519,6 +585,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
break;
|
|
case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
|
|
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, protocol))) {
|
|
/* movzwl off8(%rdi),%eax */
|
|
EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, protocol));
|
|
@@ -529,6 +596,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
EMIT2(0x86, 0xc4); /* ntohs() : xchg %al,%ah */
|
|
break;
|
|
case BPF_S_ANC_IFINDEX:
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, dev))) {
|
|
/* movq off8(%rdi),%rax */
|
|
EMIT4(0x48, 0x8b, 0x47, offsetof(struct sk_buff, dev));
|
|
@@ -544,6 +612,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
break;
|
|
case BPF_S_ANC_MARK:
|
|
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, mark))) {
|
|
/* mov off8(%rdi),%eax */
|
|
EMIT3(0x8b, 0x47, offsetof(struct sk_buff, mark));
|
|
@@ -554,6 +623,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
break;
|
|
case BPF_S_ANC_RXHASH:
|
|
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, rxhash))) {
|
|
/* mov off8(%rdi),%eax */
|
|
EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash));
|
|
@@ -564,6 +634,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
break;
|
|
case BPF_S_ANC_QUEUE:
|
|
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, queue_mapping))) {
|
|
/* movzwl off8(%rdi),%eax */
|
|
EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, queue_mapping));
|
|
@@ -583,6 +654,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
case BPF_S_ANC_VLAN_TAG:
|
|
case BPF_S_ANC_VLAN_TAG_PRESENT:
|
|
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(offsetof(struct sk_buff, vlan_tci))) {
|
|
/* movzwl off8(%rdi),%eax */
|
|
EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, vlan_tci));
|
|
@@ -604,6 +676,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
|
|
if (off < 0)
|
|
goto out;
|
|
+ seen |= SEEN_SKBREF;
|
|
if (is_imm8(off)) {
|
|
/* movzbl off8(%rdi),%eax */
|
|
EMIT4(0x0f, 0xb6, 0x47, off);
|
|
@@ -617,7 +690,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
}
|
|
case BPF_S_LD_W_ABS:
|
|
func = CHOOSE_LOAD_FUNC(K, sk_load_word);
|
|
-common_load: seen |= SEEN_DATAREF;
|
|
+common_load: seen |= SEEN_SKBREF | SEEN_DATAREF;
|
|
t_offset = func - (image + addrs[i]);
|
|
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
|
|
EMIT1_off32(0xe8, t_offset); /* call */
|
|
@@ -630,14 +703,14 @@ common_load: seen |= SEEN_DATAREF;
|
|
goto common_load;
|
|
case BPF_S_LDX_B_MSH:
|
|
func = CHOOSE_LOAD_FUNC(K, sk_load_byte_msh);
|
|
- seen |= SEEN_DATAREF | SEEN_XREG;
|
|
+ seen |= SEEN_XREG | SEEN_SKBREF | SEEN_DATAREF;
|
|
t_offset = func - (image + addrs[i]);
|
|
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
|
|
EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */
|
|
break;
|
|
case BPF_S_LD_W_IND:
|
|
func = sk_load_word;
|
|
-common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG;
|
|
+common_load_ind: seen |= SEEN_XREG | SEEN_SKBREF | SEEN_DATAREF;
|
|
t_offset = func - (image + addrs[i]);
|
|
if (K) {
|
|
if (is_imm8(K)) {
|
|
@@ -725,6 +798,72 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
|
|
}
|
|
EMIT_COND_JMP(f_op, f_offset);
|
|
break;
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+ case BPF_S_ANC_SECCOMP_LD_W:
|
|
+ seen |= SEEN_SECCOMP;
|
|
+ if (K == BPF_DATA(nr)) {
|
|
+ /* A = task_pt_regs(current)->orig_ax */
|
|
+ EMIT_REGS_LOAD(PT_REGS(orig_ax));
|
|
+ break;
|
|
+ }
|
|
+ if (K == BPF_DATA(arch)) {
|
|
+ /* A = AUDIT_ARCH_X86_64 */
|
|
+ EMIT1_off32(0xb8, AUDIT_ARCH_X86_64); /* mov imm32,%eax */
|
|
+#ifdef CONFIG_IA32_EMULATION
|
|
+ /* A = compat ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64 */
|
|
+ EMIT1_off32(0xb9, AUDIT_ARCH_I386); /* mov imm32,%ecx */
|
|
+ EMIT2(0x85, 0xff); /* test %edi,%edi */
|
|
+ EMIT3(0x0f, 0x45, 0xc1); /* cmovne %ecx,%eax*/
|
|
+#endif /* CONFIG_IA32_EMULATION */
|
|
+ break;
|
|
+ }
|
|
+ if (K >= BPF_DATA(args[0]) && K < BPF_DATA(args[6])) {
|
|
+ int arg = (K - BPF_DATA(args[0])) / sizeof(u64);
|
|
+ int off = K % sizeof(u64);
|
|
+
|
|
+ switch (arg) {
|
|
+ case 0: off += PT_REGS(di); break;
|
|
+ case 1: off += PT_REGS(si); break;
|
|
+ case 2: off += PT_REGS(dx); break;
|
|
+ case 3: off += PT_REGS(r10); break;
|
|
+ case 4: off += PT_REGS(r8); break;
|
|
+ case 5: off += PT_REGS(r9); break;
|
|
+ }
|
|
+ EMIT_REGS_LOAD(off);
|
|
+#ifdef CONFIG_IA32_EMULATION
|
|
+ off = K % sizeof(u64);
|
|
+ switch (arg) {
|
|
+ case 0: off += PT_REGS(bx); break;
|
|
+ case 1: off += PT_REGS(cx); break;
|
|
+ case 2: off += PT_REGS(dx); break;
|
|
+ case 3: off += PT_REGS(si); break;
|
|
+ case 4: off += PT_REGS(di); break;
|
|
+ case 5: off += PT_REGS(bp); break;
|
|
+ }
|
|
+ if (is_imm8(off)) {
|
|
+ /* mov off8(%r8),%ecx */
|
|
+ EMIT4(0x41, 0x8b, 0x48, off);
|
|
+ } else {
|
|
+ /* mov off32(%r8),%ecx */
|
|
+ EMIT3(0x41, 0x8b, 0x88);
|
|
+ EMIT(off, 4);
|
|
+ }
|
|
+ EMIT2(0x85, 0xff); /* test %edi,%edi */
|
|
+ EMIT3(0x0f, 0x45, 0xc1); /* cmovne %ecx,%eax*/
|
|
+#endif /* CONFIG_IA32_EMULATION */
|
|
+ break;
|
|
+ }
|
|
+ if (K == BPF_DATA(instruction_pointer)) {
|
|
+ /* A = task_pt_regs(current)->ip */
|
|
+ EMIT_REGS_LOAD(PT_REGS(ip));
|
|
+ break;
|
|
+ }
|
|
+ if (K == BPF_DATA(instruction_pointer) + sizeof(u32)) {
|
|
+ EMIT_REGS_LOAD(PT_REGS(ip) + 4);
|
|
+ break;
|
|
+ }
|
|
+ goto out;
|
|
+#endif /* CONFIG_SECCOMP_FILTER_JIT */
|
|
default:
|
|
/* hmm, too complex filter, give up with jit compiler */
|
|
goto out;
|
|
@@ -732,10 +871,9 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
|
|
ilen = prog - temp;
|
|
if (image) {
|
|
if (unlikely(proglen + ilen > oldproglen)) {
|
|
- pr_err("bpb_jit_compile fatal error\n");
|
|
- kfree(addrs);
|
|
+ pr_err("bpf_jit_compile fatal error\n");
|
|
module_free(NULL, header);
|
|
- return;
|
|
+ goto out;
|
|
}
|
|
memcpy(image + proglen, temp, ilen);
|
|
}
|
|
@@ -747,7 +885,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
|
|
* use it to give the cleanup instruction(s) addr
|
|
*/
|
|
cleanup_addr = proglen - 1; /* ret */
|
|
- if (seen_or_pass0)
|
|
+ if (NEED_PERILOGUE(seen_or_pass0))
|
|
cleanup_addr -= 1; /* leaveq */
|
|
if (seen_or_pass0 & SEEN_XREG)
|
|
cleanup_addr -= 4; /* mov -8(%rbp),%rbx */
|
|
@@ -771,11 +909,11 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
|
|
if (image) {
|
|
bpf_flush_icache(header, image + proglen);
|
|
set_memory_ro((unsigned long)header, header->pages);
|
|
- fp->bpf_func = (void *)image;
|
|
+ bpf_func = (void *)image;
|
|
}
|
|
out:
|
|
kfree(addrs);
|
|
- return;
|
|
+ return bpf_func;
|
|
}
|
|
|
|
static void bpf_jit_free_deferred(struct work_struct *work)
|
|
@@ -798,3 +936,38 @@ void bpf_jit_free(struct sk_filter *fp)
|
|
kfree(fp);
|
|
}
|
|
}
|
|
+
|
|
+void bpf_jit_compile(struct sk_filter *fp)
|
|
+{
|
|
+ u8 seen_all = SEEN_XREG | SEEN_MEM | SEEN_SKBREF | SEEN_DATAREF;
|
|
+ void *bpf_func = __bpf_jit_compile(fp->insns, fp->len, seen_all);
|
|
+
|
|
+ if (bpf_func)
|
|
+ fp->bpf_func = bpf_func;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+void seccomp_jit_compile(struct seccomp_filter *fp)
|
|
+{
|
|
+ struct sock_filter *filter = seccomp_filter_get_insns(fp);
|
|
+ unsigned int flen = seccomp_filter_get_len(fp);
|
|
+ u8 seen_all = SEEN_XREG | SEEN_MEM | SEEN_SECCOMP;
|
|
+ void *bpf_func = __bpf_jit_compile(filter, flen, seen_all);
|
|
+
|
|
+ if (bpf_func)
|
|
+ seccomp_filter_set_bpf_func(fp, bpf_func);
|
|
+}
|
|
+
|
|
+void seccomp_jit_free(struct seccomp_filter *fp)
|
|
+{
|
|
+ void *bpf_func = seccomp_filter_get_bpf_func(fp);
|
|
+
|
|
+ if (bpf_func) {
|
|
+ unsigned long addr = (unsigned long)bpf_func & PAGE_MASK;
|
|
+ struct bpf_binary_header *header = (void *)addr;
|
|
+
|
|
+ set_memory_rw(addr, header->pages);
|
|
+ module_free(NULL, header);
|
|
+ }
|
|
+}
|
|
+#endif /* CONFIG_SECCOMP_FILTER_JIT */
|
|
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
|
|
index 3737f72..f7a4aba 100644
|
|
--- a/include/linux/miscdevice.h
|
|
+++ b/include/linux/miscdevice.h
|
|
@@ -3,6 +3,7 @@
|
|
#include <linux/major.h>
|
|
#include <linux/list.h>
|
|
#include <linux/types.h>
|
|
+#include <../graphene/graphene.h>
|
|
|
|
/*
|
|
* These allocations are managed by device@lanana.org. If you use an
|
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
|
index a781dec..3381137 100644
|
|
--- a/include/linux/sched.h
|
|
+++ b/include/linux/sched.h
|
|
@@ -1161,6 +1161,11 @@ enum perf_event_task_context {
|
|
perf_nr_task_contexts,
|
|
};
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+# include <../graphene/graphene.h>
|
|
+struct graphene_struct;
|
|
+#endif
|
|
+
|
|
struct task_struct {
|
|
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
|
|
void *stack;
|
|
@@ -1581,6 +1586,11 @@ struct task_struct {
|
|
unsigned int sequential_io;
|
|
unsigned int sequential_io_avg;
|
|
#endif
|
|
+
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ /* for graphene tasks */
|
|
+ struct graphene_struct *graphene; /* structure to store graphene info */
|
|
+#endif
|
|
};
|
|
|
|
/* Future-safe accessor for struct task_struct's cpus_allowed. */
|
|
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
|
|
index 6f19cfd..ed258f4 100644
|
|
--- a/include/linux/seccomp.h
|
|
+++ b/include/linux/seccomp.h
|
|
@@ -77,6 +77,14 @@ static inline int seccomp_mode(struct seccomp *s)
|
|
extern void put_seccomp_filter(struct task_struct *tsk);
|
|
extern void get_seccomp_filter(struct task_struct *tsk);
|
|
extern u32 seccomp_bpf_load(int off);
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+struct sock_filter *seccomp_filter_get_insns(struct seccomp_filter *);
|
|
+unsigned int seccomp_filter_get_len(struct seccomp_filter *);
|
|
+void *seccomp_filter_get_bpf_func(struct seccomp_filter *);
|
|
+void seccomp_filter_set_bpf_func(struct seccomp_filter *, void *);
|
|
+void seccomp_jit_compile(struct seccomp_filter *fp);
|
|
+void seccomp_jit_free(struct seccomp_filter *fp);
|
|
+#endif
|
|
#else /* CONFIG_SECCOMP_FILTER */
|
|
static inline void put_seccomp_filter(struct task_struct *tsk)
|
|
{
|
|
diff --git a/kernel/fork.c b/kernel/fork.c
|
|
index a17621c..41d5958 100644
|
|
--- a/kernel/fork.c
|
|
+++ b/kernel/fork.c
|
|
@@ -11,6 +11,7 @@
|
|
* management can be a bitch. See 'mm/memory.c': 'copy_page_range()'
|
|
*/
|
|
|
|
+#include <linux/version.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/init.h>
|
|
#include <linux/unistd.h>
|
|
@@ -84,6 +85,10 @@
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/task.h>
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+# include <../graphene/graphene.h>
|
|
+#endif
|
|
+
|
|
/*
|
|
* Protected counters by write_lock_irq(&tasklist_lock)
|
|
*/
|
|
@@ -242,6 +247,10 @@ void __put_task_struct(struct task_struct *tsk)
|
|
delayacct_tsk_free(tsk);
|
|
put_signal_struct(tsk->signal);
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ put_graphene_struct(tsk);
|
|
+#endif
|
|
+
|
|
if (!profile_handoff_task(tsk))
|
|
free_task(tsk);
|
|
}
|
|
@@ -322,6 +331,16 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
|
|
tsk->stack_canary = get_random_int();
|
|
#endif
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ err = dup_graphene_struct(tsk);
|
|
+ if (err)
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
|
|
+ goto free_ti;
|
|
+#else
|
|
+ goto out;
|
|
+#endif
|
|
+#endif
|
|
+
|
|
/*
|
|
* One for us, one for whoever does the "release_task()" (usually
|
|
* parent)
|
|
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
|
|
index b7a1004..5def696 100644
|
|
--- a/kernel/seccomp.c
|
|
+++ b/kernel/seccomp.c
|
|
@@ -55,9 +55,34 @@ struct seccomp_filter {
|
|
atomic_t usage;
|
|
struct seccomp_filter *prev;
|
|
unsigned short len; /* Instruction count */
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+ void *bpf_func;
|
|
+#endif
|
|
struct sock_filter insns[];
|
|
};
|
|
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+struct sock_filter *seccomp_filter_get_insns(struct seccomp_filter *fp)
|
|
+{
|
|
+ return fp->insns;
|
|
+}
|
|
+
|
|
+unsigned int seccomp_filter_get_len(struct seccomp_filter *fp)
|
|
+{
|
|
+ return fp->len;
|
|
+}
|
|
+
|
|
+void *seccomp_filter_get_bpf_func(struct seccomp_filter *fp)
|
|
+{
|
|
+ return fp->bpf_func;
|
|
+}
|
|
+
|
|
+void seccomp_filter_set_bpf_func(struct seccomp_filter *fp, void *bpf_func)
|
|
+{
|
|
+ fp->bpf_func = bpf_func;
|
|
+}
|
|
+#endif
|
|
+
|
|
/* Limit any path through the tree to 256KB worth of instructions. */
|
|
#define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
|
|
|
|
@@ -213,7 +238,16 @@ static u32 seccomp_run_filters(int syscall)
|
|
* value always takes priority (ignoring the DATA).
|
|
*/
|
|
for (f = current->seccomp.filter; f; f = f->prev) {
|
|
- u32 cur_ret = sk_run_filter(NULL, f->insns);
|
|
+ u32 cur_ret;
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+ void * bpf_func = seccomp_filter_get_bpf_func(f);
|
|
+ if (bpf_func)
|
|
+ cur_ret = (*(unsigned int (*)(const struct sk_buff *,
|
|
+ const struct sock_filter *))
|
|
+ bpf_func) (NULL, f->insns);
|
|
+ else
|
|
+#endif
|
|
+ cur_ret = sk_run_filter(NULL, f->insns);
|
|
if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
|
|
ret = cur_ret;
|
|
}
|
|
@@ -275,6 +309,10 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
|
|
if (ret)
|
|
goto fail;
|
|
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+ seccomp_jit_compile(filter);
|
|
+#endif
|
|
+
|
|
/*
|
|
* If there is an existing filter, make it the prev and don't drop its
|
|
* task reference.
|
|
@@ -332,6 +370,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;
|
|
+#ifdef CONFIG_SECCOMP_FILTER_JIT
|
|
+ seccomp_jit_free(freeme);
|
|
+#endif
|
|
kfree(freeme);
|
|
}
|
|
}
|
|
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
|
index 4257b7e..b21c19d 100644
|
|
--- a/security/apparmor/lsm.c
|
|
+++ b/security/apparmor/lsm.c
|
|
@@ -36,6 +36,10 @@
|
|
#include "include/policy.h"
|
|
#include "include/procattr.h"
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+# include <../graphene/graphene.h>
|
|
+#endif
|
|
+
|
|
/* Flag indicating whether initialization completed */
|
|
int apparmor_initialized __initdata;
|
|
|
|
@@ -165,6 +169,12 @@ static int common_perm(int op, struct path *path, u32 mask,
|
|
struct aa_profile *profile;
|
|
int error = 0;
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ if (GRAPHENE_ENABLED() &&
|
|
+ (error = graphene_common_perm(op, path, mask)))
|
|
+ return error;
|
|
+#endif
|
|
+
|
|
profile = __aa_current_profile();
|
|
if (!unconfined(profile))
|
|
error = aa_path_perm(op, profile, path, 0, mask, cond);
|
|
@@ -377,6 +387,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
|
|
{
|
|
struct aa_file_cxt *fcxt = file->f_security;
|
|
struct aa_profile *profile;
|
|
+ u32 mask;
|
|
int error = 0;
|
|
|
|
if (!mediated_filesystem(file_inode(file)))
|
|
@@ -388,10 +399,21 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
|
|
* actually execute the image.
|
|
*/
|
|
if (current->in_execve) {
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ if (GRAPHENE_ENABLED() && (error = graphene_execve_open(file)))
|
|
+ return error;
|
|
+#endif
|
|
fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
|
|
return 0;
|
|
}
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ mask = aa_map_file_to_perms(file);
|
|
+ if (GRAPHENE_ENABLED() &&
|
|
+ (error = graphene_common_perm(OP_OPEN, &file->f_path, mask)))
|
|
+ return error;
|
|
+#endif
|
|
+
|
|
profile = aa_cred_profile(cred);
|
|
if (!unconfined(profile)) {
|
|
struct inode *inode = file_inode(file);
|
|
@@ -647,6 +669,14 @@ static struct security_operations apparmor_ops = {
|
|
.getprocattr = apparmor_getprocattr,
|
|
.setprocattr = apparmor_setprocattr,
|
|
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ .socket_bind = graphene_socket_bind,
|
|
+ .socket_listen = graphene_socket_listen,
|
|
+ .socket_connect = graphene_socket_connect,
|
|
+ .socket_sendmsg = graphene_socket_sendmsg,
|
|
+ .socket_recvmsg = graphene_socket_recvmsg,
|
|
+#endif
|
|
+
|
|
.cred_alloc_blank = apparmor_cred_alloc_blank,
|
|
.cred_free = apparmor_cred_free,
|
|
.cred_prepare = apparmor_cred_prepare,
|
|
@@ -658,6 +688,10 @@ static struct security_operations apparmor_ops = {
|
|
.bprm_secureexec = apparmor_bprm_secureexec,
|
|
|
|
.task_setrlimit = apparmor_task_setrlimit,
|
|
+
|
|
+#ifdef CONFIG_GRAPHENE
|
|
+ .task_kill = graphene_task_kill,
|
|
+#endif
|
|
};
|
|
|
|
/*
|