18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2018 Facebook
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <stdio.h>
58c2ecf20Sopenharmony_ci#include <unistd.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <arpa/inet.h>
88c2ecf20Sopenharmony_ci#include <sys/types.h>
98c2ecf20Sopenharmony_ci#include <sys/socket.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/filter.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "cgroup_helpers.h"
168c2ecf20Sopenharmony_ci#include <bpf/bpf_endian.h>
178c2ecf20Sopenharmony_ci#include "bpf_rlimit.h"
188c2ecf20Sopenharmony_ci#include "bpf_util.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define CG_PATH		"/foo"
218c2ecf20Sopenharmony_ci#define MAX_INSNS	512
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cichar bpf_log_buf[BPF_LOG_BUF_SIZE];
248c2ecf20Sopenharmony_cistatic bool verbose = false;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct sock_test {
278c2ecf20Sopenharmony_ci	const char *descr;
288c2ecf20Sopenharmony_ci	/* BPF prog properties */
298c2ecf20Sopenharmony_ci	struct bpf_insn	insns[MAX_INSNS];
308c2ecf20Sopenharmony_ci	enum bpf_attach_type expected_attach_type;
318c2ecf20Sopenharmony_ci	enum bpf_attach_type attach_type;
328c2ecf20Sopenharmony_ci	/* Socket properties */
338c2ecf20Sopenharmony_ci	int domain;
348c2ecf20Sopenharmony_ci	int type;
358c2ecf20Sopenharmony_ci	/* Endpoint to bind() to */
368c2ecf20Sopenharmony_ci	const char *ip;
378c2ecf20Sopenharmony_ci	unsigned short port;
388c2ecf20Sopenharmony_ci	/* Expected test result */
398c2ecf20Sopenharmony_ci	enum {
408c2ecf20Sopenharmony_ci		LOAD_REJECT,
418c2ecf20Sopenharmony_ci		ATTACH_REJECT,
428c2ecf20Sopenharmony_ci		BIND_REJECT,
438c2ecf20Sopenharmony_ci		SUCCESS,
448c2ecf20Sopenharmony_ci	} result;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic struct sock_test tests[] = {
488c2ecf20Sopenharmony_ci	{
498c2ecf20Sopenharmony_ci		"bind4 load with invalid access: src_ip6",
508c2ecf20Sopenharmony_ci		.insns = {
518c2ecf20Sopenharmony_ci			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
528c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
538c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_ip6[0])),
548c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
558c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
568c2ecf20Sopenharmony_ci		},
578c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
588c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
598c2ecf20Sopenharmony_ci		0,
608c2ecf20Sopenharmony_ci		0,
618c2ecf20Sopenharmony_ci		NULL,
628c2ecf20Sopenharmony_ci		0,
638c2ecf20Sopenharmony_ci		LOAD_REJECT,
648c2ecf20Sopenharmony_ci	},
658c2ecf20Sopenharmony_ci	{
668c2ecf20Sopenharmony_ci		"bind4 load with invalid access: mark",
678c2ecf20Sopenharmony_ci		.insns = {
688c2ecf20Sopenharmony_ci			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
698c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
708c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, mark)),
718c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
728c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
738c2ecf20Sopenharmony_ci		},
748c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
758c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
768c2ecf20Sopenharmony_ci		0,
778c2ecf20Sopenharmony_ci		0,
788c2ecf20Sopenharmony_ci		NULL,
798c2ecf20Sopenharmony_ci		0,
808c2ecf20Sopenharmony_ci		LOAD_REJECT,
818c2ecf20Sopenharmony_ci	},
828c2ecf20Sopenharmony_ci	{
838c2ecf20Sopenharmony_ci		"bind6 load with invalid access: src_ip4",
848c2ecf20Sopenharmony_ci		.insns = {
858c2ecf20Sopenharmony_ci			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
868c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
878c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_ip4)),
888c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
898c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
908c2ecf20Sopenharmony_ci		},
918c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
928c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
938c2ecf20Sopenharmony_ci		0,
948c2ecf20Sopenharmony_ci		0,
958c2ecf20Sopenharmony_ci		NULL,
968c2ecf20Sopenharmony_ci		0,
978c2ecf20Sopenharmony_ci		LOAD_REJECT,
988c2ecf20Sopenharmony_ci	},
998c2ecf20Sopenharmony_ci	{
1008c2ecf20Sopenharmony_ci		"sock_create load with invalid access: src_port",
1018c2ecf20Sopenharmony_ci		.insns = {
1028c2ecf20Sopenharmony_ci			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
1038c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
1048c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_port)),
1058c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1068c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1078c2ecf20Sopenharmony_ci		},
1088c2ecf20Sopenharmony_ci		BPF_CGROUP_INET_SOCK_CREATE,
1098c2ecf20Sopenharmony_ci		BPF_CGROUP_INET_SOCK_CREATE,
1108c2ecf20Sopenharmony_ci		0,
1118c2ecf20Sopenharmony_ci		0,
1128c2ecf20Sopenharmony_ci		NULL,
1138c2ecf20Sopenharmony_ci		0,
1148c2ecf20Sopenharmony_ci		LOAD_REJECT,
1158c2ecf20Sopenharmony_ci	},
1168c2ecf20Sopenharmony_ci	{
1178c2ecf20Sopenharmony_ci		"sock_create load w/o expected_attach_type (compat mode)",
1188c2ecf20Sopenharmony_ci		.insns = {
1198c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1208c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1218c2ecf20Sopenharmony_ci		},
1228c2ecf20Sopenharmony_ci		0,
1238c2ecf20Sopenharmony_ci		BPF_CGROUP_INET_SOCK_CREATE,
1248c2ecf20Sopenharmony_ci		AF_INET,
1258c2ecf20Sopenharmony_ci		SOCK_STREAM,
1268c2ecf20Sopenharmony_ci		"127.0.0.1",
1278c2ecf20Sopenharmony_ci		8097,
1288c2ecf20Sopenharmony_ci		SUCCESS,
1298c2ecf20Sopenharmony_ci	},
1308c2ecf20Sopenharmony_ci	{
1318c2ecf20Sopenharmony_ci		"sock_create load w/ expected_attach_type",
1328c2ecf20Sopenharmony_ci		.insns = {
1338c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1348c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1358c2ecf20Sopenharmony_ci		},
1368c2ecf20Sopenharmony_ci		BPF_CGROUP_INET_SOCK_CREATE,
1378c2ecf20Sopenharmony_ci		BPF_CGROUP_INET_SOCK_CREATE,
1388c2ecf20Sopenharmony_ci		AF_INET,
1398c2ecf20Sopenharmony_ci		SOCK_STREAM,
1408c2ecf20Sopenharmony_ci		"127.0.0.1",
1418c2ecf20Sopenharmony_ci		8097,
1428c2ecf20Sopenharmony_ci		SUCCESS,
1438c2ecf20Sopenharmony_ci	},
1448c2ecf20Sopenharmony_ci	{
1458c2ecf20Sopenharmony_ci		"attach type mismatch bind4 vs bind6",
1468c2ecf20Sopenharmony_ci		.insns = {
1478c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1488c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1498c2ecf20Sopenharmony_ci		},
1508c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
1518c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
1528c2ecf20Sopenharmony_ci		0,
1538c2ecf20Sopenharmony_ci		0,
1548c2ecf20Sopenharmony_ci		NULL,
1558c2ecf20Sopenharmony_ci		0,
1568c2ecf20Sopenharmony_ci		ATTACH_REJECT,
1578c2ecf20Sopenharmony_ci	},
1588c2ecf20Sopenharmony_ci	{
1598c2ecf20Sopenharmony_ci		"attach type mismatch bind6 vs bind4",
1608c2ecf20Sopenharmony_ci		.insns = {
1618c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1628c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1638c2ecf20Sopenharmony_ci		},
1648c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
1658c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
1668c2ecf20Sopenharmony_ci		0,
1678c2ecf20Sopenharmony_ci		0,
1688c2ecf20Sopenharmony_ci		NULL,
1698c2ecf20Sopenharmony_ci		0,
1708c2ecf20Sopenharmony_ci		ATTACH_REJECT,
1718c2ecf20Sopenharmony_ci	},
1728c2ecf20Sopenharmony_ci	{
1738c2ecf20Sopenharmony_ci		"attach type mismatch default vs bind4",
1748c2ecf20Sopenharmony_ci		.insns = {
1758c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1768c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1778c2ecf20Sopenharmony_ci		},
1788c2ecf20Sopenharmony_ci		0,
1798c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
1808c2ecf20Sopenharmony_ci		0,
1818c2ecf20Sopenharmony_ci		0,
1828c2ecf20Sopenharmony_ci		NULL,
1838c2ecf20Sopenharmony_ci		0,
1848c2ecf20Sopenharmony_ci		ATTACH_REJECT,
1858c2ecf20Sopenharmony_ci	},
1868c2ecf20Sopenharmony_ci	{
1878c2ecf20Sopenharmony_ci		"attach type mismatch bind6 vs sock_create",
1888c2ecf20Sopenharmony_ci		.insns = {
1898c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
1908c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
1918c2ecf20Sopenharmony_ci		},
1928c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
1938c2ecf20Sopenharmony_ci		BPF_CGROUP_INET_SOCK_CREATE,
1948c2ecf20Sopenharmony_ci		0,
1958c2ecf20Sopenharmony_ci		0,
1968c2ecf20Sopenharmony_ci		NULL,
1978c2ecf20Sopenharmony_ci		0,
1988c2ecf20Sopenharmony_ci		ATTACH_REJECT,
1998c2ecf20Sopenharmony_ci	},
2008c2ecf20Sopenharmony_ci	{
2018c2ecf20Sopenharmony_ci		"bind4 reject all",
2028c2ecf20Sopenharmony_ci		.insns = {
2038c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 0),
2048c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
2058c2ecf20Sopenharmony_ci		},
2068c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
2078c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
2088c2ecf20Sopenharmony_ci		AF_INET,
2098c2ecf20Sopenharmony_ci		SOCK_STREAM,
2108c2ecf20Sopenharmony_ci		"0.0.0.0",
2118c2ecf20Sopenharmony_ci		0,
2128c2ecf20Sopenharmony_ci		BIND_REJECT,
2138c2ecf20Sopenharmony_ci	},
2148c2ecf20Sopenharmony_ci	{
2158c2ecf20Sopenharmony_ci		"bind6 reject all",
2168c2ecf20Sopenharmony_ci		.insns = {
2178c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 0),
2188c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
2198c2ecf20Sopenharmony_ci		},
2208c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
2218c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
2228c2ecf20Sopenharmony_ci		AF_INET6,
2238c2ecf20Sopenharmony_ci		SOCK_STREAM,
2248c2ecf20Sopenharmony_ci		"::",
2258c2ecf20Sopenharmony_ci		0,
2268c2ecf20Sopenharmony_ci		BIND_REJECT,
2278c2ecf20Sopenharmony_ci	},
2288c2ecf20Sopenharmony_ci	{
2298c2ecf20Sopenharmony_ci		"bind6 deny specific IP & port",
2308c2ecf20Sopenharmony_ci		.insns = {
2318c2ecf20Sopenharmony_ci			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci			/* if (ip == expected && port == expected) */
2348c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
2358c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_ip6[3])),
2368c2ecf20Sopenharmony_ci			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
2378c2ecf20Sopenharmony_ci				    __bpf_constant_ntohl(0x00000001), 4),
2388c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
2398c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_port)),
2408c2ecf20Sopenharmony_ci			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci			/* return DENY; */
2438c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 0),
2448c2ecf20Sopenharmony_ci			BPF_JMP_A(1),
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci			/* else return ALLOW; */
2478c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
2488c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
2498c2ecf20Sopenharmony_ci		},
2508c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
2518c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
2528c2ecf20Sopenharmony_ci		AF_INET6,
2538c2ecf20Sopenharmony_ci		SOCK_STREAM,
2548c2ecf20Sopenharmony_ci		"::1",
2558c2ecf20Sopenharmony_ci		8193,
2568c2ecf20Sopenharmony_ci		BIND_REJECT,
2578c2ecf20Sopenharmony_ci	},
2588c2ecf20Sopenharmony_ci	{
2598c2ecf20Sopenharmony_ci		"bind4 allow specific IP & port",
2608c2ecf20Sopenharmony_ci		.insns = {
2618c2ecf20Sopenharmony_ci			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci			/* if (ip == expected && port == expected) */
2648c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
2658c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_ip4)),
2668c2ecf20Sopenharmony_ci			BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
2678c2ecf20Sopenharmony_ci				    __bpf_constant_ntohl(0x7F000001), 4),
2688c2ecf20Sopenharmony_ci			BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
2698c2ecf20Sopenharmony_ci				    offsetof(struct bpf_sock, src_port)),
2708c2ecf20Sopenharmony_ci			BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci			/* return ALLOW; */
2738c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
2748c2ecf20Sopenharmony_ci			BPF_JMP_A(1),
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci			/* else return DENY; */
2778c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 0),
2788c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
2798c2ecf20Sopenharmony_ci		},
2808c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
2818c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
2828c2ecf20Sopenharmony_ci		AF_INET,
2838c2ecf20Sopenharmony_ci		SOCK_STREAM,
2848c2ecf20Sopenharmony_ci		"127.0.0.1",
2858c2ecf20Sopenharmony_ci		4098,
2868c2ecf20Sopenharmony_ci		SUCCESS,
2878c2ecf20Sopenharmony_ci	},
2888c2ecf20Sopenharmony_ci	{
2898c2ecf20Sopenharmony_ci		"bind4 allow all",
2908c2ecf20Sopenharmony_ci		.insns = {
2918c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
2928c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
2938c2ecf20Sopenharmony_ci		},
2948c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
2958c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_POST_BIND,
2968c2ecf20Sopenharmony_ci		AF_INET,
2978c2ecf20Sopenharmony_ci		SOCK_STREAM,
2988c2ecf20Sopenharmony_ci		"0.0.0.0",
2998c2ecf20Sopenharmony_ci		0,
3008c2ecf20Sopenharmony_ci		SUCCESS,
3018c2ecf20Sopenharmony_ci	},
3028c2ecf20Sopenharmony_ci	{
3038c2ecf20Sopenharmony_ci		"bind6 allow all",
3048c2ecf20Sopenharmony_ci		.insns = {
3058c2ecf20Sopenharmony_ci			BPF_MOV64_IMM(BPF_REG_0, 1),
3068c2ecf20Sopenharmony_ci			BPF_EXIT_INSN(),
3078c2ecf20Sopenharmony_ci		},
3088c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
3098c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_POST_BIND,
3108c2ecf20Sopenharmony_ci		AF_INET6,
3118c2ecf20Sopenharmony_ci		SOCK_STREAM,
3128c2ecf20Sopenharmony_ci		"::",
3138c2ecf20Sopenharmony_ci		0,
3148c2ecf20Sopenharmony_ci		SUCCESS,
3158c2ecf20Sopenharmony_ci	},
3168c2ecf20Sopenharmony_ci};
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic size_t probe_prog_length(const struct bpf_insn *fp)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	size_t len;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	for (len = MAX_INSNS - 1; len > 0; --len)
3238c2ecf20Sopenharmony_ci		if (fp[len].code != 0 || fp[len].imm != 0)
3248c2ecf20Sopenharmony_ci			break;
3258c2ecf20Sopenharmony_ci	return len + 1;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int load_sock_prog(const struct bpf_insn *prog,
3298c2ecf20Sopenharmony_ci			  enum bpf_attach_type attach_type)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct bpf_load_program_attr attr;
3328c2ecf20Sopenharmony_ci	int ret;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	memset(&attr, 0, sizeof(struct bpf_load_program_attr));
3358c2ecf20Sopenharmony_ci	attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
3368c2ecf20Sopenharmony_ci	attr.expected_attach_type = attach_type;
3378c2ecf20Sopenharmony_ci	attr.insns = prog;
3388c2ecf20Sopenharmony_ci	attr.insns_cnt = probe_prog_length(attr.insns);
3398c2ecf20Sopenharmony_ci	attr.license = "GPL";
3408c2ecf20Sopenharmony_ci	attr.log_level = 2;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	ret = bpf_load_program_xattr(&attr, bpf_log_buf, BPF_LOG_BUF_SIZE);
3438c2ecf20Sopenharmony_ci	if (verbose && ret < 0)
3448c2ecf20Sopenharmony_ci		fprintf(stderr, "%s\n", bpf_log_buf);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return ret;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int attach_sock_prog(int cgfd, int progfd,
3508c2ecf20Sopenharmony_ci			    enum bpf_attach_type attach_type)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE);
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic int bind_sock(int domain, int type, const char *ip, unsigned short port)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct sockaddr_storage addr;
3588c2ecf20Sopenharmony_ci	struct sockaddr_in6 *addr6;
3598c2ecf20Sopenharmony_ci	struct sockaddr_in *addr4;
3608c2ecf20Sopenharmony_ci	int sockfd = -1;
3618c2ecf20Sopenharmony_ci	socklen_t len;
3628c2ecf20Sopenharmony_ci	int err = 0;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	sockfd = socket(domain, type, 0);
3658c2ecf20Sopenharmony_ci	if (sockfd < 0)
3668c2ecf20Sopenharmony_ci		goto err;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	memset(&addr, 0, sizeof(addr));
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (domain == AF_INET) {
3718c2ecf20Sopenharmony_ci		len = sizeof(struct sockaddr_in);
3728c2ecf20Sopenharmony_ci		addr4 = (struct sockaddr_in *)&addr;
3738c2ecf20Sopenharmony_ci		addr4->sin_family = domain;
3748c2ecf20Sopenharmony_ci		addr4->sin_port = htons(port);
3758c2ecf20Sopenharmony_ci		if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1)
3768c2ecf20Sopenharmony_ci			goto err;
3778c2ecf20Sopenharmony_ci	} else if (domain == AF_INET6) {
3788c2ecf20Sopenharmony_ci		len = sizeof(struct sockaddr_in6);
3798c2ecf20Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)&addr;
3808c2ecf20Sopenharmony_ci		addr6->sin6_family = domain;
3818c2ecf20Sopenharmony_ci		addr6->sin6_port = htons(port);
3828c2ecf20Sopenharmony_ci		if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1)
3838c2ecf20Sopenharmony_ci			goto err;
3848c2ecf20Sopenharmony_ci	} else {
3858c2ecf20Sopenharmony_ci		goto err;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1)
3898c2ecf20Sopenharmony_ci		goto err;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	goto out;
3928c2ecf20Sopenharmony_cierr:
3938c2ecf20Sopenharmony_ci	err = -1;
3948c2ecf20Sopenharmony_ciout:
3958c2ecf20Sopenharmony_ci	close(sockfd);
3968c2ecf20Sopenharmony_ci	return err;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int run_test_case(int cgfd, const struct sock_test *test)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	int progfd = -1;
4028c2ecf20Sopenharmony_ci	int err = 0;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	printf("Test case: %s .. ", test->descr);
4058c2ecf20Sopenharmony_ci	progfd = load_sock_prog(test->insns, test->expected_attach_type);
4068c2ecf20Sopenharmony_ci	if (progfd < 0) {
4078c2ecf20Sopenharmony_ci		if (test->result == LOAD_REJECT)
4088c2ecf20Sopenharmony_ci			goto out;
4098c2ecf20Sopenharmony_ci		else
4108c2ecf20Sopenharmony_ci			goto err;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (attach_sock_prog(cgfd, progfd, test->attach_type) == -1) {
4148c2ecf20Sopenharmony_ci		if (test->result == ATTACH_REJECT)
4158c2ecf20Sopenharmony_ci			goto out;
4168c2ecf20Sopenharmony_ci		else
4178c2ecf20Sopenharmony_ci			goto err;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (bind_sock(test->domain, test->type, test->ip, test->port) == -1) {
4218c2ecf20Sopenharmony_ci		/* sys_bind() may fail for different reasons, errno has to be
4228c2ecf20Sopenharmony_ci		 * checked to confirm that BPF program rejected it.
4238c2ecf20Sopenharmony_ci		 */
4248c2ecf20Sopenharmony_ci		if (test->result == BIND_REJECT && errno == EPERM)
4258c2ecf20Sopenharmony_ci			goto out;
4268c2ecf20Sopenharmony_ci		else
4278c2ecf20Sopenharmony_ci			goto err;
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if (test->result != SUCCESS)
4328c2ecf20Sopenharmony_ci		goto err;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	goto out;
4358c2ecf20Sopenharmony_cierr:
4368c2ecf20Sopenharmony_ci	err = -1;
4378c2ecf20Sopenharmony_ciout:
4388c2ecf20Sopenharmony_ci	/* Detaching w/o checking return code: best effort attempt. */
4398c2ecf20Sopenharmony_ci	if (progfd != -1)
4408c2ecf20Sopenharmony_ci		bpf_prog_detach(cgfd, test->attach_type);
4418c2ecf20Sopenharmony_ci	close(progfd);
4428c2ecf20Sopenharmony_ci	printf("[%s]\n", err ? "FAIL" : "PASS");
4438c2ecf20Sopenharmony_ci	return err;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic int run_tests(int cgfd)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	int passes = 0;
4498c2ecf20Sopenharmony_ci	int fails = 0;
4508c2ecf20Sopenharmony_ci	int i;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
4538c2ecf20Sopenharmony_ci		if (run_test_case(cgfd, &tests[i]))
4548c2ecf20Sopenharmony_ci			++fails;
4558c2ecf20Sopenharmony_ci		else
4568c2ecf20Sopenharmony_ci			++passes;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci	printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
4598c2ecf20Sopenharmony_ci	return fails ? -1 : 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ciint main(int argc, char **argv)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	int cgfd = -1;
4658c2ecf20Sopenharmony_ci	int err = 0;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	cgfd = cgroup_setup_and_join(CG_PATH);
4688c2ecf20Sopenharmony_ci	if (cgfd < 0)
4698c2ecf20Sopenharmony_ci		goto err;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (run_tests(cgfd))
4728c2ecf20Sopenharmony_ci		goto err;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	goto out;
4758c2ecf20Sopenharmony_cierr:
4768c2ecf20Sopenharmony_ci	err = -1;
4778c2ecf20Sopenharmony_ciout:
4788c2ecf20Sopenharmony_ci	close(cgfd);
4798c2ecf20Sopenharmony_ci	cleanup_cgroup_environment();
4808c2ecf20Sopenharmony_ci	return err;
4818c2ecf20Sopenharmony_ci}
482