-
Notifications
You must be signed in to change notification settings - Fork 54.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bpf: Allow any port in bpf_bind helper
We want to have a tighter control on what ports we bind to in the BPF_CGROUP_INET{4,6}_CONNECT hooks even if it means connect() becomes slightly more expensive. The expensive part comes from the fact that we now need to call inet_csk_get_port() that verifies that the port is not used and allocates an entry in the hash table for it. Since we can't rely on "snum || !bind_address_no_port" to prevent us from calling POST_BIND hook anymore, let's add another bind flag to indicate that the call site is BPF program. v5: * fix wrong AF_INET (should be AF_INET6) in the bpf program for v6 v3: * More bpf_bind documentation refinements (Martin KaFai Lau) * Add UDP tests as well (Martin KaFai Lau) * Don't start the thread, just do socket+bind+listen (Martin KaFai Lau) v2: * Update documentation (Andrey Ignatov) * Pass BIND_FORCE_ADDRESS_NO_PORT conditionally (Andrey Ignatov) Signed-off-by: Stanislav Fomichev <sdf@google.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Andrey Ignatov <rdna@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Link: https://lore.kernel.org/bpf/20200508174611.228805-5-sdf@google.com
- Loading branch information
Showing
9 changed files
with
203 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
tools/testing/selftests/bpf/prog_tests/connect_force_port.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#include <test_progs.h> | ||
#include "cgroup_helpers.h" | ||
#include "network_helpers.h" | ||
|
||
static int verify_port(int family, int fd, int expected) | ||
{ | ||
struct sockaddr_storage addr; | ||
socklen_t len = sizeof(addr); | ||
__u16 port; | ||
|
||
if (getsockname(fd, (struct sockaddr *)&addr, &len)) { | ||
log_err("Failed to get server addr"); | ||
return -1; | ||
} | ||
|
||
if (family == AF_INET) | ||
port = ((struct sockaddr_in *)&addr)->sin_port; | ||
else | ||
port = ((struct sockaddr_in6 *)&addr)->sin6_port; | ||
|
||
if (ntohs(port) != expected) { | ||
log_err("Unexpected port %d, expected %d", ntohs(port), | ||
expected); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int run_test(int cgroup_fd, int server_fd, int family, int type) | ||
{ | ||
struct bpf_prog_load_attr attr = { | ||
.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
}; | ||
struct bpf_object *obj; | ||
int expected_port; | ||
int prog_fd; | ||
int err; | ||
int fd; | ||
|
||
if (family == AF_INET) { | ||
attr.file = "./connect_force_port4.o"; | ||
attr.expected_attach_type = BPF_CGROUP_INET4_CONNECT; | ||
expected_port = 22222; | ||
} else { | ||
attr.file = "./connect_force_port6.o"; | ||
attr.expected_attach_type = BPF_CGROUP_INET6_CONNECT; | ||
expected_port = 22223; | ||
} | ||
|
||
err = bpf_prog_load_xattr(&attr, &obj, &prog_fd); | ||
if (err) { | ||
log_err("Failed to load BPF object"); | ||
return -1; | ||
} | ||
|
||
err = bpf_prog_attach(prog_fd, cgroup_fd, attr.expected_attach_type, | ||
0); | ||
if (err) { | ||
log_err("Failed to attach BPF program"); | ||
goto close_bpf_object; | ||
} | ||
|
||
fd = connect_to_fd(family, type, server_fd); | ||
if (fd < 0) { | ||
err = -1; | ||
goto close_bpf_object; | ||
} | ||
|
||
err = verify_port(family, fd, expected_port); | ||
|
||
close(fd); | ||
|
||
close_bpf_object: | ||
bpf_object__close(obj); | ||
return err; | ||
} | ||
|
||
void test_connect_force_port(void) | ||
{ | ||
int server_fd, cgroup_fd; | ||
|
||
cgroup_fd = test__join_cgroup("/connect_force_port"); | ||
if (CHECK_FAIL(cgroup_fd < 0)) | ||
return; | ||
|
||
server_fd = start_server(AF_INET, SOCK_STREAM); | ||
if (CHECK_FAIL(server_fd < 0)) | ||
goto close_cgroup_fd; | ||
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM)); | ||
close(server_fd); | ||
|
||
server_fd = start_server(AF_INET6, SOCK_STREAM); | ||
if (CHECK_FAIL(server_fd < 0)) | ||
goto close_cgroup_fd; | ||
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM)); | ||
close(server_fd); | ||
|
||
server_fd = start_server(AF_INET, SOCK_DGRAM); | ||
if (CHECK_FAIL(server_fd < 0)) | ||
goto close_cgroup_fd; | ||
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM)); | ||
close(server_fd); | ||
|
||
server_fd = start_server(AF_INET6, SOCK_DGRAM); | ||
if (CHECK_FAIL(server_fd < 0)) | ||
goto close_cgroup_fd; | ||
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM)); | ||
close(server_fd); | ||
|
||
close_cgroup_fd: | ||
close(cgroup_fd); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <string.h> | ||
|
||
#include <linux/bpf.h> | ||
#include <linux/in.h> | ||
#include <linux/in6.h> | ||
#include <sys/socket.h> | ||
|
||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_endian.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
int _version SEC("version") = 1; | ||
|
||
SEC("cgroup/connect4") | ||
int _connect4(struct bpf_sock_addr *ctx) | ||
{ | ||
struct sockaddr_in sa = {}; | ||
|
||
sa.sin_family = AF_INET; | ||
sa.sin_port = bpf_htons(22222); | ||
sa.sin_addr.s_addr = bpf_htonl(0x7f000001); /* 127.0.0.1 */ | ||
|
||
if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) | ||
return 0; | ||
|
||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <string.h> | ||
|
||
#include <linux/bpf.h> | ||
#include <linux/in.h> | ||
#include <linux/in6.h> | ||
#include <sys/socket.h> | ||
|
||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_endian.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
int _version SEC("version") = 1; | ||
|
||
SEC("cgroup/connect6") | ||
int _connect6(struct bpf_sock_addr *ctx) | ||
{ | ||
struct sockaddr_in6 sa = {}; | ||
|
||
sa.sin6_family = AF_INET6; | ||
sa.sin6_port = bpf_htons(22223); | ||
sa.sin6_addr.s6_addr32[3] = bpf_htonl(1); /* ::1 */ | ||
|
||
if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) | ||
return 0; | ||
|
||
return 1; | ||
} |