1*3ce6b424SNuoqi Gui // SPDX-License-Identifier: GPL-2.0 2*3ce6b424SNuoqi Gui /* Bounds checks for PTR_TO_FLOW_KEYS pointer arithmetic. */ 3*3ce6b424SNuoqi Gui 4*3ce6b424SNuoqi Gui #include "vmlinux.h" 5*3ce6b424SNuoqi Gui #include <bpf/bpf_helpers.h> 6*3ce6b424SNuoqi Gui #include "bpf_misc.h" 7*3ce6b424SNuoqi Gui 8*3ce6b424SNuoqi Gui /* sizeof(struct bpf_flow_keys) is well under 4096, so +0x1000 is OOB. */ 9*3ce6b424SNuoqi Gui 10*3ce6b424SNuoqi Gui SEC("flow_dissector") 11*3ce6b424SNuoqi Gui __description("flow_keys: in-bounds constant pointer arithmetic accepted") 12*3ce6b424SNuoqi Gui __success 13*3ce6b424SNuoqi Gui __naked void flow_keys_const_inbounds(void) 14*3ce6b424SNuoqi Gui { 15*3ce6b424SNuoqi Gui asm volatile (" \ 16*3ce6b424SNuoqi Gui r1 = *(u64 *)(r1 + %[flow_keys]); \ 17*3ce6b424SNuoqi Gui r1 += 8; \ 18*3ce6b424SNuoqi Gui r0 = *(u64 *)(r1 + 0); \ 19*3ce6b424SNuoqi Gui r0 = 0; \ 20*3ce6b424SNuoqi Gui exit; \ 21*3ce6b424SNuoqi Gui " : 22*3ce6b424SNuoqi Gui : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) 23*3ce6b424SNuoqi Gui : __clobber_all); 24*3ce6b424SNuoqi Gui } 25*3ce6b424SNuoqi Gui 26*3ce6b424SNuoqi Gui SEC("flow_dissector") 27*3ce6b424SNuoqi Gui __description("flow_keys: OOB via constant pointer arithmetic rejected") 28*3ce6b424SNuoqi Gui __failure __msg("invalid access to flow keys off=4096 size=8") 29*3ce6b424SNuoqi Gui __naked void flow_keys_const_oob_read(void) 30*3ce6b424SNuoqi Gui { 31*3ce6b424SNuoqi Gui asm volatile (" \ 32*3ce6b424SNuoqi Gui r1 = *(u64 *)(r1 + %[flow_keys]); \ 33*3ce6b424SNuoqi Gui r1 += 4096; \ 34*3ce6b424SNuoqi Gui r0 = *(u64 *)(r1 + 0); \ 35*3ce6b424SNuoqi Gui r0 = 0; \ 36*3ce6b424SNuoqi Gui exit; \ 37*3ce6b424SNuoqi Gui " : 38*3ce6b424SNuoqi Gui : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) 39*3ce6b424SNuoqi Gui : __clobber_all); 40*3ce6b424SNuoqi Gui } 41*3ce6b424SNuoqi Gui 42*3ce6b424SNuoqi Gui SEC("flow_dissector") 43*3ce6b424SNuoqi Gui __description("flow_keys: OOB write via constant pointer arithmetic rejected") 44*3ce6b424SNuoqi Gui __failure __msg("invalid access to flow keys off=4096 size=8") 45*3ce6b424SNuoqi Gui __naked void flow_keys_const_oob_write(void) 46*3ce6b424SNuoqi Gui { 47*3ce6b424SNuoqi Gui asm volatile (" \ 48*3ce6b424SNuoqi Gui r1 = *(u64 *)(r1 + %[flow_keys]); \ 49*3ce6b424SNuoqi Gui r1 += 4096; \ 50*3ce6b424SNuoqi Gui r2 = 0; \ 51*3ce6b424SNuoqi Gui *(u64 *)(r1 + 0) = r2; \ 52*3ce6b424SNuoqi Gui r0 = 0; \ 53*3ce6b424SNuoqi Gui exit; \ 54*3ce6b424SNuoqi Gui " : 55*3ce6b424SNuoqi Gui : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) 56*3ce6b424SNuoqi Gui : __clobber_all); 57*3ce6b424SNuoqi Gui } 58*3ce6b424SNuoqi Gui 59*3ce6b424SNuoqi Gui /* Equivalent OOB expressed directly in insn->off; this form was always 60*3ce6b424SNuoqi Gui * rejected and is kept to show both forms now share one diagnostic. 61*3ce6b424SNuoqi Gui */ 62*3ce6b424SNuoqi Gui SEC("flow_dissector") 63*3ce6b424SNuoqi Gui __description("flow_keys: OOB via insn->off rejected") 64*3ce6b424SNuoqi Gui __failure __msg("invalid access to flow keys off=4096 size=8") 65*3ce6b424SNuoqi Gui __naked void flow_keys_insn_off_oob(void) 66*3ce6b424SNuoqi Gui { 67*3ce6b424SNuoqi Gui asm volatile (" \ 68*3ce6b424SNuoqi Gui r1 = *(u64 *)(r1 + %[flow_keys]); \ 69*3ce6b424SNuoqi Gui r0 = *(u64 *)(r1 + 4096); \ 70*3ce6b424SNuoqi Gui r0 = 0; \ 71*3ce6b424SNuoqi Gui exit; \ 72*3ce6b424SNuoqi Gui " : 73*3ce6b424SNuoqi Gui : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) 74*3ce6b424SNuoqi Gui : __clobber_all); 75*3ce6b424SNuoqi Gui } 76*3ce6b424SNuoqi Gui 77*3ce6b424SNuoqi Gui SEC("flow_dissector") 78*3ce6b424SNuoqi Gui __description("flow_keys: variable pointer arithmetic rejected") 79*3ce6b424SNuoqi Gui __failure __msg("R1 pointer arithmetic on flow_keys prohibited") 80*3ce6b424SNuoqi Gui __naked void flow_keys_var_read(void) 81*3ce6b424SNuoqi Gui { 82*3ce6b424SNuoqi Gui asm volatile (" \ 83*3ce6b424SNuoqi Gui r6 = r1; \ 84*3ce6b424SNuoqi Gui call %[bpf_get_prandom_u32]; \ 85*3ce6b424SNuoqi Gui r0 &= 0xFFFF; \ 86*3ce6b424SNuoqi Gui r1 = *(u64 *)(r6 + %[flow_keys]); \ 87*3ce6b424SNuoqi Gui r1 += r0; \ 88*3ce6b424SNuoqi Gui r0 = *(u64 *)(r1 + 0); \ 89*3ce6b424SNuoqi Gui r0 = 0; \ 90*3ce6b424SNuoqi Gui exit; \ 91*3ce6b424SNuoqi Gui " : 92*3ce6b424SNuoqi Gui : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)), 93*3ce6b424SNuoqi Gui __imm(bpf_get_prandom_u32) 94*3ce6b424SNuoqi Gui : __clobber_all); 95*3ce6b424SNuoqi Gui } 96*3ce6b424SNuoqi Gui 97*3ce6b424SNuoqi Gui char _license[] SEC("license") = "GPL"; 98