Skip to content

Commit d01f471

Browse files
menglongdongNobody
authored andcommitted
bpf: selftests: add bind retry for post_bind{4, 6}
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>
1 parent b4e6348 commit d01f471

File tree

1 file changed

+146
-20
lines changed

1 file changed

+146
-20
lines changed

tools/testing/selftests/bpf/test_sock.c

Lines changed: 146 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@ struct sock_test {
3535
/* Endpoint to bind() to */
3636
const char *ip;
3737
unsigned short port;
38+
unsigned short port_retry;
3839
/* Expected test result */
3940
enum {
4041
LOAD_REJECT,
4142
ATTACH_REJECT,
4243
BIND_REJECT,
4344
SUCCESS,
45+
RETRY_SUCCESS,
46+
RETRY_REJECT
4447
} result;
4548
};
4649

@@ -60,6 +63,7 @@ static struct sock_test tests[] = {
6063
0,
6164
NULL,
6265
0,
66+
0,
6367
LOAD_REJECT,
6468
},
6569
{
@@ -77,6 +81,7 @@ static struct sock_test tests[] = {
7781
0,
7882
NULL,
7983
0,
84+
0,
8085
LOAD_REJECT,
8186
},
8287
{
@@ -94,6 +99,7 @@ static struct sock_test tests[] = {
9499
0,
95100
NULL,
96101
0,
102+
0,
97103
LOAD_REJECT,
98104
},
99105
{
@@ -111,6 +117,7 @@ static struct sock_test tests[] = {
111117
0,
112118
NULL,
113119
0,
120+
0,
114121
LOAD_REJECT,
115122
},
116123
{
@@ -125,6 +132,7 @@ static struct sock_test tests[] = {
125132
SOCK_STREAM,
126133
"127.0.0.1",
127134
8097,
135+
0,
128136
SUCCESS,
129137
},
130138
{
@@ -139,6 +147,7 @@ static struct sock_test tests[] = {
139147
SOCK_STREAM,
140148
"127.0.0.1",
141149
8097,
150+
0,
142151
SUCCESS,
143152
},
144153
{
@@ -153,6 +162,7 @@ static struct sock_test tests[] = {
153162
0,
154163
NULL,
155164
0,
165+
0,
156166
ATTACH_REJECT,
157167
},
158168
{
@@ -167,6 +177,7 @@ static struct sock_test tests[] = {
167177
0,
168178
NULL,
169179
0,
180+
0,
170181
ATTACH_REJECT,
171182
},
172183
{
@@ -181,6 +192,7 @@ static struct sock_test tests[] = {
181192
0,
182193
NULL,
183194
0,
195+
0,
184196
ATTACH_REJECT,
185197
},
186198
{
@@ -195,6 +207,7 @@ static struct sock_test tests[] = {
195207
0,
196208
NULL,
197209
0,
210+
0,
198211
ATTACH_REJECT,
199212
},
200213
{
@@ -209,6 +222,7 @@ static struct sock_test tests[] = {
209222
SOCK_STREAM,
210223
"0.0.0.0",
211224
0,
225+
0,
212226
BIND_REJECT,
213227
},
214228
{
@@ -223,6 +237,7 @@ static struct sock_test tests[] = {
223237
SOCK_STREAM,
224238
"::",
225239
0,
240+
0,
226241
BIND_REJECT,
227242
},
228243
{
@@ -253,6 +268,7 @@ static struct sock_test tests[] = {
253268
SOCK_STREAM,
254269
"::1",
255270
8193,
271+
0,
256272
BIND_REJECT,
257273
},
258274
{
@@ -283,8 +299,102 @@ static struct sock_test tests[] = {
283299
SOCK_STREAM,
284300
"127.0.0.1",
285301
4098,
302+
0,
286303
SUCCESS,
287304
},
305+
{
306+
"bind4 deny specific IP & port of TCP, and retry",
307+
.insns = {
308+
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
309+
310+
/* if (ip == expected && port == expected) */
311+
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
312+
offsetof(struct bpf_sock, src_ip4)),
313+
BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
314+
__bpf_constant_ntohl(0x7F000001), 4),
315+
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
316+
offsetof(struct bpf_sock, src_port)),
317+
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
318+
319+
/* return DENY; */
320+
BPF_MOV64_IMM(BPF_REG_0, 0),
321+
BPF_JMP_A(1),
322+
323+
/* else return ALLOW; */
324+
BPF_MOV64_IMM(BPF_REG_0, 1),
325+
BPF_EXIT_INSN(),
326+
},
327+
BPF_CGROUP_INET4_POST_BIND,
328+
BPF_CGROUP_INET4_POST_BIND,
329+
AF_INET,
330+
SOCK_STREAM,
331+
"127.0.0.1",
332+
4098,
333+
5000,
334+
RETRY_SUCCESS,
335+
},
336+
{
337+
"bind4 deny specific IP & port of UDP, and retry",
338+
.insns = {
339+
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
340+
341+
/* if (ip == expected && port == expected) */
342+
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
343+
offsetof(struct bpf_sock, src_ip4)),
344+
BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
345+
__bpf_constant_ntohl(0x7F000001), 4),
346+
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
347+
offsetof(struct bpf_sock, src_port)),
348+
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
349+
350+
/* return DENY; */
351+
BPF_MOV64_IMM(BPF_REG_0, 0),
352+
BPF_JMP_A(1),
353+
354+
/* else return ALLOW; */
355+
BPF_MOV64_IMM(BPF_REG_0, 1),
356+
BPF_EXIT_INSN(),
357+
},
358+
BPF_CGROUP_INET4_POST_BIND,
359+
BPF_CGROUP_INET4_POST_BIND,
360+
AF_INET,
361+
SOCK_DGRAM,
362+
"127.0.0.1",
363+
4098,
364+
5000,
365+
RETRY_SUCCESS,
366+
},
367+
{
368+
"bind6 deny specific IP & port, and retry",
369+
.insns = {
370+
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
371+
372+
/* if (ip == expected && port == expected) */
373+
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
374+
offsetof(struct bpf_sock, src_ip6[3])),
375+
BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
376+
__bpf_constant_ntohl(0x00000001), 4),
377+
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
378+
offsetof(struct bpf_sock, src_port)),
379+
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
380+
381+
/* return DENY; */
382+
BPF_MOV64_IMM(BPF_REG_0, 0),
383+
BPF_JMP_A(1),
384+
385+
/* else return ALLOW; */
386+
BPF_MOV64_IMM(BPF_REG_0, 1),
387+
BPF_EXIT_INSN(),
388+
},
389+
BPF_CGROUP_INET6_POST_BIND,
390+
BPF_CGROUP_INET6_POST_BIND,
391+
AF_INET6,
392+
SOCK_STREAM,
393+
"::1",
394+
8193,
395+
9000,
396+
RETRY_SUCCESS,
397+
},
288398
{
289399
"bind4 allow all",
290400
.insns = {
@@ -297,6 +407,7 @@ static struct sock_test tests[] = {
297407
SOCK_STREAM,
298408
"0.0.0.0",
299409
0,
410+
0,
300411
SUCCESS,
301412
},
302413
{
@@ -311,6 +422,7 @@ static struct sock_test tests[] = {
311422
SOCK_STREAM,
312423
"::",
313424
0,
425+
0,
314426
SUCCESS,
315427
},
316428
};
@@ -351,14 +463,15 @@ static int attach_sock_prog(int cgfd, int progfd,
351463
return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE);
352464
}
353465

354-
static int bind_sock(int domain, int type, const char *ip, unsigned short port)
466+
static int bind_sock(int domain, int type, const char *ip,
467+
unsigned short port, unsigned short port_retry)
355468
{
356469
struct sockaddr_storage addr;
357470
struct sockaddr_in6 *addr6;
358471
struct sockaddr_in *addr4;
359472
int sockfd = -1;
360473
socklen_t len;
361-
int err = 0;
474+
int res = SUCCESS;
362475

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

387-
if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1)
388-
goto err;
500+
if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
501+
/* sys_bind() may fail for different reasons, errno has to be
502+
* checked to confirm that BPF program rejected it.
503+
*/
504+
if (errno != EPERM)
505+
goto err;
506+
if (port_retry)
507+
goto retry;
508+
res = BIND_REJECT;
509+
goto out;
510+
}
389511

512+
goto out;
513+
retry:
514+
if (domain == AF_INET)
515+
addr4->sin_port = htons(port_retry);
516+
else
517+
addr6->sin6_port = htons(port_retry);
518+
if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
519+
if (errno != EPERM)
520+
goto err;
521+
res = RETRY_REJECT;
522+
} else {
523+
res = RETRY_SUCCESS;
524+
}
390525
goto out;
391526
err:
392-
err = -1;
527+
res = -1;
393528
out:
394529
close(sockfd);
395-
return err;
530+
return res;
396531
}
397532

398533
static int run_test_case(int cgfd, const struct sock_test *test)
399534
{
400535
int progfd = -1;
401536
int err = 0;
537+
int res;
402538

403539
printf("Test case: %s .. ", test->descr);
404540
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)
416552
goto err;
417553
}
418554

419-
if (bind_sock(test->domain, test->type, test->ip, test->port) == -1) {
420-
/* sys_bind() may fail for different reasons, errno has to be
421-
* checked to confirm that BPF program rejected it.
422-
*/
423-
if (test->result == BIND_REJECT && errno == EPERM)
424-
goto out;
425-
else
426-
goto err;
427-
}
428-
555+
res = bind_sock(test->domain, test->type, test->ip, test->port,
556+
test->port_retry);
557+
if (res > 0 && test->result == res)
558+
goto out;
429559

430-
if (test->result != SUCCESS)
431-
goto err;
432-
433-
goto out;
434560
err:
435561
err = -1;
436562
out:

0 commit comments

Comments
 (0)