aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2018-03-30 18:08:03 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-03-30 20:15:30 -0400
commite50b0a6f089308bec6b2d0198abed231dee4d277 (patch)
tree66724709a340804aa54832903b69650130ff2983 /tools
parent4fbac77d2d092b475dda9eea66da674369665427 (diff)
selftests/bpf: Selftest for sys_bind hooks
Add selftest to work with bpf_sock_addr context from `BPF_PROG_TYPE_CGROUP_SOCK_ADDR` programs. Try to bind(2) on IP:port and apply: * loads to make sure context can be read correctly, including narrow loads (byte, half) for IP and full-size loads (word) for all fields; * stores to those fields allowed by verifier. All combination from IPv4/IPv6 and TCP/UDP are tested. Both scenarios are tested: * valid programs can be loaded and attached; * invalid programs can be neither loaded nor attached. Test passes when expected data can be read from context in the BPF-program, and after the call to bind(2) socket is bound to IP:port pair that was written by BPF-program to the context. Example: # ./test_sock_addr Attached bind4 program. Test case #1 (IPv4/TCP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Test case #2 (IPv4/UDP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Attached bind6 program. Test case #3 (IPv6/TCP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Test case #4 (IPv6/UDP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) ### SUCCESS Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools')
-rw-r--r--tools/include/uapi/linux/bpf.h23
-rw-r--r--tools/lib/bpf/libbpf.c6
-rw-r--r--tools/testing/selftests/bpf/Makefile3
-rw-r--r--tools/testing/selftests/bpf/test_sock_addr.c486
4 files changed, 517 insertions, 1 deletions
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index e1c1fed63396..f2120c5c0578 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -136,6 +136,7 @@ enum bpf_prog_type {
136 BPF_PROG_TYPE_CGROUP_DEVICE, 136 BPF_PROG_TYPE_CGROUP_DEVICE,
137 BPF_PROG_TYPE_SK_MSG, 137 BPF_PROG_TYPE_SK_MSG,
138 BPF_PROG_TYPE_RAW_TRACEPOINT, 138 BPF_PROG_TYPE_RAW_TRACEPOINT,
139 BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
139}; 140};
140 141
141enum bpf_attach_type { 142enum bpf_attach_type {
@@ -147,6 +148,8 @@ enum bpf_attach_type {
147 BPF_SK_SKB_STREAM_VERDICT, 148 BPF_SK_SKB_STREAM_VERDICT,
148 BPF_CGROUP_DEVICE, 149 BPF_CGROUP_DEVICE,
149 BPF_SK_MSG_VERDICT, 150 BPF_SK_MSG_VERDICT,
151 BPF_CGROUP_INET4_BIND,
152 BPF_CGROUP_INET6_BIND,
150 __MAX_BPF_ATTACH_TYPE 153 __MAX_BPF_ATTACH_TYPE
151}; 154};
152 155
@@ -1009,6 +1012,26 @@ struct bpf_map_info {
1009 __u64 netns_ino; 1012 __u64 netns_ino;
1010} __attribute__((aligned(8))); 1013} __attribute__((aligned(8)));
1011 1014
1015/* User bpf_sock_addr struct to access socket fields and sockaddr struct passed
1016 * by user and intended to be used by socket (e.g. to bind to, depends on
1017 * attach attach type).
1018 */
1019struct bpf_sock_addr {
1020 __u32 user_family; /* Allows 4-byte read, but no write. */
1021 __u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write.
1022 * Stored in network byte order.
1023 */
1024 __u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write.
1025 * Stored in network byte order.
1026 */
1027 __u32 user_port; /* Allows 4-byte read and write.
1028 * Stored in network byte order
1029 */
1030 __u32 family; /* Allows 4-byte read, but no write */
1031 __u32 type; /* Allows 4-byte read, but no write */
1032 __u32 protocol; /* Allows 4-byte read, but no write */
1033};
1034
1012/* User bpf_sock_ops struct to access socket values and specify request ops 1035/* User bpf_sock_ops struct to access socket values and specify request ops
1013 * and their replies. 1036 * and their replies.
1014 * Some of this fields are in network (bigendian) byte order and may need 1037 * Some of this fields are in network (bigendian) byte order and may need
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 48e3e743ebf7..d7ce8818982c 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1859,6 +1859,9 @@ static void bpf_program__set_expected_attach_type(struct bpf_program *prog,
1859 1859
1860#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) 1860#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0)
1861 1861
1862#define BPF_SA_PROG_SEC(string, ptype) \
1863 BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype)
1864
1862static const struct { 1865static const struct {
1863 const char *sec; 1866 const char *sec;
1864 size_t len; 1867 size_t len;
@@ -1882,10 +1885,13 @@ static const struct {
1882 BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), 1885 BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS),
1883 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), 1886 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB),
1884 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), 1887 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG),
1888 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND),
1889 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND),
1885}; 1890};
1886 1891
1887#undef BPF_PROG_SEC 1892#undef BPF_PROG_SEC
1888#undef BPF_PROG_SEC_FULL 1893#undef BPF_PROG_SEC_FULL
1894#undef BPF_SA_PROG_SEC
1889 1895
1890static int bpf_program__identify_section(struct bpf_program *prog) 1896static int bpf_program__identify_section(struct bpf_program *prog)
1891{ 1897{
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index f35fb02bdf56..f4717c910874 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -23,7 +23,7 @@ urandom_read: urandom_read.c
23 23
24# Order correspond to 'make run_tests' order 24# Order correspond to 'make run_tests' order
25TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ 25TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
26 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user 26 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user test_sock_addr
27 27
28TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ 28TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
29 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ 29 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \
@@ -51,6 +51,7 @@ $(TEST_GEN_PROGS): $(BPFOBJ)
51$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a 51$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
52 52
53$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c 53$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
54$(OUTPUT)/test_sock_addr: cgroup_helpers.c
54 55
55.PHONY: force 56.PHONY: force
56 57
diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c
new file mode 100644
index 000000000000..a57e13a65e37
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_sock_addr.c
@@ -0,0 +1,486 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7
8#include <arpa/inet.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11
12#include <linux/filter.h>
13
14#include <bpf/bpf.h>
15
16#include "cgroup_helpers.h"
17
18#define CG_PATH "/foo"
19
20#define SERV4_IP "192.168.1.254"
21#define SERV4_REWRITE_IP "127.0.0.1"
22#define SERV4_PORT 4040
23#define SERV4_REWRITE_PORT 4444
24
25#define SERV6_IP "face:b00c:1234:5678::abcd"
26#define SERV6_REWRITE_IP "::1"
27#define SERV6_PORT 6060
28#define SERV6_REWRITE_PORT 6666
29
30#define INET_NTOP_BUF 40
31
32typedef int (*load_fn)(enum bpf_attach_type, const char *comment);
33typedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
34
35struct program {
36 enum bpf_attach_type type;
37 load_fn loadfn;
38 int fd;
39 const char *name;
40 enum bpf_attach_type invalid_type;
41};
42
43char bpf_log_buf[BPF_LOG_BUF_SIZE];
44
45static int mk_sockaddr(int domain, const char *ip, unsigned short port,
46 struct sockaddr *addr, socklen_t addr_len)
47{
48 struct sockaddr_in6 *addr6;
49 struct sockaddr_in *addr4;
50
51 if (domain != AF_INET && domain != AF_INET6) {
52 log_err("Unsupported address family");
53 return -1;
54 }
55
56 memset(addr, 0, addr_len);
57
58 if (domain == AF_INET) {
59 if (addr_len < sizeof(struct sockaddr_in))
60 return -1;
61 addr4 = (struct sockaddr_in *)addr;
62 addr4->sin_family = domain;
63 addr4->sin_port = htons(port);
64 if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) {
65 log_err("Invalid IPv4: %s", ip);
66 return -1;
67 }
68 } else if (domain == AF_INET6) {
69 if (addr_len < sizeof(struct sockaddr_in6))
70 return -1;
71 addr6 = (struct sockaddr_in6 *)addr;
72 addr6->sin6_family = domain;
73 addr6->sin6_port = htons(port);
74 if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) {
75 log_err("Invalid IPv6: %s", ip);
76 return -1;
77 }
78 }
79
80 return 0;
81