Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add test for conditional jumps on same scalar register

Add test cases to verify the correctness of the BPF verifier's branch analysis
when conditional jumps are performed on the same scalar register. And make sure
that JGT does not trigger verifier BUG.

Signed-off-by: KaFai Wan <kafai.wan@linux.dev>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20251103063108.1111764-3-kafai.wan@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

KaFai Wan and committed by
Alexei Starovoitov
9f32bfec d43ad9da

+154
+154
tools/testing/selftests/bpf/progs/verifier_bounds.c
··· 1709 1709 : __clobber_all); 1710 1710 } 1711 1711 1712 + SEC("socket") 1713 + __description("conditional jump on same register, branch taken") 1714 + __not_msg("20: (b7) r0 = 1 {{.*}} R0=1") 1715 + __success __log_level(2) 1716 + __retval(0) __flag(BPF_F_TEST_REG_INVARIANTS) 1717 + __naked void condition_jump_on_same_register(void *ctx) 1718 + { 1719 + asm volatile(" \ 1720 + call %[bpf_get_prandom_u32]; \ 1721 + w8 = 0x80000000; \ 1722 + r0 &= r8; \ 1723 + if r0 == r0 goto +1; \ 1724 + goto l1_%=; \ 1725 + if r0 >= r0 goto +1; \ 1726 + goto l1_%=; \ 1727 + if r0 s>= r0 goto +1; \ 1728 + goto l1_%=; \ 1729 + if r0 <= r0 goto +1; \ 1730 + goto l1_%=; \ 1731 + if r0 s<= r0 goto +1; \ 1732 + goto l1_%=; \ 1733 + if r0 != r0 goto l1_%=; \ 1734 + if r0 > r0 goto l1_%=; \ 1735 + if r0 s> r0 goto l1_%=; \ 1736 + if r0 < r0 goto l1_%=; \ 1737 + if r0 s< r0 goto l1_%=; \ 1738 + l0_%=: r0 = 0; \ 1739 + exit; \ 1740 + l1_%=: r0 = 1; \ 1741 + exit; \ 1742 + " : 1743 + : __imm(bpf_get_prandom_u32) 1744 + : __clobber_all); 1745 + } 1746 + 1747 + SEC("socket") 1748 + __description("jset on same register, constant value branch taken") 1749 + __not_msg("7: (b7) r0 = 1 {{.*}} R0=1") 1750 + __success __log_level(2) 1751 + __retval(0) __flag(BPF_F_TEST_REG_INVARIANTS) 1752 + __naked void jset_on_same_register_1(void *ctx) 1753 + { 1754 + asm volatile(" \ 1755 + r0 = 0; \ 1756 + if r0 & r0 goto l1_%=; \ 1757 + r0 = 1; \ 1758 + if r0 & r0 goto +1; \ 1759 + goto l1_%=; \ 1760 + l0_%=: r0 = 0; \ 1761 + exit; \ 1762 + l1_%=: r0 = 1; \ 1763 + exit; \ 1764 + " : 1765 + : __imm(bpf_get_prandom_u32) 1766 + : __clobber_all); 1767 + } 1768 + 1769 + SEC("socket") 1770 + __description("jset on same register, scalar value branch taken") 1771 + __not_msg("12: (b7) r0 = 1 {{.*}} R0=1") 1772 + __success __log_level(2) 1773 + __retval(0) __flag(BPF_F_TEST_REG_INVARIANTS) 1774 + __naked void jset_on_same_register_2(void *ctx) 1775 + { 1776 + asm volatile(" \ 1777 + /* range [1;2] */ \ 1778 + call %[bpf_get_prandom_u32]; \ 1779 + r0 &= 0x1; \ 1780 + r0 += 1; \ 1781 + if r0 & r0 goto +1; \ 1782 + goto l1_%=; \ 1783 + /* range [-2;-1] */ \ 1784 + call %[bpf_get_prandom_u32]; \ 1785 + r0 &= 0x1; \ 1786 + r0 -= 2; \ 1787 + if r0 & r0 goto +1; \ 1788 + goto l1_%=; \ 1789 + l0_%=: r0 = 0; \ 1790 + exit; \ 1791 + l1_%=: r0 = 1; \ 1792 + exit; \ 1793 + " : 1794 + : __imm(bpf_get_prandom_u32) 1795 + : __clobber_all); 1796 + } 1797 + 1798 + SEC("socket") 1799 + __description("jset on same register, scalar value unknown branch 1") 1800 + __msg("3: (b7) r0 = 0 {{.*}} R0=0") 1801 + __msg("5: (b7) r0 = 1 {{.*}} R0=1") 1802 + __success __log_level(2) 1803 + __flag(BPF_F_TEST_REG_INVARIANTS) 1804 + __naked void jset_on_same_register_3(void *ctx) 1805 + { 1806 + asm volatile(" \ 1807 + /* range [0;1] */ \ 1808 + call %[bpf_get_prandom_u32]; \ 1809 + r0 &= 0x1; \ 1810 + if r0 & r0 goto l1_%=; \ 1811 + l0_%=: r0 = 0; \ 1812 + exit; \ 1813 + l1_%=: r0 = 1; \ 1814 + exit; \ 1815 + " : 1816 + : __imm(bpf_get_prandom_u32) 1817 + : __clobber_all); 1818 + } 1819 + 1820 + SEC("socket") 1821 + __description("jset on same register, scalar value unknown branch 2") 1822 + __msg("4: (b7) r0 = 0 {{.*}} R0=0") 1823 + __msg("6: (b7) r0 = 1 {{.*}} R0=1") 1824 + __success __log_level(2) 1825 + __flag(BPF_F_TEST_REG_INVARIANTS) 1826 + __naked void jset_on_same_register_4(void *ctx) 1827 + { 1828 + asm volatile(" \ 1829 + /* range [-1;0] */ \ 1830 + call %[bpf_get_prandom_u32]; \ 1831 + r0 &= 0x1; \ 1832 + r0 -= 1; \ 1833 + if r0 & r0 goto l1_%=; \ 1834 + l0_%=: r0 = 0; \ 1835 + exit; \ 1836 + l1_%=: r0 = 1; \ 1837 + exit; \ 1838 + " : 1839 + : __imm(bpf_get_prandom_u32) 1840 + : __clobber_all); 1841 + } 1842 + 1843 + SEC("socket") 1844 + __description("jset on same register, scalar value unknown branch 3") 1845 + __msg("4: (b7) r0 = 0 {{.*}} R0=0") 1846 + __msg("6: (b7) r0 = 1 {{.*}} R0=1") 1847 + __success __log_level(2) 1848 + __flag(BPF_F_TEST_REG_INVARIANTS) 1849 + __naked void jset_on_same_register_5(void *ctx) 1850 + { 1851 + asm volatile(" \ 1852 + /* range [-1;1] */ \ 1853 + call %[bpf_get_prandom_u32]; \ 1854 + r0 &= 0x2; \ 1855 + r0 -= 1; \ 1856 + if r0 & r0 goto l1_%=; \ 1857 + l0_%=: r0 = 0; \ 1858 + exit; \ 1859 + l1_%=: r0 = 1; \ 1860 + exit; \ 1861 + " : 1862 + : __imm(bpf_get_prandom_u32) 1863 + : __clobber_all); 1864 + } 1865 + 1712 1866 char _license[] SEC("license") = "GPL";