diff options
Diffstat (limited to 'tools/testing/selftests/bpf/prog_tests/sockopt.c')
| -rw-r--r-- | tools/testing/selftests/bpf/prog_tests/sockopt.c | 100 | 
1 files changed, 93 insertions, 7 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c index aa4debf62fc6..9e6a5e3ed4de 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c @@ -5,10 +5,15 @@  static char bpf_log_buf[4096];  static bool verbose; +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +  enum sockopt_test_error {  	OK = 0,  	DENY_LOAD,  	DENY_ATTACH, +	EOPNOTSUPP_GETSOCKOPT,  	EPERM_GETSOCKOPT,  	EFAULT_GETSOCKOPT,  	EPERM_SETSOCKOPT, @@ -273,10 +278,31 @@ static struct sockopt_test {  		.error = EFAULT_GETSOCKOPT,  	},  	{ -		.descr = "getsockopt: deny arbitrary ctx->retval", +		.descr = "getsockopt: ignore >PAGE_SIZE optlen",  		.insns = { -			/* ctx->retval = 123 */ -			BPF_MOV64_IMM(BPF_REG_0, 123), +			/* write 0xFF to the first optval byte */ + +			/* r6 = ctx->optval */ +			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, +				    offsetof(struct bpf_sockopt, optval)), +			/* r2 = ctx->optval */ +			BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), +			/* r6 = ctx->optval + 1 */ +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + +			/* r7 = ctx->optval_end */ +			BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, +				    offsetof(struct bpf_sockopt, optval_end)), + +			/* if (ctx->optval + 1 <= ctx->optval_end) { */ +			BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), +			/* ctx->optval[0] = 0xF0 */ +			BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xFF), +			/* } */ + +			/* retval changes are ignored */ +			/* ctx->retval = 5 */ +			BPF_MOV64_IMM(BPF_REG_0, 5),  			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,  				    offsetof(struct bpf_sockopt, retval)), @@ -287,9 +313,11 @@ static struct sockopt_test {  		.attach_type = BPF_CGROUP_GETSOCKOPT,  		.expected_attach_type = BPF_CGROUP_GETSOCKOPT, -		.get_optlen = 64, - -		.error = EFAULT_GETSOCKOPT, +		.get_level = 1234, +		.get_optname = 5678, +		.get_optval = {}, /* the changes are ignored */ +		.get_optlen = PAGE_SIZE + 1, +		.error = EOPNOTSUPP_GETSOCKOPT,  	},  	{  		.descr = "getsockopt: support smaller ctx->optlen", @@ -649,6 +677,45 @@ static struct sockopt_test {  		.error = EFAULT_SETSOCKOPT,  	},  	{ +		.descr = "setsockopt: ignore >PAGE_SIZE optlen", +		.insns = { +			/* write 0xFF to the first optval byte */ + +			/* r6 = ctx->optval */ +			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, +				    offsetof(struct bpf_sockopt, optval)), +			/* r2 = ctx->optval */ +			BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), +			/* r6 = ctx->optval + 1 */ +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + +			/* r7 = ctx->optval_end */ +			BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, +				    offsetof(struct bpf_sockopt, optval_end)), + +			/* if (ctx->optval + 1 <= ctx->optval_end) { */ +			BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), +			/* ctx->optval[0] = 0xF0 */ +			BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0), +			/* } */ + +			BPF_MOV64_IMM(BPF_REG_0, 1), +			BPF_EXIT_INSN(), +		}, +		.attach_type = BPF_CGROUP_SETSOCKOPT, +		.expected_attach_type = BPF_CGROUP_SETSOCKOPT, + +		.set_level = SOL_IP, +		.set_optname = IP_TOS, +		.set_optval = {}, +		.set_optlen = PAGE_SIZE + 1, + +		.get_level = SOL_IP, +		.get_optname = IP_TOS, +		.get_optval = {}, /* the changes are ignored */ +		.get_optlen = 4, +	}, +	{  		.descr = "setsockopt: allow changing ctx->optlen within bounds",  		.insns = {  			/* r6 = ctx->optval */ @@ -906,6 +973,13 @@ static int run_test(int cgroup_fd, struct sockopt_test *test)  	}  	if (test->set_optlen) { +		if (test->set_optlen >= PAGE_SIZE) { +			int num_pages = test->set_optlen / PAGE_SIZE; +			int remainder = test->set_optlen % PAGE_SIZE; + +			test->set_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder; +		} +  		err = setsockopt(sock_fd, test->set_level, test->set_optname,  				 test->set_optval, test->set_optlen);  		if (err) { @@ -921,7 +995,15 @@ static int run_test(int cgroup_fd, struct sockopt_test *test)  	}  	if (test->get_optlen) { +		if (test->get_optlen >= PAGE_SIZE) { +			int num_pages = test->get_optlen / PAGE_SIZE; +			int remainder = test->get_optlen % PAGE_SIZE; + +			test->get_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder; +		} +  		optval = malloc(test->get_optlen); +		memset(optval, 0, test->get_optlen);  		socklen_t optlen = test->get_optlen;  		socklen_t expected_get_optlen = test->get_optlen_ret ?:  			test->get_optlen; @@ -929,6 +1011,8 @@ static int run_test(int cgroup_fd, struct sockopt_test *test)  		err = getsockopt(sock_fd, test->get_level, test->get_optname,  				 optval, &optlen);  		if (err) { +			if (errno == EOPNOTSUPP && test->error == EOPNOTSUPP_GETSOCKOPT) +				goto free_optval;  			if (errno == EPERM && test->error == EPERM_GETSOCKOPT)  				goto free_optval;  			if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT) @@ -976,7 +1060,9 @@ void test_sockopt(void)  		return;  	for (i = 0; i < ARRAY_SIZE(tests); i++) { -		test__start_subtest(tests[i].descr); +		if (!test__start_subtest(tests[i].descr)) +			continue; +  		ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);  	}  |