Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1/*
   2 * Testsuite for eBPF verifier
   3 *
   4 * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of version 2 of the GNU General Public
   8 * License as published by the Free Software Foundation.
   9 */
  10#include <stdio.h>
  11#include <unistd.h>
  12#include <linux/bpf.h>
  13#include <errno.h>
  14#include <linux/unistd.h>
  15#include <string.h>
  16#include <linux/filter.h>
  17#include <stddef.h>
  18#include <stdbool.h>
  19#include <sys/resource.h>
  20#include "libbpf.h"
  21
  22#define MAX_INSNS 512
  23#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
  24
  25#define MAX_FIXUPS 8
  26
  27struct bpf_test {
  28	const char *descr;
  29	struct bpf_insn	insns[MAX_INSNS];
  30	int fixup[MAX_FIXUPS];
  31	int prog_array_fixup[MAX_FIXUPS];
  32	const char *errstr;
  33	const char *errstr_unpriv;
  34	enum {
  35		UNDEF,
  36		ACCEPT,
  37		REJECT
  38	} result, result_unpriv;
  39	enum bpf_prog_type prog_type;
  40};
  41
  42static struct bpf_test tests[] = {
  43	{
  44		"add+sub+mul",
  45		.insns = {
  46			BPF_MOV64_IMM(BPF_REG_1, 1),
  47			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 2),
  48			BPF_MOV64_IMM(BPF_REG_2, 3),
  49			BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_2),
  50			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -1),
  51			BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 3),
  52			BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
  53			BPF_EXIT_INSN(),
  54		},
  55		.result = ACCEPT,
  56	},
  57	{
  58		"unreachable",
  59		.insns = {
  60			BPF_EXIT_INSN(),
  61			BPF_EXIT_INSN(),
  62		},
  63		.errstr = "unreachable",
  64		.result = REJECT,
  65	},
  66	{
  67		"unreachable2",
  68		.insns = {
  69			BPF_JMP_IMM(BPF_JA, 0, 0, 1),
  70			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
  71			BPF_EXIT_INSN(),
  72		},
  73		.errstr = "unreachable",
  74		.result = REJECT,
  75	},
  76	{
  77		"out of range jump",
  78		.insns = {
  79			BPF_JMP_IMM(BPF_JA, 0, 0, 1),
  80			BPF_EXIT_INSN(),
  81		},
  82		.errstr = "jump out of range",
  83		.result = REJECT,
  84	},
  85	{
  86		"out of range jump2",
  87		.insns = {
  88			BPF_JMP_IMM(BPF_JA, 0, 0, -2),
  89			BPF_EXIT_INSN(),
  90		},
  91		.errstr = "jump out of range",
  92		.result = REJECT,
  93	},
  94	{
  95		"test1 ld_imm64",
  96		.insns = {
  97			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1),
  98			BPF_LD_IMM64(BPF_REG_0, 0),
  99			BPF_LD_IMM64(BPF_REG_0, 0),
 100			BPF_LD_IMM64(BPF_REG_0, 1),
 101			BPF_LD_IMM64(BPF_REG_0, 1),
 102			BPF_MOV64_IMM(BPF_REG_0, 2),
 103			BPF_EXIT_INSN(),
 104		},
 105		.errstr = "invalid BPF_LD_IMM insn",
 106		.errstr_unpriv = "R1 pointer comparison",
 107		.result = REJECT,
 108	},
 109	{
 110		"test2 ld_imm64",
 111		.insns = {
 112			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1),
 113			BPF_LD_IMM64(BPF_REG_0, 0),
 114			BPF_LD_IMM64(BPF_REG_0, 0),
 115			BPF_LD_IMM64(BPF_REG_0, 1),
 116			BPF_LD_IMM64(BPF_REG_0, 1),
 117			BPF_EXIT_INSN(),
 118		},
 119		.errstr = "invalid BPF_LD_IMM insn",
 120		.errstr_unpriv = "R1 pointer comparison",
 121		.result = REJECT,
 122	},
 123	{
 124		"test3 ld_imm64",
 125		.insns = {
 126			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1),
 127			BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0),
 128			BPF_LD_IMM64(BPF_REG_0, 0),
 129			BPF_LD_IMM64(BPF_REG_0, 0),
 130			BPF_LD_IMM64(BPF_REG_0, 1),
 131			BPF_LD_IMM64(BPF_REG_0, 1),
 132			BPF_EXIT_INSN(),
 133		},
 134		.errstr = "invalid bpf_ld_imm64 insn",
 135		.result = REJECT,
 136	},
 137	{
 138		"test4 ld_imm64",
 139		.insns = {
 140			BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0),
 141			BPF_EXIT_INSN(),
 142		},
 143		.errstr = "invalid bpf_ld_imm64 insn",
 144		.result = REJECT,
 145	},
 146	{
 147		"test5 ld_imm64",
 148		.insns = {
 149			BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0),
 150		},
 151		.errstr = "invalid bpf_ld_imm64 insn",
 152		.result = REJECT,
 153	},
 154	{
 155		"no bpf_exit",
 156		.insns = {
 157			BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2),
 158		},
 159		.errstr = "jump out of range",
 160		.result = REJECT,
 161	},
 162	{
 163		"loop (back-edge)",
 164		.insns = {
 165			BPF_JMP_IMM(BPF_JA, 0, 0, -1),
 166			BPF_EXIT_INSN(),
 167		},
 168		.errstr = "back-edge",
 169		.result = REJECT,
 170	},
 171	{
 172		"loop2 (back-edge)",
 173		.insns = {
 174			BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
 175			BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
 176			BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
 177			BPF_JMP_IMM(BPF_JA, 0, 0, -4),
 178			BPF_EXIT_INSN(),
 179		},
 180		.errstr = "back-edge",
 181		.result = REJECT,
 182	},
 183	{
 184		"conditional loop",
 185		.insns = {
 186			BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
 187			BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
 188			BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
 189			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3),
 190			BPF_EXIT_INSN(),
 191		},
 192		.errstr = "back-edge",
 193		.result = REJECT,
 194	},
 195	{
 196		"read uninitialized register",
 197		.insns = {
 198			BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
 199			BPF_EXIT_INSN(),
 200		},
 201		.errstr = "R2 !read_ok",
 202		.result = REJECT,
 203	},
 204	{
 205		"read invalid register",
 206		.insns = {
 207			BPF_MOV64_REG(BPF_REG_0, -1),
 208			BPF_EXIT_INSN(),
 209		},
 210		.errstr = "R15 is invalid",
 211		.result = REJECT,
 212	},
 213	{
 214		"program doesn't init R0 before exit",
 215		.insns = {
 216			BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_1),
 217			BPF_EXIT_INSN(),
 218		},
 219		.errstr = "R0 !read_ok",
 220		.result = REJECT,
 221	},
 222	{
 223		"program doesn't init R0 before exit in all branches",
 224		.insns = {
 225			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 226			BPF_MOV64_IMM(BPF_REG_0, 1),
 227			BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2),
 228			BPF_EXIT_INSN(),
 229		},
 230		.errstr = "R0 !read_ok",
 231		.errstr_unpriv = "R1 pointer comparison",
 232		.result = REJECT,
 233	},
 234	{
 235		"stack out of bounds",
 236		.insns = {
 237			BPF_ST_MEM(BPF_DW, BPF_REG_10, 8, 0),
 238			BPF_EXIT_INSN(),
 239		},
 240		.errstr = "invalid stack",
 241		.result = REJECT,
 242	},
 243	{
 244		"invalid call insn1",
 245		.insns = {
 246			BPF_RAW_INSN(BPF_JMP | BPF_CALL | BPF_X, 0, 0, 0, 0),
 247			BPF_EXIT_INSN(),
 248		},
 249		.errstr = "BPF_CALL uses reserved",
 250		.result = REJECT,
 251	},
 252	{
 253		"invalid call insn2",
 254		.insns = {
 255			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 1, 0),
 256			BPF_EXIT_INSN(),
 257		},
 258		.errstr = "BPF_CALL uses reserved",
 259		.result = REJECT,
 260	},
 261	{
 262		"invalid function call",
 263		.insns = {
 264			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 1234567),
 265			BPF_EXIT_INSN(),
 266		},
 267		.errstr = "invalid func 1234567",
 268		.result = REJECT,
 269	},
 270	{
 271		"uninitialized stack1",
 272		.insns = {
 273			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 274			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 275			BPF_LD_MAP_FD(BPF_REG_1, 0),
 276			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 277			BPF_EXIT_INSN(),
 278		},
 279		.fixup = {2},
 280		.errstr = "invalid indirect read from stack",
 281		.result = REJECT,
 282	},
 283	{
 284		"uninitialized stack2",
 285		.insns = {
 286			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 287			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -8),
 288			BPF_EXIT_INSN(),
 289		},
 290		.errstr = "invalid read from stack",
 291		.result = REJECT,
 292	},
 293	{
 294		"check valid spill/fill",
 295		.insns = {
 296			/* spill R1(ctx) into stack */
 297			BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
 298
 299			/* fill it back into R2 */
 300			BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8),
 301
 302			/* should be able to access R0 = *(R2 + 8) */
 303			/* BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8), */
 304			BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
 305			BPF_EXIT_INSN(),
 306		},
 307		.errstr_unpriv = "R0 leaks addr",
 308		.result = ACCEPT,
 309		.result_unpriv = REJECT,
 310	},
 311	{
 312		"check corrupted spill/fill",
 313		.insns = {
 314			/* spill R1(ctx) into stack */
 315			BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
 316
 317			/* mess up with R1 pointer on stack */
 318			BPF_ST_MEM(BPF_B, BPF_REG_10, -7, 0x23),
 319
 320			/* fill back into R0 should fail */
 321			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8),
 322
 323			BPF_EXIT_INSN(),
 324		},
 325		.errstr_unpriv = "attempt to corrupt spilled",
 326		.errstr = "corrupted spill",
 327		.result = REJECT,
 328	},
 329	{
 330		"invalid src register in STX",
 331		.insns = {
 332			BPF_STX_MEM(BPF_B, BPF_REG_10, -1, -1),
 333			BPF_EXIT_INSN(),
 334		},
 335		.errstr = "R15 is invalid",
 336		.result = REJECT,
 337	},
 338	{
 339		"invalid dst register in STX",
 340		.insns = {
 341			BPF_STX_MEM(BPF_B, 14, BPF_REG_10, -1),
 342			BPF_EXIT_INSN(),
 343		},
 344		.errstr = "R14 is invalid",
 345		.result = REJECT,
 346	},
 347	{
 348		"invalid dst register in ST",
 349		.insns = {
 350			BPF_ST_MEM(BPF_B, 14, -1, -1),
 351			BPF_EXIT_INSN(),
 352		},
 353		.errstr = "R14 is invalid",
 354		.result = REJECT,
 355	},
 356	{
 357		"invalid src register in LDX",
 358		.insns = {
 359			BPF_LDX_MEM(BPF_B, BPF_REG_0, 12, 0),
 360			BPF_EXIT_INSN(),
 361		},
 362		.errstr = "R12 is invalid",
 363		.result = REJECT,
 364	},
 365	{
 366		"invalid dst register in LDX",
 367		.insns = {
 368			BPF_LDX_MEM(BPF_B, 11, BPF_REG_1, 0),
 369			BPF_EXIT_INSN(),
 370		},
 371		.errstr = "R11 is invalid",
 372		.result = REJECT,
 373	},
 374	{
 375		"junk insn",
 376		.insns = {
 377			BPF_RAW_INSN(0, 0, 0, 0, 0),
 378			BPF_EXIT_INSN(),
 379		},
 380		.errstr = "invalid BPF_LD_IMM",
 381		.result = REJECT,
 382	},
 383	{
 384		"junk insn2",
 385		.insns = {
 386			BPF_RAW_INSN(1, 0, 0, 0, 0),
 387			BPF_EXIT_INSN(),
 388		},
 389		.errstr = "BPF_LDX uses reserved fields",
 390		.result = REJECT,
 391	},
 392	{
 393		"junk insn3",
 394		.insns = {
 395			BPF_RAW_INSN(-1, 0, 0, 0, 0),
 396			BPF_EXIT_INSN(),
 397		},
 398		.errstr = "invalid BPF_ALU opcode f0",
 399		.result = REJECT,
 400	},
 401	{
 402		"junk insn4",
 403		.insns = {
 404			BPF_RAW_INSN(-1, -1, -1, -1, -1),
 405			BPF_EXIT_INSN(),
 406		},
 407		.errstr = "invalid BPF_ALU opcode f0",
 408		.result = REJECT,
 409	},
 410	{
 411		"junk insn5",
 412		.insns = {
 413			BPF_RAW_INSN(0x7f, -1, -1, -1, -1),
 414			BPF_EXIT_INSN(),
 415		},
 416		.errstr = "BPF_ALU uses reserved fields",
 417		.result = REJECT,
 418	},
 419	{
 420		"misaligned read from stack",
 421		.insns = {
 422			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 423			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -4),
 424			BPF_EXIT_INSN(),
 425		},
 426		.errstr = "misaligned access",
 427		.result = REJECT,
 428	},
 429	{
 430		"invalid map_fd for function call",
 431		.insns = {
 432			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 433			BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10),
 434			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 435			BPF_LD_MAP_FD(BPF_REG_1, 0),
 436			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem),
 437			BPF_EXIT_INSN(),
 438		},
 439		.errstr = "fd 0 is not pointing to valid bpf_map",
 440		.result = REJECT,
 441	},
 442	{
 443		"don't check return value before access",
 444		.insns = {
 445			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 446			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 447			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 448			BPF_LD_MAP_FD(BPF_REG_1, 0),
 449			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 450			BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0),
 451			BPF_EXIT_INSN(),
 452		},
 453		.fixup = {3},
 454		.errstr = "R0 invalid mem access 'map_value_or_null'",
 455		.result = REJECT,
 456	},
 457	{
 458		"access memory with incorrect alignment",
 459		.insns = {
 460			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 461			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 462			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 463			BPF_LD_MAP_FD(BPF_REG_1, 0),
 464			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 465			BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
 466			BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0),
 467			BPF_EXIT_INSN(),
 468		},
 469		.fixup = {3},
 470		.errstr = "misaligned access",
 471		.result = REJECT,
 472	},
 473	{
 474		"sometimes access memory with incorrect alignment",
 475		.insns = {
 476			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 477			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 478			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 479			BPF_LD_MAP_FD(BPF_REG_1, 0),
 480			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 481			BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
 482			BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0),
 483			BPF_EXIT_INSN(),
 484			BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1),
 485			BPF_EXIT_INSN(),
 486		},
 487		.fixup = {3},
 488		.errstr = "R0 invalid mem access",
 489		.errstr_unpriv = "R0 leaks addr",
 490		.result = REJECT,
 491	},
 492	{
 493		"jump test 1",
 494		.insns = {
 495			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 496			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -8),
 497			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1),
 498			BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0),
 499			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 1),
 500			BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 1),
 501			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 1),
 502			BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 2),
 503			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 1),
 504			BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 3),
 505			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 1),
 506			BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 4),
 507			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1),
 508			BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 5),
 509			BPF_MOV64_IMM(BPF_REG_0, 0),
 510			BPF_EXIT_INSN(),
 511		},
 512		.errstr_unpriv = "R1 pointer comparison",
 513		.result_unpriv = REJECT,
 514		.result = ACCEPT,
 515	},
 516	{
 517		"jump test 2",
 518		.insns = {
 519			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 520			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2),
 521			BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0),
 522			BPF_JMP_IMM(BPF_JA, 0, 0, 14),
 523			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 2),
 524			BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0),
 525			BPF_JMP_IMM(BPF_JA, 0, 0, 11),
 526			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 2),
 527			BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0),
 528			BPF_JMP_IMM(BPF_JA, 0, 0, 8),
 529			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 2),
 530			BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0),
 531			BPF_JMP_IMM(BPF_JA, 0, 0, 5),
 532			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 2),
 533			BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0),
 534			BPF_JMP_IMM(BPF_JA, 0, 0, 2),
 535			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1),
 536			BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0),
 537			BPF_MOV64_IMM(BPF_REG_0, 0),
 538			BPF_EXIT_INSN(),
 539		},
 540		.errstr_unpriv = "R1 pointer comparison",
 541		.result_unpriv = REJECT,
 542		.result = ACCEPT,
 543	},
 544	{
 545		"jump test 3",
 546		.insns = {
 547			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 548			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3),
 549			BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0),
 550			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 551			BPF_JMP_IMM(BPF_JA, 0, 0, 19),
 552			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 3),
 553			BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0),
 554			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16),
 555			BPF_JMP_IMM(BPF_JA, 0, 0, 15),
 556			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 3),
 557			BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0),
 558			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -32),
 559			BPF_JMP_IMM(BPF_JA, 0, 0, 11),
 560			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 3),
 561			BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0),
 562			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -40),
 563			BPF_JMP_IMM(BPF_JA, 0, 0, 7),
 564			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 3),
 565			BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0),
 566			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48),
 567			BPF_JMP_IMM(BPF_JA, 0, 0, 3),
 568			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 0),
 569			BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0),
 570			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -56),
 571			BPF_LD_MAP_FD(BPF_REG_1, 0),
 572			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem),
 573			BPF_EXIT_INSN(),
 574		},
 575		.fixup = {24},
 576		.errstr_unpriv = "R1 pointer comparison",
 577		.result_unpriv = REJECT,
 578		.result = ACCEPT,
 579	},
 580	{
 581		"jump test 4",
 582		.insns = {
 583			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 584			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 585			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 586			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 587			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 588			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 589			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 590			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 591			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 592			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 593			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 594			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 595			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 596			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 597			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 598			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 599			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 600			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 601			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 602			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 603			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 604			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 605			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 606			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 607			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 608			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 609			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 610			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 611			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 612			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 613			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 614			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 615			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1),
 616			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2),
 617			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3),
 618			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4),
 619			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0),
 620			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0),
 621			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0),
 622			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0),
 623			BPF_MOV64_IMM(BPF_REG_0, 0),
 624			BPF_EXIT_INSN(),
 625		},
 626		.errstr_unpriv = "R1 pointer comparison",
 627		.result_unpriv = REJECT,
 628		.result = ACCEPT,
 629	},
 630	{
 631		"jump test 5",
 632		.insns = {
 633			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 634			BPF_MOV64_REG(BPF_REG_3, BPF_REG_2),
 635			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 636			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
 637			BPF_JMP_IMM(BPF_JA, 0, 0, 2),
 638			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
 639			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
 640			BPF_MOV64_IMM(BPF_REG_0, 0),
 641			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 642			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
 643			BPF_JMP_IMM(BPF_JA, 0, 0, 2),
 644			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
 645			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
 646			BPF_MOV64_IMM(BPF_REG_0, 0),
 647			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 648			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
 649			BPF_JMP_IMM(BPF_JA, 0, 0, 2),
 650			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
 651			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
 652			BPF_MOV64_IMM(BPF_REG_0, 0),
 653			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 654			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
 655			BPF_JMP_IMM(BPF_JA, 0, 0, 2),
 656			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
 657			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
 658			BPF_MOV64_IMM(BPF_REG_0, 0),
 659			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 660			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
 661			BPF_JMP_IMM(BPF_JA, 0, 0, 2),
 662			BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
 663			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
 664			BPF_MOV64_IMM(BPF_REG_0, 0),
 665			BPF_EXIT_INSN(),
 666		},
 667		.errstr_unpriv = "R1 pointer comparison",
 668		.result_unpriv = REJECT,
 669		.result = ACCEPT,
 670	},
 671	{
 672		"access skb fields ok",
 673		.insns = {
 674			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 675				    offsetof(struct __sk_buff, len)),
 676			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1),
 677			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 678				    offsetof(struct __sk_buff, mark)),
 679			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1),
 680			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 681				    offsetof(struct __sk_buff, pkt_type)),
 682			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1),
 683			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 684				    offsetof(struct __sk_buff, queue_mapping)),
 685			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
 686			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 687				    offsetof(struct __sk_buff, protocol)),
 688			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
 689			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 690				    offsetof(struct __sk_buff, vlan_present)),
 691			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
 692			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 693				    offsetof(struct __sk_buff, vlan_tci)),
 694			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
 695			BPF_EXIT_INSN(),
 696		},
 697		.result = ACCEPT,
 698	},
 699	{
 700		"access skb fields bad1",
 701		.insns = {
 702			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -4),
 703			BPF_EXIT_INSN(),
 704		},
 705		.errstr = "invalid bpf_context access",
 706		.result = REJECT,
 707	},
 708	{
 709		"access skb fields bad2",
 710		.insns = {
 711			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 9),
 712			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 713			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 714			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 715			BPF_LD_MAP_FD(BPF_REG_1, 0),
 716			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 717			BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
 718			BPF_EXIT_INSN(),
 719			BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
 720			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 721				    offsetof(struct __sk_buff, pkt_type)),
 722			BPF_EXIT_INSN(),
 723		},
 724		.fixup = {4},
 725		.errstr = "different pointers",
 726		.errstr_unpriv = "R1 pointer comparison",
 727		.result = REJECT,
 728	},
 729	{
 730		"access skb fields bad3",
 731		.insns = {
 732			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
 733			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 734				    offsetof(struct __sk_buff, pkt_type)),
 735			BPF_EXIT_INSN(),
 736			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 737			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 738			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 739			BPF_LD_MAP_FD(BPF_REG_1, 0),
 740			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 741			BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
 742			BPF_EXIT_INSN(),
 743			BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
 744			BPF_JMP_IMM(BPF_JA, 0, 0, -12),
 745		},
 746		.fixup = {6},
 747		.errstr = "different pointers",
 748		.errstr_unpriv = "R1 pointer comparison",
 749		.result = REJECT,
 750	},
 751	{
 752		"access skb fields bad4",
 753		.insns = {
 754			BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 3),
 755			BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
 756				    offsetof(struct __sk_buff, len)),
 757			BPF_MOV64_IMM(BPF_REG_0, 0),
 758			BPF_EXIT_INSN(),
 759			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 760			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
 761			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
 762			BPF_LD_MAP_FD(BPF_REG_1, 0),
 763			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
 764			BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
 765			BPF_EXIT_INSN(),
 766			BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
 767			BPF_JMP_IMM(BPF_JA, 0, 0, -13),
 768		},
 769		.fixup = {7},
 770		.errstr = "different pointers",
 771		.errstr_unpriv = "R1 pointer comparison",
 772		.result = REJECT,
 773	},
 774	{
 775		"check skb->mark is not writeable by sockets",
 776		.insns = {
 777			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
 778				    offsetof(struct __sk_buff, mark)),
 779			BPF_EXIT_INSN(),
 780		},
 781		.errstr = "invalid bpf_context access",
 782		.errstr_unpriv = "R1 leaks addr",
 783		.result = REJECT,
 784	},
 785	{
 786		"check skb->tc_index is not writeable by sockets",
 787		.insns = {
 788			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
 789				    offsetof(struct __sk_buff, tc_index)),
 790			BPF_EXIT_INSN(),
 791		},
 792		.errstr = "invalid bpf_context access",
 793		.errstr_unpriv = "R1 leaks addr",
 794		.result = REJECT,
 795	},
 796	{
 797		"check non-u32 access to cb",
 798		.insns = {
 799			BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_1,
 800				    offsetof(struct __sk_buff, cb[0])),
 801			BPF_EXIT_INSN(),
 802		},
 803		.errstr = "invalid bpf_context access",
 804		.errstr_unpriv = "R1 leaks addr",
 805		.result = REJECT,
 806	},
 807	{
 808		"check out of range skb->cb access",
 809		.insns = {
 810			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 811				    offsetof(struct __sk_buff, cb[0]) + 256),
 812			BPF_EXIT_INSN(),
 813		},
 814		.errstr = "invalid bpf_context access",
 815		.errstr_unpriv = "",
 816		.result = REJECT,
 817		.prog_type = BPF_PROG_TYPE_SCHED_ACT,
 818	},
 819	{
 820		"write skb fields from socket prog",
 821		.insns = {
 822			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 823				    offsetof(struct __sk_buff, cb[4])),
 824			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1),
 825			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 826				    offsetof(struct __sk_buff, mark)),
 827			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 828				    offsetof(struct __sk_buff, tc_index)),
 829			BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1),
 830			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
 831				    offsetof(struct __sk_buff, cb[0])),
 832			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
 833				    offsetof(struct __sk_buff, cb[2])),
 834			BPF_EXIT_INSN(),
 835		},
 836		.result = ACCEPT,
 837		.errstr_unpriv = "R1 leaks addr",
 838		.result_unpriv = REJECT,
 839	},
 840	{
 841		"write skb fields from tc_cls_act prog",
 842		.insns = {
 843			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 844				    offsetof(struct __sk_buff, cb[0])),
 845			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 846				    offsetof(struct __sk_buff, mark)),
 847			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 848				    offsetof(struct __sk_buff, tc_index)),
 849			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 850				    offsetof(struct __sk_buff, tc_index)),
 851			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 852				    offsetof(struct __sk_buff, cb[3])),
 853			BPF_EXIT_INSN(),
 854		},
 855		.errstr_unpriv = "",
 856		.result_unpriv = REJECT,
 857		.result = ACCEPT,
 858		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 859	},
 860	{
 861		"PTR_TO_STACK store/load",
 862		.insns = {
 863			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
 864			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10),
 865			BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c),
 866			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2),
 867			BPF_EXIT_INSN(),
 868		},
 869		.result = ACCEPT,
 870	},
 871	{
 872		"PTR_TO_STACK store/load - bad alignment on off",
 873		.insns = {
 874			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
 875			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
 876			BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c),
 877			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2),
 878			BPF_EXIT_INSN(),
 879		},
 880		.result = REJECT,
 881		.errstr = "misaligned access off -6 size 8",
 882	},
 883	{
 884		"PTR_TO_STACK store/load - bad alignment on reg",
 885		.insns = {
 886			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
 887			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10),
 888			BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c),
 889			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8),
 890			BPF_EXIT_INSN(),
 891		},
 892		.result = REJECT,
 893		.errstr = "misaligned access off -2 size 8",
 894	},
 895	{
 896		"PTR_TO_STACK store/load - out of bounds low",
 897		.insns = {
 898			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
 899			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -80000),
 900			BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c),
 901			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8),
 902			BPF_EXIT_INSN(),
 903		},
 904		.result = REJECT,
 905		.errstr = "invalid stack off=-79992 size=8",
 906	},
 907	{
 908		"PTR_TO_STACK store/load - out of bounds high",
 909		.insns = {
 910			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
 911			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
 912			BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c),
 913			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8),
 914			BPF_EXIT_INSN(),
 915		},
 916		.result = REJECT,
 917		.errstr = "invalid stack off=0 size=8",
 918	},
 919	{
 920		"unpriv: return pointer",
 921		.insns = {
 922			BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
 923			BPF_EXIT_INSN(),
 924		},
 925		.result = ACCEPT,
 926		.result_unpriv = REJECT,
 927		.errstr_unpriv = "R0 leaks addr",
 928	},
 929	{
 930		"unpriv: add const to pointer",
 931		.insns = {
 932			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
 933			BPF_MOV64_IMM(BPF_REG_0, 0),
 934			BPF_EXIT_INSN(),
 935		},
 936		.result = ACCEPT,
 937		.result_unpriv = REJECT,
 938		.errstr_unpriv = "R1 pointer arithmetic",
 939	},
 940	{
 941		"unpriv: add pointer to pointer",
 942		.insns = {
 943			BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_10),
 944			BPF_MOV64_IMM(BPF_REG_0, 0),
 945			BPF_EXIT_INSN(),
 946		},
 947		.result = ACCEPT,
 948		.result_unpriv = REJECT,
 949		.errstr_unpriv = "R1 pointer arithmetic",
 950	},
 951	{
 952		"unpriv: neg pointer",
 953		.insns = {
 954			BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
 955			BPF_MOV64_IMM(BPF_REG_0, 0),
 956			BPF_EXIT_INSN(),
 957		},
 958		.result = ACCEPT,
 959		.result_unpriv = REJECT,
 960		.errstr_unpriv = "R1 pointer arithmetic",
 961	},
 962	{
 963		"unpriv: cmp pointer with const",
 964		.insns = {
 965			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
 966			BPF_MOV64_IMM(BPF_REG_0, 0),
 967			BPF_EXIT_INSN(),
 968		},
 969		.result = ACCEPT,
 970		.result_unpriv = REJECT,
 971		.errstr_unpriv = "R1 pointer comparison",
 972	},
 973	{
 974		"unpriv: cmp pointer with pointer",
 975		.insns = {
 976			BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0),
 977			BPF_MOV64_IMM(BPF_REG_0, 0),
 978			BPF_EXIT_INSN(),
 979		},
 980		.result = ACCEPT,
 981		.result_unpriv = REJECT,
 982		.errstr_unpriv = "R10 pointer comparison",
 983	},
 984	{
 985		"unpriv: check that printk is disallowed",
 986		.insns = {
 987			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
 988			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
 989			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
 990			BPF_MOV64_IMM(BPF_REG_2, 8),
 991			BPF_MOV64_REG(BPF_REG_3, BPF_REG_1),
 992			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_trace_printk),
 993			BPF_MOV64_IMM(BPF_REG_0, 0),
 994			BPF_EXIT_INSN(),
 995		},
 996		.errstr_unpriv = "unknown func 6",
 997		.result_unpriv = REJECT,
 998		.result = ACCEPT,
 999	},
