From 9c05cc1bd18e278f0cfd5a490644105aa7cbbf52 Mon Sep 17 00:00:00 2001
From: Alexei Starovoitov <ast@plumgrid.com>
Date: Wed, 10 Sep 2014 19:41:31 -0700
Subject: [PATCH] bpf: add compat_sys_bpf wrapper

to support 32-bit user space with 64-bit kernel

Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
 arch/x86/syscalls/syscall_32.tbl  |    2 +-
 include/uapi/asm-generic/unistd.h |    2 +-
 kernel/bpf/syscall.c              |   95 +++++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 9fe1b5d002f0..2b1ddf1ddb5e 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -363,4 +363,4 @@
 354	i386	seccomp			sys_seccomp
 355	i386	getrandom		sys_getrandom
 356	i386	memfd_create		sys_memfd_create
-357	i386	bpf			sys_bpf
+357	i386	bpf			sys_bpf				compat_sys_bpf
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 22749c134117..94afed93f3cc 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -706,7 +706,7 @@ __SYSCALL(__NR_getrandom, sys_getrandom)
 #define __NR_memfd_create 279
 __SYSCALL(__NR_memfd_create, sys_memfd_create)
 #define __NR_bpf 280
-__SYSCALL(__NR_bpf, sys_bpf)
+__SC_COMP(__NR_bpf, sys_bpf, compat_sys_bpf)
 
 #undef __NR_syscalls
 #define __NR_syscalls 281
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6cdfe388c789..4f2c5441e175 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -16,6 +16,7 @@
 #include <linux/file.h>
 #include <linux/license.h>
 #include <linux/filter.h>
+#include <linux/compat.h>
 
 static LIST_HEAD(bpf_map_types);
 
@@ -576,6 +577,100 @@ free_attr:
 	return err;
 }
 
+#ifdef CONFIG_COMPAT
+union compat_bpf_attr {
+	struct {
+		enum bpf_map_type map_type;
+		__u32	key_size;
+		__u32	value_size;
+		__u32	max_entries;
+	};
+
+	struct {
+		int map_fd;
+		compat_uptr_t key;
+		union {
+			compat_uptr_t value;
+			compat_uptr_t next_key;
+		};
+	};
+
+	struct {
+		enum bpf_prog_type prog_type;
+		__u32 insn_cnt;
+		compat_uptr_t insns;
+		compat_uptr_t license;
+		__u32 log_level;
+		__u32 log_size;
+		compat_uptr_t log_buf;
+	};
+};
+COMPAT_SYSCALL_DEFINE3(bpf, int, cmd, union compat_bpf_attr __user *, uattr,
+		       unsigned int, size)
+{
+	union compat_bpf_attr compat_attr = {};
+	union bpf_attr attr = {};
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (size > sizeof(compat_attr))
+		return -EINVAL;
+
+	if (copy_from_user(&compat_attr, uattr, size) != 0)
+		return -EFAULT;
+
+	switch (cmd) {
+	case BPF_MAP_CREATE:
+		attr.map_type = compat_attr.map_type;
+		attr.key_size = compat_attr.key_size;
+		attr.value_size = compat_attr.value_size;
+		attr.max_entries = compat_attr.max_entries;
+		err = map_create(&attr);
+		break;
+	case BPF_MAP_LOOKUP_ELEM:
+		attr.map_fd = compat_attr.map_fd;
+		attr.key = compat_ptr(compat_attr.key);
+		attr.value = compat_ptr(compat_attr.value);
+		err = map_lookup_elem(&attr);
+		break;
+	case BPF_MAP_UPDATE_ELEM:
+		attr.map_fd = compat_attr.map_fd;
+		attr.key = compat_ptr(compat_attr.key);
+		attr.value = compat_ptr(compat_attr.value);
+		err = map_update_elem(&attr);
+		break;
+	case BPF_MAP_DELETE_ELEM:
+		attr.map_fd = compat_attr.map_fd;
+		attr.key = compat_ptr(compat_attr.key);
+		err = map_delete_elem(&attr);
+		break;
+	case BPF_MAP_GET_NEXT_KEY:
+		attr.map_fd = compat_attr.map_fd;
+		attr.key = compat_ptr(compat_attr.key);
+		attr.next_key = compat_ptr(compat_attr.next_key);
+		err = map_get_next_key(&attr);
+		break;
+	case BPF_PROG_LOAD:
+		attr.prog_type = compat_attr.prog_type;
+		attr.insn_cnt = compat_attr.insn_cnt;
+		attr.insns = compat_ptr(compat_attr.insns);
+		attr.license = compat_ptr(compat_attr.license);
+		attr.log_level = compat_attr.log_level;
+		attr.log_size = compat_attr.log_size;
+		attr.log_buf = compat_ptr(compat_attr.log_buf);
+		err = bpf_prog_load(&attr);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+#endif
+
 /* called from eBPF program under rcu lock
  *
  * if kernel subsystem is allowing eBPF programs to call this function,
-- 
1.7.9.5

