| .. | .. |
|---|
| 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 | +}, |
|---|