brintos

brintos / linux-shallow public Read only

0
0
Text · 28.9 KiB · eaac83a Raw
1221 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <test_progs.h>3#include <io_uring/mini_liburing.h>4#include "cgroup_helpers.h"5 6static char bpf_log_buf[4096];7static bool verbose;8 9#ifndef PAGE_SIZE10#define PAGE_SIZE 409611#endif12 13enum sockopt_test_error {14	OK = 0,15	DENY_LOAD,16	DENY_ATTACH,17	EOPNOTSUPP_GETSOCKOPT,18	EPERM_GETSOCKOPT,19	EFAULT_GETSOCKOPT,20	EPERM_SETSOCKOPT,21	EFAULT_SETSOCKOPT,22};23 24static struct sockopt_test {25	const char			*descr;26	const struct bpf_insn		insns[64];27	enum bpf_prog_type		prog_type;28	enum bpf_attach_type		attach_type;29	enum bpf_attach_type		expected_attach_type;30 31	int				set_optname;32	int				set_level;33	const char			set_optval[64];34	socklen_t			set_optlen;35 36	int				get_optname;37	int				get_level;38	const char			get_optval[64];39	socklen_t			get_optlen;40	socklen_t			get_optlen_ret;41 42	enum sockopt_test_error		error;43	bool				io_uring_support;44} tests[] = {45 46	/* ==================== getsockopt ====================  */47 48	{49		.descr = "getsockopt: no expected_attach_type",50		.insns = {51			/* return 1 */52			BPF_MOV64_IMM(BPF_REG_0, 1),53			BPF_EXIT_INSN(),54 55		},56		.attach_type = BPF_CGROUP_GETSOCKOPT,57		.expected_attach_type = 0,58		.error = DENY_LOAD,59	},60	{61		.descr = "getsockopt: wrong expected_attach_type",62		.insns = {63			/* return 1 */64			BPF_MOV64_IMM(BPF_REG_0, 1),65			BPF_EXIT_INSN(),66 67		},68		.attach_type = BPF_CGROUP_GETSOCKOPT,69		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,70		.error = DENY_ATTACH,71	},72	{73		.descr = "getsockopt: bypass bpf hook",74		.insns = {75			/* return 1 */76			BPF_MOV64_IMM(BPF_REG_0, 1),77			BPF_EXIT_INSN(),78		},79		.attach_type = BPF_CGROUP_GETSOCKOPT,80		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,81 82		.get_level = SOL_IP,83		.set_level = SOL_IP,84 85		.get_optname = IP_TOS,86		.set_optname = IP_TOS,87 88		.set_optval = { 1 << 3 },89		.set_optlen = 1,90 91		.get_optval = { 1 << 3 },92		.get_optlen = 1,93	},94	{95		.descr = "getsockopt: return EPERM from bpf hook",96		.insns = {97			BPF_MOV64_IMM(BPF_REG_0, 0),98			BPF_EXIT_INSN(),99		},100		.attach_type = BPF_CGROUP_GETSOCKOPT,101		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,102 103		.get_level = SOL_IP,104		.get_optname = IP_TOS,105 106		.get_optlen = 1,107		.error = EPERM_GETSOCKOPT,108	},109	{110		.descr = "getsockopt: no optval bounds check, deny loading",111		.insns = {112			/* r6 = ctx->optval */113			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,114				    offsetof(struct bpf_sockopt, optval)),115 116			/* ctx->optval[0] = 0x80 */117			BPF_MOV64_IMM(BPF_REG_0, 0x80),118			BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0),119 120			/* return 1 */121			BPF_MOV64_IMM(BPF_REG_0, 1),122			BPF_EXIT_INSN(),123		},124		.attach_type = BPF_CGROUP_GETSOCKOPT,125		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,126		.error = DENY_LOAD,127	},128	{129		.descr = "getsockopt: read ctx->level",130		.insns = {131			/* r6 = ctx->level */132			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,133				    offsetof(struct bpf_sockopt, level)),134 135			/* if (ctx->level == 123) { */136			BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),137			/* ctx->retval = 0 */138			BPF_MOV64_IMM(BPF_REG_0, 0),139			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,140				    offsetof(struct bpf_sockopt, retval)),141			/* return 1 */142			BPF_MOV64_IMM(BPF_REG_0, 1),143			BPF_JMP_A(1),144			/* } else { */145			/* return 0 */146			BPF_MOV64_IMM(BPF_REG_0, 0),147			/* } */148			BPF_EXIT_INSN(),149		},150		.attach_type = BPF_CGROUP_GETSOCKOPT,151		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,152 153		.get_level = 123,154 155		.get_optlen = 1,156	},157	{158		.descr = "getsockopt: deny writing to ctx->level",159		.insns = {160			/* ctx->level = 1 */161			BPF_MOV64_IMM(BPF_REG_0, 1),162			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,163				    offsetof(struct bpf_sockopt, level)),164			BPF_EXIT_INSN(),165		},166		.attach_type = BPF_CGROUP_GETSOCKOPT,167		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,168 169		.error = DENY_LOAD,170	},171	{172		.descr = "getsockopt: read ctx->optname",173		.insns = {174			/* r6 = ctx->optname */175			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,176				    offsetof(struct bpf_sockopt, optname)),177 178			/* if (ctx->optname == 123) { */179			BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),180			/* ctx->retval = 0 */181			BPF_MOV64_IMM(BPF_REG_0, 0),182			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,183				    offsetof(struct bpf_sockopt, retval)),184			/* return 1 */185			BPF_MOV64_IMM(BPF_REG_0, 1),186			BPF_JMP_A(1),187			/* } else { */188			/* return 0 */189			BPF_MOV64_IMM(BPF_REG_0, 0),190			/* } */191			BPF_EXIT_INSN(),192		},193		.attach_type = BPF_CGROUP_GETSOCKOPT,194		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,195 196		.get_optname = 123,197 198		.get_optlen = 1,199	},200	{201		.descr = "getsockopt: read ctx->retval",202		.insns = {203			/* r6 = ctx->retval */204			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,205				    offsetof(struct bpf_sockopt, retval)),206 207			/* return 1 */208			BPF_MOV64_IMM(BPF_REG_0, 1),209			BPF_EXIT_INSN(),210		},211		.attach_type = BPF_CGROUP_GETSOCKOPT,212		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,213 214		.get_level = SOL_IP,215		.get_optname = IP_TOS,216		.get_optlen = 1,217	},218	{219		.descr = "getsockopt: deny writing to ctx->optname",220		.insns = {221			/* ctx->optname = 1 */222			BPF_MOV64_IMM(BPF_REG_0, 1),223			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,224				    offsetof(struct bpf_sockopt, optname)),225			BPF_EXIT_INSN(),226		},227		.attach_type = BPF_CGROUP_GETSOCKOPT,228		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,229 230		.error = DENY_LOAD,231	},232	{233		.descr = "getsockopt: read ctx->optlen",234		.insns = {235			/* r6 = ctx->optlen */236			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,237				    offsetof(struct bpf_sockopt, optlen)),238 239			/* if (ctx->optlen == 64) { */240			BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),241			/* ctx->retval = 0 */242			BPF_MOV64_IMM(BPF_REG_0, 0),243			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,244				    offsetof(struct bpf_sockopt, retval)),245			/* return 1 */246			BPF_MOV64_IMM(BPF_REG_0, 1),247			BPF_JMP_A(1),248			/* } else { */249			/* return 0 */250			BPF_MOV64_IMM(BPF_REG_0, 0),251			/* } */252			BPF_EXIT_INSN(),253		},254		.attach_type = BPF_CGROUP_GETSOCKOPT,255		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,256 257		.get_level = SOL_SOCKET,258		.get_optlen = 64,259		.io_uring_support = true,260	},261	{262		.descr = "getsockopt: deny bigger ctx->optlen",263		.insns = {264			/* ctx->optlen = 65 */265			BPF_MOV64_IMM(BPF_REG_0, 65),266			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,267				    offsetof(struct bpf_sockopt, optlen)),268 269			/* ctx->retval = 0 */270			BPF_MOV64_IMM(BPF_REG_0, 0),271			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,272				    offsetof(struct bpf_sockopt, retval)),273 274			/* return 1 */275			BPF_MOV64_IMM(BPF_REG_0, 1),276			BPF_EXIT_INSN(),277		},278		.attach_type = BPF_CGROUP_GETSOCKOPT,279		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,280 281		.get_optlen = 64,282 283		.error = EFAULT_GETSOCKOPT,284		.io_uring_support = true,285	},286	{287		.descr = "getsockopt: ignore >PAGE_SIZE optlen",288		.insns = {289			/* write 0xFF to the first optval byte */290 291			/* r6 = ctx->optval */292			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,293				    offsetof(struct bpf_sockopt, optval)),294			/* r2 = ctx->optval */295			BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),296			/* r6 = ctx->optval + 1 */297			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),298 299			/* r7 = ctx->optval_end */300			BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,301				    offsetof(struct bpf_sockopt, optval_end)),302 303			/* if (ctx->optval + 1 <= ctx->optval_end) { */304			BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),305			/* ctx->optval[0] = 0xF0 */306			BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xFF),307			/* } */308 309			/* retval changes are ignored */310			/* ctx->retval = 5 */311			BPF_MOV64_IMM(BPF_REG_0, 5),312			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,313				    offsetof(struct bpf_sockopt, retval)),314 315			/* return 1 */316			BPF_MOV64_IMM(BPF_REG_0, 1),317			BPF_EXIT_INSN(),318		},319		.attach_type = BPF_CGROUP_GETSOCKOPT,320		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,321 322		.get_level = 1234,323		.get_optname = 5678,324		.get_optval = {}, /* the changes are ignored */325		.get_optlen = PAGE_SIZE + 1,326		.error = EOPNOTSUPP_GETSOCKOPT,327		.io_uring_support = true,328	},329	{330		.descr = "getsockopt: support smaller ctx->optlen",331		.insns = {332			/* ctx->optlen = 32 */333			BPF_MOV64_IMM(BPF_REG_0, 32),334			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,335				    offsetof(struct bpf_sockopt, optlen)),336			/* ctx->retval = 0 */337			BPF_MOV64_IMM(BPF_REG_0, 0),338			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,339				    offsetof(struct bpf_sockopt, retval)),340			/* return 1 */341			BPF_MOV64_IMM(BPF_REG_0, 1),342			BPF_EXIT_INSN(),343		},344		.attach_type = BPF_CGROUP_GETSOCKOPT,345		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,346 347		.get_level = SOL_SOCKET,348		.get_optlen = 64,349		.get_optlen_ret = 32,350		.io_uring_support = true,351	},352	{353		.descr = "getsockopt: deny writing to ctx->optval",354		.insns = {355			/* ctx->optval = 1 */356			BPF_MOV64_IMM(BPF_REG_0, 1),357			BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,358				    offsetof(struct bpf_sockopt, optval)),359			BPF_EXIT_INSN(),360		},361		.attach_type = BPF_CGROUP_GETSOCKOPT,362		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,363 364		.error = DENY_LOAD,365	},366	{367		.descr = "getsockopt: deny writing to ctx->optval_end",368		.insns = {369			/* ctx->optval_end = 1 */370			BPF_MOV64_IMM(BPF_REG_0, 1),371			BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,372				    offsetof(struct bpf_sockopt, optval_end)),373			BPF_EXIT_INSN(),374		},375		.attach_type = BPF_CGROUP_GETSOCKOPT,376		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,377 378		.error = DENY_LOAD,379	},380	{381		.descr = "getsockopt: rewrite value",382		.insns = {383			/* r6 = ctx->optval */384			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,385				    offsetof(struct bpf_sockopt, optval)),386			/* r2 = ctx->optval */387			BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),388			/* r6 = ctx->optval + 1 */389			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),390 391			/* r7 = ctx->optval_end */392			BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,393				    offsetof(struct bpf_sockopt, optval_end)),394 395			/* if (ctx->optval + 1 <= ctx->optval_end) { */396			BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),397			/* ctx->optval[0] = 0xF0 */398			BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),399			/* } */400 401			/* ctx->retval = 0 */402			BPF_MOV64_IMM(BPF_REG_0, 0),403			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,404				    offsetof(struct bpf_sockopt, retval)),405 406			/* return 1*/407			BPF_MOV64_IMM(BPF_REG_0, 1),408			BPF_EXIT_INSN(),409		},410		.attach_type = BPF_CGROUP_GETSOCKOPT,411		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,412 413		.get_level = SOL_IP,414		.get_optname = IP_TOS,415 416		.get_optval = { 0xF0 },417		.get_optlen = 1,418	},419 420	/* ==================== setsockopt ====================  */421 422	{423		.descr = "setsockopt: no expected_attach_type",424		.insns = {425			/* return 1 */426			BPF_MOV64_IMM(BPF_REG_0, 1),427			BPF_EXIT_INSN(),428 429		},430		.attach_type = BPF_CGROUP_SETSOCKOPT,431		.expected_attach_type = 0,432		.error = DENY_LOAD,433	},434	{435		.descr = "setsockopt: wrong expected_attach_type",436		.insns = {437			/* return 1 */438			BPF_MOV64_IMM(BPF_REG_0, 1),439			BPF_EXIT_INSN(),440 441		},442		.attach_type = BPF_CGROUP_SETSOCKOPT,443		.expected_attach_type = BPF_CGROUP_GETSOCKOPT,444		.error = DENY_ATTACH,445	},446	{447		.descr = "setsockopt: bypass bpf hook",448		.insns = {449			/* return 1 */450			BPF_MOV64_IMM(BPF_REG_0, 1),451			BPF_EXIT_INSN(),452		},453		.attach_type = BPF_CGROUP_SETSOCKOPT,454		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,455 456		.get_level = SOL_IP,457		.set_level = SOL_IP,458 459		.get_optname = IP_TOS,460		.set_optname = IP_TOS,461 462		.set_optval = { 1 << 3 },463		.set_optlen = 1,464 465		.get_optval = { 1 << 3 },466		.get_optlen = 1,467	},468	{469		.descr = "setsockopt: return EPERM from bpf hook",470		.insns = {471			/* return 0 */472			BPF_MOV64_IMM(BPF_REG_0, 0),473			BPF_EXIT_INSN(),474		},475		.attach_type = BPF_CGROUP_SETSOCKOPT,476		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,477 478		.set_level = SOL_IP,479		.set_optname = IP_TOS,480 481		.set_optlen = 1,482		.error = EPERM_SETSOCKOPT,483	},484	{485		.descr = "setsockopt: no optval bounds check, deny loading",486		.insns = {487			/* r6 = ctx->optval */488			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,489				    offsetof(struct bpf_sockopt, optval)),490 491			/* r0 = ctx->optval[0] */492			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0),493 494			/* return 1 */495			BPF_MOV64_IMM(BPF_REG_0, 1),496			BPF_EXIT_INSN(),497		},498		.attach_type = BPF_CGROUP_SETSOCKOPT,499		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,500		.error = DENY_LOAD,501	},502	{503		.descr = "setsockopt: read ctx->level",504		.insns = {505			/* r6 = ctx->level */506			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,507				    offsetof(struct bpf_sockopt, level)),508 509			/* if (ctx->level == 123) { */510			BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),511			/* ctx->optlen = -1 */512			BPF_MOV64_IMM(BPF_REG_0, -1),513			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,514				    offsetof(struct bpf_sockopt, optlen)),515			/* return 1 */516			BPF_MOV64_IMM(BPF_REG_0, 1),517			BPF_JMP_A(1),518			/* } else { */519			/* return 0 */520			BPF_MOV64_IMM(BPF_REG_0, 0),521			/* } */522			BPF_EXIT_INSN(),523		},524		.attach_type = BPF_CGROUP_SETSOCKOPT,525		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,526 527		.set_level = 123,528 529		.set_optlen = 1,530		.io_uring_support = true,531	},532	{533		.descr = "setsockopt: allow changing ctx->level",534		.insns = {535			/* ctx->level = SOL_IP */536			BPF_MOV64_IMM(BPF_REG_0, SOL_IP),537			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,538				    offsetof(struct bpf_sockopt, level)),539			/* return 1 */540			BPF_MOV64_IMM(BPF_REG_0, 1),541			BPF_EXIT_INSN(),542		},543		.attach_type = BPF_CGROUP_SETSOCKOPT,544		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,545 546		.get_level = SOL_IP,547		.set_level = 234, /* should be rewritten to SOL_IP */548 549		.get_optname = IP_TOS,550		.set_optname = IP_TOS,551 552		.set_optval = { 1 << 3 },553		.set_optlen = 1,554		.get_optval = { 1 << 3 },555		.get_optlen = 1,556	},557	{558		.descr = "setsockopt: read ctx->optname",559		.insns = {560			/* r6 = ctx->optname */561			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,562				    offsetof(struct bpf_sockopt, optname)),563 564			/* if (ctx->optname == 123) { */565			BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),566			/* ctx->optlen = -1 */567			BPF_MOV64_IMM(BPF_REG_0, -1),568			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,569				    offsetof(struct bpf_sockopt, optlen)),570			/* return 1 */571			BPF_MOV64_IMM(BPF_REG_0, 1),572			BPF_JMP_A(1),573			/* } else { */574			/* return 0 */575			BPF_MOV64_IMM(BPF_REG_0, 0),576			/* } */577			BPF_EXIT_INSN(),578		},579		.attach_type = BPF_CGROUP_SETSOCKOPT,580		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,581 582		.set_optname = 123,583 584		.set_optlen = 1,585		.io_uring_support = true,586	},587	{588		.descr = "setsockopt: allow changing ctx->optname",589		.insns = {590			/* ctx->optname = IP_TOS */591			BPF_MOV64_IMM(BPF_REG_0, IP_TOS),592			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,593				    offsetof(struct bpf_sockopt, optname)),594			/* return 1 */595			BPF_MOV64_IMM(BPF_REG_0, 1),596			BPF_EXIT_INSN(),597		},598		.attach_type = BPF_CGROUP_SETSOCKOPT,599		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,600 601		.get_level = SOL_IP,602		.set_level = SOL_IP,603 604		.get_optname = IP_TOS,605		.set_optname = 456, /* should be rewritten to IP_TOS */606 607		.set_optval = { 1 << 3 },608		.set_optlen = 1,609		.get_optval = { 1 << 3 },610		.get_optlen = 1,611	},612	{613		.descr = "setsockopt: read ctx->optlen",614		.insns = {615			/* r6 = ctx->optlen */616			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,617				    offsetof(struct bpf_sockopt, optlen)),618 619			/* if (ctx->optlen == 64) { */620			BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),621			/* ctx->optlen = -1 */622			BPF_MOV64_IMM(BPF_REG_0, -1),623			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,624				    offsetof(struct bpf_sockopt, optlen)),625			/* return 1 */626			BPF_MOV64_IMM(BPF_REG_0, 1),627			BPF_JMP_A(1),628			/* } else { */629			/* return 0 */630			BPF_MOV64_IMM(BPF_REG_0, 0),631			/* } */632			BPF_EXIT_INSN(),633		},634		.attach_type = BPF_CGROUP_SETSOCKOPT,635		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,636 637		.set_optlen = 64,638		.io_uring_support = true,639	},640	{641		.descr = "setsockopt: ctx->optlen == -1 is ok",642		.insns = {643			/* ctx->optlen = -1 */644			BPF_MOV64_IMM(BPF_REG_0, -1),645			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,646				    offsetof(struct bpf_sockopt, optlen)),647			/* return 1 */648			BPF_MOV64_IMM(BPF_REG_0, 1),649			BPF_EXIT_INSN(),650		},651		.attach_type = BPF_CGROUP_SETSOCKOPT,652		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,653 654		.set_optlen = 64,655		.io_uring_support = true,656	},657	{658		.descr = "setsockopt: deny ctx->optlen < 0 (except -1)",659		.insns = {660			/* ctx->optlen = -2 */661			BPF_MOV64_IMM(BPF_REG_0, -2),662			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,663				    offsetof(struct bpf_sockopt, optlen)),664			/* return 1 */665			BPF_MOV64_IMM(BPF_REG_0, 1),666			BPF_EXIT_INSN(),667		},668		.attach_type = BPF_CGROUP_SETSOCKOPT,669		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,670 671		.set_optlen = 4,672 673		.error = EFAULT_SETSOCKOPT,674		.io_uring_support = true,675	},676	{677		.descr = "setsockopt: deny ctx->optlen > input optlen",678		.insns = {679			/* ctx->optlen = 65 */680			BPF_MOV64_IMM(BPF_REG_0, 65),681			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,682				    offsetof(struct bpf_sockopt, optlen)),683			BPF_MOV64_IMM(BPF_REG_0, 1),684			BPF_EXIT_INSN(),685		},686		.attach_type = BPF_CGROUP_SETSOCKOPT,687		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,688 689		.set_optlen = 64,690 691		.error = EFAULT_SETSOCKOPT,692		.io_uring_support = true,693	},694	{695		.descr = "setsockopt: ignore >PAGE_SIZE optlen",696		.insns = {697			/* write 0xFF to the first optval byte */698 699			/* r6 = ctx->optval */700			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,701				    offsetof(struct bpf_sockopt, optval)),702			/* r2 = ctx->optval */703			BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),704			/* r6 = ctx->optval + 1 */705			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),706 707			/* r7 = ctx->optval_end */708			BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,709				    offsetof(struct bpf_sockopt, optval_end)),710 711			/* if (ctx->optval + 1 <= ctx->optval_end) { */712			BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),713			/* ctx->optval[0] = 0xF0 */714			BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),715			/* } */716 717			BPF_MOV64_IMM(BPF_REG_0, 1),718			BPF_EXIT_INSN(),719		},720		.attach_type = BPF_CGROUP_SETSOCKOPT,721		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,722 723		.set_level = SOL_IP,724		.set_optname = IP_TOS,725		.set_optval = {},726		.set_optlen = PAGE_SIZE + 1,727 728		.get_level = SOL_IP,729		.get_optname = IP_TOS,730		.get_optval = {}, /* the changes are ignored */731		.get_optlen = 4,732	},733	{734		.descr = "setsockopt: allow changing ctx->optlen within bounds",735		.insns = {736			/* r6 = ctx->optval */737			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,738				    offsetof(struct bpf_sockopt, optval)),739			/* r2 = ctx->optval */740			BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),741			/* r6 = ctx->optval + 1 */742			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),743 744			/* r7 = ctx->optval_end */745			BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,746				    offsetof(struct bpf_sockopt, optval_end)),747 748			/* if (ctx->optval + 1 <= ctx->optval_end) { */749			BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),750			/* ctx->optval[0] = 1 << 3 */751			BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3),752			/* } */753 754			/* ctx->optlen = 1 */755			BPF_MOV64_IMM(BPF_REG_0, 1),756			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,757				    offsetof(struct bpf_sockopt, optlen)),758 759			/* return 1*/760			BPF_MOV64_IMM(BPF_REG_0, 1),761			BPF_EXIT_INSN(),762		},763		.attach_type = BPF_CGROUP_SETSOCKOPT,764		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,765 766		.get_level = SOL_IP,767		.set_level = SOL_IP,768 769		.get_optname = IP_TOS,770		.set_optname = IP_TOS,771 772		.set_optval = { 1, 1, 1, 1 },773		.set_optlen = 4,774		.get_optval = { 1 << 3 },775		.get_optlen = 1,776	},777	{778		.descr = "setsockopt: deny write ctx->retval",779		.insns = {780			/* ctx->retval = 0 */781			BPF_MOV64_IMM(BPF_REG_0, 0),782			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,783				    offsetof(struct bpf_sockopt, retval)),784 785			/* return 1 */786			BPF_MOV64_IMM(BPF_REG_0, 1),787			BPF_EXIT_INSN(),788		},789		.attach_type = BPF_CGROUP_SETSOCKOPT,790		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,791 792		.error = DENY_LOAD,793	},794	{795		.descr = "setsockopt: deny read ctx->retval",796		.insns = {797			/* r6 = ctx->retval */798			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,799				    offsetof(struct bpf_sockopt, retval)),800 801			/* return 1 */802			BPF_MOV64_IMM(BPF_REG_0, 1),803			BPF_EXIT_INSN(),804		},805		.attach_type = BPF_CGROUP_SETSOCKOPT,806		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,807 808		.error = DENY_LOAD,809	},810	{811		.descr = "setsockopt: deny writing to ctx->optval",812		.insns = {813			/* ctx->optval = 1 */814			BPF_MOV64_IMM(BPF_REG_0, 1),815			BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,816				    offsetof(struct bpf_sockopt, optval)),817			BPF_EXIT_INSN(),818		},819		.attach_type = BPF_CGROUP_SETSOCKOPT,820		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,821 822		.error = DENY_LOAD,823	},824	{825		.descr = "setsockopt: deny writing to ctx->optval_end",826		.insns = {827			/* ctx->optval_end = 1 */828			BPF_MOV64_IMM(BPF_REG_0, 1),829			BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,830				    offsetof(struct bpf_sockopt, optval_end)),831			BPF_EXIT_INSN(),832		},833		.attach_type = BPF_CGROUP_SETSOCKOPT,834		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,835 836		.error = DENY_LOAD,837	},838	{839		.descr = "setsockopt: allow IP_TOS <= 128",840		.insns = {841			/* r6 = ctx->optval */842			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,843				    offsetof(struct bpf_sockopt, optval)),844			/* r7 = ctx->optval + 1 */845			BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),846			BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),847 848			/* r8 = ctx->optval_end */849			BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,850				    offsetof(struct bpf_sockopt, optval_end)),851 852			/* if (ctx->optval + 1 <= ctx->optval_end) { */853			BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),854 855			/* r9 = ctx->optval[0] */856			BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),857 858			/* if (ctx->optval[0] < 128) */859			BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),860			BPF_MOV64_IMM(BPF_REG_0, 1),861			BPF_JMP_A(1),862			/* } */863 864			/* } else { */865			BPF_MOV64_IMM(BPF_REG_0, 0),866			/* } */867 868			BPF_EXIT_INSN(),869		},870		.attach_type = BPF_CGROUP_SETSOCKOPT,871		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,872 873		.get_level = SOL_IP,874		.set_level = SOL_IP,875 876		.get_optname = IP_TOS,877		.set_optname = IP_TOS,878 879		.set_optval = { 0x80 },880		.set_optlen = 1,881		.get_optval = { 0x80 },882		.get_optlen = 1,883	},884	{885		.descr = "setsockopt: deny IP_TOS > 128",886		.insns = {887			/* r6 = ctx->optval */888			BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,889				    offsetof(struct bpf_sockopt, optval)),890			/* r7 = ctx->optval + 1 */891			BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),892			BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),893 894			/* r8 = ctx->optval_end */895			BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,896				    offsetof(struct bpf_sockopt, optval_end)),897 898			/* if (ctx->optval + 1 <= ctx->optval_end) { */899			BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),900 901			/* r9 = ctx->optval[0] */902			BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),903 904			/* if (ctx->optval[0] < 128) */905			BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),906			BPF_MOV64_IMM(BPF_REG_0, 1),907			BPF_JMP_A(1),908			/* } */909 910			/* } else { */911			BPF_MOV64_IMM(BPF_REG_0, 0),912			/* } */913 914			BPF_EXIT_INSN(),915		},916		.attach_type = BPF_CGROUP_SETSOCKOPT,917		.expected_attach_type = BPF_CGROUP_SETSOCKOPT,918 919		.get_level = SOL_IP,920		.set_level = SOL_IP,921 922		.get_optname = IP_TOS,923		.set_optname = IP_TOS,924 925		.set_optval = { 0x81 },926		.set_optlen = 1,927		.get_optval = { 0x00 },928		.get_optlen = 1,929 930		.error = EPERM_SETSOCKOPT,931	},932 933	/* ==================== prog_type ====================  */934 935	{936		.descr = "can attach only BPF_CGROUP_SETSOCKOP",937		.insns = {938			/* return 1 */939			BPF_MOV64_IMM(BPF_REG_0, 1),940			BPF_EXIT_INSN(),941 942		},943		.prog_type = BPF_PROG_TYPE_CGROUP_SKB,944		.attach_type = BPF_CGROUP_SETSOCKOPT,945		.expected_attach_type = 0,946		.error = DENY_ATTACH,947	},948 949	{950		.descr = "can attach only BPF_CGROUP_GETSOCKOP",951		.insns = {952			/* return 1 */953			BPF_MOV64_IMM(BPF_REG_0, 1),954			BPF_EXIT_INSN(),955 956		},957		.prog_type = BPF_PROG_TYPE_CGROUP_SKB,958		.attach_type = BPF_CGROUP_GETSOCKOPT,959		.expected_attach_type = 0,960		.error = DENY_ATTACH,961	},962};963 964static int load_prog(const struct bpf_insn *insns,965		     enum bpf_prog_type prog_type,966		     enum bpf_attach_type expected_attach_type)967{968	LIBBPF_OPTS(bpf_prog_load_opts, opts,969		.expected_attach_type = expected_attach_type,970		.log_level = 2,971		.log_buf = bpf_log_buf,972		.log_size = sizeof(bpf_log_buf),973	);974	int fd, insns_cnt = 0;975 976	for (;977	     insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);978	     insns_cnt++) {979	}980	insns_cnt++;981 982	fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);983	if (verbose && fd < 0)984		fprintf(stderr, "%s\n", bpf_log_buf);985 986	return fd;987}988 989/* Core function that handles io_uring ring initialization,990 * sending SQE with sockopt command and waiting for the CQE.991 */992static int uring_sockopt(int op, int fd, int level, int optname,993			 const void *optval, socklen_t optlen)994{995	struct io_uring_cqe *cqe;996	struct io_uring_sqe *sqe;997	struct io_uring ring;998	int err;999 1000	err = io_uring_queue_init(1, &ring, 0);1001	if (!ASSERT_OK(err, "io_uring initialization"))1002		return err;1003 1004	sqe = io_uring_get_sqe(&ring);1005	if (!ASSERT_NEQ(sqe, NULL, "Get an SQE")) {1006		err = -1;1007		goto fail;1008	}1009 1010	io_uring_prep_cmd(sqe, op, fd, level, optname, optval, optlen);1011 1012	err = io_uring_submit(&ring);1013	if (!ASSERT_EQ(err, 1, "Submit SQE"))1014		goto fail;1015 1016	err = io_uring_wait_cqe(&ring, &cqe);1017	if (!ASSERT_OK(err, "Wait for CQE"))1018		goto fail;1019 1020	err = cqe->res;1021 1022fail:1023	io_uring_queue_exit(&ring);1024 1025	return err;1026}1027 1028static int uring_setsockopt(int fd, int level, int optname, const void *optval,1029			    socklen_t optlen)1030{1031	return uring_sockopt(SOCKET_URING_OP_SETSOCKOPT, fd, level, optname,1032			     optval, optlen);1033}1034 1035static int uring_getsockopt(int fd, int level, int optname, void *optval,1036			    socklen_t *optlen)1037{1038	int ret = uring_sockopt(SOCKET_URING_OP_GETSOCKOPT, fd, level, optname,1039				optval, *optlen);1040	if (ret < 0)1041		return ret;1042 1043	/* Populate optlen back to be compatible with systemcall interface,1044	 * and simplify the test.1045	 */1046	*optlen = ret;1047 1048	return 0;1049}1050 1051/* Execute the setsocktopt operation */1052static int call_setsockopt(bool use_io_uring, int fd, int level, int optname,1053			   const void *optval, socklen_t optlen)1054{1055	if (use_io_uring)1056		return uring_setsockopt(fd, level, optname, optval, optlen);1057 1058	return setsockopt(fd, level, optname, optval, optlen);1059}1060 1061/* Execute the getsocktopt operation */1062static int call_getsockopt(bool use_io_uring, int fd, int level, int optname,1063			   void *optval, socklen_t *optlen)1064{1065	if (use_io_uring)1066		return uring_getsockopt(fd, level, optname, optval, optlen);1067 1068	return getsockopt(fd, level, optname, optval, optlen);1069}1070 1071static int run_test(int cgroup_fd, struct sockopt_test *test, bool use_io_uring,1072		    bool use_link)1073{1074	int prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT;1075	int sock_fd, err, prog_fd, link_fd = -1;1076	void *optval = NULL;1077	int ret = 0;1078 1079	if (test->prog_type)1080		prog_type = test->prog_type;1081 1082	prog_fd = load_prog(test->insns, prog_type, test->expected_attach_type);1083	if (prog_fd < 0) {1084		if (test->error == DENY_LOAD)1085			return 0;1086 1087		log_err("Failed to load BPF program");1088		return -1;1089	}1090 1091	if (use_link) {1092		err = bpf_link_create(prog_fd, cgroup_fd, test->attach_type, NULL);1093		link_fd = err;1094	} else {1095		err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);1096	}1097	if (err < 0) {1098		if (test->error == DENY_ATTACH)1099			goto close_prog_fd;1100 1101		log_err("Failed to attach BPF program");1102		ret = -1;1103		goto close_prog_fd;1104	}1105 1106	sock_fd = socket(AF_INET, SOCK_STREAM, 0);1107	if (sock_fd < 0) {1108		log_err("Failed to create AF_INET socket");1109		ret = -1;1110		goto detach_prog;1111	}1112 1113	if (test->set_optlen) {1114		if (test->set_optlen >= PAGE_SIZE) {1115			int num_pages = test->set_optlen / PAGE_SIZE;1116			int remainder = test->set_optlen % PAGE_SIZE;1117 1118			test->set_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder;1119		}1120 1121		err = call_setsockopt(use_io_uring, sock_fd, test->set_level,1122				      test->set_optname, test->set_optval,1123				      test->set_optlen);1124		if (err) {1125			if (errno == EPERM && test->error == EPERM_SETSOCKOPT)1126				goto close_sock_fd;1127			if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT)1128				goto free_optval;1129 1130			log_err("Failed to call setsockopt");1131			ret = -1;1132			goto close_sock_fd;1133		}1134	}1135 1136	if (test->get_optlen) {1137		if (test->get_optlen >= PAGE_SIZE) {1138			int num_pages = test->get_optlen / PAGE_SIZE;1139			int remainder = test->get_optlen % PAGE_SIZE;1140 1141			test->get_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder;1142		}1143 1144		optval = malloc(test->get_optlen);1145		memset(optval, 0, test->get_optlen);1146		socklen_t optlen = test->get_optlen;1147		socklen_t expected_get_optlen = test->get_optlen_ret ?:1148			test->get_optlen;1149 1150		err = call_getsockopt(use_io_uring, sock_fd, test->get_level,1151				      test->get_optname, optval, &optlen);1152		if (err) {1153			if (errno == EOPNOTSUPP && test->error == EOPNOTSUPP_GETSOCKOPT)1154				goto free_optval;1155			if (errno == EPERM && test->error == EPERM_GETSOCKOPT)1156				goto free_optval;1157			if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT)1158				goto free_optval;1159 1160			log_err("Failed to call getsockopt");1161			ret = -1;1162			goto free_optval;1163		}1164 1165		if (optlen != expected_get_optlen) {1166			errno = 0;1167			log_err("getsockopt returned unexpected optlen");1168			ret = -1;1169			goto free_optval;1170		}1171 1172		if (memcmp(optval, test->get_optval, optlen) != 0) {1173			errno = 0;1174			log_err("getsockopt returned unexpected optval");1175			ret = -1;1176			goto free_optval;1177		}1178	}1179 1180	ret = test->error != OK;1181 1182free_optval:1183	free(optval);1184close_sock_fd:1185	close(sock_fd);1186detach_prog:1187	if (use_link) {1188		if (link_fd >= 0)1189			close(link_fd);1190	} else {1191		bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);1192	}1193close_prog_fd:1194	close(prog_fd);1195	return ret;1196}1197 1198void test_sockopt(void)1199{1200	int cgroup_fd, i;1201 1202	cgroup_fd = test__join_cgroup("/sockopt");1203	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))1204		return;1205 1206	for (i = 0; i < ARRAY_SIZE(tests); i++) {1207		if (!test__start_subtest(tests[i].descr))1208			continue;1209 1210		ASSERT_OK(run_test(cgroup_fd, &tests[i], false, false),1211			  tests[i].descr);1212		ASSERT_OK(run_test(cgroup_fd, &tests[i], false, true),1213			  tests[i].descr);1214		if (tests[i].io_uring_support)1215			ASSERT_OK(run_test(cgroup_fd, &tests[i], true, false),1216				  tests[i].descr);1217	}1218 1219	close(cgroup_fd);1220}1221