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

bpf: remove {update,get}_loop_entry functions

The previous patch switched read and precision tracking for
iterator-based loops from state-graph-based loop tracking to
control-flow-graph-based loop tracking.

This patch removes the now-unused `update_loop_entry()` and
`get_loop_entry()` functions, which were part of the state-graph-based
logic.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250611200836.4135542-9-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
0e0da5f9 c9e31900

+1 -179
-15
include/linux/bpf_verifier.h
··· 449 449 /* first and last insn idx of this verifier state */ 450 450 u32 first_insn_idx; 451 451 u32 last_insn_idx; 452 - /* If this state is a part of states loop this field points to some 453 - * parent of this state such that: 454 - * - it is also a member of the same states loop; 455 - * - DFS states traversal starting from initial state visits loop_entry 456 - * state before this state. 457 - * Used to compute topmost loop entry for state loops. 458 - * State loops might appear because of open coded iterators logic. 459 - * See get_loop_entry() for more information. 460 - */ 461 - struct bpf_verifier_state *loop_entry; 462 452 /* if this state is a backedge state then equal_state 463 453 * records cached state to which this state is equal. 464 454 */ ··· 463 473 u32 dfs_depth; 464 474 u32 callback_unroll_depth; 465 475 u32 may_goto_depth; 466 - /* If this state was ever pointed-to by other state's loop_entry field 467 - * this flag would be set to true. Used to avoid freeing such states 468 - * while they are still in use. 469 - */ 470 - u32 used_as_loop_entry; 471 476 }; 472 477 473 478 #define bpf_get_spilled_reg(slot, frame, mask) \
+1 -164
kernel/bpf/verifier.c
··· 1682 1682 kfree(state); 1683 1683 } 1684 1684 1685 - /* struct bpf_verifier_state->{parent,loop_entry} refer to states 1685 + /* struct bpf_verifier_state->parent refers to states 1686 1686 * that are in either of env->{expored_states,free_list}. 1687 1687 * In both cases the state is contained in struct bpf_verifier_state_list. 1688 1688 */ ··· 1693 1693 return NULL; 1694 1694 } 1695 1695 1696 - static struct bpf_verifier_state_list *state_loop_entry_as_list(struct bpf_verifier_state *st) 1697 - { 1698 - if (st->loop_entry) 1699 - return container_of(st->loop_entry, struct bpf_verifier_state_list, state); 1700 - return NULL; 1701 - } 1702 - 1703 1696 static bool incomplete_read_marks(struct bpf_verifier_env *env, 1704 1697 struct bpf_verifier_state *st); 1705 1698 1706 1699 /* A state can be freed if it is no longer referenced: 1707 1700 * - is in the env->free_list; 1708 1701 * - has no children states; 1709 - * - is not used as loop_entry. 1710 - * 1711 - * Freeing a state can make it's loop_entry free-able. 1712 1702 */ 1713 1703 static void maybe_free_verifier_state(struct bpf_verifier_env *env, 1714 1704 struct bpf_verifier_state_list *sl) ··· 1755 1765 dst_state->last_insn_idx = src->last_insn_idx; 1756 1766 dst_state->dfs_depth = src->dfs_depth; 1757 1767 dst_state->callback_unroll_depth = src->callback_unroll_depth; 1758 - dst_state->used_as_loop_entry = src->used_as_loop_entry; 1759 1768 dst_state->may_goto_depth = src->may_goto_depth; 1760 - dst_state->loop_entry = src->loop_entry; 1761 1769 dst_state->equal_state = src->equal_state; 1762 1770 for (i = 0; i <= src->curframe; i++) { 1763 1771 dst = dst_state->frame[i]; ··· 1797 1809 return false; 1798 1810 1799 1811 return true; 1800 - } 1801 - 1802 - /* Open coded iterators allow back-edges in the state graph in order to 1803 - * check unbounded loops that iterators. 1804 - * 1805 - * In is_state_visited() it is necessary to know if explored states are 1806 - * part of some loops in order to decide whether non-exact states 1807 - * comparison could be used: 1808 - * - non-exact states comparison establishes sub-state relation and uses 1809 - * read and precision marks to do so, these marks are propagated from 1810 - * children states and thus are not guaranteed to be final in a loop; 1811 - * - exact states comparison just checks if current and explored states 1812 - * are identical (and thus form a back-edge). 1813 - * 1814 - * Paper "A New Algorithm for Identifying Loops in Decompilation" 1815 - * by Tao Wei, Jian Mao, Wei Zou and Yu Chen [1] presents a convenient 1816 - * algorithm for loop structure detection and gives an overview of 1817 - * relevant terminology. It also has helpful illustrations. 1818 - * 1819 - * [1] https://api.semanticscholar.org/CorpusID:15784067 1820 - * 1821 - * We use a similar algorithm but because loop nested structure is 1822 - * irrelevant for verifier ours is significantly simpler and resembles 1823 - * strongly connected components algorithm from Sedgewick's textbook. 1824 - * 1825 - * Define topmost loop entry as a first node of the loop traversed in a 1826 - * depth first search starting from initial state. The goal of the loop 1827 - * tracking algorithm is to associate topmost loop entries with states 1828 - * derived from these entries. 1829 - * 1830 - * For each step in the DFS states traversal algorithm needs to identify 1831 - * the following situations: 1832 - * 1833 - * initial initial initial 1834 - * | | | 1835 - * V V V 1836 - * ... ... .---------> hdr 1837 - * | | | | 1838 - * V V | V 1839 - * cur .-> succ | .------... 1840 - * | | | | | | 1841 - * V | V | V V 1842 - * succ '-- cur | ... ... 1843 - * | | | 1844 - * | V V 1845 - * | succ <- cur 1846 - * | | 1847 - * | V 1848 - * | ... 1849 - * | | 1850 - * '----' 1851 - * 1852 - * (A) successor state of cur (B) successor state of cur or it's entry 1853 - * not yet traversed are in current DFS path, thus cur and succ 1854 - * are members of the same outermost loop 1855 - * 1856 - * initial initial 1857 - * | | 1858 - * V V 1859 - * ... ... 1860 - * | | 1861 - * V V 1862 - * .------... .------... 1863 - * | | | | 1864 - * V V V V 1865 - * .-> hdr ... ... ... 1866 - * | | | | | 1867 - * | V V V V 1868 - * | succ <- cur succ <- cur 1869 - * | | | 1870 - * | V V 1871 - * | ... ... 1872 - * | | | 1873 - * '----' exit 1874 - * 1875 - * (C) successor state of cur is a part of some loop but this loop 1876 - * does not include cur or successor state is not in a loop at all. 1877 - * 1878 - * Algorithm could be described as the following python code: 1879 - * 1880 - * traversed = set() # Set of traversed nodes 1881 - * entries = {} # Mapping from node to loop entry 1882 - * depths = {} # Depth level assigned to graph node 1883 - * path = set() # Current DFS path 1884 - * 1885 - * # Find outermost loop entry known for n 1886 - * def get_loop_entry(n): 1887 - * h = entries.get(n, None) 1888 - * while h in entries: 1889 - * h = entries[h] 1890 - * return h 1891 - * 1892 - * # Update n's loop entry if h comes before n in current DFS path. 1893 - * def update_loop_entry(n, h): 1894 - * if h in path and depths[entries.get(n, n)] < depths[n]: 1895 - * entries[n] = h1 1896 - * 1897 - * def dfs(n, depth): 1898 - * traversed.add(n) 1899 - * path.add(n) 1900 - * depths[n] = depth 1901 - * for succ in G.successors(n): 1902 - * if succ not in traversed: 1903 - * # Case A: explore succ and update cur's loop entry 1904 - * # only if succ's entry is in current DFS path. 1905 - * dfs(succ, depth + 1) 1906 - * h = entries.get(succ, None) 1907 - * update_loop_entry(n, h) 1908 - * else: 1909 - * # Case B or C depending on `h1 in path` check in update_loop_entry(). 1910 - * update_loop_entry(n, succ) 1911 - * path.remove(n) 1912 - * 1913 - * To adapt this algorithm for use with verifier: 1914 - * - use st->branch == 0 as a signal that DFS of succ had been finished 1915 - * and cur's loop entry has to be updated (case A), handle this in 1916 - * update_branch_counts(); 1917 - * - use st->branch > 0 as a signal that st is in the current DFS path; 1918 - * - handle cases B and C in is_state_visited(). 1919 - */ 1920 - static struct bpf_verifier_state *get_loop_entry(struct bpf_verifier_env *env, 1921 - struct bpf_verifier_state *st) 1922 - { 1923 - struct bpf_verifier_state *topmost = st->loop_entry; 1924 - u32 steps = 0; 1925 - 1926 - while (topmost && topmost->loop_entry) { 1927 - if (verifier_bug_if(steps++ > st->dfs_depth, env, "infinite loop")) 1928 - return ERR_PTR(-EFAULT); 1929 - topmost = topmost->loop_entry; 1930 - } 1931 - return topmost; 1932 - } 1933 - 1934 - static void update_loop_entry(struct bpf_verifier_env *env, 1935 - struct bpf_verifier_state *cur, struct bpf_verifier_state *hdr) 1936 - { 1937 - /* The hdr->branches check decides between cases B and C in 1938 - * comment for get_loop_entry(). If hdr->branches == 0 then 1939 - * head's topmost loop entry is not in current DFS path, 1940 - * hence 'cur' and 'hdr' are not in the same loop and there is 1941 - * no need to update cur->loop_entry. 1942 - */ 1943 - if (hdr->branches && hdr->dfs_depth < (cur->loop_entry ?: cur)->dfs_depth) { 1944 - if (cur->loop_entry) { 1945 - cur->loop_entry->used_as_loop_entry--; 1946 - maybe_free_verifier_state(env, state_loop_entry_as_list(cur)); 1947 - } 1948 - cur->loop_entry = hdr; 1949 - hdr->used_as_loop_entry++; 1950 - } 1951 1812 } 1952 1813 1953 1814 /* Return IP for a given frame in a call stack */