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>
2018-03-31 05:08:03 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
// Copyright (c) 2018 Facebook
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
2018-05-25 22:55:27 +07:00
|
|
|
#include <netinet/in.h>
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
#include <sys/types.h>
|
2018-05-25 22:55:27 +07:00
|
|
|
#include <sys/select.h>
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <linux/filter.h>
|
|
|
|
|
|
|
|
#include <bpf/bpf.h>
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
#include <bpf/libbpf.h>
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
#include "cgroup_helpers.h"
|
2018-04-19 00:49:12 +07:00
|
|
|
#include "bpf_rlimit.h"
|
2018-08-08 15:01:27 +07:00
|
|
|
#include "bpf_util.h"
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
#ifndef ENOTSUPP
|
|
|
|
# define ENOTSUPP 524
|
|
|
|
#endif
|
|
|
|
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
#define CG_PATH "/foo"
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
#define CONNECT4_PROG_PATH "./connect4_prog.o"
|
|
|
|
#define CONNECT6_PROG_PATH "./connect6_prog.o"
|
2018-05-25 22:55:27 +07:00
|
|
|
#define SENDMSG4_PROG_PATH "./sendmsg4_prog.o"
|
|
|
|
#define SENDMSG6_PROG_PATH "./sendmsg6_prog.o"
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
#define SERV4_IP "192.168.1.254"
|
|
|
|
#define SERV4_REWRITE_IP "127.0.0.1"
|
2018-05-25 22:55:27 +07:00
|
|
|
#define SRC4_IP "172.16.0.1"
|
2018-05-25 22:55:26 +07:00
|
|
|
#define SRC4_REWRITE_IP "127.0.0.4"
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
#define SERV4_PORT 4040
|
|
|
|
#define SERV4_REWRITE_PORT 4444
|
|
|
|
|
|
|
|
#define SERV6_IP "face:b00c:1234:5678::abcd"
|
|
|
|
#define SERV6_REWRITE_IP "::1"
|
2018-05-25 22:55:27 +07:00
|
|
|
#define SERV6_V4MAPPED_IP "::ffff:192.168.0.4"
|
|
|
|
#define SRC6_IP "::1"
|
2018-05-25 22:55:26 +07:00
|
|
|
#define SRC6_REWRITE_IP "::6"
|
2019-01-04 16:07:08 +07:00
|
|
|
#define WILDCARD6_IP "::"
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
#define SERV6_PORT 6060
|
|
|
|
#define SERV6_REWRITE_PORT 6666
|
|
|
|
|
|
|
|
#define INET_NTOP_BUF 40
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
struct sock_addr_test;
|
|
|
|
|
|
|
|
typedef int (*load_fn)(const struct sock_addr_test *test);
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
typedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
char bpf_log_buf[BPF_LOG_BUF_SIZE];
|
|
|
|
|
|
|
|
struct sock_addr_test {
|
|
|
|
const char *descr;
|
|
|
|
/* BPF prog properties */
|
|
|
|
load_fn loadfn;
|
|
|
|
enum bpf_attach_type expected_attach_type;
|
|
|
|
enum bpf_attach_type attach_type;
|
|
|
|
/* Socket properties */
|
|
|
|
int domain;
|
|
|
|
int type;
|
|
|
|
/* IP:port pairs for BPF prog to override */
|
|
|
|
const char *requested_ip;
|
|
|
|
unsigned short requested_port;
|
|
|
|
const char *expected_ip;
|
|
|
|
unsigned short expected_port;
|
|
|
|
const char *expected_src_ip;
|
|
|
|
/* Expected test result */
|
|
|
|
enum {
|
|
|
|
LOAD_REJECT,
|
|
|
|
ATTACH_REJECT,
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
ATTACH_OKAY,
|
2018-05-25 22:55:27 +07:00
|
|
|
SYSCALL_EPERM,
|
|
|
|
SYSCALL_ENOTSUPP,
|
2018-05-25 22:55:26 +07:00
|
|
|
SUCCESS,
|
|
|
|
} expected_result;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
};
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int bind4_prog_load(const struct sock_addr_test *test);
|
|
|
|
static int bind6_prog_load(const struct sock_addr_test *test);
|
|
|
|
static int connect4_prog_load(const struct sock_addr_test *test);
|
|
|
|
static int connect6_prog_load(const struct sock_addr_test *test);
|
2019-01-04 16:07:08 +07:00
|
|
|
static int sendmsg_allow_prog_load(const struct sock_addr_test *test);
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg_deny_prog_load(const struct sock_addr_test *test);
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int recvmsg_allow_prog_load(const struct sock_addr_test *test);
|
|
|
|
static int recvmsg_deny_prog_load(const struct sock_addr_test *test);
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int recvmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test);
|
|
|
|
static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int recvmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test);
|
|
|
|
static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test);
|
2019-01-04 16:07:08 +07:00
|
|
|
static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test);
|
2018-05-25 22:55:26 +07:00
|
|
|
|
|
|
|
static struct sock_addr_test tests[] = {
|
|
|
|
/* bind */
|
|
|
|
{
|
|
|
|
"bind4: load prog with wrong expected attach type",
|
|
|
|
bind4_prog_load,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind4: attach prog with wrong attach type",
|
|
|
|
bind4_prog_load,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind4: rewrite IP & TCP port in",
|
|
|
|
bind4_prog_load,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
NULL,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind4: rewrite IP & UDP port in",
|
|
|
|
bind4_prog_load,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
NULL,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind6: load prog with wrong expected attach type",
|
|
|
|
bind6_prog_load,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind6: attach prog with wrong attach type",
|
|
|
|
bind6_prog_load,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
BPF_CGROUP_INET4_BIND,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind6: rewrite IP & TCP port in",
|
|
|
|
bind6_prog_load,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_STREAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
NULL,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bind6: rewrite IP & UDP port in",
|
|
|
|
bind6_prog_load,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
BPF_CGROUP_INET6_BIND,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
NULL,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
|
|
|
|
/* connect */
|
|
|
|
{
|
|
|
|
"connect4: load prog with wrong expected attach type",
|
|
|
|
connect4_prog_load,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect4: attach prog with wrong attach type",
|
|
|
|
connect4_prog_load,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect4: rewrite IP & TCP port",
|
|
|
|
connect4_prog_load,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SRC4_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect4: rewrite IP & UDP port",
|
|
|
|
connect4_prog_load,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SRC4_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect6: load prog with wrong expected attach type",
|
|
|
|
connect6_prog_load,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect6: attach prog with wrong attach type",
|
|
|
|
connect6_prog_load,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
BPF_CGROUP_INET4_CONNECT,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_STREAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect6: rewrite IP & TCP port",
|
|
|
|
connect6_prog_load,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_STREAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"connect6: rewrite IP & UDP port",
|
|
|
|
connect6_prog_load,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
BPF_CGROUP_INET6_CONNECT,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
2018-05-25 22:55:27 +07:00
|
|
|
|
|
|
|
/* sendmsg */
|
|
|
|
{
|
|
|
|
"sendmsg4: load prog with wrong expected attach type",
|
|
|
|
sendmsg4_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg4: attach prog with wrong attach type",
|
|
|
|
sendmsg4_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg4: rewrite IP & port (asm)",
|
|
|
|
sendmsg4_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SRC4_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg4: rewrite IP & port (C)",
|
|
|
|
sendmsg4_rw_c_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SRC4_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg4: deny call",
|
|
|
|
sendmsg_deny_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV4_IP,
|
|
|
|
SERV4_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SRC4_REWRITE_IP,
|
|
|
|
SYSCALL_EPERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg6: load prog with wrong expected attach type",
|
|
|
|
sendmsg6_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg6: attach prog with wrong attach type",
|
|
|
|
sendmsg6_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP4_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg6: rewrite IP & port (asm)",
|
|
|
|
sendmsg6_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg6: rewrite IP & port (C)",
|
|
|
|
sendmsg6_rw_c_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg6: IPv4-mapped IPv6",
|
|
|
|
sendmsg6_rw_v4mapped_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SYSCALL_ENOTSUPP,
|
|
|
|
},
|
2019-01-04 16:07:08 +07:00
|
|
|
{
|
|
|
|
"sendmsg6: set dst IP = [::] (BSD'ism)",
|
|
|
|
sendmsg6_rw_wildcard_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"sendmsg6: preserve dst IP = [::] (BSD'ism)",
|
|
|
|
sendmsg_allow_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
WILDCARD6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SRC6_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
2018-05-25 22:55:27 +07:00
|
|
|
{
|
|
|
|
"sendmsg6: deny call",
|
|
|
|
sendmsg_deny_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
BPF_CGROUP_UDP6_SENDMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_IP,
|
|
|
|
SERV6_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SRC6_REWRITE_IP,
|
|
|
|
SYSCALL_EPERM,
|
|
|
|
},
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
|
|
|
|
/* recvmsg */
|
|
|
|
{
|
|
|
|
"recvmsg4: return code ok",
|
|
|
|
recvmsg_allow_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_RECVMSG,
|
|
|
|
BPF_CGROUP_UDP4_RECVMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_OKAY,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"recvmsg4: return code !ok",
|
|
|
|
recvmsg_deny_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_RECVMSG,
|
|
|
|
BPF_CGROUP_UDP4_RECVMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"recvmsg6: return code ok",
|
|
|
|
recvmsg_allow_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_RECVMSG,
|
|
|
|
BPF_CGROUP_UDP6_RECVMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
ATTACH_OKAY,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"recvmsg6: return code !ok",
|
|
|
|
recvmsg_deny_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_RECVMSG,
|
|
|
|
BPF_CGROUP_UDP6_RECVMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
LOAD_REJECT,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"recvmsg4: rewrite IP & port (asm)",
|
|
|
|
recvmsg4_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP4_RECVMSG,
|
|
|
|
BPF_CGROUP_UDP4_RECVMSG,
|
|
|
|
AF_INET,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SERV4_REWRITE_IP,
|
|
|
|
SERV4_REWRITE_PORT,
|
|
|
|
SERV4_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"recvmsg6: rewrite IP & port (asm)",
|
|
|
|
recvmsg6_rw_asm_prog_load,
|
|
|
|
BPF_CGROUP_UDP6_RECVMSG,
|
|
|
|
BPF_CGROUP_UDP6_RECVMSG,
|
|
|
|
AF_INET6,
|
|
|
|
SOCK_DGRAM,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SERV6_REWRITE_IP,
|
|
|
|
SERV6_REWRITE_PORT,
|
|
|
|
SERV6_IP,
|
|
|
|
SUCCESS,
|
|
|
|
},
|
2018-05-25 22:55:26 +07:00
|
|
|
};
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
static int mk_sockaddr(int domain, const char *ip, unsigned short port,
|
|
|
|
struct sockaddr *addr, socklen_t addr_len)
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 *addr6;
|
|
|
|
struct sockaddr_in *addr4;
|
|
|
|
|
|
|
|
if (domain != AF_INET && domain != AF_INET6) {
|
|
|
|
log_err("Unsupported address family");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(addr, 0, addr_len);
|
|
|
|
|
|
|
|
if (domain == AF_INET) {
|
|
|
|
if (addr_len < sizeof(struct sockaddr_in))
|
|
|
|
return -1;
|
|
|
|
addr4 = (struct sockaddr_in *)addr;
|
|
|
|
addr4->sin_family = domain;
|
|
|
|
addr4->sin_port = htons(port);
|
|
|
|
if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) {
|
|
|
|
log_err("Invalid IPv4: %s", ip);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (domain == AF_INET6) {
|
|
|
|
if (addr_len < sizeof(struct sockaddr_in6))
|
|
|
|
return -1;
|
|
|
|
addr6 = (struct sockaddr_in6 *)addr;
|
|
|
|
addr6->sin6_family = domain;
|
|
|
|
addr6->sin6_port = htons(port);
|
|
|
|
if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) {
|
|
|
|
log_err("Invalid IPv6: %s", ip);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int load_insns(const struct sock_addr_test *test,
|
|
|
|
const struct bpf_insn *insns, size_t insns_cnt)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
|
|
|
struct bpf_load_program_attr load_attr;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
|
|
|
|
load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
|
2018-05-25 22:55:26 +07:00
|
|
|
load_attr.expected_attach_type = test->expected_attach_type;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
load_attr.insns = insns;
|
|
|
|
load_attr.insns_cnt = insns_cnt;
|
|
|
|
load_attr.license = "GPL";
|
|
|
|
|
|
|
|
ret = bpf_load_program_xattr(&load_attr, bpf_log_buf, BPF_LOG_BUF_SIZE);
|
2018-05-25 22:55:26 +07:00
|
|
|
if (ret < 0 && test->expected_result != LOAD_REJECT) {
|
|
|
|
log_err(">>> Loading program error.\n"
|
|
|
|
">>> Verifier output:\n%s\n-------\n", bpf_log_buf);
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* [1] These testing programs try to read different context fields, including
|
|
|
|
* narrow loads of different sizes from user_ip4 and user_ip6, and write to
|
|
|
|
* those allowed to be overridden.
|
|
|
|
*
|
|
|
|
* [2] BPF_LD_IMM64 & BPF_JMP_REG are used below whenever there is a need to
|
|
|
|
* compare a register with unsigned 32bit integer. BPF_JMP_IMM can't be used
|
|
|
|
* in such cases since it accepts only _signed_ 32bit integer as IMM
|
|
|
|
* argument. Also note that BPF_LD_IMM64 contains 2 instructions what matters
|
|
|
|
* to count jumps properly.
|
|
|
|
*/
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int bind4_prog_load(const struct sock_addr_test *test)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
|
|
|
union {
|
|
|
|
uint8_t u4_addr8[4];
|
|
|
|
uint16_t u4_addr16[2];
|
|
|
|
uint32_t u4_addr32;
|
|
|
|
} ip4;
|
|
|
|
struct sockaddr_in addr4_rw;
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, SERV4_IP, (void *)&ip4) != 1) {
|
|
|
|
log_err("Invalid IPv4: %s", SERV4_IP);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
|
|
|
|
(struct sockaddr *)&addr4_rw, sizeof(addr4_rw)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* See [1]. */
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
|
|
|
|
|
|
|
/* if (sk.family == AF_INET && */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, family)),
|
2018-11-11 13:15:15 +07:00
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 24),
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
/* (sk.type == SOCK_DGRAM || sk.type == SOCK_STREAM) && */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, type)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 1),
|
|
|
|
BPF_JMP_A(1),
|
2018-11-11 13:15:15 +07:00
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_STREAM, 20),
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
/* 1st_byte_of_user_ip4 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4)),
|
2018-11-11 13:15:15 +07:00
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[0], 18),
|
|
|
|
|
|
|
|
/* 2nd_byte_of_user_ip4 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4) + 1),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[1], 16),
|
|
|
|
|
|
|
|
/* 3rd_byte_of_user_ip4 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4) + 2),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[2], 14),
|
|
|
|
|
|
|
|
/* 4th_byte_of_user_ip4 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4) + 3),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[3], 12),
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
/* 1st_half_of_user_ip4 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4)),
|
2018-11-11 13:15:15 +07:00
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr16[0], 10),
|
|
|
|
|
|
|
|
/* 2nd_half_of_user_ip4 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4) + 2),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr16[1], 8),
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
/* whole_user_ip4 == expected) { */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4)),
|
|
|
|
BPF_LD_IMM64(BPF_REG_8, ip4.u4_addr32), /* See [2]. */
|
|
|
|
BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 4),
|
|
|
|
|
|
|
|
/* user_ip4 = addr4_rw.sin_addr */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_addr.s_addr),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4)),
|
|
|
|
|
|
|
|
/* user_port = addr4_rw.sin_port */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_port),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_port)),
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* return 1 */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int bind6_prog_load(const struct sock_addr_test *test)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
|
|
|
struct sockaddr_in6 addr6_rw;
|
|
|
|
struct in6_addr ip6;
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET6, SERV6_IP, (void *)&ip6) != 1) {
|
|
|
|
log_err("Invalid IPv6: %s", SERV6_IP);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mk_sockaddr(AF_INET6, SERV6_REWRITE_IP, SERV6_REWRITE_PORT,
|
|
|
|
(struct sockaddr *)&addr6_rw, sizeof(addr6_rw)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* See [1]. */
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
|
|
|
|
|
|
|
/* if (sk.family == AF_INET6 && */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, family)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
|
|
|
|
|
|
|
|
/* 5th_byte_of_user_ip6 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip6[1])),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr[4], 16),
|
|
|
|
|
|
|
|
/* 3rd_half_of_user_ip6 == expected && */
|
|
|
|
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip6[1])),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr16[2], 14),
|
|
|
|
|
|
|
|
/* last_word_of_user_ip6 == expected) { */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip6[3])),
|
|
|
|
BPF_LD_IMM64(BPF_REG_8, ip6.s6_addr32[3]), /* See [2]. */
|
|
|
|
BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 10),
|
|
|
|
|
|
|
|
|
|
|
|
#define STORE_IPV6_WORD(N) \
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_addr.s6_addr32[N]), \
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip6[N]))
|
|
|
|
|
|
|
|
/* user_ip6 = addr6_rw.sin6_addr */
|
|
|
|
STORE_IPV6_WORD(0),
|
|
|
|
STORE_IPV6_WORD(1),
|
|
|
|
STORE_IPV6_WORD(2),
|
|
|
|
STORE_IPV6_WORD(3),
|
|
|
|
|
|
|
|
/* user_port = addr6_rw.sin6_port */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_port),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_port)),
|
|
|
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* return 1 */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int load_path(const struct sock_addr_test *test, const char *path)
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
{
|
|
|
|
struct bpf_prog_load_attr attr;
|
|
|
|
struct bpf_object *obj;
|
|
|
|
int prog_fd;
|
|
|
|
|
|
|
|
memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
|
|
|
|
attr.file = path;
|
|
|
|
attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
|
2018-05-25 22:55:26 +07:00
|
|
|
attr.expected_attach_type = test->expected_attach_type;
|
selftests: bpf: enable hi32 randomization for all tests
The previous libbpf patch allows user to specify "prog_flags" to bpf
program load APIs. To enable high 32-bit randomization for a test, we need
to set BPF_F_TEST_RND_HI32 in "prog_flags".
To enable such randomization for all tests, we need to make sure all places
are passing BPF_F_TEST_RND_HI32. Changing them one by one is not
convenient, also, it would be better if a test could be switched to
"normal" running mode without code change.
Given the program load APIs used across bpf selftests are mostly:
bpf_prog_load: load from file
bpf_load_program: load from raw insns
A test_stub.c is implemented for bpf seltests, it offers two functions for
testing purpose:
bpf_prog_test_load
bpf_test_load_program
The are the same as "bpf_prog_load" and "bpf_load_program", except they
also set BPF_F_TEST_RND_HI32. Given *_xattr functions are the APIs to
customize any "prog_flags", it makes little sense to put these two
functions into libbpf.
Then, the following CFLAGS are passed to compilations for host programs:
-Dbpf_prog_load=bpf_prog_test_load
-Dbpf_load_program=bpf_test_load_program
They migrate the used load APIs to the test version, hence enable high
32-bit randomization for these tests without changing source code.
Besides all these, there are several testcases are using
"bpf_prog_load_attr" directly, their call sites are updated to pass
BPF_F_TEST_RND_HI32.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-05-25 05:25:21 +07:00
|
|
|
attr.prog_flags = BPF_F_TEST_RND_HI32;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
|
|
|
|
if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) {
|
2018-05-25 22:55:26 +07:00
|
|
|
if (test->expected_result != LOAD_REJECT)
|
|
|
|
log_err(">>> Loading program (%s) error.\n", path);
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return prog_fd;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int connect4_prog_load(const struct sock_addr_test *test)
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
return load_path(test, CONNECT4_PROG_PATH);
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int connect6_prog_load(const struct sock_addr_test *test)
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
return load_path(test, CONNECT6_PROG_PATH);
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
}
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int xmsg_ret_only_prog_load(const struct sock_addr_test *test,
|
|
|
|
int32_t rc)
|
2018-05-25 22:55:27 +07:00
|
|
|
{
|
|
|
|
struct bpf_insn insns[] = {
|
2019-01-04 16:07:08 +07:00
|
|
|
/* return rc */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, rc),
|
2018-05-25 22:55:27 +07:00
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
|
|
|
}
|
|
|
|
|
2019-01-04 16:07:08 +07:00
|
|
|
static int sendmsg_allow_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
return xmsg_ret_only_prog_load(test, /*rc*/ 1);
|
2019-01-04 16:07:08 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int sendmsg_deny_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
return xmsg_ret_only_prog_load(test, /*rc*/ 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int recvmsg_allow_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return xmsg_ret_only_prog_load(test, /*rc*/ 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int recvmsg_deny_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return xmsg_ret_only_prog_load(test, /*rc*/ 0);
|
2019-01-04 16:07:08 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
struct sockaddr_in dst4_rw_addr;
|
|
|
|
struct in_addr src4_rw_ip;
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) {
|
|
|
|
log_err("Invalid IPv4: %s", SRC4_REWRITE_IP);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
|
|
|
|
(struct sockaddr *)&dst4_rw_addr,
|
|
|
|
sizeof(dst4_rw_addr)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
|
|
|
|
|
|
|
/* if (sk.family == AF_INET && */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, family)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8),
|
|
|
|
|
|
|
|
/* sk.type == SOCK_DGRAM) { */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, type)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6),
|
|
|
|
|
|
|
|
/* msg_src_ip4 = src4_rw_ip */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, msg_src_ip4)),
|
|
|
|
|
|
|
|
/* user_ip4 = dst4_rw_addr.sin_addr */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4)),
|
|
|
|
|
|
|
|
/* user_port = dst4_rw_addr.sin_port */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_port)),
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* return 1 */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
|
|
|
}
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int recvmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
struct sockaddr_in src4_rw_addr;
|
|
|
|
|
|
|
|
if (mk_sockaddr(AF_INET, SERV4_IP, SERV4_PORT,
|
|
|
|
(struct sockaddr *)&src4_rw_addr,
|
|
|
|
sizeof(src4_rw_addr)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
|
|
|
|
|
|
|
/* if (sk.family == AF_INET && */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, family)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 6),
|
|
|
|
|
|
|
|
/* sk.type == SOCK_DGRAM) { */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, type)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 4),
|
|
|
|
|
|
|
|
/* user_ip4 = src4_rw_addr.sin_addr */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, src4_rw_addr.sin_addr.s_addr),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_ip4)),
|
|
|
|
|
|
|
|
/* user_port = src4_rw_addr.sin_port */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, src4_rw_addr.sin_port),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_port)),
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* return 1 */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return load_path(test, SENDMSG4_PROG_PATH);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test,
|
|
|
|
const char *rw_dst_ip)
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 dst6_rw_addr;
|
|
|
|
struct in6_addr src6_rw_ip;
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) {
|
|
|
|
log_err("Invalid IPv6: %s", SRC6_REWRITE_IP);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT,
|
|
|
|
(struct sockaddr *)&dst6_rw_addr,
|
|
|
|
sizeof(dst6_rw_addr)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
|
|
|
|
|
|
|
/* if (sk.family == AF_INET6) { */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, family)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
|
|
|
|
|
|
|
|
#define STORE_IPV6_WORD_N(DST, SRC, N) \
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, SRC[N]), \
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \
|
|
|
|
offsetof(struct bpf_sock_addr, DST[N]))
|
|
|
|
|
|
|
|
#define STORE_IPV6(DST, SRC) \
|
|
|
|
STORE_IPV6_WORD_N(DST, SRC, 0), \
|
|
|
|
STORE_IPV6_WORD_N(DST, SRC, 1), \
|
|
|
|
STORE_IPV6_WORD_N(DST, SRC, 2), \
|
|
|
|
STORE_IPV6_WORD_N(DST, SRC, 3)
|
|
|
|
|
|
|
|
STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32),
|
|
|
|
STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32),
|
|
|
|
|
|
|
|
/* user_port = dst6_rw_addr.sin6_port */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_port)),
|
|
|
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* return 1 */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP);
|
|
|
|
}
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int recvmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 src6_rw_addr;
|
|
|
|
|
|
|
|
if (mk_sockaddr(AF_INET6, SERV6_IP, SERV6_PORT,
|
|
|
|
(struct sockaddr *)&src6_rw_addr,
|
|
|
|
sizeof(src6_rw_addr)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
|
|
|
|
|
|
|
/* if (sk.family == AF_INET6) { */
|
|
|
|
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
|
|
|
|
offsetof(struct bpf_sock_addr, family)),
|
|
|
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 10),
|
|
|
|
|
|
|
|
STORE_IPV6(user_ip6, src6_rw_addr.sin6_addr.s6_addr32),
|
|
|
|
|
|
|
|
/* user_port = dst6_rw_addr.sin6_port */
|
|
|
|
BPF_MOV32_IMM(BPF_REG_7, src6_rw_addr.sin6_port),
|
|
|
|
BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
|
|
|
|
offsetof(struct bpf_sock_addr, user_port)),
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* return 1 */
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
|
|
|
return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP);
|
|
|
|
}
|
|
|
|
|
2019-01-04 16:07:08 +07:00
|
|
|
static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP);
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test)
|
|
|
|
{
|
|
|
|
return load_path(test, SENDMSG6_PROG_PATH);
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int cmp_addr(const struct sockaddr_storage *addr1,
|
|
|
|
const struct sockaddr_storage *addr2, int cmp_port)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
const struct sockaddr_in *four1, *four2;
|
|
|
|
const struct sockaddr_in6 *six1, *six2;
|
|
|
|
|
|
|
|
if (addr1->ss_family != addr2->ss_family)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (addr1->ss_family == AF_INET) {
|
|
|
|
four1 = (const struct sockaddr_in *)addr1;
|
|
|
|
four2 = (const struct sockaddr_in *)addr2;
|
|
|
|
return !((four1->sin_port == four2->sin_port || !cmp_port) &&
|
|
|
|
four1->sin_addr.s_addr == four2->sin_addr.s_addr);
|
|
|
|
} else if (addr1->ss_family == AF_INET6) {
|
|
|
|
six1 = (const struct sockaddr_in6 *)addr1;
|
|
|
|
six2 = (const struct sockaddr_in6 *)addr2;
|
|
|
|
return !((six1->sin6_port == six2->sin6_port || !cmp_port) &&
|
|
|
|
!memcmp(&six1->sin6_addr, &six2->sin6_addr,
|
|
|
|
sizeof(struct in6_addr)));
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
2018-05-25 22:55:26 +07:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmp_sock_addr(info_fn fn, int sock1,
|
|
|
|
const struct sockaddr_storage *addr2, int cmp_port)
|
|
|
|
{
|
|
|
|
struct sockaddr_storage addr1;
|
|
|
|
socklen_t len1 = sizeof(addr1);
|
|
|
|
|
|
|
|
memset(&addr1, 0, len1);
|
|
|
|
if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return cmp_addr(&addr1, addr2, cmp_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2)
|
|
|
|
{
|
|
|
|
return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0);
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1);
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2)
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1);
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
}
|
|
|
|
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
static int start_server(int type, const struct sockaddr_storage *addr,
|
|
|
|
socklen_t addr_len)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = socket(addr->ss_family, type, 0);
|
|
|
|
if (fd == -1) {
|
|
|
|
log_err("Failed to create server socket");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) {
|
|
|
|
log_err("Failed to bind server socket");
|
|
|
|
goto close_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == SOCK_STREAM) {
|
|
|
|
if (listen(fd, 128) == -1) {
|
|
|
|
log_err("Failed to listen on server socket");
|
|
|
|
goto close_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
close_out:
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
out:
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
static int connect_to_server(int type, const struct sockaddr_storage *addr,
|
|
|
|
socklen_t addr_len)
|
|
|
|
{
|
|
|
|
int domain;
|
2018-05-25 22:55:26 +07:00
|
|
|
int fd = -1;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
|
|
|
|
domain = addr->ss_family;
|
|
|
|
|
|
|
|
if (domain != AF_INET && domain != AF_INET6) {
|
|
|
|
log_err("Unsupported address family");
|
2018-05-25 22:55:26 +07:00
|
|
|
goto err;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
fd = socket(domain, type, 0);
|
|
|
|
if (fd == -1) {
|
2018-05-25 22:55:26 +07:00
|
|
|
log_err("Failed to create client socket");
|
|
|
|
goto err;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) {
|
|
|
|
log_err("Fail to connect to server");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
goto out;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
err:
|
|
|
|
close(fd);
|
2018-05-25 22:55:26 +07:00
|
|
|
fd = -1;
|
|
|
|
out:
|
|
|
|
return fd;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
int init_pktinfo(int domain, struct cmsghdr *cmsg)
|
|
|
|
{
|
|
|
|
struct in6_pktinfo *pktinfo6;
|
|
|
|
struct in_pktinfo *pktinfo4;
|
|
|
|
|
|
|
|
if (domain == AF_INET) {
|
|
|
|
cmsg->cmsg_level = SOL_IP;
|
|
|
|
cmsg->cmsg_type = IP_PKTINFO;
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
|
|
|
pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
|
|
|
memset(pktinfo4, 0, sizeof(struct in_pktinfo));
|
|
|
|
if (inet_pton(domain, SRC4_IP,
|
|
|
|
(void *)&pktinfo4->ipi_spec_dst) != 1)
|
|
|
|
return -1;
|
|
|
|
} else if (domain == AF_INET6) {
|
|
|
|
cmsg->cmsg_level = SOL_IPV6;
|
|
|
|
cmsg->cmsg_type = IPV6_PKTINFO;
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
|
|
|
pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
|
|
|
|
memset(pktinfo6, 0, sizeof(struct in6_pktinfo));
|
|
|
|
if (inet_pton(domain, SRC6_IP,
|
|
|
|
(void *)&pktinfo6->ipi6_addr) != 1)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:22:41 +07:00
|
|
|
static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
|
|
|
|
socklen_t addr_len, int set_cmsg, int flags,
|
|
|
|
int *syscall_err)
|
2018-05-25 22:55:27 +07:00
|
|
|
{
|
|
|
|
union {
|
|
|
|
char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
|
|
|
struct cmsghdr align;
|
|
|
|
} control6;
|
|
|
|
union {
|
|
|
|
char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
|
|
|
struct cmsghdr align;
|
|
|
|
} control4;
|
|
|
|
struct msghdr hdr;
|
|
|
|
struct iovec iov;
|
|
|
|
char data = 'a';
|
|
|
|
int domain;
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
domain = addr->ss_family;
|
|
|
|
|
|
|
|
if (domain != AF_INET && domain != AF_INET6) {
|
|
|
|
log_err("Unsupported address family");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:22:41 +07:00
|
|
|
fd = socket(domain, type, 0);
|
2018-05-25 22:55:27 +07:00
|
|
|
if (fd == -1) {
|
|
|
|
log_err("Failed to create client socket");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&iov, 0, sizeof(iov));
|
|
|
|
iov.iov_base = &data;
|
|
|
|
iov.iov_len = sizeof(data);
|
|
|
|
|
|
|
|
memset(&hdr, 0, sizeof(hdr));
|
|
|
|
hdr.msg_name = (void *)addr;
|
|
|
|
hdr.msg_namelen = addr_len;
|
|
|
|
hdr.msg_iov = &iov;
|
|
|
|
hdr.msg_iovlen = 1;
|
|
|
|
|
|
|
|
if (set_cmsg) {
|
|
|
|
if (domain == AF_INET) {
|
|
|
|
hdr.msg_control = &control4;
|
|
|
|
hdr.msg_controllen = sizeof(control4.buf);
|
|
|
|
} else if (domain == AF_INET6) {
|
|
|
|
hdr.msg_control = &control6;
|
|
|
|
hdr.msg_controllen = sizeof(control6.buf);
|
|
|
|
}
|
|
|
|
if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) {
|
|
|
|
log_err("Fail to init pktinfo");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:22:41 +07:00
|
|
|
if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
|
2018-05-25 22:55:27 +07:00
|
|
|
log_err("Fail to send message to server");
|
|
|
|
*syscall_err = errno;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
err:
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
out:
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:22:41 +07:00
|
|
|
static int fastconnect_to_server(const struct sockaddr_storage *addr,
|
|
|
|
socklen_t addr_len)
|
|
|
|
{
|
|
|
|
int sendmsg_err;
|
|
|
|
|
|
|
|
return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
|
|
|
|
MSG_FASTOPEN, &sendmsg_err);
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
struct msghdr hdr;
|
|
|
|
struct iovec iov;
|
|
|
|
char data[64];
|
|
|
|
fd_set rfds;
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(sockfd, &rfds);
|
|
|
|
|
|
|
|
tv.tv_sec = 2;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
|
|
|
if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 ||
|
|
|
|
!FD_ISSET(sockfd, &rfds))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
memset(&iov, 0, sizeof(iov));
|
|
|
|
iov.iov_base = data;
|
|
|
|
iov.iov_len = sizeof(data);
|
|
|
|
|
|
|
|
memset(&hdr, 0, sizeof(hdr));
|
|
|
|
hdr.msg_name = src_addr;
|
|
|
|
hdr.msg_namelen = sizeof(struct sockaddr_storage);
|
|
|
|
hdr.msg_iov = &iov;
|
|
|
|
hdr.msg_iovlen = 1;
|
|
|
|
|
|
|
|
return recvmsg(sockfd, &hdr, 0);
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int init_addrs(const struct sock_addr_test *test,
|
|
|
|
struct sockaddr_storage *requested_addr,
|
|
|
|
struct sockaddr_storage *expected_addr,
|
|
|
|
struct sockaddr_storage *expected_src_addr)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
socklen_t addr_len = sizeof(struct sockaddr_storage);
|
|
|
|
|
|
|
|
if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port,
|
|
|
|
(struct sockaddr *)expected_addr, addr_len) == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port,
|
|
|
|
(struct sockaddr *)requested_addr, addr_len) == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (test->expected_src_ip &&
|
|
|
|
mk_sockaddr(test->domain, test->expected_src_ip, 0,
|
|
|
|
(struct sockaddr *)expected_src_addr, addr_len) == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
return -1;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int run_bind_test_case(const struct sock_addr_test *test)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
socklen_t addr_len = sizeof(struct sockaddr_storage);
|
|
|
|
struct sockaddr_storage requested_addr;
|
|
|
|
struct sockaddr_storage expected_addr;
|
|
|
|
int clientfd = -1;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
int servfd = -1;
|
|
|
|
int err = 0;
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (init_addrs(test, &requested_addr, &expected_addr, NULL))
|
|
|
|
goto err;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
servfd = start_server(test->type, &requested_addr, addr_len);
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
if (servfd == -1)
|
|
|
|
goto err;
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (cmp_local_addr(servfd, &expected_addr))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Try to connect to server just in case */
|
|
|
|
clientfd = connect_to_server(test->type, &expected_addr, addr_len);
|
|
|
|
if (clientfd == -1)
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
goto err;
|
|
|
|
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
goto out;
|
|
|
|
err:
|
|
|
|
err = -1;
|
|
|
|
out:
|
2018-05-25 22:55:26 +07:00
|
|
|
close(clientfd);
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
close(servfd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int run_connect_test_case(const struct sock_addr_test *test)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
socklen_t addr_len = sizeof(struct sockaddr_storage);
|
|
|
|
struct sockaddr_storage expected_src_addr;
|
|
|
|
struct sockaddr_storage requested_addr;
|
|
|
|
struct sockaddr_storage expected_addr;
|
|
|
|
int clientfd = -1;
|
|
|
|
int servfd = -1;
|
|
|
|
int err = 0;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (init_addrs(test, &requested_addr, &expected_addr,
|
|
|
|
&expected_src_addr))
|
|
|
|
goto err;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
/* Prepare server to connect to */
|
|
|
|
servfd = start_server(test->type, &expected_addr, addr_len);
|
|
|
|
if (servfd == -1)
|
|
|
|
goto err;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
clientfd = connect_to_server(test->type, &requested_addr, addr_len);
|
|
|
|
if (clientfd == -1)
|
|
|
|
goto err;
|
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT
attach types.
Try to connect(2) to specified IP:port and test that:
* remote IP:port pair is overridden;
* local end of connection is bound to specified IP.
All combinations of IPv4/IPv6 and TCP/UDP are tested.
Example:
# tcpdump -pn -i lo -w connect.pcap 2>/dev/null &
[1] 478
# strace -qqf -e connect -o connect.trace ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available ... OK
Load bind4 with invalid type (can pollute stderr) ... REJECTED
Load bind4 with valid type ... OK
Attach bind4 with invalid type ... REJECTED
Attach bind4 with valid type ... OK
Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 23569
1: (63) *(u32 *)(r1 +24) = r2
2: (b7) r2 = 16777343
3: (63) *(u32 *)(r1 +4) = r2
invalid bpf_context access off=4 size=4
[ 1518.404609] random: crng init done
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect4'
libbpf: failed to load object './connect4_prog.o'
... REJECTED
Load connect4 with valid type ... OK
Attach connect4 with invalid type ... REJECTED
Attach connect4 with valid type ... OK
Test case #1 (IPv4/TCP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068)
Test case #2 (IPv4/UDP):
Requested: bind(192.168.1.254, 4040) ..
Actual: bind(127.0.0.1, 4444)
Requested: connect(192.168.1.254, 4040) from (*, *) ..
Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447)
Load bind6 with invalid type (can pollute stderr) ... REJECTED
Load bind6 with valid type ... OK
Attach bind6 with invalid type ... REJECTED
Attach bind6 with valid type ... OK
Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \
program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r6 = 0
1: (63) *(u32 *)(r1 +12) = r6
invalid bpf_context access off=12 size=4
libbpf: -- END LOG --
libbpf: failed to load program 'cgroup/connect6'
libbpf: failed to load object './connect6_prog.o'
... REJECTED
Load connect6 with valid type ... OK
Attach connect6 with invalid type ... REJECTED
Attach connect6 with valid type ... OK
Test case #3 (IPv6/TCP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 37458)
Test case #4 (IPv6/UDP):
Requested: bind(face:b00c:1234:5678::abcd, 6060) ..
Actual: bind(::1, 6666)
Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *)
Actual: connect(::1, 6666) from (::6, 39315)
### SUCCESS
# egrep 'connect\(.*AF_INET' connect.trace | \
> egrep -vw 'htons\(1025\)' | fold -b -s -w 72
502 connect(7, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(8, {sa_family=AF_INET, sin_port=htons(4040),
sin_addr=inet_addr("192.168.1.254")}, 128) = 0
502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060),
inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0
# fg
tcpdump -pn -i lo -w connect.pcap 2> /dev/null
# tcpdump -r connect.pcap -n tcp | cut -c 1-72
reading from file connect.pcap, link-type EN10MB (Ethernet)
17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333
17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112
17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w
17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1,
17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win
17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac
17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt
17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-03-31 05:08:06 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
/* Make sure src and dst addrs were overridden properly */
|
|
|
|
if (cmp_peer_addr(clientfd, &expected_addr))
|
|
|
|
goto err;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (cmp_local_ip(clientfd, &expected_src_addr))
|
|
|
|
goto err;
|
|
|
|
|
2018-06-27 04:22:41 +07:00
|
|
|
if (test->type == SOCK_STREAM) {
|
|
|
|
/* Test TCP Fast Open scenario */
|
|
|
|
clientfd = fastconnect_to_server(&requested_addr, addr_len);
|
|
|
|
if (clientfd == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Make sure src and dst addrs were overridden properly */
|
|
|
|
if (cmp_peer_addr(clientfd, &expected_addr))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (cmp_local_ip(clientfd, &expected_src_addr))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
goto out;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
err:
|
2018-05-25 22:55:26 +07:00
|
|
|
err = -1;
|
|
|
|
out:
|
|
|
|
close(clientfd);
|
|
|
|
close(servfd);
|
|
|
|
return err;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
}
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg)
|
2018-05-25 22:55:27 +07:00
|
|
|
{
|
|
|
|
socklen_t addr_len = sizeof(struct sockaddr_storage);
|
|
|
|
struct sockaddr_storage expected_addr;
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
struct sockaddr_storage server_addr;
|
|
|
|
struct sockaddr_storage sendmsg_addr;
|
|
|
|
struct sockaddr_storage recvmsg_addr;
|
2018-05-25 22:55:27 +07:00
|
|
|
int clientfd = -1;
|
|
|
|
int servfd = -1;
|
|
|
|
int set_cmsg;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (test->type != SOCK_DGRAM)
|
|
|
|
goto err;
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr))
|
2018-05-25 22:55:27 +07:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Prepare server to sendmsg to */
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
servfd = start_server(test->type, &server_addr, addr_len);
|
2018-05-25 22:55:27 +07:00
|
|
|
if (servfd == -1)
|
|
|
|
goto err;
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) {
|
2018-05-25 22:55:27 +07:00
|
|
|
if (clientfd >= 0)
|
|
|
|
close(clientfd);
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
clientfd = sendmsg_to_server(test->type, &sendmsg_addr,
|
2018-06-27 04:22:41 +07:00
|
|
|
addr_len, set_cmsg, /*flags*/0,
|
|
|
|
&err);
|
2018-05-25 22:55:27 +07:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
else if (clientfd == -1)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Try to receive message on server instead of using
|
|
|
|
* getpeername(2) on client socket, to check that client's
|
|
|
|
* destination address was rewritten properly, since
|
|
|
|
* getpeername(2) doesn't work with unconnected datagram
|
|
|
|
* sockets.
|
|
|
|
*
|
|
|
|
* Get source address from recvmsg(2) as well to make sure
|
|
|
|
* source was rewritten properly: getsockname(2) can't be used
|
|
|
|
* since socket is unconnected and source defined for one
|
|
|
|
* specific packet may differ from the one used by default and
|
|
|
|
* returned by getsockname(2).
|
|
|
|
*/
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
if (recvmsg_from_client(servfd, &recvmsg_addr) == -1)
|
2018-05-25 22:55:27 +07:00
|
|
|
goto err;
|
|
|
|
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0))
|
2018-05-25 22:55:27 +07:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
err:
|
|
|
|
err = -1;
|
|
|
|
out:
|
|
|
|
close(clientfd);
|
|
|
|
close(servfd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int run_test_case(int cgfd, const struct sock_addr_test *test)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
2018-05-25 22:55:26 +07:00
|
|
|
int progfd = -1;
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
int err = 0;
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
printf("Test case: %s .. ", test->descr);
|
|
|
|
|
|
|
|
progfd = test->loadfn(test);
|
|
|
|
if (test->expected_result == LOAD_REJECT && progfd < 0)
|
|
|
|
goto out;
|
|
|
|
else if (test->expected_result == LOAD_REJECT || progfd < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
err = bpf_prog_attach(progfd, cgfd, test->attach_type,
|
|
|
|
BPF_F_ALLOW_OVERRIDE);
|
|
|
|
if (test->expected_result == ATTACH_REJECT && err) {
|
|
|
|
err = 0; /* error was expected, reset it */
|
|
|
|
goto out;
|
|
|
|
} else if (test->expected_result == ATTACH_REJECT || err) {
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
goto err;
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
} else if (test->expected_result == ATTACH_OKAY) {
|
|
|
|
err = 0;
|
|
|
|
goto out;
|
2018-05-25 22:55:26 +07:00
|
|
|
}
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
switch (test->attach_type) {
|
|
|
|
case BPF_CGROUP_INET4_BIND:
|
|
|
|
case BPF_CGROUP_INET6_BIND:
|
|
|
|
err = run_bind_test_case(test);
|
|
|
|
break;
|
|
|
|
case BPF_CGROUP_INET4_CONNECT:
|
|
|
|
case BPF_CGROUP_INET6_CONNECT:
|
|
|
|
err = run_connect_test_case(test);
|
|
|
|
break;
|
2018-05-25 22:55:27 +07:00
|
|
|
case BPF_CGROUP_UDP4_SENDMSG:
|
|
|
|
case BPF_CGROUP_UDP6_SENDMSG:
|
bpf: more msg_name rewrite tests to test_sock_addr
Extend test_sock_addr for recvmsg test cases, bigger parts of the
sendmsg code can be reused for this. Below are the strace view of
the recvmsg rewrites; the sendmsg side does not have a BPF prog
connected to it for the context of this test:
IPv4 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x13 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 128) = 0
[pid 4846] socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999995})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, msg_namelen=128->16, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x13 /* BPF_??? */}, 112) = 0
IPv6 test case:
[pid 4846] bpf(BPF_PROG_ATTACH, {target_fd=3, attach_bpf_fd=4, attach_type=0x14 /* BPF_??? */, attach_flags=BPF_F_ALLOW_OVERRIDE}, 112) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[pid 4846] bind(5, {sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 128) = 0
[pid 4846] socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6
[pid 4846] sendmsg(6, {msg_name={sa_family=AF_INET6, sin6_port=htons(6666), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128, msg_iov=[{iov_base="a", iov_len=1}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] select(6, [5], NULL, NULL, {tv_sec=2, tv_usec=0}) = 1 (in [5], left {tv_sec=1, tv_usec=999996})
[pid 4846] recvmsg(5, {msg_name={sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=128->28, msg_iov=[{iov_base="a", iov_len=64}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1
[pid 4846] close(6) = 0
[pid 4846] close(5) = 0
[pid 4846] bpf(BPF_PROG_DETACH, {target_fd=3, attach_type=0x14 /* BPF_??? */}, 112) = 0
test_sock_addr run w/o strace view:
# ./test_sock_addr.sh
[...]
Test case: recvmsg4: return code ok .. [PASS]
Test case: recvmsg4: return code !ok .. [PASS]
Test case: recvmsg6: return code ok .. [PASS]
Test case: recvmsg6: return code !ok .. [PASS]
Test case: recvmsg4: rewrite IP & port (asm) .. [PASS]
Test case: recvmsg6: rewrite IP & port (asm) .. [PASS]
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrey Ignatov <rdna@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-06-07 06:49:01 +07:00
|
|
|
err = run_xmsg_test_case(test, 1);
|
|
|
|
break;
|
|
|
|
case BPF_CGROUP_UDP4_RECVMSG:
|
|
|
|
case BPF_CGROUP_UDP6_RECVMSG:
|
|
|
|
err = run_xmsg_test_case(test, 0);
|
2018-05-25 22:55:27 +07:00
|
|
|
break;
|
2018-05-25 22:55:26 +07:00
|
|
|
default:
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
goto err;
|
2018-05-25 22:55:26 +07:00
|
|
|
}
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
2018-05-25 22:55:27 +07:00
|
|
|
if (test->expected_result == SYSCALL_EPERM && err == EPERM) {
|
|
|
|
err = 0; /* error was expected, reset it */
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) {
|
|
|
|
err = 0; /* error was expected, reset it */
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (err || test->expected_result != SUCCESS)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
err:
|
|
|
|
err = -1;
|
|
|
|
out:
|
2018-05-25 22:55:26 +07:00
|
|
|
/* Detaching w/o checking return code: best effort attempt. */
|
|
|
|
if (progfd != -1)
|
|
|
|
bpf_prog_detach(cgfd, test->attach_type);
|
|
|
|
close(progfd);
|
|
|
|
printf("[%s]\n", err ? "FAIL" : "PASS");
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
static int run_tests(int cgfd)
|
|
|
|
{
|
|
|
|
int passes = 0;
|
|
|
|
int fails = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
|
|
|
|
if (run_test_case(cgfd, &tests[i]))
|
|
|
|
++fails;
|
|
|
|
else
|
|
|
|
++passes;
|
|
|
|
}
|
|
|
|
printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
|
|
|
|
return fails ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
{
|
|
|
|
int cgfd = -1;
|
|
|
|
int err = 0;
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (argc < 2) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s has to be run via %s.sh. Skip direct run.\n",
|
|
|
|
argv[0], argv[0]);
|
|
|
|
exit(err);
|
|
|
|
}
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
|
|
|
|
if (setup_cgroup_environment())
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
cgfd = create_and_get_cgroup(CG_PATH);
|
2019-01-08 00:46:46 +07:00
|
|
|
if (cgfd < 0)
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (join_cgroup(CG_PATH))
|
|
|
|
goto err;
|
|
|
|
|
2018-05-25 22:55:26 +07:00
|
|
|
if (run_tests(cgfd))
|
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>
2018-03-31 05:08:03 +07:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
err:
|
|
|
|
err = -1;
|
|
|
|
out:
|
|
|
|
close(cgfd);
|
|
|
|
cleanup_cgroup_environment();
|
|
|
|
return err;
|
|
|
|
}
|