All of lore.kernel.org
 help / color / mirror / Atom feed
From: menglong8.dong@gmail.com
To: kuba@kernel.org, daniel@iogearbox.net
Cc: davem@davemloft.net, yoshfuji@linux-ipv6.org, dsahern@kernel.org,
	edumazet@google.com, shuah@kernel.org, ast@kernel.org,
	andrii@kernel.org, kafai@fb.com, songliubraving@fb.com,
	yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-kselftest@vger.kernel.org, bpf@vger.kernel.org,
	Menglong Dong <imagedong@tencent.com>
Subject: [PATCH v3 net-next 2/2] bpf: selftests: add bind retry for post_bind{4, 6}
Date: Wed,  5 Jan 2022 21:18:49 +0800	[thread overview]
Message-ID: <20220105131849.2559506-3-imagedong@tencent.com> (raw)
In-Reply-To: <20220105131849.2559506-1-imagedong@tencent.com>

From: Menglong Dong <imagedong@tencent.com>

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>
---
 tools/testing/selftests/bpf/test_sock.c | 166 +++++++++++++++++++++---
 1 file changed, 146 insertions(+), 20 deletions(-)

diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/test_sock.c
index e8edd3dd3ec2..68525d68d4e5 100644
--- a/tools/testing/selftests/bpf/test_sock.c
+++ b/tools/testing/selftests/bpf/test_sock.c
@@ -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;
 };
 
@@ -60,6 +63,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		LOAD_REJECT,
 	},
 	{
@@ -77,6 +81,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		LOAD_REJECT,
 	},
 	{
@@ -94,6 +99,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		LOAD_REJECT,
 	},
 	{
@@ -111,6 +117,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		LOAD_REJECT,
 	},
 	{
@@ -125,6 +132,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"127.0.0.1",
 		8097,
+		0,
 		SUCCESS,
 	},
 	{
@@ -139,6 +147,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"127.0.0.1",
 		8097,
+		0,
 		SUCCESS,
 	},
 	{
@@ -153,6 +162,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		ATTACH_REJECT,
 	},
 	{
@@ -167,6 +177,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		ATTACH_REJECT,
 	},
 	{
@@ -181,6 +192,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		ATTACH_REJECT,
 	},
 	{
@@ -195,6 +207,7 @@ static struct sock_test tests[] = {
 		0,
 		NULL,
 		0,
+		0,
 		ATTACH_REJECT,
 	},
 	{
@@ -209,6 +222,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"0.0.0.0",
 		0,
+		0,
 		BIND_REJECT,
 	},
 	{
@@ -223,6 +237,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"::",
 		0,
+		0,
 		BIND_REJECT,
 	},
 	{
@@ -253,6 +268,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"::1",
 		8193,
+		0,
 		BIND_REJECT,
 	},
 	{
@@ -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 = {
@@ -297,6 +407,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"0.0.0.0",
 		0,
+		0,
 		SUCCESS,
 	},
 	{
@@ -311,6 +422,7 @@ static struct sock_test tests[] = {
 		SOCK_STREAM,
 		"::",
 		0,
+		0,
 		SUCCESS,
 	},
 };
@@ -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)
@@ -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);
@@ -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:
-- 
2.30.2


  parent reply	other threads:[~2022-01-05 13:21 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-05 13:18 [PATCH v3 net-next 0/2] net: bpf: handle return value of post_bind{4,6} and add selftests for it menglong8.dong
2022-01-05 13:18 ` [PATCH v3 net-next 1/2] net: bpf: handle return value of BPF_CGROUP_RUN_PROG_INET{4,6}_POST_BIND() menglong8.dong
2022-01-05 13:18 ` menglong8.dong [this message]
2022-01-05 13:57   ` [PATCH v3 net-next 2/2] bpf: selftests: add bind retry for post_bind{4, 6} Eric Dumazet
2022-01-05 14:45     ` Menglong Dong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220105131849.2559506-3-imagedong@tencent.com \
    --to=menglong8.dong@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=imagedong@tencent.com \
    --cc=john.fastabend@gmail.com \
    --cc=kafai@fb.com \
    --cc=kpsingh@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=shuah@kernel.org \
    --cc=songliubraving@fb.com \
    --cc=yhs@fb.com \
    --cc=yoshfuji@linux-ipv6.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.