| 646 | } |
| 647 | |
| 648 | static const char * |
| 649 | eval_alu(struct bpf_verifier *bvf, const struct ebpf_insn *ins) |
| 650 | { |
| 651 | uint64_t msk; |
| 652 | uint32_t op; |
| 653 | size_t opsz, sz; |
| 654 | const char *err; |
| 655 | struct bpf_eval_state *st; |
| 656 | struct bpf_reg_val *rd, rs; |
| 657 | |
| 658 | sz = (BPF_CLASS(ins->code) == BPF_ALU) ? |
| 659 | sizeof(uint32_t) : sizeof(uint64_t); |
| 660 | opsz = sz * CHAR_BIT; |
| 661 | msk = RTE_LEN2MASK(opsz, uint64_t); |
| 662 | |
| 663 | st = bvf->evst; |
| 664 | rd = st->rv + ins->dst_reg; |
| 665 | |
| 666 | if (BPF_SRC(ins->code) == BPF_X) { |
| 667 | rs = st->rv[ins->src_reg]; |
| 668 | eval_apply_mask(&rs, msk); |
| 669 | } else { |
| 670 | rs = (struct bpf_reg_val){.v = {.size = sz,},}; |
| 671 | eval_fill_imm(&rs, msk, ins->imm); |
| 672 | } |
| 673 | |
| 674 | eval_apply_mask(rd, msk); |
| 675 | |
| 676 | op = BPF_OP(ins->code); |
| 677 | |
| 678 | /* Allow self-xor as way to zero register */ |
| 679 | if (op == BPF_XOR && BPF_SRC(ins->code) == BPF_X && |
| 680 | ins->src_reg == ins->dst_reg) { |
| 681 | eval_fill_imm(&rs, UINT64_MAX, 0); |
| 682 | eval_fill_imm(rd, UINT64_MAX, 0); |
| 683 | } |
| 684 | |
| 685 | err = eval_defined((op != EBPF_MOV) ? rd : NULL, |
| 686 | (op != BPF_NEG) ? &rs : NULL); |
| 687 | if (err != NULL) |
| 688 | return err; |
| 689 | |
| 690 | if (op == BPF_ADD) |
| 691 | eval_add(rd, &rs, msk); |
| 692 | else if (op == BPF_SUB) |
| 693 | eval_sub(rd, &rs, msk); |
| 694 | else if (op == BPF_LSH) |
| 695 | eval_lsh(rd, &rs, opsz, msk); |
| 696 | else if (op == BPF_RSH) |
| 697 | eval_rsh(rd, &rs, opsz, msk); |
| 698 | else if (op == EBPF_ARSH) |
| 699 | eval_arsh(rd, &rs, opsz, msk); |
| 700 | else if (op == BPF_AND) |
| 701 | eval_and(rd, &rs, opsz, msk); |
| 702 | else if (op == BPF_OR) |
| 703 | eval_or(rd, &rs, opsz, msk); |
| 704 | else if (op == BPF_XOR) |
| 705 | eval_xor(rd, &rs, opsz, msk); |
nothing calls this directly
no test coverage detected