Skip to content

Commit 89aa075

Browse files
Alexei Starovoitovdavem330
Alexei Starovoitov
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ddd872b commit 89aa075

File tree

18 files changed

+155
-2
lines changed

18 files changed

+155
-2
lines changed

arch/alpha/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,7 @@
8989

9090
#define SO_INCOMING_CPU 49
9191

92+
#define SO_ATTACH_BPF 50
93+
#define SO_DETACH_BPF SO_DETACH_FILTER
94+
9295
#endif /* _UAPI_ASM_SOCKET_H */

arch/avr32/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,7 @@
8282

8383
#define SO_INCOMING_CPU 49
8484

85+
#define SO_ATTACH_BPF 50
86+
#define SO_DETACH_BPF SO_DETACH_FILTER
87+
8588
#endif /* _UAPI__ASM_AVR32_SOCKET_H */

arch/cris/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484

8585
#define SO_INCOMING_CPU 49
8686

87+
#define SO_ATTACH_BPF 50
88+
#define SO_DETACH_BPF SO_DETACH_FILTER
89+
8790
#endif /* _ASM_SOCKET_H */
8891

8992

arch/frv/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,8 @@
8282

8383
#define SO_INCOMING_CPU 49
8484

85+
#define SO_ATTACH_BPF 50
86+
#define SO_DETACH_BPF SO_DETACH_FILTER
87+
8588
#endif /* _ASM_SOCKET_H */
8689

arch/ia64/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,7 @@
9191

9292
#define SO_INCOMING_CPU 49
9393

94+
#define SO_ATTACH_BPF 50
95+
#define SO_DETACH_BPF SO_DETACH_FILTER
96+
9497
#endif /* _ASM_IA64_SOCKET_H */

arch/m32r/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,7 @@
8282

8383
#define SO_INCOMING_CPU 49
8484

85+
#define SO_ATTACH_BPF 50
86+
#define SO_DETACH_BPF SO_DETACH_FILTER
87+
8588
#endif /* _ASM_M32R_SOCKET_H */

arch/mips/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,7 @@
100100

101101
#define SO_INCOMING_CPU 49
102102

103+
#define SO_ATTACH_BPF 50
104+
#define SO_DETACH_BPF SO_DETACH_FILTER
105+
103106
#endif /* _UAPI_ASM_SOCKET_H */

arch/mn10300/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,7 @@
8282

8383
#define SO_INCOMING_CPU 49
8484

85+
#define SO_ATTACH_BPF 50
86+
#define SO_DETACH_BPF SO_DETACH_FILTER
87+
8588
#endif /* _ASM_SOCKET_H */

arch/parisc/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,7 @@
8181

8282
#define SO_INCOMING_CPU 0x402A
8383

84+
#define SO_ATTACH_BPF 0x402B
85+
#define SO_DETACH_BPF SO_DETACH_FILTER
86+
8487
#endif /* _UAPI_ASM_SOCKET_H */

arch/powerpc/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,7 @@
8989

9090
#define SO_INCOMING_CPU 49
9191

92+
#define SO_ATTACH_BPF 50
93+
#define SO_DETACH_BPF SO_DETACH_FILTER
94+
9295
#endif /* _ASM_POWERPC_SOCKET_H */

arch/s390/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,7 @@
8888

8989
#define SO_INCOMING_CPU 49
9090

91+
#define SO_ATTACH_BPF 50
92+
#define SO_DETACH_BPF SO_DETACH_FILTER
93+
9194
#endif /* _ASM_SOCKET_H */

arch/sparc/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@
7878

7979
#define SO_INCOMING_CPU 0x0033
8080

81+
#define SO_ATTACH_BPF 0x0034
82+
#define SO_DETACH_BPF SO_DETACH_FILTER
83+
8184
/* Security levels - as per NRL IPv6 - don't actually do anything */
8285
#define SO_SECURITY_AUTHENTICATION 0x5001
8386
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002

arch/xtensa/include/uapi/asm/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,7 @@
9393

9494
#define SO_INCOMING_CPU 49
9595

96+
#define SO_ATTACH_BPF 50
97+
#define SO_DETACH_BPF SO_DETACH_FILTER
98+
9699
#endif /* _XTENSA_SOCKET_H */

include/linux/bpf.h

+4
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ struct bpf_prog_aux {
128128
struct work_struct work;
129129
};
130130

131+
#ifdef CONFIG_BPF_SYSCALL
131132
void bpf_prog_put(struct bpf_prog *prog);
133+
#else
134+
static inline void bpf_prog_put(struct bpf_prog *prog) {}
135+
#endif
132136
struct bpf_prog *bpf_prog_get(u32 ufd);
133137
/* verify correctness of eBPF program */
134138
int bpf_check(struct bpf_prog *fp, union bpf_attr *attr);

include/linux/filter.h

+1
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog);
381381
void bpf_prog_destroy(struct bpf_prog *fp);
382382

383383
int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
384+
int sk_attach_bpf(u32 ufd, struct sock *sk);
384385
int sk_detach_filter(struct sock *sk);
385386

386387
int bpf_check_classic(const struct sock_filter *filter, unsigned int flen);

include/uapi/asm-generic/socket.h

+3
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,7 @@
8484

8585
#define SO_INCOMING_CPU 49
8686

87+
#define SO_ATTACH_BPF 50
88+
#define SO_DETACH_BPF SO_DETACH_FILTER
89+
8790
#endif /* __ASM_GENERIC_SOCKET_H */

net/core/filter.c

+95-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <linux/ratelimit.h>
4545
#include <linux/seccomp.h>
4646
#include <linux/if_vlan.h>
47+
#include <linux/bpf.h>
4748

4849
/**
4950
* sk_filter - run a packet through a socket filter
@@ -813,8 +814,12 @@ static void bpf_release_orig_filter(struct bpf_prog *fp)
813814

814815
static void __bpf_prog_release(struct bpf_prog *prog)
815816
{
816-
bpf_release_orig_filter(prog);
817-
bpf_prog_free(prog);
817+
if (prog->aux->prog_type == BPF_PROG_TYPE_SOCKET_FILTER) {
818+
bpf_prog_put(prog);
819+
} else {
820+
bpf_release_orig_filter(prog);
821+
bpf_prog_free(prog);
822+
}
818823
}
819824

820825
static void __sk_filter_release(struct sk_filter *fp)
@@ -1088,6 +1093,94 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
10881093
}
10891094
EXPORT_SYMBOL_GPL(sk_attach_filter);
10901095

1096+
#ifdef CONFIG_BPF_SYSCALL
1097+
int 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+
*/
1142+
static 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+
1156+
static 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+
1162+
static 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+
1167+
static struct bpf_prog_type_list tl = {
1168+
.ops = &sock_filter_ops,
1169+
.type = BPF_PROG_TYPE_SOCKET_FILTER,
1170+
};
1171+
1172+
static int __init register_sock_filter_ops(void)
1173+
{
1174+
bpf_register_prog_type(&tl);
1175+
return 0;
1176+
}
1177+
late_initcall(register_sock_filter_ops);
1178+
#else
1179+
int sk_attach_bpf(u32 ufd, struct sock *sk)
1180+
{
1181+
return -EOPNOTSUPP;
1182+
}
1183+
#endif
10911184
int sk_detach_filter(struct sock *sk)
10921185
{
10931186
int ret = -ENOENT;

net/core/sock.c

+13
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,19 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
888888
}
889889
break;
890890

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+
891904
case SO_DETACH_FILTER:
892905
ret = sk_detach_filter(sk);
893906
break;

0 commit comments

Comments
 (0)