aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2014-12-01 18:06:35 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-06 00:47:32 -0500
commit89aa075832b0da4402acebd698d0411dcc82d03e (patch)
tree99e7aa6cc85d3cd4ed0caaa6f1e5aea79e7cfcba
parentddd872bc3098f9d9abe1680a6b2013e59e3337f7 (diff)
net: sock: allow eBPF programs to be attached to sockets
introduce new setsockopt() command: setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)) where prog_fd was received from syscall bpf(BPF_PROG_LOAD, attr, ...) and attr->prog_type == BPF_PROG_TYPE_SOCKET_FILTER setsockopt() calls bpf_prog_get() which increments refcnt of the program, so it doesn't get unloaded while socket is using the program. The same eBPF program can be attached to multiple sockets. User task exit automatically closes socket which calls sk_filter_uncharge() which decrements refcnt of eBPF program Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/alpha/include/uapi/asm/socket.h3
-rw-r--r--arch/avr32/include/uapi/asm/socket.h3
-rw-r--r--arch/cris/include/uapi/asm/socket.h3
-rw-r--r--arch/frv/include/uapi/asm/socket.h3
-rw-r--r--arch/ia64/include/uapi/asm/socket.h3
-rw-r--r--arch/m32r/include/uapi/asm/socket.h3
-rw-r--r--arch/mips/include/uapi/asm/socket.h3
-rw-r--r--arch/mn10300/include/uapi/asm/socket.h3
-rw-r--r--arch/parisc/include/uapi/asm/socket.h3
-rw-r--r--arch/powerpc/include/uapi/asm/socket.h3
-rw-r--r--arch/s390/include/uapi/asm/socket.h3
-rw-r--r--arch/sparc/include/uapi/asm/socket.h3
-rw-r--r--arch/xtensa/include/uapi/asm/socket.h3
-rw-r--r--include/linux/bpf.h4
-rw-r--r--include/linux/filter.h1
-rw-r--r--include/uapi/asm-generic/socket.h3
-rw-r--r--net/core/filter.c97
-rw-r--r--net/core/sock.c13
18 files changed, 155 insertions, 2 deletions
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index e2fe0700b3b4..9a20821b111c 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -89,4 +89,7 @@
89 89
90#define SO_INCOMING_CPU 49 90#define SO_INCOMING_CPU 49
91 91
92#define SO_ATTACH_BPF 50
93#define SO_DETACH_BPF SO_DETACH_FILTER
94
92#endif /* _UAPI_ASM_SOCKET_H */ 95#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 92121b0f5b98..2b65ed6b277c 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -82,4 +82,7 @@
82 82
83#define SO_INCOMING_CPU 49 83#define SO_INCOMING_CPU 49
84 84
85#define SO_ATTACH_BPF 50
86#define SO_DETACH_BPF SO_DETACH_FILTER
87
85#endif /* _UAPI__ASM_AVR32_SOCKET_H */ 88#endif /* _UAPI__ASM_AVR32_SOCKET_H */
diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h
index 60f60f5b9b35..e2503d9f1869 100644
--- a/arch/cris/include/uapi/asm/socket.h
+++ b/arch/cris/include/uapi/asm/socket.h
@@ -84,6 +84,9 @@
84 84
85#define SO_INCOMING_CPU 49 85#define SO_INCOMING_CPU 49
86 86
87#define SO_ATTACH_BPF 50
88#define SO_DETACH_BPF SO_DETACH_FILTER
89
87#endif /* _ASM_SOCKET_H */ 90#endif /* _ASM_SOCKET_H */
88 91
89 92
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index 2c6890209ea6..4823ad125578 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -82,5 +82,8 @@
82 82
83#define SO_INCOMING_CPU 49 83#define SO_INCOMING_CPU 49
84 84
85#define SO_ATTACH_BPF 50
86#define SO_DETACH_BPF SO_DETACH_FILTER
87
85#endif /* _ASM_SOCKET_H */ 88#endif /* _ASM_SOCKET_H */
86 89
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index 09a93fb566f6..59be3d87f86d 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -91,4 +91,7 @@
91 91
92#define SO_INCOMING_CPU 49 92#define SO_INCOMING_CPU 49
93 93
94#define SO_ATTACH_BPF 50
95#define SO_DETACH_BPF SO_DETACH_FILTER
96
94#endif /* _ASM_IA64_SOCKET_H */ 97#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h
index e8589819c274..7bc4cb273856 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -82,4 +82,7 @@
82 82
83#define SO_INCOMING_CPU 49 83#define SO_INCOMING_CPU 49
84 84
85#define SO_ATTACH_BPF 50
86#define SO_DETACH_BPF SO_DETACH_FILTER
87
85#endif /* _ASM_M32R_SOCKET_H */ 88#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 2e9ee8c55a10..dec3c850f36b 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -100,4 +100,7 @@
100 100
101#define SO_INCOMING_CPU 49 101#define SO_INCOMING_CPU 49
102 102
103#define SO_ATTACH_BPF 50
104#define SO_DETACH_BPF SO_DETACH_FILTER
105
103#endif /* _UAPI_ASM_SOCKET_H */ 106#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index f3492e8c9f70..cab7d6d50051 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -82,4 +82,7 @@
82 82
83#define SO_INCOMING_CPU 49 83#define SO_INCOMING_CPU 49
84 84
85#define SO_ATTACH_BPF 50
86#define SO_DETACH_BPF SO_DETACH_FILTER
87
85#endif /* _ASM_SOCKET_H */ 88#endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index 7984a1cab3da..a5cd40cd8ee1 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -81,4 +81,7 @@
81 81
82#define SO_INCOMING_CPU 0x402A 82#define SO_INCOMING_CPU 0x402A
83 83
84#define SO_ATTACH_BPF 0x402B
85#define SO_DETACH_BPF SO_DETACH_FILTER
86
84#endif /* _UAPI_ASM_SOCKET_H */ 87#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index 3474e4ef166d..c046666038f8 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -89,4 +89,7 @@
89 89
90#define SO_INCOMING_CPU 49 90#define SO_INCOMING_CPU 49
91 91
92#define SO_ATTACH_BPF 50
93#define SO_DETACH_BPF SO_DETACH_FILTER
94
92#endif /* _ASM_POWERPC_SOCKET_H */ 95#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 8457636c33e1..296942d56e6a 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -88,4 +88,7 @@
88 88
89#define SO_INCOMING_CPU 49 89#define SO_INCOMING_CPU 49
90 90
91#define SO_ATTACH_BPF 50
92#define SO_DETACH_BPF SO_DETACH_FILTER
93
91#endif /* _ASM_SOCKET_H */ 94#endif /* _ASM_SOCKET_H */
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 4a8003a94163..e6a16c40be5f 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -78,6 +78,9 @@
78 78
79#define SO_INCOMING_CPU 0x0033 79#define SO_INCOMING_CPU 0x0033
80 80
81#define SO_ATTACH_BPF 0x0034
82#define SO_DETACH_BPF SO_DETACH_FILTER
83
81/* Security levels - as per NRL IPv6 - don't actually do anything */ 84/* Security levels - as per NRL IPv6 - don't actually do anything */
82#define SO_SECURITY_AUTHENTICATION 0x5001 85#define SO_SECURITY_AUTHENTICATION 0x5001
83#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 86#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h
index c46f6a696849..4120af086160 100644
--- a/arch/xtensa/include/uapi/asm/socket.h
+++ b/arch/xtensa/include/uapi/asm/socket.h
@@ -93,4 +93,7 @@
93 93
94#define SO_INCOMING_CPU 49 94#define SO_INCOMING_CPU 49
95 95
96#define SO_ATTACH_BPF 50
97#define SO_DETACH_BPF SO_DETACH_FILTER
98
96#endif /* _XTENSA_SOCKET_H */ 99#endif /* _XTENSA_SOCKET_H */
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 75e94eaa228b..bbfceb756452 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -128,7 +128,11 @@ struct bpf_prog_aux {
128 struct work_struct work; 128 struct work_struct work;
129}; 129};
130 130
131#ifdef CONFIG_BPF_SYSCALL
131void bpf_prog_put(struct bpf_prog *prog); 132void bpf_prog_put(struct bpf_prog *prog);
133#else
134static inline void bpf_prog_put(struct bpf_prog *prog) {}
135#endif
132struct bpf_prog *bpf_prog_get(u32 ufd); 136struct bpf_prog *bpf_prog_get(u32 ufd);
133/* verify correctness of eBPF program */ 137/* verify correctness of eBPF program */
134int bpf_check(struct bpf_prog *fp, union bpf_attr *attr); 138int bpf_check(struct bpf_prog *fp, union bpf_attr *attr);
diff --git a/include/linux/filter.h b/include/linux/filter.h
index ca95abd2bed1..caac2087a4d5 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -381,6 +381,7 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog);
381void bpf_prog_destroy(struct bpf_prog *fp); 381void bpf_prog_destroy(struct bpf_prog *fp);
382 382
383int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); 383int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
384int sk_attach_bpf(u32 ufd, struct sock *sk);
384int sk_detach_filter(struct sock *sk); 385int sk_detach_filter(struct sock *sk);
385 386
386int bpf_check_classic(const struct sock_filter *filter, unsigned int flen); 387int bpf_check_classic(const struct sock_filter *filter, unsigned int flen);
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index f541ccefd4ac..5c15c2a5c123 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -84,4 +84,7 @@
84 84
85#define SO_INCOMING_CPU 49 85#define SO_INCOMING_CPU 49
86 86
87#define SO_ATTACH_BPF 50
88#define SO_DETACH_BPF SO_DETACH_FILTER
89
87#endif /* __ASM_GENERIC_SOCKET_H */ 90#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/net/core/filter.c b/net/core/filter.c
index 647b12265e18..8cc3c03078b3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -44,6 +44,7 @@
44#include <linux/ratelimit.h> 44#include <linux/ratelimit.h>
45#include <linux/seccomp.h> 45#include <linux/seccomp.h>
46#include <linux/if_vlan.h> 46#include <linux/if_vlan.h>
47#include <linux/bpf.h>
47 48
48/** 49/**
49 * sk_filter - run a packet through a socket filter 50 * sk_filter - run a packet through a socket filter
@@ -813,8 +814,12 @@ static void bpf_release_orig_filter(struct bpf_prog *fp)
813 814
814static void __bpf_prog_release(struct bpf_prog *prog) 815static void __bpf_prog_release(struct bpf_prog *prog)
815{ 816{
816 bpf_release_orig_filter(prog); 817 if (prog->aux->prog_type == BPF_PROG_TYPE_SOCKET_FILTER) {
817 bpf_prog_free(prog); 818 bpf_prog_put(prog);
819 } else {
820 bpf_release_orig_filter(prog);
821 bpf_prog_free(prog);
822 }
818} 823}
819 824
820static void __sk_filter_release(struct sk_filter *fp) 825static void __sk_filter_release(struct sk_filter *fp)
@@ -1088,6 +1093,94 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
1088} 1093}
1089EXPORT_SYMBOL_GPL(sk_attach_filter); 1094EXPORT_SYMBOL_GPL(sk_attach_filter);
1090 1095
1096#ifdef CONFIG_BPF_SYSCALL
1097int sk_attach_bpf(u32 ufd, struct sock *sk)
1098{
1099 struct sk_filter *fp, *old_fp;
1100 struct bpf_prog *prog;
1101
1102 if (sock_flag(sk, SOCK_FILTER_LOCKED))
1103 return -EPERM;
1104
1105 prog = bpf_prog_get(ufd);
1106 if (!prog)
1107 return -EINVAL;
1108
1109 if (prog->aux->prog_type != BPF_PROG_TYPE_SOCKET_FILTER) {
1110 /* valid fd, but invalid program type */
1111 bpf_prog_put(prog);
1112 return -EINVAL;
1113 }
1114
1115 fp = kmalloc(sizeof(*fp), GFP_KERNEL);
1116 if (!fp) {
1117 bpf_prog_put(prog);
1118 return -ENOMEM;
1119 }
1120 fp->prog = prog;
1121
1122 atomic_set(&fp->refcnt, 0);
1123
1124 if (!sk_filter_charge(sk, fp)) {
1125 __sk_filter_release(fp);
1126 return -ENOMEM;
1127 }
1128
1129 old_fp = rcu_dereference_protected(sk->sk_filter,
1130 sock_owned_by_user(sk));
1131 rcu_assign_pointer(sk->sk_filter, fp);
1132
1133 if (old_fp)
1134 sk_filter_uncharge(sk, old_fp);
1135
1136 return 0;
1137}
1138
1139/* allow socket filters to call
1140 * bpf_map_lookup_elem(), bpf_map_update_elem(), bpf_map_delete_elem()
1141 */
1142static const struct bpf_func_proto *sock_filter_func_proto(enum bpf_func_id func_id)
1143{
1144 switch (func_id) {
1145 case BPF_FUNC_map_lookup_elem:
1146 return &bpf_map_lookup_elem_proto;
1147 case BPF_FUNC_map_update_elem:
1148 return &bpf_map_update_elem_proto;
1149 case BPF_FUNC_map_delete_elem:
1150 return &bpf_map_delete_elem_proto;
1151 default:
1152 return NULL;
1153 }
1154}
1155
1156static bool sock_filter_is_valid_access(int off, int size, enum bpf_access_type type)
1157{
1158 /* skb fields cannot be accessed yet */
1159 return false;
1160}
1161
1162static struct bpf_verifier_ops sock_filter_ops = {
1163 .get_func_proto = sock_filter_func_proto,
1164 .is_valid_access = sock_filter_is_valid_access,
1165};
1166
1167static struct bpf_prog_type_list tl = {
1168 .ops = &sock_filter_ops,
1169 .type = BPF_PROG_TYPE_SOCKET_FILTER,
1170};
1171
1172static int __init register_sock_filter_ops(void)
1173{
1174 bpf_register_prog_type(&tl);
1175 return 0;
1176}
1177late_initcall(register_sock_filter_ops);
1178#else
1179int sk_attach_bpf(u32 ufd, struct sock *sk)
1180{
1181 return -EOPNOTSUPP;
1182}
1183#endif
1091int sk_detach_filter(struct sock *sk) 1184int sk_detach_filter(struct sock *sk)
1092{ 1185{
1093 int ret = -ENOENT; 1186 int ret = -ENOENT;
diff --git a/net/core/sock.c b/net/core/sock.c
index 0725cf0cb685..9a56b2000c3f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -888,6 +888,19 @@ set_rcvbuf:
888 } 888 }
889 break; 889 break;
890 890
891 case SO_ATTACH_BPF:
892 ret = -EINVAL;
893 if (optlen == sizeof(u32)) {
894 u32 ufd;
895
896 ret = -EFAULT;
897 if (copy_from_user(&ufd, optval, sizeof(ufd)))
898 break;
899
900 ret = sk_attach_bpf(ufd, sk);
901 }
902 break;
903
891 case SO_DETACH_FILTER: 904 case SO_DETACH_FILTER:
892 ret = sk_detach_filter(sk); 905 ret = sk_detach_filter(sk);
893 break; 906 break;