214 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Converted from tools/testing/selftests/bpf/verifier/jeq_infer_not_null.c */3 4#include <linux/bpf.h>5#include <bpf/bpf_helpers.h>6#include "bpf_misc.h"7 8struct {9 __uint(type, BPF_MAP_TYPE_XSKMAP);10 __uint(max_entries, 1);11 __type(key, int);12 __type(value, int);13} map_xskmap SEC(".maps");14 15/* This is equivalent to the following program:16 *17 * r6 = skb->sk;18 * r7 = sk_fullsock(r6);19 * r0 = sk_fullsock(r6);20 * if (r0 == 0) return 0; (a)21 * if (r0 != r7) return 0; (b)22 * *r7->type; (c)23 * return 0;24 *25 * It is safe to dereference r7 at point (c), because of (a) and (b).26 * The test verifies that relation r0 == r7 is propagated from (b) to (c).27 */28SEC("cgroup/skb")29__description("jne/jeq infer not null, PTR_TO_SOCKET_OR_NULL -> PTR_TO_SOCKET for JNE false branch")30__success __failure_unpriv __msg_unpriv("R7 pointer comparison")31__retval(0)32__naked void socket_for_jne_false_branch(void)33{34 asm volatile (" \35 /* r6 = skb->sk; */ \36 r6 = *(u64*)(r1 + %[__sk_buff_sk]); \37 /* if (r6 == 0) return 0; */ \38 if r6 == 0 goto l0_%=; \39 /* r7 = sk_fullsock(skb); */ \40 r1 = r6; \41 call %[bpf_sk_fullsock]; \42 r7 = r0; \43 /* r0 = sk_fullsock(skb); */ \44 r1 = r6; \45 call %[bpf_sk_fullsock]; \46 /* if (r0 == null) return 0; */ \47 if r0 == 0 goto l0_%=; \48 /* if (r0 == r7) r0 = *(r7->type); */ \49 if r0 != r7 goto l0_%=; /* Use ! JNE ! */\50 r0 = *(u32*)(r7 + %[bpf_sock_type]); \51l0_%=: /* return 0 */ \52 r0 = 0; \53 exit; \54" :55 : __imm(bpf_sk_fullsock),56 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),57 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))58 : __clobber_all);59}60 61/* Same as above, but verify that another branch of JNE still62 * prohibits access to PTR_MAYBE_NULL.63 */64SEC("cgroup/skb")65__description("jne/jeq infer not null, PTR_TO_SOCKET_OR_NULL unchanged for JNE true branch")66__failure __msg("R7 invalid mem access 'sock_or_null'")67__failure_unpriv __msg_unpriv("R7 pointer comparison")68__naked void unchanged_for_jne_true_branch(void)69{70 asm volatile (" \71 /* r6 = skb->sk */ \72 r6 = *(u64*)(r1 + %[__sk_buff_sk]); \73 /* if (r6 == 0) return 0; */ \74 if r6 == 0 goto l0_%=; \75 /* r7 = sk_fullsock(skb); */ \76 r1 = r6; \77 call %[bpf_sk_fullsock]; \78 r7 = r0; \79 /* r0 = sk_fullsock(skb); */ \80 r1 = r6; \81 call %[bpf_sk_fullsock]; \82 /* if (r0 == null) return 0; */ \83 if r0 != 0 goto l0_%=; \84 /* if (r0 == r7) return 0; */ \85 if r0 != r7 goto l1_%=; /* Use ! JNE ! */\86 goto l0_%=; \87l1_%=: /* r0 = *(r7->type); */ \88 r0 = *(u32*)(r7 + %[bpf_sock_type]); \89l0_%=: /* return 0 */ \90 r0 = 0; \91 exit; \92" :93 : __imm(bpf_sk_fullsock),94 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),95 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))96 : __clobber_all);97}98 99/* Same as a first test, but not null should be inferred for JEQ branch */100SEC("cgroup/skb")101__description("jne/jeq infer not null, PTR_TO_SOCKET_OR_NULL -> PTR_TO_SOCKET for JEQ true branch")102__success __failure_unpriv __msg_unpriv("R7 pointer comparison")103__retval(0)104__naked void socket_for_jeq_true_branch(void)105{106 asm volatile (" \107 /* r6 = skb->sk; */ \108 r6 = *(u64*)(r1 + %[__sk_buff_sk]); \109 /* if (r6 == null) return 0; */ \110 if r6 == 0 goto l0_%=; \111 /* r7 = sk_fullsock(skb); */ \112 r1 = r6; \113 call %[bpf_sk_fullsock]; \114 r7 = r0; \115 /* r0 = sk_fullsock(skb); */ \116 r1 = r6; \117 call %[bpf_sk_fullsock]; \118 /* if (r0 == null) return 0; */ \119 if r0 == 0 goto l0_%=; \120 /* if (r0 != r7) return 0; */ \121 if r0 == r7 goto l1_%=; /* Use ! JEQ ! */\122 goto l0_%=; \123l1_%=: /* r0 = *(r7->type); */ \124 r0 = *(u32*)(r7 + %[bpf_sock_type]); \125l0_%=: /* return 0; */ \126 r0 = 0; \127 exit; \128" :129 : __imm(bpf_sk_fullsock),130 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),131 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))132 : __clobber_all);133}134 135/* Same as above, but verify that another branch of JNE still136 * prohibits access to PTR_MAYBE_NULL.137 */138SEC("cgroup/skb")139__description("jne/jeq infer not null, PTR_TO_SOCKET_OR_NULL unchanged for JEQ false branch")140__failure __msg("R7 invalid mem access 'sock_or_null'")141__failure_unpriv __msg_unpriv("R7 pointer comparison")142__naked void unchanged_for_jeq_false_branch(void)143{144 asm volatile (" \145 /* r6 = skb->sk; */ \146 r6 = *(u64*)(r1 + %[__sk_buff_sk]); \147 /* if (r6 == null) return 0; */ \148 if r6 == 0 goto l0_%=; \149 /* r7 = sk_fullsock(skb); */ \150 r1 = r6; \151 call %[bpf_sk_fullsock]; \152 r7 = r0; \153 /* r0 = sk_fullsock(skb); */ \154 r1 = r6; \155 call %[bpf_sk_fullsock]; \156 /* if (r0 == null) return 0; */ \157 if r0 == 0 goto l0_%=; \158 /* if (r0 != r7) r0 = *(r7->type); */ \159 if r0 == r7 goto l0_%=; /* Use ! JEQ ! */\160 r0 = *(u32*)(r7 + %[bpf_sock_type]); \161l0_%=: /* return 0; */ \162 r0 = 0; \163 exit; \164" :165 : __imm(bpf_sk_fullsock),166 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),167 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))168 : __clobber_all);169}170 171/* Maps are treated in a different branch of `mark_ptr_not_null_reg`,172 * so separate test for maps case.173 */174SEC("xdp")175__description("jne/jeq infer not null, PTR_TO_MAP_VALUE_OR_NULL -> PTR_TO_MAP_VALUE")176__success __retval(0)177__naked void null_ptr_to_map_value(void)178{179 asm volatile (" \180 /* r9 = &some stack to use as key */ \181 r1 = 0; \182 *(u32*)(r10 - 8) = r1; \183 r9 = r10; \184 r9 += -8; \185 /* r8 = process local map */ \186 r8 = %[map_xskmap] ll; \187 /* r6 = map_lookup_elem(r8, r9); */ \188 r1 = r8; \189 r2 = r9; \190 call %[bpf_map_lookup_elem]; \191 r6 = r0; \192 /* r7 = map_lookup_elem(r8, r9); */ \193 r1 = r8; \194 r2 = r9; \195 call %[bpf_map_lookup_elem]; \196 r7 = r0; \197 /* if (r6 == 0) return 0; */ \198 if r6 == 0 goto l0_%=; \199 /* if (r6 != r7) return 0; */ \200 if r6 != r7 goto l0_%=; \201 /* read *r7; */ \202 r0 = *(u32*)(r7 + %[bpf_xdp_sock_queue_id]); \203l0_%=: /* return 0; */ \204 r0 = 0; \205 exit; \206" :207 : __imm(bpf_map_lookup_elem),208 __imm_addr(map_xskmap),209 __imm_const(bpf_xdp_sock_queue_id, offsetof(struct bpf_xdp_sock, queue_id))210 : __clobber_all);211}212 213char _license[] SEC("license") = "GPL";214