1000	{
1001		"unpriv: pass pointer to helper function",
1002		.insns = {
1003			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
1004			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1005			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1006			BPF_LD_MAP_FD(BPF_REG_1, 0),
1007			BPF_MOV64_REG(BPF_REG_3, BPF_REG_2),
1008			BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
1009			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem),
1010			BPF_MOV64_IMM(BPF_REG_0, 0),
1011			BPF_EXIT_INSN(),
1012		},
1013		.fixup = {3},
1014		.errstr_unpriv = "R4 leaks addr",
1015		.result_unpriv = REJECT,
1016		.result = ACCEPT,
1017	},
1018	{
1019		"unpriv: indirectly pass pointer on stack to helper function",
1020		.insns = {
1021			BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1022			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1023			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1024			BPF_LD_MAP_FD(BPF_REG_1, 0),
1025			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1026			BPF_MOV64_IMM(BPF_REG_0, 0),
1027			BPF_EXIT_INSN(),
1028		},
1029		.fixup = {3},
1030		.errstr = "invalid indirect read from stack off -8+0 size 8",
1031		.result = REJECT,
1032	},
1033	{
1034		"unpriv: mangle pointer on stack 1",
1035		.insns = {
1036			BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1037			BPF_ST_MEM(BPF_W, BPF_REG_10, -8, 0),
1038			BPF_MOV64_IMM(BPF_REG_0, 0),
1039			BPF_EXIT_INSN(),
1040		},
1041		.errstr_unpriv = "attempt to corrupt spilled",
1042		.result_unpriv = REJECT,
1043		.result = ACCEPT,
1044	},
1045	{
1046		"unpriv: mangle pointer on stack 2",
1047		.insns = {
1048			BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1049			BPF_ST_MEM(BPF_B, BPF_REG_10, -1, 0),
1050			BPF_MOV64_IMM(BPF_REG_0, 0),
1051			BPF_EXIT_INSN(),
1052		},
1053		.errstr_unpriv = "attempt to corrupt spilled",
1054		.result_unpriv = REJECT,
1055		.result = ACCEPT,
1056	},
1057	{
1058		"unpriv: read pointer from stack in small chunks",
1059		.insns = {
1060			BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8),
1061			BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_10, -8),
1062			BPF_MOV64_IMM(BPF_REG_0, 0),
1063			BPF_EXIT_INSN(),
1064		},
1065		.errstr = "invalid size",
1066		.result = REJECT,
1067	},
1068	{
1069		"unpriv: write pointer into ctx",
1070		.insns = {
1071			BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0),
1072			BPF_MOV64_IMM(BPF_REG_0, 0),
1073			BPF_EXIT_INSN(),
1074		},
1075		.errstr_unpriv = "R1 leaks addr",
1076		.result_unpriv = REJECT,
1077		.errstr = "invalid bpf_context access",
1078		.result = REJECT,
1079	},
1080	{
1081		"unpriv: write pointer into map elem value",
1082		.insns = {
1083			BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
1084			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1085			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1086			BPF_LD_MAP_FD(BPF_REG_1, 0),
1087			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1088			BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
1089			BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
1090			BPF_EXIT_INSN(),
1091		},
1092		.fixup = {3},
1093		.errstr_unpriv = "R0 leaks addr",
1094		.result_unpriv = REJECT,
1095		.result = ACCEPT,
1096	},
1097	{
1098		"unpriv: partial copy of pointer",
1099		.insns = {
1100			BPF_MOV32_REG(BPF_REG_1, BPF_REG_10),
1101			BPF_MOV64_IMM(BPF_REG_0, 0),
1102			BPF_EXIT_INSN(),
1103		},
1104		.errstr_unpriv = "R10 partial copy",
1105		.result_unpriv = REJECT,
1106		.result = ACCEPT,
1107	},
1108	{
1109		"unpriv: pass pointer to tail_call",
1110		.insns = {
1111			BPF_MOV64_REG(BPF_REG_3, BPF_REG_1),
1112			BPF_LD_MAP_FD(BPF_REG_2, 0),
1113			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call),
1114			BPF_MOV64_IMM(BPF_REG_0, 0),
1115			BPF_EXIT_INSN(),
1116		},
1117		.prog_array_fixup = {1},
1118		.errstr_unpriv = "R3 leaks addr into helper",
1119		.result_unpriv = REJECT,
1120		.result = ACCEPT,
1121	},
1122	{
1123		"unpriv: cmp map pointer with zero",
1124		.insns = {
1125			BPF_MOV64_IMM(BPF_REG_1, 0),
1126			BPF_LD_MAP_FD(BPF_REG_1, 0),
1127			BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
1128			BPF_MOV64_IMM(BPF_REG_0, 0),
1129			BPF_EXIT_INSN(),
1130		},
1131		.fixup = {1},
1132		.errstr_unpriv = "R1 pointer comparison",
1133		.result_unpriv = REJECT,
1134		.result = ACCEPT,
1135	},
1136	{
1137		"unpriv: write into frame pointer",
1138		.insns = {
1139			BPF_MOV64_REG(BPF_REG_10, BPF_REG_1),
1140			BPF_MOV64_IMM(BPF_REG_0, 0),
1141			BPF_EXIT_INSN(),
1142		},
1143		.errstr = "frame pointer is read only",
1144		.result = REJECT,
1145	},
1146	{
1147		"unpriv: cmp of frame pointer",
1148		.insns = {
1149			BPF_JMP_IMM(BPF_JEQ, BPF_REG_10, 0, 0),
1150			BPF_MOV64_IMM(BPF_REG_0, 0),
1151			BPF_EXIT_INSN(),
1152		},
1153		.errstr_unpriv = "R10 pointer comparison",
1154		.result_unpriv = REJECT,
1155		.result = ACCEPT,
1156	},
1157	{
1158		"unpriv: cmp of stack pointer",
1159		.insns = {
1160			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1161			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1162			BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 0),
1163			BPF_MOV64_IMM(BPF_REG_0, 0),
1164			BPF_EXIT_INSN(),
1165		},
1166		.errstr_unpriv = "R2 pointer comparison",
1167		.result_unpriv = REJECT,
1168		.result = ACCEPT,
1169	},
1170	{
1171		"unpriv: obfuscate stack pointer",
1172		.insns = {
1173			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
1174			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1175			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
1176			BPF_MOV64_IMM(BPF_REG_0, 0),
1177			BPF_EXIT_INSN(),
1178		},
1179		.errstr_unpriv = "R2 pointer arithmetic",
1180		.result_unpriv = REJECT,
1181		.result = ACCEPT,
1182	},
1183};
1184
1185static int probe_filter_length(struct bpf_insn *fp)
1186{
1187	int len = 0;
1188
1189	for (len = MAX_INSNS - 1; len > 0; --len)
1190		if (fp[len].code != 0 || fp[len].imm != 0)
1191			break;
1192
1193	return len + 1;
1194}
1195
1196static int create_map(void)
1197{
1198	int map_fd;
1199
1200	map_fd = bpf_create_map(BPF_MAP_TYPE_HASH,
1201				sizeof(long long), sizeof(long long), 1024, 0);
1202	if (map_fd < 0)
1203		printf("failed to create map '%s'\n", strerror(errno));
1204
1205	return map_fd;
1206}
1207
1208static int create_prog_array(void)
1209{
1210	int map_fd;
1211
1212	map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY,
1213				sizeof(int), sizeof(int), 4, 0);
1214	if (map_fd < 0)
1215		printf("failed to create prog_array '%s'\n", strerror(errno));
1216
1217	return map_fd;
1218}
1219
1220static int test(void)
1221{
1222	int prog_fd, i, pass_cnt = 0, err_cnt = 0;
1223	bool unpriv = geteuid() != 0;
1224
1225	for (i = 0; i < ARRAY_SIZE(tests); i++) {
1226		struct bpf_insn *prog = tests[i].insns;
1227		int prog_type = tests[i].prog_type;
1228		int prog_len = probe_filter_length(prog);
1229		int *fixup = tests[i].fixup;
1230		int *prog_array_fixup = tests[i].prog_array_fixup;
1231		int expected_result;
1232		const char *expected_errstr;
1233		int map_fd = -1, prog_array_fd = -1;
1234
1235		if (*fixup) {
1236			map_fd = create_map();
1237
1238			do {
1239				prog[*fixup].imm = map_fd;
1240				fixup++;
1241			} while (*fixup);
1242		}
1243		if (*prog_array_fixup) {
1244			prog_array_fd = create_prog_array();
1245
1246			do {
1247				prog[*prog_array_fixup].imm = prog_array_fd;
1248				prog_array_fixup++;
1249			} while (*prog_array_fixup);
1250		}
1251		printf("#%d %s ", i, tests[i].descr);
1252
1253		prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER,
1254					prog, prog_len * sizeof(struct bpf_insn),
1255					"GPL", 0);
1256
1257		if (unpriv && tests[i].result_unpriv != UNDEF)
1258			expected_result = tests[i].result_unpriv;
1259		else
1260			expected_result = tests[i].result;
1261
1262		if (unpriv && tests[i].errstr_unpriv)
1263			expected_errstr = tests[i].errstr_unpriv;
1264		else
1265			expected_errstr = tests[i].errstr;
1266
1267		if (expected_result == ACCEPT) {
1268			if (prog_fd < 0) {
1269				printf("FAIL\nfailed to load prog '%s'\n",
1270				       strerror(errno));
1271				printf("%s", bpf_log_buf);
1272				err_cnt++;
1273				goto fail;
1274			}
1275		} else {
1276			if (prog_fd >= 0) {
1277				printf("FAIL\nunexpected success to load\n");
1278				printf("%s", bpf_log_buf);
1279				err_cnt++;
1280				goto fail;
1281			}
1282			if (strstr(bpf_log_buf, expected_errstr) == 0) {
1283				printf("FAIL\nunexpected error message: %s",
1284				       bpf_log_buf);
1285				err_cnt++;
1286				goto fail;
1287			}
1288		}
1289
1290		pass_cnt++;
1291		printf("OK\n");
1292fail:
1293		if (map_fd >= 0)
1294			close(map_fd);
1295		if (prog_array_fd >= 0)
1296			close(prog_array_fd);
1297		close(prog_fd);
1298
1299	}
1300	printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt);
1301
1302	return 0;
1303}
1304
1305int main(void)
1306{
1307	struct rlimit r = {1 << 20, 1 << 20};
1308
1309	setrlimit(RLIMIT_MEMLOCK, &r);
1310	return test();
1311}