Skip to content

Commit

Permalink
bpf: selftests: add bind retry for post_bind{4, 6}
Browse files Browse the repository at this point in the history
With previous patch, kernel is able to 'put_port' after sys_bind()
fails. Add the test for that case: rebind another port after
sys_bind() fails. If the bind success, it means previous bind
operation is already undoed.

Signed-off-by: Menglong Dong <imagedong@tencent.com>
  • Loading branch information
menglongdong authored and Nobody committed Dec 31, 2021
1 parent e8bfd34 commit bffd947
Showing 1 changed file with 146 additions and 20 deletions.
166 changes: 146 additions & 20 deletions tools/testing/selftests/bpf/test_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@ struct sock_test {
/* Endpoint to bind() to */
const char *ip;
unsigned short port;
unsigned short port_retry;
/* Expected test result */
enum {
LOAD_REJECT,
ATTACH_REJECT,
BIND_REJECT,
SUCCESS,
RETRY_SUCCESS,
RETRY_REJECT
} result;
};

Expand All @@ -60,6 +63,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
LOAD_REJECT,
},
{
Expand All @@ -77,6 +81,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
LOAD_REJECT,
},
{
Expand All @@ -94,6 +99,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
LOAD_REJECT,
},
{
Expand All @@ -111,6 +117,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
LOAD_REJECT,
},
{
Expand All @@ -125,6 +132,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"127.0.0.1",
8097,
0,
SUCCESS,
},
{
Expand All @@ -139,6 +147,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"127.0.0.1",
8097,
0,
SUCCESS,
},
{
Expand All @@ -153,6 +162,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
ATTACH_REJECT,
},
{
Expand All @@ -167,6 +177,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
ATTACH_REJECT,
},
{
Expand All @@ -181,6 +192,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
ATTACH_REJECT,
},
{
Expand All @@ -195,6 +207,7 @@ static struct sock_test tests[] = {
0,
NULL,
0,
0,
ATTACH_REJECT,
},
{
Expand All @@ -209,6 +222,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"0.0.0.0",
0,
0,
BIND_REJECT,
},
{
Expand All @@ -223,6 +237,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"::",
0,
0,
BIND_REJECT,
},
{
Expand Down Expand Up @@ -253,6 +268,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"::1",
8193,
0,
BIND_REJECT,
},
{
Expand Down Expand Up @@ -283,8 +299,102 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"127.0.0.1",
4098,
0,
SUCCESS,
},
{
"bind4 deny specific IP & port of TCP, and retry",
.insns = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),

/* if (ip == expected && port == expected) */
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
offsetof(struct bpf_sock, src_ip4)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
__bpf_constant_ntohl(0x7F000001), 4),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
offsetof(struct bpf_sock, src_port)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),

/* return DENY; */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_JMP_A(1),

/* else return ALLOW; */
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
BPF_CGROUP_INET4_POST_BIND,
BPF_CGROUP_INET4_POST_BIND,
AF_INET,
SOCK_STREAM,
"127.0.0.1",
4098,
5000,
RETRY_SUCCESS,
},
{
"bind4 deny specific IP & port of UDP, and retry",
.insns = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),

/* if (ip == expected && port == expected) */
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
offsetof(struct bpf_sock, src_ip4)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
__bpf_constant_ntohl(0x7F000001), 4),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
offsetof(struct bpf_sock, src_port)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),

/* return DENY; */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_JMP_A(1),

/* else return ALLOW; */
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
BPF_CGROUP_INET4_POST_BIND,
BPF_CGROUP_INET4_POST_BIND,
AF_INET,
SOCK_DGRAM,
"127.0.0.1",
4098,
5000,
RETRY_SUCCESS,
},
{
"bind6 deny specific IP & port, and retry",
.insns = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),

/* if (ip == expected && port == expected) */
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
offsetof(struct bpf_sock, src_ip6[3])),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
__bpf_constant_ntohl(0x00000001), 4),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
offsetof(struct bpf_sock, src_port)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),

/* return DENY; */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_JMP_A(1),

/* else return ALLOW; */
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
BPF_CGROUP_INET6_POST_BIND,
BPF_CGROUP_INET6_POST_BIND,
AF_INET6,
SOCK_STREAM,
"::1",
8193,
9000,
RETRY_SUCCESS,
},
{
"bind4 allow all",
.insns = {
Expand All @@ -297,6 +407,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"0.0.0.0",
0,
0,
SUCCESS,
},
{
Expand All @@ -311,6 +422,7 @@ static struct sock_test tests[] = {
SOCK_STREAM,
"::",
0,
0,
SUCCESS,
},
};
Expand Down Expand Up @@ -351,14 +463,15 @@ static int attach_sock_prog(int cgfd, int progfd,
return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE);
}

static int bind_sock(int domain, int type, const char *ip, unsigned short port)
static int bind_sock(int domain, int type, const char *ip,
unsigned short port, unsigned short port_retry)
{
struct sockaddr_storage addr;
struct sockaddr_in6 *addr6;
struct sockaddr_in *addr4;
int sockfd = -1;
socklen_t len;
int err = 0;
int res = SUCCESS;

sockfd = socket(domain, type, 0);
if (sockfd < 0)
Expand All @@ -384,21 +497,44 @@ static int bind_sock(int domain, int type, const char *ip, unsigned short port)
goto err;
}

if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1)
goto err;
if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
/* sys_bind() may fail for different reasons, errno has to be
* checked to confirm that BPF program rejected it.
*/
if (errno != EPERM)
goto err;
if (port_retry)
goto retry;
res = BIND_REJECT;
goto out;
}

goto out;
retry:
if (domain == AF_INET)
addr4->sin_port = htons(port_retry);
else
addr6->sin6_port = htons(port_retry);
if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
if (errno != EPERM)
goto err;
res = RETRY_REJECT;
} else {
res = RETRY_SUCCESS;
}
goto out;
err:
err = -1;
res = -1;
out:
close(sockfd);
return err;
return res;
}

static int run_test_case(int cgfd, const struct sock_test *test)
{
int progfd = -1;
int err = 0;
int res;

printf("Test case: %s .. ", test->descr);
progfd = load_sock_prog(test->insns, test->expected_attach_type);
Expand All @@ -416,21 +552,11 @@ static int run_test_case(int cgfd, const struct sock_test *test)
goto err;
}

if (bind_sock(test->domain, test->type, test->ip, test->port) == -1) {
/* sys_bind() may fail for different reasons, errno has to be
* checked to confirm that BPF program rejected it.
*/
if (test->result == BIND_REJECT && errno == EPERM)
goto out;
else
goto err;
}

res = bind_sock(test->domain, test->type, test->ip, test->port,
test->port_retry);
if (res > 0 && test->result == res)
goto out;

if (test->result != SUCCESS)
goto err;

goto out;
err:
err = -1;
out:
Expand Down

0 comments on commit bffd947

Please sign in to comment.