Back to home page

OSCL-LXR

 
 

    


0001 {
0002     "variable-offset ctx access",
0003     .insns = {
0004     /* Get an unknown value */
0005     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0006     /* Make it small and 4-byte aligned */
0007     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0008     /* add it to skb.  We now have either &skb->len or
0009      * &skb->pkt_type, but we don't know which
0010      */
0011     BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
0012     /* dereference it */
0013     BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
0014     BPF_EXIT_INSN(),
0015     },
0016     .errstr = "variable ctx access var_off=(0x0; 0x4)",
0017     .result = REJECT,
0018     .prog_type = BPF_PROG_TYPE_LWT_IN,
0019 },
0020 {
0021     "variable-offset stack read, priv vs unpriv",
0022     .insns = {
0023     /* Fill the top 8 bytes of the stack */
0024     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0025     /* Get an unknown value */
0026     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0027     /* Make it small and 4-byte aligned */
0028     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0029     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
0030     /* add it to fp.  We now have either fp-4 or fp-8, but
0031      * we don't know which
0032      */
0033     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0034     /* dereference it for a stack read */
0035     BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
0036     BPF_MOV64_IMM(BPF_REG_0, 0),
0037     BPF_EXIT_INSN(),
0038     },
0039     .result = ACCEPT,
0040     .result_unpriv = REJECT,
0041     .errstr_unpriv = "R2 variable stack access prohibited for !root",
0042     .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
0043 },
0044 {
0045     "variable-offset stack read, uninitialized",
0046     .insns = {
0047     /* Get an unknown value */
0048     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0049     /* Make it small and 4-byte aligned */
0050     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0051     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
0052     /* add it to fp.  We now have either fp-4 or fp-8, but
0053      * we don't know which
0054      */
0055     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0056     /* dereference it for a stack read */
0057     BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
0058     BPF_MOV64_IMM(BPF_REG_0, 0),
0059     BPF_EXIT_INSN(),
0060     },
0061     .result = REJECT,
0062     .errstr = "invalid variable-offset read from stack R2",
0063     .prog_type = BPF_PROG_TYPE_LWT_IN,
0064 },
0065 {
0066     "variable-offset stack write, priv vs unpriv",
0067     .insns = {
0068     /* Get an unknown value */
0069     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0070     /* Make it small and 8-byte aligned */
0071     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
0072     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
0073     /* Add it to fp.  We now have either fp-8 or fp-16, but
0074      * we don't know which
0075      */
0076     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0077     /* Dereference it for a stack write */
0078     BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
0079     /* Now read from the address we just wrote. This shows
0080      * that, after a variable-offset write, a priviledged
0081      * program can read the slots that were in the range of
0082      * that write (even if the verifier doesn't actually know
0083      * if the slot being read was really written to or not.
0084      */
0085     BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, 0),
0086     BPF_MOV64_IMM(BPF_REG_0, 0),
0087     BPF_EXIT_INSN(),
0088     },
0089     /* Variable stack access is rejected for unprivileged.
0090      */
0091     .errstr_unpriv = "R2 variable stack access prohibited for !root",
0092     .result_unpriv = REJECT,
0093     .result = ACCEPT,
0094 },
0095 {
0096     "variable-offset stack write clobbers spilled regs",
0097     .insns = {
0098     /* Dummy instruction; needed because we need to patch the next one
0099      * and we can't patch the first instruction.
0100      */
0101     BPF_MOV64_IMM(BPF_REG_6, 0),
0102     /* Make R0 a map ptr */
0103     BPF_LD_MAP_FD(BPF_REG_0, 0),
0104     /* Get an unknown value */
0105     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0106     /* Make it small and 8-byte aligned */
0107     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
0108     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
0109     /* Add it to fp. We now have either fp-8 or fp-16, but
0110      * we don't know which.
0111      */
0112     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0113     /* Spill R0(map ptr) into stack */
0114     BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
0115     /* Dereference the unknown value for a stack write */
0116     BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
0117     /* Fill the register back into R2 */
0118     BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8),
0119     /* Try to dereference R2 for a memory load */
0120     BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8),
0121     BPF_EXIT_INSN(),
0122     },
0123     .fixup_map_hash_8b = { 1 },
0124     /* The unpriviledged case is not too interesting; variable
0125      * stack access is rejected.
0126      */
0127     .errstr_unpriv = "R2 variable stack access prohibited for !root",
0128     .result_unpriv = REJECT,
0129     /* In the priviledged case, dereferencing a spilled-and-then-filled
0130      * register is rejected because the previous variable offset stack
0131      * write might have overwritten the spilled pointer (i.e. we lose track
0132      * of the spilled register when we analyze the write).
0133      */
0134     .errstr = "R2 invalid mem access 'scalar'",
0135     .result = REJECT,
0136 },
0137 {
0138     "indirect variable-offset stack access, unbounded",
0139     .insns = {
0140     BPF_MOV64_IMM(BPF_REG_2, 6),
0141     BPF_MOV64_IMM(BPF_REG_3, 28),
0142     /* Fill the top 16 bytes of the stack. */
0143     BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
0144     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0145     /* Get an unknown value. */
0146     BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_sock_ops,
0147                                bytes_received)),
0148     /* Check the lower bound but don't check the upper one. */
0149     BPF_JMP_IMM(BPF_JSLT, BPF_REG_4, 0, 4),
0150     /* Point the lower bound to initialized stack. Offset is now in range
0151      * from fp-16 to fp+0x7fffffffffffffef, i.e. max value is unbounded.
0152      */
0153     BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
0154     BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
0155     BPF_MOV64_IMM(BPF_REG_5, 8),
0156     /* Dereference it indirectly. */
0157     BPF_EMIT_CALL(BPF_FUNC_getsockopt),
0158     BPF_MOV64_IMM(BPF_REG_0, 0),
0159     BPF_EXIT_INSN(),
0160     },
0161     .errstr = "invalid unbounded variable-offset indirect access to stack R4",
0162     .result = REJECT,
0163     .prog_type = BPF_PROG_TYPE_SOCK_OPS,
0164 },
0165 {
0166     "indirect variable-offset stack access, max out of bound",
0167     .insns = {
0168     /* Fill the top 8 bytes of the stack */
0169     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0170     /* Get an unknown value */
0171     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0172     /* Make it small and 4-byte aligned */
0173     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0174     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
0175     /* add it to fp.  We now have either fp-4 or fp-8, but
0176      * we don't know which
0177      */
0178     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0179     /* dereference it indirectly */
0180     BPF_LD_MAP_FD(BPF_REG_1, 0),
0181     BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
0182     BPF_MOV64_IMM(BPF_REG_0, 0),
0183     BPF_EXIT_INSN(),
0184     },
0185     .fixup_map_hash_8b = { 5 },
0186     .errstr = "invalid variable-offset indirect access to stack R2",
0187     .result = REJECT,
0188     .prog_type = BPF_PROG_TYPE_LWT_IN,
0189 },
0190 {
0191     "indirect variable-offset stack access, min out of bound",
0192     .insns = {
0193     /* Fill the top 8 bytes of the stack */
0194     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0195     /* Get an unknown value */
0196     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0197     /* Make it small and 4-byte aligned */
0198     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0199     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 516),
0200     /* add it to fp.  We now have either fp-516 or fp-512, but
0201      * we don't know which
0202      */
0203     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0204     /* dereference it indirectly */
0205     BPF_LD_MAP_FD(BPF_REG_1, 0),
0206     BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
0207     BPF_MOV64_IMM(BPF_REG_0, 0),
0208     BPF_EXIT_INSN(),
0209     },
0210     .fixup_map_hash_8b = { 5 },
0211     .errstr = "invalid variable-offset indirect access to stack R2",
0212     .result = REJECT,
0213     .prog_type = BPF_PROG_TYPE_LWT_IN,
0214 },
0215 {
0216     "indirect variable-offset stack access, max_off+size > max_initialized",
0217     .insns = {
0218     /* Fill only the second from top 8 bytes of the stack. */
0219     BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
0220     /* Get an unknown value. */
0221     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0222     /* Make it small and 4-byte aligned. */
0223     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0224     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
0225     /* Add it to fp.  We now have either fp-12 or fp-16, but we don't know
0226      * which. fp-12 size 8 is partially uninitialized stack.
0227      */
0228     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0229     /* Dereference it indirectly. */
0230     BPF_LD_MAP_FD(BPF_REG_1, 0),
0231     BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
0232     BPF_MOV64_IMM(BPF_REG_0, 0),
0233     BPF_EXIT_INSN(),
0234     },
0235     .fixup_map_hash_8b = { 5 },
0236     .errstr = "invalid indirect read from stack R2 var_off",
0237     .result = REJECT,
0238     .prog_type = BPF_PROG_TYPE_LWT_IN,
0239 },
0240 {
0241     "indirect variable-offset stack access, min_off < min_initialized",
0242     .insns = {
0243     /* Fill only the top 8 bytes of the stack. */
0244     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0245     /* Get an unknown value */
0246     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0247     /* Make it small and 4-byte aligned. */
0248     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0249     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
0250     /* Add it to fp.  We now have either fp-12 or fp-16, but we don't know
0251      * which. fp-16 size 8 is partially uninitialized stack.
0252      */
0253     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0254     /* Dereference it indirectly. */
0255     BPF_LD_MAP_FD(BPF_REG_1, 0),
0256     BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
0257     BPF_MOV64_IMM(BPF_REG_0, 0),
0258     BPF_EXIT_INSN(),
0259     },
0260     .fixup_map_hash_8b = { 5 },
0261     .errstr = "invalid indirect read from stack R2 var_off",
0262     .result = REJECT,
0263     .prog_type = BPF_PROG_TYPE_LWT_IN,
0264 },
0265 {
0266     "indirect variable-offset stack access, priv vs unpriv",
0267     .insns = {
0268     /* Fill the top 16 bytes of the stack. */
0269     BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
0270     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0271     /* Get an unknown value. */
0272     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0273     /* Make it small and 4-byte aligned. */
0274     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0275     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
0276     /* Add it to fp.  We now have either fp-12 or fp-16, we don't know
0277      * which, but either way it points to initialized stack.
0278      */
0279     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0280     /* Dereference it indirectly. */
0281     BPF_LD_MAP_FD(BPF_REG_1, 0),
0282     BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
0283     BPF_MOV64_IMM(BPF_REG_0, 0),
0284     BPF_EXIT_INSN(),
0285     },
0286     .fixup_map_hash_8b = { 6 },
0287     .errstr_unpriv = "R2 variable stack access prohibited for !root",
0288     .result_unpriv = REJECT,
0289     .result = ACCEPT,
0290     .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
0291 },
0292 {
0293     "indirect variable-offset stack access, uninitialized",
0294     .insns = {
0295     BPF_MOV64_IMM(BPF_REG_2, 6),
0296     BPF_MOV64_IMM(BPF_REG_3, 28),
0297     /* Fill the top 16 bytes of the stack. */
0298     BPF_ST_MEM(BPF_W, BPF_REG_10, -16, 0),
0299     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0300     /* Get an unknown value. */
0301     BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, 0),
0302     /* Make it small and 4-byte aligned. */
0303     BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 4),
0304     BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
0305     /* Add it to fp.  We now have either fp-12 or fp-16, we don't know
0306      * which, but either way it points to initialized stack.
0307      */
0308     BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
0309     BPF_MOV64_IMM(BPF_REG_5, 8),
0310     /* Dereference it indirectly. */
0311     BPF_EMIT_CALL(BPF_FUNC_getsockopt),
0312     BPF_MOV64_IMM(BPF_REG_0, 0),
0313     BPF_EXIT_INSN(),
0314     },
0315     .errstr = "invalid indirect read from stack R4 var_off",
0316     .result = REJECT,
0317     .prog_type = BPF_PROG_TYPE_SOCK_OPS,
0318 },
0319 {
0320     "indirect variable-offset stack access, ok",
0321     .insns = {
0322     /* Fill the top 16 bytes of the stack. */
0323     BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
0324     BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
0325     /* Get an unknown value. */
0326     BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
0327     /* Make it small and 4-byte aligned. */
0328     BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
0329     BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
0330     /* Add it to fp.  We now have either fp-12 or fp-16, we don't know
0331      * which, but either way it points to initialized stack.
0332      */
0333     BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
0334     /* Dereference it indirectly. */
0335     BPF_LD_MAP_FD(BPF_REG_1, 0),
0336     BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
0337     BPF_MOV64_IMM(BPF_REG_0, 0),
0338     BPF_EXIT_INSN(),
0339     },
0340     .fixup_map_hash_8b = { 6 },
0341     .result = ACCEPT,
0342     .prog_type = BPF_PROG_TYPE_LWT_IN,
0343 },