@@ -1672,7 +1672,7 @@ static void free_verifier_state(struct bpf_verifier_state *state,
1672
1672
kfree(state);
1673
1673
}
1674
1674
1675
- /* struct bpf_verifier_state->{ parent,loop_entry} refer to states
1675
+ /* struct bpf_verifier_state->parent refers to states
1676
1676
* that are in either of env->{expored_states,free_list}.
1677
1677
* In both cases the state is contained in struct bpf_verifier_state_list.
1678
1678
*/
@@ -1683,36 +1683,18 @@ static struct bpf_verifier_state_list *state_parent_as_list(struct bpf_verifier_
1683
1683
return NULL;
1684
1684
}
1685
1685
1686
- static struct bpf_verifier_state_list *state_loop_entry_as_list(struct bpf_verifier_state *st)
1687
- {
1688
- if (st->loop_entry)
1689
- return container_of(st->loop_entry, struct bpf_verifier_state_list, state);
1690
- return NULL;
1691
- }
1692
-
1693
1686
/* A state can be freed if it is no longer referenced:
1694
1687
* - is in the env->free_list;
1695
1688
* - has no children states;
1696
- * - is not used as loop_entry.
1697
- *
1698
- * Freeing a state can make it's loop_entry free-able.
1699
1689
*/
1700
1690
static void maybe_free_verifier_state(struct bpf_verifier_env *env,
1701
1691
struct bpf_verifier_state_list *sl)
1702
1692
{
1703
- struct bpf_verifier_state_list *loop_entry_sl;
1704
-
1705
- while (sl && sl->in_free_list &&
1706
- sl->state.branches == 0 &&
1707
- sl->state.used_as_loop_entry == 0) {
1708
- loop_entry_sl = state_loop_entry_as_list(&sl->state);
1709
- if (loop_entry_sl)
1710
- loop_entry_sl->state.used_as_loop_entry--;
1693
+ if (sl->in_free_list && sl->state.branches == 0) {
1711
1694
list_del(&sl->node);
1712
1695
free_verifier_state(&sl->state, false);
1713
1696
kfree(sl);
1714
1697
env->free_list_size--;
1715
- sl = loop_entry_sl;
1716
1698
}
1717
1699
}
1718
1700
@@ -1753,9 +1735,7 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state,
1753
1735
dst_state->insn_hist_end = src->insn_hist_end;
1754
1736
dst_state->dfs_depth = src->dfs_depth;
1755
1737
dst_state->callback_unroll_depth = src->callback_unroll_depth;
1756
- dst_state->used_as_loop_entry = src->used_as_loop_entry;
1757
1738
dst_state->may_goto_depth = src->may_goto_depth;
1758
- dst_state->loop_entry = src->loop_entry;
1759
1739
dst_state->scc_epoch = src->scc_epoch;
1760
1740
for (i = 0; i <= src->curframe; i++) {
1761
1741
dst = dst_state->frame[i];
@@ -1858,160 +1838,6 @@ static void mark_state_loops_possible(struct bpf_verifier_env *env,
1858
1838
scc_info->state_loops_possible = 1;
1859
1839
}
1860
1840
1861
- /* Open coded iterators allow back-edges in the state graph in order to
1862
- * check unbounded loops that iterators.
1863
- *
1864
- * In is_state_visited() it is necessary to know if explored states are
1865
- * part of some loops in order to decide whether non-exact states
1866
- * comparison could be used:
1867
- * - non-exact states comparison establishes sub-state relation and uses
1868
- * read and precision marks to do so, these marks are propagated from
1869
- * children states and thus are not guaranteed to be final in a loop;
1870
- * - exact states comparison just checks if current and explored states
1871
- * are identical (and thus form a back-edge).
1872
- *
1873
- * Paper "A New Algorithm for Identifying Loops in Decompilation"
1874
- * by Tao Wei, Jian Mao, Wei Zou and Yu Chen [1] presents a convenient
1875
- * algorithm for loop structure detection and gives an overview of
1876
- * relevant terminology. It also has helpful illustrations.
1877
- *
1878
- * [1] https://api.semanticscholar.org/CorpusID:15784067
1879
- *
1880
- * We use a similar algorithm but because loop nested structure is
1881
- * irrelevant for verifier ours is significantly simpler and resembles
1882
- * strongly connected components algorithm from Sedgewick's textbook.
1883
- *
1884
- * Define topmost loop entry as a first node of the loop traversed in a
1885
- * depth first search starting from initial state. The goal of the loop
1886
- * tracking algorithm is to associate topmost loop entries with states
1887
- * derived from these entries.
1888
- *
1889
- * For each step in the DFS states traversal algorithm needs to identify
1890
- * the following situations:
1891
- *
1892
- * initial initial initial
1893
- * | | |
1894
- * V V V
1895
- * ... ... .---------> hdr
1896
- * | | | |
1897
- * V V | V
1898
- * cur .-> succ | .------...
1899
- * | | | | | |
1900
- * V | V | V V
1901
- * succ '-- cur | ... ...
1902
- * | | |
1903
- * | V V
1904
- * | succ <- cur
1905
- * | |
1906
- * | V
1907
- * | ...
1908
- * | |
1909
- * '----'
1910
- *
1911
- * (A) successor state of cur (B) successor state of cur or it's entry
1912
- * not yet traversed are in current DFS path, thus cur and succ
1913
- * are members of the same outermost loop
1914
- *
1915
- * initial initial
1916
- * | |
1917
- * V V
1918
- * ... ...
1919
- * | |
1920
- * V V
1921
- * .------... .------...
1922
- * | | | |
1923
- * V V V V
1924
- * .-> hdr ... ... ...
1925
- * | | | | |
1926
- * | V V V V
1927
- * | succ <- cur succ <- cur
1928
- * | | |
1929
- * | V V
1930
- * | ... ...
1931
- * | | |
1932
- * '----' exit
1933
- *
1934
- * (C) successor state of cur is a part of some loop but this loop
1935
- * does not include cur or successor state is not in a loop at all.
1936
- *
1937
- * Algorithm could be described as the following python code:
1938
- *
1939
- * traversed = set() # Set of traversed nodes
1940
- * entries = {} # Mapping from node to loop entry
1941
- * depths = {} # Depth level assigned to graph node
1942
- * path = set() # Current DFS path
1943
- *
1944
- * # Find outermost loop entry known for n
1945
- * def get_loop_entry(n):
1946
- * h = entries.get(n, None)
1947
- * while h in entries:
1948
- * h = entries[h]
1949
- * return h
1950
- *
1951
- * # Update n's loop entry if h comes before n in current DFS path.
1952
- * def update_loop_entry(n, h):
1953
- * if h in path and depths[entries.get(n, n)] < depths[n]:
1954
- * entries[n] = h1
1955
- *
1956
- * def dfs(n, depth):
1957
- * traversed.add(n)
1958
- * path.add(n)
1959
- * depths[n] = depth
1960
- * for succ in G.successors(n):
1961
- * if succ not in traversed:
1962
- * # Case A: explore succ and update cur's loop entry
1963
- * # only if succ's entry is in current DFS path.
1964
- * dfs(succ, depth + 1)
1965
- * h = entries.get(succ, None)
1966
- * update_loop_entry(n, h)
1967
- * else:
1968
- * # Case B or C depending on `h1 in path` check in update_loop_entry().
1969
- * update_loop_entry(n, succ)
1970
- * path.remove(n)
1971
- *
1972
- * To adapt this algorithm for use with verifier:
1973
- * - use st->branch == 0 as a signal that DFS of succ had been finished
1974
- * and cur's loop entry has to be updated (case A), handle this in
1975
- * update_branch_counts();
1976
- * - use st->branch > 0 as a signal that st is in the current DFS path;
1977
- * - handle cases B and C in is_state_visited().
1978
- */
1979
- static struct bpf_verifier_state *get_loop_entry(struct bpf_verifier_env *env,
1980
- struct bpf_verifier_state *st)
1981
- {
1982
- struct bpf_verifier_state *topmost = st->loop_entry;
1983
- u32 steps = 0;
1984
-
1985
- while (topmost && topmost->loop_entry) {
1986
- if (steps++ > st->dfs_depth) {
1987
- WARN_ONCE(true, "verifier bug: infinite loop in get_loop_entry\n");
1988
- verbose(env, "verifier bug: infinite loop in get_loop_entry()\n");
1989
- return ERR_PTR(-EFAULT);
1990
- }
1991
- topmost = topmost->loop_entry;
1992
- }
1993
- return topmost;
1994
- }
1995
-
1996
- static void update_loop_entry(struct bpf_verifier_env *env,
1997
- struct bpf_verifier_state *cur, struct bpf_verifier_state *hdr)
1998
- {
1999
- /* The hdr->branches check decides between cases B and C in
2000
- * comment for get_loop_entry(). If hdr->branches == 0 then
2001
- * head's topmost loop entry is not in current DFS path,
2002
- * hence 'cur' and 'hdr' are not in the same loop and there is
2003
- * no need to update cur->loop_entry.
2004
- */
2005
- if (hdr->branches && hdr->dfs_depth < (cur->loop_entry ?: cur)->dfs_depth) {
2006
- if (cur->loop_entry) {
2007
- cur->loop_entry->used_as_loop_entry--;
2008
- maybe_free_verifier_state(env, state_loop_entry_as_list(cur));
2009
- }
2010
- cur->loop_entry = hdr;
2011
- hdr->used_as_loop_entry++;
2012
- }
2013
- }
2014
-
2015
1841
static void update_branch_counts(struct bpf_verifier_env *env, struct bpf_verifier_state *st)
2016
1842
{
2017
1843
struct bpf_verifier_state_list *sl = NULL, *parent_sl;
0 commit comments