var_off.c (11491B)
1{ 2 "variable-offset ctx access", 3 .insns = { 4 /* Get an unknown value */ 5 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 6 /* Make it small and 4-byte aligned */ 7 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 8 /* add it to skb. We now have either &skb->len or 9 * &skb->pkt_type, but we don't know which 10 */ 11 BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), 12 /* dereference it */ 13 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), 14 BPF_EXIT_INSN(), 15 }, 16 .errstr = "variable ctx access var_off=(0x0; 0x4)", 17 .result = REJECT, 18 .prog_type = BPF_PROG_TYPE_LWT_IN, 19}, 20{ 21 "variable-offset stack read, priv vs unpriv", 22 .insns = { 23 /* Fill the top 8 bytes of the stack */ 24 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 25 /* Get an unknown value */ 26 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 27 /* Make it small and 4-byte aligned */ 28 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 29 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8), 30 /* add it to fp. We now have either fp-4 or fp-8, but 31 * we don't know which 32 */ 33 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 34 /* dereference it for a stack read */ 35 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0), 36 BPF_MOV64_IMM(BPF_REG_0, 0), 37 BPF_EXIT_INSN(), 38 }, 39 .result = ACCEPT, 40 .result_unpriv = REJECT, 41 .errstr_unpriv = "R2 variable stack access prohibited for !root", 42 .prog_type = BPF_PROG_TYPE_CGROUP_SKB, 43}, 44{ 45 "variable-offset stack read, uninitialized", 46 .insns = { 47 /* Get an unknown value */ 48 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 49 /* Make it small and 4-byte aligned */ 50 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 51 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8), 52 /* add it to fp. We now have either fp-4 or fp-8, but 53 * we don't know which 54 */ 55 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 56 /* dereference it for a stack read */ 57 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0), 58 BPF_MOV64_IMM(BPF_REG_0, 0), 59 BPF_EXIT_INSN(), 60 }, 61 .result = REJECT, 62 .errstr = "invalid variable-offset read from stack R2", 63 .prog_type = BPF_PROG_TYPE_LWT_IN, 64}, 65{ 66 "variable-offset stack write, priv vs unpriv", 67 .insns = { 68 /* Get an unknown value */ 69 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 70 /* Make it small and 8-byte aligned */ 71 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8), 72 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 73 /* Add it to fp. We now have either fp-8 or fp-16, but 74 * we don't know which 75 */ 76 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 77 /* Dereference it for a stack write */ 78 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), 79 /* Now read from the address we just wrote. This shows 80 * that, after a variable-offset write, a priviledged 81 * program can read the slots that were in the range of 82 * that write (even if the verifier doesn't actually know 83 * if the slot being read was really written to or not. 84 */ 85 BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, 0), 86 BPF_MOV64_IMM(BPF_REG_0, 0), 87 BPF_EXIT_INSN(), 88 }, 89 /* Variable stack access is rejected for unprivileged. 90 */ 91 .errstr_unpriv = "R2 variable stack access prohibited for !root", 92 .result_unpriv = REJECT, 93 .result = ACCEPT, 94}, 95{ 96 "variable-offset stack write clobbers spilled regs", 97 .insns = { 98 /* Dummy instruction; needed because we need to patch the next one 99 * and we can't patch the first instruction. 100 */ 101 BPF_MOV64_IMM(BPF_REG_6, 0), 102 /* Make R0 a map ptr */ 103 BPF_LD_MAP_FD(BPF_REG_0, 0), 104 /* Get an unknown value */ 105 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 106 /* Make it small and 8-byte aligned */ 107 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8), 108 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 109 /* Add it to fp. We now have either fp-8 or fp-16, but 110 * we don't know which. 111 */ 112 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 113 /* Spill R0(map ptr) into stack */ 114 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), 115 /* Dereference the unknown value for a stack write */ 116 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), 117 /* Fill the register back into R2 */ 118 BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8), 119 /* Try to dereference R2 for a memory load */ 120 BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8), 121 BPF_EXIT_INSN(), 122 }, 123 .fixup_map_hash_8b = { 1 }, 124 /* The unpriviledged case is not too interesting; variable 125 * stack access is rejected. 126 */ 127 .errstr_unpriv = "R2 variable stack access prohibited for !root", 128 .result_unpriv = REJECT, 129 /* In the priviledged case, dereferencing a spilled-and-then-filled 130 * register is rejected because the previous variable offset stack 131 * write might have overwritten the spilled pointer (i.e. we lose track 132 * of the spilled register when we analyze the write). 133 */ 134 .errstr = "R2 invalid mem access 'scalar'", 135 .result = REJECT, 136}, 137{ 138 "indirect variable-offset stack access, unbounded", 139 .insns = { 140 BPF_MOV64_IMM(BPF_REG_2, 6), 141 BPF_MOV64_IMM(BPF_REG_3, 28), 142 /* Fill the top 16 bytes of the stack. */ 143 BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0), 144 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 145 /* Get an unknown value. */ 146 BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_sock_ops, 147 bytes_received)), 148 /* Check the lower bound but don't check the upper one. */ 149 BPF_JMP_IMM(BPF_JSLT, BPF_REG_4, 0, 4), 150 /* Point the lower bound to initialized stack. Offset is now in range 151 * from fp-16 to fp+0x7fffffffffffffef, i.e. max value is unbounded. 152 */ 153 BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16), 154 BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10), 155 BPF_MOV64_IMM(BPF_REG_5, 8), 156 /* Dereference it indirectly. */ 157 BPF_EMIT_CALL(BPF_FUNC_getsockopt), 158 BPF_MOV64_IMM(BPF_REG_0, 0), 159 BPF_EXIT_INSN(), 160 }, 161 .errstr = "invalid unbounded variable-offset indirect access to stack R4", 162 .result = REJECT, 163 .prog_type = BPF_PROG_TYPE_SOCK_OPS, 164}, 165{ 166 "indirect variable-offset stack access, max out of bound", 167 .insns = { 168 /* Fill the top 8 bytes of the stack */ 169 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 170 /* Get an unknown value */ 171 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 172 /* Make it small and 4-byte aligned */ 173 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 174 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8), 175 /* add it to fp. We now have either fp-4 or fp-8, but 176 * we don't know which 177 */ 178 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 179 /* dereference it indirectly */ 180 BPF_LD_MAP_FD(BPF_REG_1, 0), 181 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 182 BPF_MOV64_IMM(BPF_REG_0, 0), 183 BPF_EXIT_INSN(), 184 }, 185 .fixup_map_hash_8b = { 5 }, 186 .errstr = "invalid variable-offset indirect access to stack R2", 187 .result = REJECT, 188 .prog_type = BPF_PROG_TYPE_LWT_IN, 189}, 190{ 191 "indirect variable-offset stack access, min out of bound", 192 .insns = { 193 /* Fill the top 8 bytes of the stack */ 194 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 195 /* Get an unknown value */ 196 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 197 /* Make it small and 4-byte aligned */ 198 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 199 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 516), 200 /* add it to fp. We now have either fp-516 or fp-512, but 201 * we don't know which 202 */ 203 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 204 /* dereference it indirectly */ 205 BPF_LD_MAP_FD(BPF_REG_1, 0), 206 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 207 BPF_MOV64_IMM(BPF_REG_0, 0), 208 BPF_EXIT_INSN(), 209 }, 210 .fixup_map_hash_8b = { 5 }, 211 .errstr = "invalid variable-offset indirect access to stack R2", 212 .result = REJECT, 213 .prog_type = BPF_PROG_TYPE_LWT_IN, 214}, 215{ 216 "indirect variable-offset stack access, max_off+size > max_initialized", 217 .insns = { 218 /* Fill only the second from top 8 bytes of the stack. */ 219 BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0), 220 /* Get an unknown value. */ 221 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 222 /* Make it small and 4-byte aligned. */ 223 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 224 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 225 /* Add it to fp. We now have either fp-12 or fp-16, but we don't know 226 * which. fp-12 size 8 is partially uninitialized stack. 227 */ 228 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 229 /* Dereference it indirectly. */ 230 BPF_LD_MAP_FD(BPF_REG_1, 0), 231 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), 232 BPF_MOV64_IMM(BPF_REG_0, 0), 233 BPF_EXIT_INSN(), 234 }, 235 .fixup_map_hash_8b = { 5 }, 236 .errstr = "invalid indirect read from stack R2 var_off", 237 .result = REJECT, 238 .prog_type = BPF_PROG_TYPE_LWT_IN, 239}, 240{ 241 "indirect variable-offset stack access, min_off < min_initialized", 242 .insns = { 243 /* Fill only the top 8 bytes of the stack. */ 244 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 245 /* Get an unknown value */ 246 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 247 /* Make it small and 4-byte aligned. */ 248 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 249 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 250 /* Add it to fp. We now have either fp-12 or fp-16, but we don't know 251 * which. fp-16 size 8 is partially uninitialized stack. 252 */ 253 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 254 /* Dereference it indirectly. */ 255 BPF_LD_MAP_FD(BPF_REG_1, 0), 256 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), 257 BPF_MOV64_IMM(BPF_REG_0, 0), 258 BPF_EXIT_INSN(), 259 }, 260 .fixup_map_hash_8b = { 5 }, 261 .errstr = "invalid indirect read from stack R2 var_off", 262 .result = REJECT, 263 .prog_type = BPF_PROG_TYPE_LWT_IN, 264}, 265{ 266 "indirect variable-offset stack access, priv vs unpriv", 267 .insns = { 268 /* Fill the top 16 bytes of the stack. */ 269 BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0), 270 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 271 /* Get an unknown value. */ 272 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 273 /* Make it small and 4-byte aligned. */ 274 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 275 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 276 /* Add it to fp. We now have either fp-12 or fp-16, we don't know 277 * which, but either way it points to initialized stack. 278 */ 279 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 280 /* Dereference it indirectly. */ 281 BPF_LD_MAP_FD(BPF_REG_1, 0), 282 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), 283 BPF_MOV64_IMM(BPF_REG_0, 0), 284 BPF_EXIT_INSN(), 285 }, 286 .fixup_map_hash_8b = { 6 }, 287 .errstr_unpriv = "R2 variable stack access prohibited for !root", 288 .result_unpriv = REJECT, 289 .result = ACCEPT, 290 .prog_type = BPF_PROG_TYPE_CGROUP_SKB, 291}, 292{ 293 "indirect variable-offset stack access, uninitialized", 294 .insns = { 295 BPF_MOV64_IMM(BPF_REG_2, 6), 296 BPF_MOV64_IMM(BPF_REG_3, 28), 297 /* Fill the top 16 bytes of the stack. */ 298 BPF_ST_MEM(BPF_W, BPF_REG_10, -16, 0), 299 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 300 /* Get an unknown value. */ 301 BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, 0), 302 /* Make it small and 4-byte aligned. */ 303 BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 4), 304 BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16), 305 /* Add it to fp. We now have either fp-12 or fp-16, we don't know 306 * which, but either way it points to initialized stack. 307 */ 308 BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10), 309 BPF_MOV64_IMM(BPF_REG_5, 8), 310 /* Dereference it indirectly. */ 311 BPF_EMIT_CALL(BPF_FUNC_getsockopt), 312 BPF_MOV64_IMM(BPF_REG_0, 0), 313 BPF_EXIT_INSN(), 314 }, 315 .errstr = "invalid indirect read from stack R4 var_off", 316 .result = REJECT, 317 .prog_type = BPF_PROG_TYPE_SOCK_OPS, 318}, 319{ 320 "indirect variable-offset stack access, ok", 321 .insns = { 322 /* Fill the top 16 bytes of the stack. */ 323 BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0), 324 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 325 /* Get an unknown value. */ 326 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 327 /* Make it small and 4-byte aligned. */ 328 BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 329 BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 330 /* Add it to fp. We now have either fp-12 or fp-16, we don't know 331 * which, but either way it points to initialized stack. 332 */ 333 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 334 /* Dereference it indirectly. */ 335 BPF_LD_MAP_FD(BPF_REG_1, 0), 336 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), 337 BPF_MOV64_IMM(BPF_REG_0, 0), 338 BPF_EXIT_INSN(), 339 }, 340 .fixup_map_hash_8b = { 6 }, 341 .result = ACCEPT, 342 .prog_type = BPF_PROG_TYPE_LWT_IN, 343},