brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · d47e59a Raw
427 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2022 Facebook */3 4#include <errno.h>5#include <string.h>6#include <linux/bpf.h>7#include <bpf/bpf_helpers.h>8#include "bpf_misc.h"9 10char _license[] SEC("license") = "GPL";11 12#define ITER_HELPERS						\13	  __imm(bpf_iter_num_new),				\14	  __imm(bpf_iter_num_next),				\15	  __imm(bpf_iter_num_destroy)16 17SEC("?raw_tp")18__success19int force_clang_to_emit_btf_for_externs(void *ctx)20{21	/* we need this as a workaround to enforce compiler emitting BTF22	 * information for bpf_iter_num_{new,next,destroy}() kfuncs,23	 * as, apparently, it doesn't emit it for symbols only referenced from24	 * assembly (or cleanup attribute, for that matter, as well)25	 */26	bpf_repeat(0);27 28	return 0;29}30 31SEC("?raw_tp")32__success __log_level(2)33__msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")34int create_and_destroy(void *ctx)35{36	struct bpf_iter_num iter;37 38	asm volatile (39		/* create iterator */40		"r1 = %[iter];"41		"r2 = 0;"42		"r3 = 1000;"43		"call %[bpf_iter_num_new];"44		/* destroy iterator */45		"r1 = %[iter];"46		"call %[bpf_iter_num_destroy];"47		:48		: __imm_ptr(iter), ITER_HELPERS49		: __clobber_common50	);51 52	return 0;53}54 55SEC("?raw_tp")56__failure __msg("Unreleased reference id=1")57int create_and_forget_to_destroy_fail(void *ctx)58{59	struct bpf_iter_num iter;60 61	asm volatile (62		/* create iterator */63		"r1 = %[iter];"64		"r2 = 0;"65		"r3 = 1000;"66		"call %[bpf_iter_num_new];"67		:68		: __imm_ptr(iter), ITER_HELPERS69		: __clobber_common70	);71 72	return 0;73}74 75SEC("?raw_tp")76__failure __msg("expected an initialized iter_num as arg #1")77int destroy_without_creating_fail(void *ctx)78{79	/* init with zeros to stop verifier complaining about uninit stack */80	struct bpf_iter_num iter;81 82	asm volatile (83		"r1 = %[iter];"84		"call %[bpf_iter_num_destroy];"85		:86		: __imm_ptr(iter), ITER_HELPERS87		: __clobber_common88	);89 90	return 0;91}92 93SEC("?raw_tp")94__failure __msg("expected an initialized iter_num as arg #1")95int compromise_iter_w_direct_write_fail(void *ctx)96{97	struct bpf_iter_num iter;98 99	asm volatile (100		/* create iterator */101		"r1 = %[iter];"102		"r2 = 0;"103		"r3 = 1000;"104		"call %[bpf_iter_num_new];"105 106		/* directly write over first half of iter state */107		"*(u64 *)(%[iter] + 0) = r0;"108 109		/* (attempt to) destroy iterator */110		"r1 = %[iter];"111		"call %[bpf_iter_num_destroy];"112		:113		: __imm_ptr(iter), ITER_HELPERS114		: __clobber_common115	);116 117	return 0;118}119 120SEC("?raw_tp")121__failure __msg("Unreleased reference id=1")122int compromise_iter_w_direct_write_and_skip_destroy_fail(void *ctx)123{124	struct bpf_iter_num iter;125 126	asm volatile (127		/* create iterator */128		"r1 = %[iter];"129		"r2 = 0;"130		"r3 = 1000;"131		"call %[bpf_iter_num_new];"132 133		/* directly write over first half of iter state */134		"*(u64 *)(%[iter] + 0) = r0;"135 136		/* don't destroy iter, leaking ref, which should fail */137		:138		: __imm_ptr(iter), ITER_HELPERS139		: __clobber_common140	);141 142	return 0;143}144 145SEC("?raw_tp")146__failure __msg("expected an initialized iter_num as arg #1")147int compromise_iter_w_helper_write_fail(void *ctx)148{149	struct bpf_iter_num iter;150 151	asm volatile (152		/* create iterator */153		"r1 = %[iter];"154		"r2 = 0;"155		"r3 = 1000;"156		"call %[bpf_iter_num_new];"157 158		/* overwrite 8th byte with bpf_probe_read_kernel() */159		"r1 = %[iter];"160		"r1 += 7;"161		"r2 = 1;"162		"r3 = 0;" /* NULL */163		"call %[bpf_probe_read_kernel];"164 165		/* (attempt to) destroy iterator */166		"r1 = %[iter];"167		"call %[bpf_iter_num_destroy];"168		:169		: __imm_ptr(iter), ITER_HELPERS, __imm(bpf_probe_read_kernel)170		: __clobber_common171	);172 173	return 0;174}175 176static __noinline void subprog_with_iter(void)177{178	struct bpf_iter_num iter;179 180	bpf_iter_num_new(&iter, 0, 1);181 182	return;183}184 185SEC("?raw_tp")186__failure187/* ensure there was a call to subprog, which might happen without __noinline */188__msg("returning from callee:")189__msg("Unreleased reference id=1")190int leak_iter_from_subprog_fail(void *ctx)191{192	subprog_with_iter();193 194	return 0;195}196 197SEC("?raw_tp")198__success __log_level(2)199__msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")200int valid_stack_reuse(void *ctx)201{202	struct bpf_iter_num iter;203 204	asm volatile (205		/* create iterator */206		"r1 = %[iter];"207		"r2 = 0;"208		"r3 = 1000;"209		"call %[bpf_iter_num_new];"210		/* destroy iterator */211		"r1 = %[iter];"212		"call %[bpf_iter_num_destroy];"213 214		/* now reuse same stack slots */215 216		/* create iterator */217		"r1 = %[iter];"218		"r2 = 0;"219		"r3 = 1000;"220		"call %[bpf_iter_num_new];"221		/* destroy iterator */222		"r1 = %[iter];"223		"call %[bpf_iter_num_destroy];"224		:225		: __imm_ptr(iter), ITER_HELPERS226		: __clobber_common227	);228 229	return 0;230}231 232SEC("?raw_tp")233__failure __msg("expected uninitialized iter_num as arg #1")234int double_create_fail(void *ctx)235{236	struct bpf_iter_num iter;237 238	asm volatile (239		/* create iterator */240		"r1 = %[iter];"241		"r2 = 0;"242		"r3 = 1000;"243		"call %[bpf_iter_num_new];"244		/* (attempt to) create iterator again */245		"r1 = %[iter];"246		"r2 = 0;"247		"r3 = 1000;"248		"call %[bpf_iter_num_new];"249		/* destroy iterator */250		"r1 = %[iter];"251		"call %[bpf_iter_num_destroy];"252		:253		: __imm_ptr(iter), ITER_HELPERS254		: __clobber_common255	);256 257	return 0;258}259 260SEC("?raw_tp")261__failure __msg("expected an initialized iter_num as arg #1")262int double_destroy_fail(void *ctx)263{264	struct bpf_iter_num iter;265 266	asm volatile (267		/* create iterator */268		"r1 = %[iter];"269		"r2 = 0;"270		"r3 = 1000;"271		"call %[bpf_iter_num_new];"272		/* destroy iterator */273		"r1 = %[iter];"274		"call %[bpf_iter_num_destroy];"275		/* (attempt to) destroy iterator again */276		"r1 = %[iter];"277		"call %[bpf_iter_num_destroy];"278		:279		: __imm_ptr(iter), ITER_HELPERS280		: __clobber_common281	);282 283	return 0;284}285 286SEC("?raw_tp")287__failure __msg("expected an initialized iter_num as arg #1")288int next_without_new_fail(void *ctx)289{290	struct bpf_iter_num iter;291 292	asm volatile (293		/* don't create iterator and try to iterate*/294		"r1 = %[iter];"295		"call %[bpf_iter_num_next];"296		/* destroy iterator */297		"r1 = %[iter];"298		"call %[bpf_iter_num_destroy];"299		:300		: __imm_ptr(iter), ITER_HELPERS301		: __clobber_common302	);303 304	return 0;305}306 307SEC("?raw_tp")308__failure __msg("expected an initialized iter_num as arg #1")309int next_after_destroy_fail(void *ctx)310{311	struct bpf_iter_num iter;312 313	asm volatile (314		/* create iterator */315		"r1 = %[iter];"316		"r2 = 0;"317		"r3 = 1000;"318		"call %[bpf_iter_num_new];"319		/* destroy iterator */320		"r1 = %[iter];"321		"call %[bpf_iter_num_destroy];"322		/* don't create iterator and try to iterate*/323		"r1 = %[iter];"324		"call %[bpf_iter_num_next];"325		:326		: __imm_ptr(iter), ITER_HELPERS327		: __clobber_common328	);329 330	return 0;331}332 333SEC("?raw_tp")334__failure __msg("invalid read from stack")335int __naked read_from_iter_slot_fail(void)336{337	asm volatile (338		/* r6 points to struct bpf_iter_num on the stack */339		"r6 = r10;"340		"r6 += -24;"341 342		/* create iterator */343		"r1 = r6;"344		"r2 = 0;"345		"r3 = 1000;"346		"call %[bpf_iter_num_new];"347 348		/* attemp to leak bpf_iter_num state */349		"r7 = *(u64 *)(r6 + 0);"350		"r8 = *(u64 *)(r6 + 8);"351 352		/* destroy iterator */353		"r1 = r6;"354		"call %[bpf_iter_num_destroy];"355 356		/* leak bpf_iter_num state */357		"r0 = r7;"358		"if r7 > r8 goto +1;"359		"r0 = r8;"360		"exit;"361		:362		: ITER_HELPERS363		: __clobber_common, "r6", "r7", "r8"364	);365}366 367int zero;368 369SEC("?raw_tp")370__failure371__flag(BPF_F_TEST_STATE_FREQ)372__msg("Unreleased reference")373int stacksafe_should_not_conflate_stack_spill_and_iter(void *ctx)374{375	struct bpf_iter_num iter;376 377	asm volatile (378		/* Create a fork in logic, with general setup as follows:379		 *   - fallthrough (first) path is valid;380		 *   - branch (second) path is invalid.381		 * Then depending on what we do in fallthrough vs branch path,382		 * we try to detect bugs in func_states_equal(), regsafe(),383		 * refsafe(), stack_safe(), and similar by tricking verifier384		 * into believing that branch state is a valid subset of385		 * a fallthrough state. Verifier should reject overall386		 * validation, unless there is a bug somewhere in verifier387		 * logic.388		 */389		"call %[bpf_get_prandom_u32];"390		"r6 = r0;"391		"call %[bpf_get_prandom_u32];"392		"r7 = r0;"393 394		"if r6 > r7 goto bad;" /* fork */395 396		/* spill r6 into stack slot of bpf_iter_num var */397		"*(u64 *)(%[iter] + 0) = r6;"398 399		"goto skip_bad;"400 401	"bad:"402		/* create iterator in the same stack slot */403		"r1 = %[iter];"404		"r2 = 0;"405		"r3 = 1000;"406		"call %[bpf_iter_num_new];"407 408		/* but then forget about it and overwrite it back to r6 spill */409		"*(u64 *)(%[iter] + 0) = r6;"410 411	"skip_bad:"412		"goto +0;" /* force checkpoint */413 414		/* corrupt stack slots, if they are really dynptr */415		"*(u64 *)(%[iter] + 0) = r6;"416		:417		: __imm_ptr(iter),418		  __imm_addr(zero),419		  __imm(bpf_get_prandom_u32),420		  __imm(bpf_dynptr_from_mem),421		  ITER_HELPERS422		: __clobber_common, "r6", "r7"423	);424 425	return 0;426}427