.. | .. |
---|
154 | 154 | .result_unpriv = ACCEPT, |
---|
155 | 155 | .insn_processed = 15, |
---|
156 | 156 | }, |
---|
| 157 | +/* The test performs a conditional 64-bit write to a stack location |
---|
| 158 | + * fp[-8], this is followed by an unconditional 8-bit write to fp[-8], |
---|
| 159 | + * then data is read from fp[-8]. This sequence is unsafe. |
---|
| 160 | + * |
---|
| 161 | + * The test would be mistakenly marked as safe w/o dst register parent |
---|
| 162 | + * preservation in verifier.c:copy_register_state() function. |
---|
| 163 | + * |
---|
| 164 | + * Note the usage of BPF_F_TEST_STATE_FREQ to force creation of the |
---|
| 165 | + * checkpoint state after conditional 64-bit assignment. |
---|
| 166 | + */ |
---|
| 167 | +{ |
---|
| 168 | + "write tracking and register parent chain bug", |
---|
| 169 | + .insns = { |
---|
| 170 | + /* r6 = ktime_get_ns() */ |
---|
| 171 | + BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns), |
---|
| 172 | + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), |
---|
| 173 | + /* r0 = ktime_get_ns() */ |
---|
| 174 | + BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns), |
---|
| 175 | + /* if r0 > r6 goto +1 */ |
---|
| 176 | + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_6, 1), |
---|
| 177 | + /* *(u64 *)(r10 - 8) = 0xdeadbeef */ |
---|
| 178 | + BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0xdeadbeef), |
---|
| 179 | + /* r1 = 42 */ |
---|
| 180 | + BPF_MOV64_IMM(BPF_REG_1, 42), |
---|
| 181 | + /* *(u8 *)(r10 - 8) = r1 */ |
---|
| 182 | + BPF_STX_MEM(BPF_B, BPF_REG_FP, BPF_REG_1, -8), |
---|
| 183 | + /* r2 = *(u64 *)(r10 - 8) */ |
---|
| 184 | + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_FP, -8), |
---|
| 185 | + /* exit(0) */ |
---|
| 186 | + BPF_MOV64_IMM(BPF_REG_0, 0), |
---|
| 187 | + BPF_EXIT_INSN(), |
---|
| 188 | + }, |
---|
| 189 | + .flags = BPF_F_TEST_STATE_FREQ, |
---|
| 190 | + .errstr = "invalid read from stack off -8+1 size 8", |
---|
| 191 | + .result = REJECT, |
---|
| 192 | +}, |
---|