Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2018 Facebook
   3
   4#define _GNU_SOURCE
   5
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <unistd.h>
   9
  10#include <arpa/inet.h>
  11#include <netinet/in.h>
  12#include <sys/types.h>
  13#include <sys/select.h>
  14#include <sys/socket.h>
  15
  16#include <linux/filter.h>
  17
  18#include <bpf/bpf.h>
  19#include <bpf/libbpf.h>
  20
  21#include "cgroup_helpers.h"
  22#include "bpf_rlimit.h"
  23#include "bpf_util.h"
  24
  25#ifndef ENOTSUPP
  26# define ENOTSUPP 524
  27#endif
  28
  29#define CG_PATH	"/foo"
  30#define CONNECT4_PROG_PATH	"./connect4_prog.o"
  31#define CONNECT6_PROG_PATH	"./connect6_prog.o"
  32#define SENDMSG4_PROG_PATH	"./sendmsg4_prog.o"
  33#define SENDMSG6_PROG_PATH	"./sendmsg6_prog.o"
  34#define RECVMSG4_PROG_PATH	"./recvmsg4_prog.o"
  35#define RECVMSG6_PROG_PATH	"./recvmsg6_prog.o"
  36#define BIND4_PROG_PATH		"./bind4_prog.o"
  37#define BIND6_PROG_PATH		"./bind6_prog.o"
  38
  39#define SERV4_IP		"192.168.1.254"
  40#define SERV4_REWRITE_IP	"127.0.0.1"
  41#define SRC4_IP			"172.16.0.1"
  42#define SRC4_REWRITE_IP		"127.0.0.4"
  43#define SERV4_PORT		4040
  44#define SERV4_REWRITE_PORT	4444
  45
  46#define SERV6_IP		"face:b00c:1234:5678::abcd"
  47#define SERV6_REWRITE_IP	"::1"
  48#define SERV6_V4MAPPED_IP	"::ffff:192.168.0.4"
  49#define SRC6_IP			"::1"
  50#define SRC6_REWRITE_IP		"::6"
  51#define WILDCARD6_IP		"::"
  52#define SERV6_PORT		6060
  53#define SERV6_REWRITE_PORT	6666
  54
  55#define INET_NTOP_BUF	40
  56
  57struct sock_addr_test;
  58
  59typedef int (*load_fn)(const struct sock_addr_test *test);
  60typedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
  61
  62char bpf_log_buf[BPF_LOG_BUF_SIZE];
  63
  64struct sock_addr_test {
  65	const char *descr;
  66	/* BPF prog properties */
  67	load_fn loadfn;
  68	enum bpf_attach_type expected_attach_type;
  69	enum bpf_attach_type attach_type;
  70	/* Socket properties */
  71	int domain;
  72	int type;
  73	/* IP:port pairs for BPF prog to override */
  74	const char *requested_ip;
  75	unsigned short requested_port;
  76	const char *expected_ip;
  77	unsigned short expected_port;
  78	const char *expected_src_ip;
  79	/* Expected test result */
  80	enum {
  81		LOAD_REJECT,
  82		ATTACH_REJECT,
  83		ATTACH_OKAY,
  84		SYSCALL_EPERM,
  85		SYSCALL_ENOTSUPP,
  86		SUCCESS,
  87	} expected_result;
  88};
  89
  90static int bind4_prog_load(const struct sock_addr_test *test);
  91static int bind6_prog_load(const struct sock_addr_test *test);
  92static int connect4_prog_load(const struct sock_addr_test *test);
  93static int connect6_prog_load(const struct sock_addr_test *test);
  94static int sendmsg_allow_prog_load(const struct sock_addr_test *test);
  95static int sendmsg_deny_prog_load(const struct sock_addr_test *test);
  96static int recvmsg_allow_prog_load(const struct sock_addr_test *test);
  97static int recvmsg_deny_prog_load(const struct sock_addr_test *test);
  98static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
  99static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test);
 100static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test);
 101static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
 102static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test);
 103static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test);
 104static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test);
 105static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test);
 106
 107static struct sock_addr_test tests[] = {
 108	/* bind */
 109	{
 110		"bind4: load prog with wrong expected attach type",
 111		bind4_prog_load,
 112		BPF_CGROUP_INET6_BIND,
 113		BPF_CGROUP_INET4_BIND,
 114		AF_INET,
 115		SOCK_STREAM,
 116		NULL,
 117		0,
 118		NULL,
 119		0,
 120		NULL,
 121		LOAD_REJECT,
 122	},
 123	{
 124		"bind4: attach prog with wrong attach type",
 125		bind4_prog_load,
 126		BPF_CGROUP_INET4_BIND,
 127		BPF_CGROUP_INET6_BIND,
 128		AF_INET,
 129		SOCK_STREAM,
 130		NULL,
 131		0,
 132		NULL,
 133		0,
 134		NULL,
 135		ATTACH_REJECT,
 136	},
 137	{
 138		"bind4: rewrite IP & TCP port in",
 139		bind4_prog_load,
 140		BPF_CGROUP_INET4_BIND,
 141		BPF_CGROUP_INET4_BIND,
 142		AF_INET,
 143		SOCK_STREAM,
 144		SERV4_IP,
 145		SERV4_PORT,
 146		SERV4_REWRITE_IP,
 147		SERV4_REWRITE_PORT,
 148		NULL,
 149		SUCCESS,
 150	},
 151	{
 152		"bind4: rewrite IP & UDP port in",
 153		bind4_prog_load,
 154		BPF_CGROUP_INET4_BIND,
 155		BPF_CGROUP_INET4_BIND,
 156		AF_INET,
 157		SOCK_DGRAM,
 158		SERV4_IP,
 159		SERV4_PORT,
 160		SERV4_REWRITE_IP,
 161		SERV4_REWRITE_PORT,
 162		NULL,
 163		SUCCESS,
 164	},
 165	{
 166		"bind6: load prog with wrong expected attach type",
 167		bind6_prog_load,
 168		BPF_CGROUP_INET4_BIND,
 169		BPF_CGROUP_INET6_BIND,
 170		AF_INET6,
 171		SOCK_STREAM,
 172		NULL,
 173		0,
 174		NULL,
 175		0,
 176		NULL,
 177		LOAD_REJECT,
 178	},
 179	{
 180		"bind6: attach prog with wrong attach type",
 181		bind6_prog_load,
 182		BPF_CGROUP_INET6_BIND,
 183		BPF_CGROUP_INET4_BIND,
 184		AF_INET,
 185		SOCK_STREAM,
 186		NULL,
 187		0,
 188		NULL,
 189		0,
 190		NULL,
 191		ATTACH_REJECT,
 192	},
 193	{
 194		"bind6: rewrite IP & TCP port in",
 195		bind6_prog_load,
 196		BPF_CGROUP_INET6_BIND,
 197		BPF_CGROUP_INET6_BIND,
 198		AF_INET6,
 199		SOCK_STREAM,
 200		SERV6_IP,
 201		SERV6_PORT,
 202		SERV6_REWRITE_IP,
 203		SERV6_REWRITE_PORT,
 204		NULL,
 205		SUCCESS,
 206	},
 207	{
 208		"bind6: rewrite IP & UDP port in",
 209		bind6_prog_load,
 210		BPF_CGROUP_INET6_BIND,
 211		BPF_CGROUP_INET6_BIND,
 212		AF_INET6,
 213		SOCK_DGRAM,
 214		SERV6_IP,
 215		SERV6_PORT,
 216		SERV6_REWRITE_IP,
 217		SERV6_REWRITE_PORT,
 218		NULL,
 219		SUCCESS,
 220	},
 221
 222	/* connect */
 223	{
 224		"connect4: load prog with wrong expected attach type",
 225		connect4_prog_load,
 226		BPF_CGROUP_INET6_CONNECT,
 227		BPF_CGROUP_INET4_CONNECT,
 228		AF_INET,
 229		SOCK_STREAM,
 230		NULL,
 231		0,
 232		NULL,
 233		0,
 234		NULL,
 235		LOAD_REJECT,
 236	},
 237	{
 238		"connect4: attach prog with wrong attach type",
 239		connect4_prog_load,
 240		BPF_CGROUP_INET4_CONNECT,
 241		BPF_CGROUP_INET6_CONNECT,
 242		AF_INET,
 243		SOCK_STREAM,
 244		NULL,
 245		0,
 246		NULL,
 247		0,
 248		NULL,
 249		ATTACH_REJECT,
 250	},
 251	{
 252		"connect4: rewrite IP & TCP port",
 253		connect4_prog_load,
 254		BPF_CGROUP_INET4_CONNECT,
 255		BPF_CGROUP_INET4_CONNECT,
 256		AF_INET,
 257		SOCK_STREAM,
 258		SERV4_IP,
 259		SERV4_PORT,
 260		SERV4_REWRITE_IP,
 261		SERV4_REWRITE_PORT,
 262		SRC4_REWRITE_IP,
 263		SUCCESS,
 264	},
 265	{
 266		"connect4: rewrite IP & UDP port",
 267		connect4_prog_load,
 268		BPF_CGROUP_INET4_CONNECT,
 269		BPF_CGROUP_INET4_CONNECT,
 270		AF_INET,
 271		SOCK_DGRAM,
 272		SERV4_IP,
 273		SERV4_PORT,
 274		SERV4_REWRITE_IP,
 275		SERV4_REWRITE_PORT,
 276		SRC4_REWRITE_IP,
 277		SUCCESS,
 278	},
 279	{
 280		"connect6: load prog with wrong expected attach type",
 281		connect6_prog_load,
 282		BPF_CGROUP_INET4_CONNECT,
 283		BPF_CGROUP_INET6_CONNECT,
 284		AF_INET6,
 285		SOCK_STREAM,
 286		NULL,
 287		0,
 288		NULL,
 289		0,
 290		NULL,
 291		LOAD_REJECT,
 292	},
 293	{
 294		"connect6: attach prog with wrong attach type",
 295		connect6_prog_load,
 296		BPF_CGROUP_INET6_CONNECT,
 297		BPF_CGROUP_INET4_CONNECT,
 298		AF_INET,
 299		SOCK_STREAM,
 300		NULL,
 301		0,
 302		NULL,
 303		0,
 304		NULL,
 305		ATTACH_REJECT,
 306	},
 307	{
 308		"connect6: rewrite IP & TCP port",
 309		connect6_prog_load,
 310		BPF_CGROUP_INET6_CONNECT,
 311		BPF_CGROUP_INET6_CONNECT,
 312		AF_INET6,
 313		SOCK_STREAM,
 314		SERV6_IP,
 315		SERV6_PORT,
 316		SERV6_REWRITE_IP,
 317		SERV6_REWRITE_PORT,
 318		SRC6_REWRITE_IP,
 319		SUCCESS,
 320	},
 321	{
 322		"connect6: rewrite IP & UDP port",
 323		connect6_prog_load,
 324		BPF_CGROUP_INET6_CONNECT,
 325		BPF_CGROUP_INET6_CONNECT,
 326		AF_INET6,
 327		SOCK_DGRAM,
 328		SERV6_IP,
 329		SERV6_PORT,
 330		SERV6_REWRITE_IP,
 331		SERV6_REWRITE_PORT,
 332		SRC6_REWRITE_IP,
 333		SUCCESS,
 334	},
 335
 336	/* sendmsg */
 337	{
 338		"sendmsg4: load prog with wrong expected attach type",
 339		sendmsg4_rw_asm_prog_load,
 340		BPF_CGROUP_UDP6_SENDMSG,
 341		BPF_CGROUP_UDP4_SENDMSG,
 342		AF_INET,
 343		SOCK_DGRAM,
 344		NULL,
 345		0,
 346		NULL,
 347		0,
 348		NULL,
 349		LOAD_REJECT,
 350	},
 351	{
 352		"sendmsg4: attach prog with wrong attach type",
 353		sendmsg4_rw_asm_prog_load,
 354		BPF_CGROUP_UDP4_SENDMSG,
 355		BPF_CGROUP_UDP6_SENDMSG,
 356		AF_INET,
 357		SOCK_DGRAM,
 358		NULL,
 359		0,
 360		NULL,
 361		0,
 362		NULL,
 363		ATTACH_REJECT,
 364	},
 365	{
 366		"sendmsg4: rewrite IP & port (asm)",
 367		sendmsg4_rw_asm_prog_load,
 368		BPF_CGROUP_UDP4_SENDMSG,
 369		BPF_CGROUP_UDP4_SENDMSG,
 370		AF_INET,
 371		SOCK_DGRAM,
 372		SERV4_IP,
 373		SERV4_PORT,
 374		SERV4_REWRITE_IP,
 375		SERV4_REWRITE_PORT,
 376		SRC4_REWRITE_IP,
 377		SUCCESS,
 378	},
 379	{
 380		"sendmsg4: rewrite IP & port (C)",
 381		sendmsg4_rw_c_prog_load,
 382		BPF_CGROUP_UDP4_SENDMSG,
 383		BPF_CGROUP_UDP4_SENDMSG,
 384		AF_INET,
 385		SOCK_DGRAM,
 386		SERV4_IP,
 387		SERV4_PORT,
 388		SERV4_REWRITE_IP,
 389		SERV4_REWRITE_PORT,
 390		SRC4_REWRITE_IP,
 391		SUCCESS,
 392	},
 393	{
 394		"sendmsg4: deny call",
 395		sendmsg_deny_prog_load,
 396		BPF_CGROUP_UDP4_SENDMSG,
 397		BPF_CGROUP_UDP4_SENDMSG,
 398		AF_INET,
 399		SOCK_DGRAM,
 400		SERV4_IP,
 401		SERV4_PORT,
 402		SERV4_REWRITE_IP,
 403		SERV4_REWRITE_PORT,
 404		SRC4_REWRITE_IP,
 405		SYSCALL_EPERM,
 406	},
 407	{
 408		"sendmsg6: load prog with wrong expected attach type",
 409		sendmsg6_rw_asm_prog_load,
 410		BPF_CGROUP_UDP4_SENDMSG,
 411		BPF_CGROUP_UDP6_SENDMSG,
 412		AF_INET6,
 413		SOCK_DGRAM,
 414		NULL,
 415		0,
 416		NULL,
 417		0,
 418		NULL,
 419		LOAD_REJECT,
 420	},
 421	{
 422		"sendmsg6: attach prog with wrong attach type",
 423		sendmsg6_rw_asm_prog_load,
 424		BPF_CGROUP_UDP6_SENDMSG,
 425		BPF_CGROUP_UDP4_SENDMSG,
 426		AF_INET6,
 427		SOCK_DGRAM,
 428		NULL,
 429		0,
 430		NULL,
 431		0,
 432		NULL,
 433		ATTACH_REJECT,
 434	},
 435	{
 436		"sendmsg6: rewrite IP & port (asm)",
 437		sendmsg6_rw_asm_prog_load,
 438		BPF_CGROUP_UDP6_SENDMSG,
 439		BPF_CGROUP_UDP6_SENDMSG,
 440		AF_INET6,
 441		SOCK_DGRAM,
 442		SERV6_IP,
 443		SERV6_PORT,
 444		SERV6_REWRITE_IP,
 445		SERV6_REWRITE_PORT,
 446		SRC6_REWRITE_IP,
 447		SUCCESS,
 448	},
 449	{
 450		"sendmsg6: rewrite IP & port (C)",
 451		sendmsg6_rw_c_prog_load,
 452		BPF_CGROUP_UDP6_SENDMSG,
 453		BPF_CGROUP_UDP6_SENDMSG,
 454		AF_INET6,
 455		SOCK_DGRAM,
 456		SERV6_IP,
 457		SERV6_PORT,
 458		SERV6_REWRITE_IP,
 459		SERV6_REWRITE_PORT,
 460		SRC6_REWRITE_IP,
 461		SUCCESS,
 462	},
 463	{
 464		"sendmsg6: IPv4-mapped IPv6",
 465		sendmsg6_rw_v4mapped_prog_load,
 466		BPF_CGROUP_UDP6_SENDMSG,
 467		BPF_CGROUP_UDP6_SENDMSG,
 468		AF_INET6,
 469		SOCK_DGRAM,
 470		SERV6_IP,
 471		SERV6_PORT,
 472		SERV6_REWRITE_IP,
 473		SERV6_REWRITE_PORT,
 474		SRC6_REWRITE_IP,
 475		SYSCALL_ENOTSUPP,
 476	},
 477	{
 478		"sendmsg6: set dst IP = [::] (BSD'ism)",
 479		sendmsg6_rw_wildcard_prog_load,
 480		BPF_CGROUP_UDP6_SENDMSG,
 481		BPF_CGROUP_UDP6_SENDMSG,
 482		AF_INET6,
 483		SOCK_DGRAM,
 484		SERV6_IP,
 485		SERV6_PORT,
 486		SERV6_REWRITE_IP,
 487		SERV6_REWRITE_PORT,
 488		SRC6_REWRITE_IP,
 489		SUCCESS,
 490	},
 491	{
 492		"sendmsg6: preserve dst IP = [::] (BSD'ism)",
 493		sendmsg_allow_prog_load,
 494		BPF_CGROUP_UDP6_SENDMSG,
 495		BPF_CGROUP_UDP6_SENDMSG,
 496		AF_INET6,
 497		SOCK_DGRAM,
 498		WILDCARD6_IP,
 499		SERV6_PORT,
 500		SERV6_REWRITE_IP,
 501		SERV6_PORT,
 502		SRC6_IP,
 503		SUCCESS,
 504	},
 505	{
 506		"sendmsg6: deny call",
 507		sendmsg_deny_prog_load,
 508		BPF_CGROUP_UDP6_SENDMSG,
 509		BPF_CGROUP_UDP6_SENDMSG,
 510		AF_INET6,
 511		SOCK_DGRAM,
 512		SERV6_IP,
 513		SERV6_PORT,
 514		SERV6_REWRITE_IP,
 515		SERV6_REWRITE_PORT,
 516		SRC6_REWRITE_IP,
 517		SYSCALL_EPERM,
 518	},
 519
 520	/* recvmsg */
 521	{
 522		"recvmsg4: return code ok",
 523		recvmsg_allow_prog_load,
 524		BPF_CGROUP_UDP4_RECVMSG,
 525		BPF_CGROUP_UDP4_RECVMSG,
 526		AF_INET,
 527		SOCK_DGRAM,
 528		NULL,
 529		0,
 530		NULL,
 531		0,
 532		NULL,
 533		ATTACH_OKAY,
 534	},
 535	{
 536		"recvmsg4: return code !ok",
 537		recvmsg_deny_prog_load,
 538		BPF_CGROUP_UDP4_RECVMSG,
 539		BPF_CGROUP_UDP4_RECVMSG,
 540		AF_INET,
 541		SOCK_DGRAM,
 542		NULL,
 543		0,
 544		NULL,
 545		0,
 546		NULL,
 547		LOAD_REJECT,
 548	},
 549	{
 550		"recvmsg6: return code ok",
 551		recvmsg_allow_prog_load,
 552		BPF_CGROUP_UDP6_RECVMSG,
 553		BPF_CGROUP_UDP6_RECVMSG,
 554		AF_INET6,
 555		SOCK_DGRAM,
 556		NULL,
 557		0,
 558		NULL,
 559		0,
 560		NULL,
 561		ATTACH_OKAY,
 562	},
 563	{
 564		"recvmsg6: return code !ok",
 565		recvmsg_deny_prog_load,
 566		BPF_CGROUP_UDP6_RECVMSG,
 567		BPF_CGROUP_UDP6_RECVMSG,
 568		AF_INET6,
 569		SOCK_DGRAM,
 570		NULL,
 571		0,
 572		NULL,
 573		0,
 574		NULL,
 575		LOAD_REJECT,
 576	},
 577	{
 578		"recvmsg4: rewrite IP & port (C)",
 579		recvmsg4_rw_c_prog_load,
 580		BPF_CGROUP_UDP4_RECVMSG,
 581		BPF_CGROUP_UDP4_RECVMSG,
 582		AF_INET,
 583		SOCK_DGRAM,
 584		SERV4_REWRITE_IP,
 585		SERV4_REWRITE_PORT,
 586		SERV4_REWRITE_IP,
 587		SERV4_REWRITE_PORT,
 588		SERV4_IP,
 589		SUCCESS,
 590	},
 591	{
 592		"recvmsg6: rewrite IP & port (C)",
 593		recvmsg6_rw_c_prog_load,
 594		BPF_CGROUP_UDP6_RECVMSG,
 595		BPF_CGROUP_UDP6_RECVMSG,
 596		AF_INET6,
 597		SOCK_DGRAM,
 598		SERV6_REWRITE_IP,
 599		SERV6_REWRITE_PORT,
 600		SERV6_REWRITE_IP,
 601		SERV6_REWRITE_PORT,
 602		SERV6_IP,
 603		SUCCESS,
 604	},
 605};
 606
 607static int mk_sockaddr(int domain, const char *ip, unsigned short port,
 608		       struct sockaddr *addr, socklen_t addr_len)
 609{
 610	struct sockaddr_in6 *addr6;
 611	struct sockaddr_in *addr4;
 612
 613	if (domain != AF_INET && domain != AF_INET6) {
 614		log_err("Unsupported address family");
 615		return -1;
 616	}
 617
 618	memset(addr, 0, addr_len);
 619
 620	if (domain == AF_INET) {
 621		if (addr_len < sizeof(struct sockaddr_in))
 622			return -1;
 623		addr4 = (struct sockaddr_in *)addr;
 624		addr4->sin_family = domain;
 625		addr4->sin_port = htons(port);
 626		if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) {
 627			log_err("Invalid IPv4: %s", ip);
 628			return -1;
 629		}
 630	} else if (domain == AF_INET6) {
 631		if (addr_len < sizeof(struct sockaddr_in6))
 632			return -1;
 633		addr6 = (struct sockaddr_in6 *)addr;
 634		addr6->sin6_family = domain;
 635		addr6->sin6_port = htons(port);
 636		if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) {
 637			log_err("Invalid IPv6: %s", ip);
 638			return -1;
 639		}
 640	}
 641
 642	return 0;
 643}
 644
 645static int load_insns(const struct sock_addr_test *test,
 646		      const struct bpf_insn *insns, size_t insns_cnt)
 647{
 648	struct bpf_load_program_attr load_attr;
 649	int ret;
 650
 651	memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
 652	load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
 653	load_attr.expected_attach_type = test->expected_attach_type;
 654	load_attr.insns = insns;
 655	load_attr.insns_cnt = insns_cnt;
 656	load_attr.license = "GPL";
 657
 658	ret = bpf_load_program_xattr(&load_attr, bpf_log_buf, BPF_LOG_BUF_SIZE);
 659	if (ret < 0 && test->expected_result != LOAD_REJECT) {
 660		log_err(">>> Loading program error.\n"
 661			">>> Verifier output:\n%s\n-------\n", bpf_log_buf);
 662	}
 663
 664	return ret;
 665}
 666
 667static int load_path(const struct sock_addr_test *test, const char *path)
 668{
 669	struct bpf_prog_load_attr attr;
 670	struct bpf_object *obj;
 671	int prog_fd;
 672
 673	memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
 674	attr.file = path;
 675	attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
 676	attr.expected_attach_type = test->expected_attach_type;
 677	attr.prog_flags = BPF_F_TEST_RND_HI32;
 678
 679	if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) {
 680		if (test->expected_result != LOAD_REJECT)
 681			log_err(">>> Loading program (%s) error.\n", path);
 682		return -1;
 683	}
 684
 685	return prog_fd;
 686}
 687
 688static int bind4_prog_load(const struct sock_addr_test *test)
 689{
 690	return load_path(test, BIND4_PROG_PATH);
 691}
 692
 693static int bind6_prog_load(const struct sock_addr_test *test)
 694{
 695	return load_path(test, BIND6_PROG_PATH);
 696}
 697
 698static int connect4_prog_load(const struct sock_addr_test *test)
 699{
 700	return load_path(test, CONNECT4_PROG_PATH);
 701}
 702
 703static int connect6_prog_load(const struct sock_addr_test *test)
 704{
 705	return load_path(test, CONNECT6_PROG_PATH);
 706}
 707
 708static int xmsg_ret_only_prog_load(const struct sock_addr_test *test,
 709				   int32_t rc)
 710{
 711	struct bpf_insn insns[] = {
 712		/* return rc */
 713		BPF_MOV64_IMM(BPF_REG_0, rc),
 714		BPF_EXIT_INSN(),
 715	};
 716	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
 717}
 718
 719static int sendmsg_allow_prog_load(const struct sock_addr_test *test)
 720{
 721	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
 722}
 723
 724static int sendmsg_deny_prog_load(const struct sock_addr_test *test)
 725{
 726	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
 727}
 728
 729static int recvmsg_allow_prog_load(const struct sock_addr_test *test)
 730{
 731	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
 732}
 733
 734static int recvmsg_deny_prog_load(const struct sock_addr_test *test)
 735{
 736	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
 737}
 738
 739static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
 740{
 741	struct sockaddr_in dst4_rw_addr;
 742	struct in_addr src4_rw_ip;
 743
 744	if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) {
 745		log_err("Invalid IPv4: %s", SRC4_REWRITE_IP);
 746		return -1;
 747	}
 748
 749	if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
 750			(struct sockaddr *)&dst4_rw_addr,
 751			sizeof(dst4_rw_addr)) == -1)
 752		return -1;
 753
 754	struct bpf_insn insns[] = {
 755		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
 756
 757		/* if (sk.family == AF_INET && */
 758		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
 759			    offsetof(struct bpf_sock_addr, family)),
 760		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8),
 761
 762		/*     sk.type == SOCK_DGRAM)  { */
 763		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
 764			    offsetof(struct bpf_sock_addr, type)),
 765		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6),
 766
 767		/*      msg_src_ip4 = src4_rw_ip */
 768		BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr),
 769		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
 770			    offsetof(struct bpf_sock_addr, msg_src_ip4)),
 771
 772		/*      user_ip4 = dst4_rw_addr.sin_addr */
 773		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr),
 774		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
 775			    offsetof(struct bpf_sock_addr, user_ip4)),
 776
 777		/*      user_port = dst4_rw_addr.sin_port */
 778		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port),
 779		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
 780			    offsetof(struct bpf_sock_addr, user_port)),
 781		/* } */
 782
 783		/* return 1 */
 784		BPF_MOV64_IMM(BPF_REG_0, 1),
 785		BPF_EXIT_INSN(),
 786	};
 787
 788	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
 789}
 790
 791static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test)
 792{
 793	return load_path(test, RECVMSG4_PROG_PATH);
 794}
 795
 796static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test)
 797{
 798	return load_path(test, SENDMSG4_PROG_PATH);
 799}
 800
 801static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test,
 802					 const char *rw_dst_ip)
 803{
 804	struct sockaddr_in6 dst6_rw_addr;
 805	struct in6_addr src6_rw_ip;
 806
 807	if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) {
 808		log_err("Invalid IPv6: %s", SRC6_REWRITE_IP);
 809		return -1;
 810	}
 811
 812	if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT,
 813			(struct sockaddr *)&dst6_rw_addr,
 814			sizeof(dst6_rw_addr)) == -1)
 815		return -1;
 816
 817	struct bpf_insn insns[] = {
 818		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
 819
 820		/* if (sk.family == AF_INET6) { */
 821		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
 822			    offsetof(struct bpf_sock_addr, family)),
 823		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
 824
 825#define STORE_IPV6_WORD_N(DST, SRC, N)					       \
 826		BPF_MOV32_IMM(BPF_REG_7, SRC[N]),			       \
 827		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,		       \
 828			    offsetof(struct bpf_sock_addr, DST[N]))
 829
 830#define STORE_IPV6(DST, SRC)						       \
 831		STORE_IPV6_WORD_N(DST, SRC, 0),				       \
 832		STORE_IPV6_WORD_N(DST, SRC, 1),				       \
 833		STORE_IPV6_WORD_N(DST, SRC, 2),				       \
 834		STORE_IPV6_WORD_N(DST, SRC, 3)
 835
 836		STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32),
 837		STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32),
 838
 839		/*      user_port = dst6_rw_addr.sin6_port */
 840		BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port),
 841		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
 842			    offsetof(struct bpf_sock_addr, user_port)),
 843
 844		/* } */
 845
 846		/* return 1 */
 847		BPF_MOV64_IMM(BPF_REG_0, 1),
 848		BPF_EXIT_INSN(),
 849	};
 850
 851	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
 852}
 853
 854static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
 855{
 856	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP);
 857}
 858
 859static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test)
 860{
 861	return load_path(test, RECVMSG6_PROG_PATH);
 862}
 863
 864static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test)
 865{
 866	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP);
 867}
 868
 869static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test)
 870{
 871	return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP);
 872}
 873
 874static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test)
 875{
 876	return load_path(test, SENDMSG6_PROG_PATH);
 877}
 878
 879static int cmp_addr(const struct sockaddr_storage *addr1,
 880		    const struct sockaddr_storage *addr2, int cmp_port)
 881{
 882	const struct sockaddr_in *four1, *four2;
 883	const struct sockaddr_in6 *six1, *six2;
 884
 885	if (addr1->ss_family != addr2->ss_family)
 886		return -1;
 887
 888	if (addr1->ss_family == AF_INET) {
 889		four1 = (const struct sockaddr_in *)addr1;
 890		four2 = (const struct sockaddr_in *)addr2;
 891		return !((four1->sin_port == four2->sin_port || !cmp_port) &&
 892			 four1->sin_addr.s_addr == four2->sin_addr.s_addr);
 893	} else if (addr1->ss_family == AF_INET6) {
 894		six1 = (const struct sockaddr_in6 *)addr1;
 895		six2 = (const struct sockaddr_in6 *)addr2;
 896		return !((six1->sin6_port == six2->sin6_port || !cmp_port) &&
 897			 !memcmp(&six1->sin6_addr, &six2->sin6_addr,
 898				 sizeof(struct in6_addr)));
 899	}
 900
 901	return -1;
 902}
 903
 904static int cmp_sock_addr(info_fn fn, int sock1,
 905			 const struct sockaddr_storage *addr2, int cmp_port)
 906{
 907	struct sockaddr_storage addr1;
 908	socklen_t len1 = sizeof(addr1);
 909
 910	memset(&addr1, 0, len1);
 911	if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0)
 912		return -1;
 913
 914	return cmp_addr(&addr1, addr2, cmp_port);
 915}
 916
 917static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2)
 918{
 919	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0);
 920}
 921
 922static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2)
 923{
 924	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1);
 925}
 926
 927static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2)
 928{
 929	return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1);
 930}
 931
 932static int start_server(int type, const struct sockaddr_storage *addr,
 933			socklen_t addr_len)
 934{
 935	int fd;
 936
 937	fd = socket(addr->ss_family, type, 0);
 938	if (fd == -1) {
 939		log_err("Failed to create server socket");
 940		goto out;
 941	}
 942
 943	if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) {
 944		log_err("Failed to bind server socket");
 945		goto close_out;
 946	}
 947
 948	if (type == SOCK_STREAM) {
 949		if (listen(fd, 128) == -1) {
 950			log_err("Failed to listen on server socket");
 951			goto close_out;
 952		}
 953	}
 954
 955	goto out;
 956close_out:
 957	close(fd);
 958	fd = -1;
 959out:
 960	return fd;
 961}
 962
 963static int connect_to_server(int type, const struct sockaddr_storage *addr,
 964			     socklen_t addr_len)
 965{
 966	int domain;
 967	int fd = -1;
 968
 969	domain = addr->ss_family;
 970
 971	if (domain != AF_INET && domain != AF_INET6) {
 972		log_err("Unsupported address family");
 973		goto err;
 974	}
 975
 976	fd = socket(domain, type, 0);
 977	if (fd == -1) {
 978		log_err("Failed to create client socket");
 979		goto err;
 980	}
 981
 982	if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) {
 983		log_err("Fail to connect to server");
 984		goto err;
 985	}
 986
 987	goto out;
 988err:
 989	close(fd);
 990	fd = -1;
 991out:
 992	return fd;
 993}
 994
 995int init_pktinfo(int domain, struct cmsghdr *cmsg)
 996{
 997	struct in6_pktinfo *pktinfo6;
 998	struct in_pktinfo *pktinfo4;
 999
1000	if (domain == AF_INET) {
1001		cmsg->cmsg_level = SOL_IP;
1002		cmsg->cmsg_type = IP_PKTINFO;
1003		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1004		pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg);
1005		memset(pktinfo4, 0, sizeof(struct in_pktinfo));
1006		if (inet_pton(domain, SRC4_IP,
1007			      (void *)&pktinfo4->ipi_spec_dst) != 1)
1008			return -1;
1009	} else if (domain == AF_INET6) {
1010		cmsg->cmsg_level = SOL_IPV6;
1011		cmsg->cmsg_type = IPV6_PKTINFO;
1012		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1013		pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
1014		memset(pktinfo6, 0, sizeof(struct in6_pktinfo));
1015		if (inet_pton(domain, SRC6_IP,
1016			      (void *)&pktinfo6->ipi6_addr) != 1)
1017			return -1;
1018	} else {
1019		return -1;
1020	}
1021
1022	return 0;
1023}
1024
1025static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
1026			     socklen_t addr_len, int set_cmsg, int flags,
1027			     int *syscall_err)
1028{
1029	union {
1030		char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1031		struct cmsghdr align;
1032	} control6;
1033	union {
1034		char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
1035		struct cmsghdr align;
1036	} control4;
1037	struct msghdr hdr;
1038	struct iovec iov;
1039	char data = 'a';
1040	int domain;
1041	int fd = -1;
1042
1043	domain = addr->ss_family;
1044
1045	if (domain != AF_INET && domain != AF_INET6) {
1046		log_err("Unsupported address family");
1047		goto err;
1048	}
1049
1050	fd = socket(domain, type, 0);
1051	if (fd == -1) {
1052		log_err("Failed to create client socket");
1053		goto err;
1054	}
1055
1056	memset(&iov, 0, sizeof(iov));
1057	iov.iov_base = &data;
1058	iov.iov_len = sizeof(data);
1059
1060	memset(&hdr, 0, sizeof(hdr));
1061	hdr.msg_name = (void *)addr;
1062	hdr.msg_namelen = addr_len;
1063	hdr.msg_iov = &iov;
1064	hdr.msg_iovlen = 1;
1065
1066	if (set_cmsg) {
1067		if (domain == AF_INET) {
1068			hdr.msg_control = &control4;
1069			hdr.msg_controllen = sizeof(control4.buf);
1070		} else if (domain == AF_INET6) {
1071			hdr.msg_control = &control6;
1072			hdr.msg_controllen = sizeof(control6.buf);
1073		}
1074		if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) {
1075			log_err("Fail to init pktinfo");
1076			goto err;
1077		}
1078	}
1079
1080	if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
1081		log_err("Fail to send message to server");
1082		*syscall_err = errno;
1083		goto err;
1084	}
1085
1086	goto out;
1087err:
1088	close(fd);
1089	fd = -1;
1090out:
1091	return fd;
1092}
1093
1094static int fastconnect_to_server(const struct sockaddr_storage *addr,
1095				 socklen_t addr_len)
1096{
1097	int sendmsg_err;
1098
1099	return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
1100				 MSG_FASTOPEN, &sendmsg_err);
1101}
1102
1103static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
1104{
1105	struct timeval tv;
1106	struct msghdr hdr;
1107	struct iovec iov;
1108	char data[64];
1109	fd_set rfds;
1110
1111	FD_ZERO(&rfds);
1112	FD_SET(sockfd, &rfds);
1113
1114	tv.tv_sec = 2;
1115	tv.tv_usec = 0;
1116
1117	if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 ||
1118	    !FD_ISSET(sockfd, &rfds))
1119		return -1;
1120
1121	memset(&iov, 0, sizeof(iov));
1122	iov.iov_base = data;
1123	iov.iov_len = sizeof(data);
1124
1125	memset(&hdr, 0, sizeof(hdr));
1126	hdr.msg_name = src_addr;
1127	hdr.msg_namelen = sizeof(struct sockaddr_storage);
1128	hdr.msg_iov = &iov;
1129	hdr.msg_iovlen = 1;
1130
1131	return recvmsg(sockfd, &hdr, 0);
1132}
1133
1134static int init_addrs(const struct sock_addr_test *test,
1135		      struct sockaddr_storage *requested_addr,
1136		      struct sockaddr_storage *expected_addr,
1137		      struct sockaddr_storage *expected_src_addr)
1138{
1139	socklen_t addr_len = sizeof(struct sockaddr_storage);
1140
1141	if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port,
1142			(struct sockaddr *)expected_addr, addr_len) == -1)
1143		goto err;
1144
1145	if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port,
1146			(struct sockaddr *)requested_addr, addr_len) == -1)
1147		goto err;
1148
1149	if (test->expected_src_ip &&
1150	    mk_sockaddr(test->domain, test->expected_src_ip, 0,
1151			(struct sockaddr *)expected_src_addr, addr_len) == -1)
1152		goto err;
1153
1154	return 0;
1155err:
1156	return -1;
1157}
1158
1159static int run_bind_test_case(const struct sock_addr_test *test)
1160{
1161	socklen_t addr_len = sizeof(struct sockaddr_storage);
1162	struct sockaddr_storage requested_addr;
1163	struct sockaddr_storage expected_addr;
1164	int clientfd = -1;
1165	int servfd = -1;
1166	int err = 0;
1167
1168	if (init_addrs(test, &requested_addr, &expected_addr, NULL))
1169		goto err;
1170
1171	servfd = start_server(test->type, &requested_addr, addr_len);
1172	if (servfd == -1)
1173		goto err;
1174
1175	if (cmp_local_addr(servfd, &expected_addr))
1176		goto err;
1177
1178	/* Try to connect to server just in case */
1179	clientfd = connect_to_server(test->type, &expected_addr, addr_len);
1180	if (clientfd == -1)
1181		goto err;
1182
1183	goto out;
1184err:
1185	err = -1;
1186out:
1187	close(clientfd);
1188	close(servfd);
1189	return err;
1190}
1191
1192static int run_connect_test_case(const struct sock_addr_test *test)
1193{
1194	socklen_t addr_len = sizeof(struct sockaddr_storage);
1195	struct sockaddr_storage expected_src_addr;
1196	struct sockaddr_storage requested_addr;
1197	struct sockaddr_storage expected_addr;
1198	int clientfd = -1;
1199	int servfd = -1;
1200	int err = 0;
1201
1202	if (init_addrs(test, &requested_addr, &expected_addr,
1203		       &expected_src_addr))
1204		goto err;
1205
1206	/* Prepare server to connect to */
1207	servfd = start_server(test->type, &expected_addr, addr_len);
1208	if (servfd == -1)
1209		goto err;
1210
1211	clientfd = connect_to_server(test->type, &requested_addr, addr_len);
1212	if (clientfd == -1)
1213		goto err;
1214
1215	/* Make sure src and dst addrs were overridden properly */
1216	if (cmp_peer_addr(clientfd, &expected_addr))
1217		goto err;
1218
1219	if (cmp_local_ip(clientfd, &expected_src_addr))
1220		goto err;
1221
1222	if (test->type == SOCK_STREAM) {
1223		/* Test TCP Fast Open scenario */
1224		clientfd = fastconnect_to_server(&requested_addr, addr_len);
1225		if (clientfd == -1)
1226			goto err;
1227
1228		/* Make sure src and dst addrs were overridden properly */
1229		if (cmp_peer_addr(clientfd, &expected_addr))
1230			goto err;
1231
1232		if (cmp_local_ip(clientfd, &expected_src_addr))
1233			goto err;
1234	}
1235
1236	goto out;
1237err:
1238	err = -1;
1239out:
1240	close(clientfd);
1241	close(servfd);
1242	return err;
1243}
1244
1245static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg)
1246{
1247	socklen_t addr_len = sizeof(struct sockaddr_storage);
1248	struct sockaddr_storage expected_addr;
1249	struct sockaddr_storage server_addr;
1250	struct sockaddr_storage sendmsg_addr;
1251	struct sockaddr_storage recvmsg_addr;
1252	int clientfd = -1;
1253	int servfd = -1;
1254	int set_cmsg;
1255	int err = 0;
1256
1257	if (test->type != SOCK_DGRAM)
1258		goto err;
1259
1260	if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr))
1261		goto err;
1262
1263	/* Prepare server to sendmsg to */
1264	servfd = start_server(test->type, &server_addr, addr_len);
1265	if (servfd == -1)
1266		goto err;
1267
1268	for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) {
1269		if (clientfd >= 0)
1270			close(clientfd);
1271
1272		clientfd = sendmsg_to_server(test->type, &sendmsg_addr,
1273					     addr_len, set_cmsg, /*flags*/0,
1274					     &err);
1275		if (err)
1276			goto out;
1277		else if (clientfd == -1)
1278			goto err;
1279
1280		/* Try to receive message on server instead of using
1281		 * getpeername(2) on client socket, to check that client's
1282		 * destination address was rewritten properly, since
1283		 * getpeername(2) doesn't work with unconnected datagram
1284		 * sockets.
1285		 *
1286		 * Get source address from recvmsg(2) as well to make sure
1287		 * source was rewritten properly: getsockname(2) can't be used
1288		 * since socket is unconnected and source defined for one
1289		 * specific packet may differ from the one used by default and
1290		 * returned by getsockname(2).
1291		 */
1292		if (recvmsg_from_client(servfd, &recvmsg_addr) == -1)
1293			goto err;
1294
1295		if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0))
1296			goto err;
1297	}
1298
1299	goto out;
1300err:
1301	err = -1;
1302out:
1303	close(clientfd);
1304	close(servfd);
1305	return err;
1306}
1307
1308static int run_test_case(int cgfd, const struct sock_addr_test *test)
1309{
1310	int progfd = -1;
1311	int err = 0;
1312
1313	printf("Test case: %s .. ", test->descr);
1314
1315	progfd = test->loadfn(test);
1316	if (test->expected_result == LOAD_REJECT && progfd < 0)
1317		goto out;
1318	else if (test->expected_result == LOAD_REJECT || progfd < 0)
1319		goto err;
1320
1321	err = bpf_prog_attach(progfd, cgfd, test->attach_type,
1322			      BPF_F_ALLOW_OVERRIDE);
1323	if (test->expected_result == ATTACH_REJECT && err) {
1324		err = 0; /* error was expected, reset it */
1325		goto out;
1326	} else if (test->expected_result == ATTACH_REJECT || err) {
1327		goto err;
1328	} else if (test->expected_result == ATTACH_OKAY) {
1329		err = 0;
1330		goto out;
1331	}
1332
1333	switch (test->attach_type) {
1334	case BPF_CGROUP_INET4_BIND:
1335	case BPF_CGROUP_INET6_BIND:
1336		err = run_bind_test_case(test);
1337		break;
1338	case BPF_CGROUP_INET4_CONNECT:
1339	case BPF_CGROUP_INET6_CONNECT:
1340		err = run_connect_test_case(test);
1341		break;
1342	case BPF_CGROUP_UDP4_SENDMSG:
1343	case BPF_CGROUP_UDP6_SENDMSG:
1344		err = run_xmsg_test_case(test, 1);
1345		break;
1346	case BPF_CGROUP_UDP4_RECVMSG:
1347	case BPF_CGROUP_UDP6_RECVMSG:
1348		err = run_xmsg_test_case(test, 0);
1349		break;
1350	default:
1351		goto err;
1352	}
1353
1354	if (test->expected_result == SYSCALL_EPERM && err == EPERM) {
1355		err = 0; /* error was expected, reset it */
1356		goto out;
1357	}
1358
1359	if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) {
1360		err = 0; /* error was expected, reset it */
1361		goto out;
1362	}
1363
1364	if (err || test->expected_result != SUCCESS)
1365		goto err;
1366
1367	goto out;
1368err:
1369	err = -1;
1370out:
1371	/* Detaching w/o checking return code: best effort attempt. */
1372	if (progfd != -1)
1373		bpf_prog_detach(cgfd, test->attach_type);
1374	close(progfd);
1375	printf("[%s]\n", err ? "FAIL" : "PASS");
1376	return err;
1377}
1378
1379static int run_tests(int cgfd)
1380{
1381	int passes = 0;
1382	int fails = 0;
1383	int i;
1384
1385	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
1386		if (run_test_case(cgfd, &tests[i]))
1387			++fails;
1388		else
1389			++passes;
1390	}
1391	printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
1392	return fails ? -1 : 0;
1393}
1394
1395int main(int argc, char **argv)
1396{
1397	int cgfd = -1;
1398	int err = 0;
1399
1400	if (argc < 2) {
1401		fprintf(stderr,
1402			"%s has to be run via %s.sh. Skip direct run.\n",
1403			argv[0], argv[0]);
1404		exit(err);
1405	}
1406
1407	cgfd = cgroup_setup_and_join(CG_PATH);
1408	if (cgfd < 0)
1409		goto err;
1410
1411	if (run_tests(cgfd))
1412		goto err;
1413
1414	goto out;
1415err:
1416	err = -1;
1417out:
1418	close(cgfd);
1419	cleanup_cgroup_environment();
1420	return err;
1421}