> > +/*
> > + * Shift by an immediate that doesn't fit in a signed byte: the C1 shift
> > + * group takes a fixed 1-byte immediate, but imm_size() returns 4 for
> > + * counts >= 128, so the x86 JIT emits 3 stray bytes and desyncs the
> > + * instruction stream. The shift results are discarded (a count >= 64 is
> > + * UB in the interpreter); the test returns a known constant, which the
> > + * corrupted stream fails to produce.
> > + */
> > +static const struct ebpf_insn test_shift_big_imm_prog[] = {
> > + {
> > + .code = (BPF_ALU | EBPF_MOV | BPF_K),
> > + .dst_reg = EBPF_REG_2,
> > + .imm = 0x1,
> > + },
> > + {
> > + .code = (EBPF_ALU64 | BPF_LSH | BPF_K),
> > + .dst_reg = EBPF_REG_2,
> > + .imm = 137,
> > + },
> > + {
> > + .code = (EBPF_ALU64 | BPF_RSH | BPF_K),
> > + .dst_reg = EBPF_REG_2,
> > + .imm = 200,
> > + },
> > + {
> > + .code = (EBPF_ALU64 | EBPF_ARSH | BPF_K),
> > + .dst_reg = EBPF_REG_2,
> > + .imm = 255,
> > + },
> > + /* known result; a desynced stream won't reproduce it */
> > + {
> > + .code = (BPF_ALU | EBPF_MOV | BPF_K),
> > + .dst_reg = EBPF_REG_0,
> > + .imm = 0x55,
> > + },
> > + {
> > + .code = (BPF_JMP | EBPF_EXIT),
> > + },
> > +};
>
> // snip the rest
>
> Thanks a lot for adding this test. Can we use the shift results though,
> instead
> of discarding them, maybe as another test case? If the interpreter is unable
> to
> reproduce them or triggers sanitizer it needs to be fixed as well. (Apologies
> for this scope creep but I hope we get to the bottom of it eventually.)
Speaking of scope creep, this currently fails on ARM since emit_lsl (as well as
emit_lsr, emit_asr) does not clear unused immediate bits and thus the value
does not fit in the encoding.