| @@ -1620,11 +1620,10 @@ static int do_check(struct verifier_env *env) · 1619 unmodified lines |
| 1620 | 1620 | return err; |
| 1621 | 1621 | |
| 1622 | 1622 | } else if (class == BPF_LDX) { |
| 1623 | | − if (BPF_MODE(insn->code) != BPF_MEM || |
| 1624 | | − insn->imm != 0) { |
| 1625 | | − verbose("BPF_LDX uses reserved fields\n"); |
| 1626 | | − return -EINVAL; |
| 1627 | | − } |
| 1623 | + enum bpf_reg_type src_reg_type; |
| 1624 | + |
| 1625 | + /* check for reserved fields is already done */ |
| 1626 | + |
| 1628 | 1627 | /* check src operand */ |
| 1629 | 1628 | err = check_reg_arg(regs, insn->src_reg, SRC_OP); |
| 1630 | 1629 | if (err) |
| @@ -1643,6 +1642,29 @@ static int do_check(struct verifier_env *env) · 12 unmodified lines |
| 1643 | 1642 | if (err) |
| 1644 | 1643 | return err; |
| 1645 | 1644 | |
| 1645 | + src_reg_type = regs[insn->src_reg].type; |
| 1646 | + |
| 1647 | + if (insn->imm == 0 && BPF_SIZE(insn->code) == BPF_W) { |
| 1648 | + /* saw a valid insn |
| 1649 | + * dst_reg = *(u32 *)(src_reg + off) |
| 1650 | + * use reserved 'imm' field to mark this insn |
| 1651 | + */ |
| 1652 | + insn->imm = src_reg_type; |
| 1653 | + |
| 1654 | + } else if (src_reg_type != insn->imm && |
| 1655 | + (src_reg_type == PTR_TO_CTX || |
| 1656 | + insn->imm == PTR_TO_CTX)) { |
| 1657 | + /* ABuser program is trying to use the same insn |
| 1658 | + * dst_reg = *(u32*) (src_reg + off) |
| 1659 | + * with different pointer types: |
| 1660 | + * src_reg == ctx in one branch and |
| 1661 | + * src_reg == stack|map in some other branch. |
| 1662 | + * Reject it. |
| 1663 | + */ |
| 1664 | + verbose("same insn cannot be used with different pointers\n"); |
| 1665 | + return -EINVAL; |
| 1666 | + } |
| 1667 | + |
| 1646 | 1668 | } else if (class == BPF_STX) { |
| 1647 | 1669 | if (BPF_MODE(insn->code) == BPF_XADD) { |
| 1648 | 1670 | err = check_xadd(env, insn); |
| @@ -1790,6 +1812,13 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) · 141 unmodified lines |
| 1790 | 1812 | int i, j; |
| 1791 | 1813 | |
| 1792 | 1814 | for (i = 0; i < insn_cnt; i++, insn++) { |
| 1815 | + if (BPF_CLASS(insn->code) == BPF_LDX && |
| 1816 | + (BPF_MODE(insn->code) != BPF_MEM || |
| 1817 | + insn->imm != 0)) { |
| 1818 | + verbose("BPF_LDX uses reserved fields\n"); |
| 1819 | + return -EINVAL; |
| 1820 | + } |
| 1821 | + |
| 1793 | 1822 | if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) { |
| 1794 | 1823 | struct bpf_map *map; |
| 1795 | 1824 | struct fd f; |
| @@ -1881,6 +1910,92 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env) · 85 unmodified lines |
| 1881 | 1910 | insn->src_reg = 0; |
| 1882 | 1911 | } |
| 1883 | 1912 | |
| 1913 | +static void adjust_branches(struct bpf_prog *prog, int pos, int delta) |
| 1914 | +{ |
| 1915 | + struct bpf_insn *insn = prog->insnsi; |
| 1916 | + int insn_cnt = prog->len; |
| 1917 | + int i; |
| 1918 | + |
| 1919 | + for (i = 0; i < insn_cnt; i++, insn++) { |
| 1920 | + if (BPF_CLASS(insn->code) != BPF_JMP || |
| 1921 | + BPF_OP(insn->code) == BPF_CALL || |
| 1922 | + BPF_OP(insn->code) == BPF_EXIT) |
| 1923 | + continue; |
| 1924 | + |
| 1925 | + /* adjust offset of jmps if necessary */ |
| 1926 | + if (i < pos && i + insn->off + 1 > pos) |
| 1927 | + insn->off += delta; |
| 1928 | + else if (i > pos && i + insn->off + 1 < pos) |
| 1929 | + insn->off -= delta; |
| 1930 | + } |
| 1931 | +} |
| 1932 | + |
| 1933 | +/* convert load instructions that access fields of 'struct __sk_buff' |
| 1934 | + * into sequence of instructions that access fields of 'struct sk_buff' |
| 1935 | + */ |
| 1936 | +static int convert_ctx_accesses(struct verifier_env *env) |
| 1937 | +{ |
| 1938 | + struct bpf_insn *insn = env->prog->insnsi; |
| 1939 | + int insn_cnt = env->prog->len; |
| 1940 | + struct bpf_insn insn_buf[16]; |
| 1941 | + struct bpf_prog *new_prog; |
| 1942 | + u32 cnt; |
| 1943 | + int i; |
| 1944 | + |
| 1945 | + if (!env->prog->aux->ops->convert_ctx_access) |
| 1946 | + return 0; |
| 1947 | + |
| 1948 | + for (i = 0; i < insn_cnt; i++, insn++) { |
| 1949 | + if (insn->code != (BPF_LDX | BPF_MEM | BPF_W)) |
| 1950 | + continue; |
| 1951 | + |
| 1952 | + if (insn->imm != PTR_TO_CTX) { |
| 1953 | + /* clear internal mark */ |
| 1954 | + insn->imm = 0; |
| 1955 | + continue; |
| 1956 | + } |
| 1957 | + |
| 1958 | + cnt = env->prog->aux->ops-> |
| 1959 | + convert_ctx_access(insn->dst_reg, insn->src_reg, |
| 1960 | + insn->off, insn_buf); |
| 1961 | + if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) { |
| 1962 | + verbose("bpf verifier is misconfigured\n"); |
| 1963 | + return -EINVAL; |
| 1964 | + } |
| 1965 | + |
| 1966 | + if (cnt == 1) { |
| 1967 | + memcpy(insn, insn_buf, sizeof(*insn)); |
| 1968 | + continue; |
| 1969 | + } |
| 1970 | + |
| 1971 | + /* several new insns need to be inserted. Make room for them */ |
| 1972 | + insn_cnt += cnt - 1; |
| 1973 | + new_prog = bpf_prog_realloc(env->prog, |
| 1974 | + bpf_prog_size(insn_cnt), |
| 1975 | + GFP_USER); |
| 1976 | + if (!new_prog) |
| 1977 | + return -ENOMEM; |
| 1978 | + |
| 1979 | + new_prog->len = insn_cnt; |
| 1980 | + |
| 1981 | + memmove(new_prog->insnsi + i + cnt, new_prog->insns + i + 1, |
| 1982 | + sizeof(*insn) * (insn_cnt - i - cnt)); |
| 1983 | + |
| 1984 | + /* copy substitute insns in place of load instruction */ |
| 1985 | + memcpy(new_prog->insnsi + i, insn_buf, sizeof(*insn) * cnt); |
| 1986 | + |
| 1987 | + /* adjust branches in the whole program */ |
| 1988 | + adjust_branches(new_prog, i, cnt - 1); |
| 1989 | + |
| 1990 | + /* keep walking new program and skip insns we just inserted */ |
| 1991 | + env->prog = new_prog; |
| 1992 | + insn = new_prog->insnsi + i + cnt - 1; |
| 1993 | + i += cnt - 1; |
| 1994 | + } |
| 1995 | + |
| 1996 | + return 0; |
| 1997 | +} |
| 1998 | + |
| 1884 | 1999 | static void free_states(struct verifier_env *env) |
| 1885 | 2000 | { |
| 1886 | 2001 | struct verifier_state_list *sl, *sln; |
| @@ -1903,13 +2018,13 @@ static void free_states(struct verifier_env *env) · 16 unmodified lines |
| 1903 | 2018 | kfree(env->explored_states); |
| 1904 | 2019 | } |
| 1905 | 2020 | |
| 1906 | | −int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) |
| 2021 | +int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) |
| 1907 | 2022 | { |
| 1908 | 2023 | char __user *log_ubuf = NULL; |
| 1909 | 2024 | struct verifier_env *env; |
| 1910 | 2025 | int ret = -EINVAL; |
| 1911 | 2026 | |
| 1912 | | − if (prog->len <= 0 || prog->len > BPF_MAXINSNS) |
| 2027 | + if ((*prog)->len <= 0 || (*prog)->len > BPF_MAXINSNS) |
| 1913 | 2028 | return -E2BIG; |
| 1914 | 2029 | |
| 1915 | 2030 | /* 'struct verifier_env' can be global, but since it's not small, |
| @@ -1919,7 +2034,7 @@ int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) · 3 unmodified lines |
| 1919 | 2034 | if (!env) |
| 1920 | 2035 | return -ENOMEM; |
| 1921 | 2036 | |
| 1922 | | − env->prog = prog; |
| 2037 | + env->prog = *prog; |
| 1923 | 2038 | |
| 1924 | 2039 | /* grab the mutex to protect few globals used by verifier */ |
| 1925 | 2040 | mutex_lock(&bpf_verifier_lock); |
| @@ -1951,7 +2066,7 @@ int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) · 25 unmodified lines |
| 1951 | 2066 | if (ret < 0) |
| 1952 | 2067 | goto skip_full_check; |
| 1953 | 2068 | |
| 1954 | | − env->explored_states = kcalloc(prog->len, |
| 2069 | + env->explored_states = kcalloc(env->prog->len, |
| 1955 | 2070 | sizeof(struct verifier_state_list *), |
| 1956 | 2071 | GFP_USER); |
| 1957 | 2072 | ret = -ENOMEM; |
| @@ -1968,6 +2083,10 @@ skip_full_check: · 10 unmodified lines |
| 1968 | 2083 | while (pop_stack(env, NULL) >= 0); |
| 1969 | 2084 | free_states(env); |
| 1970 | 2085 | |
| 2086 | + if (ret == 0) |
| 2087 | + /* program is valid, convert *(u32*)(ctx + off) accesses */ |
| 2088 | + ret = convert_ctx_accesses(env); |
| 2089 | + |
| 1971 | 2090 | if (log_level && log_len >= log_size - 1) { |
| 1972 | 2091 | BUG_ON(log_len >= log_size); |
| 1973 | 2092 | /* verifier log exceeded user supplied buffer */ |
| @@ -1983,18 +2102,18 @@ skip_full_check: · 9 unmodified lines |
| 1983 | 2102 | |
| 1984 | 2103 | if (ret == 0 && env->used_map_cnt) { |
| 1985 | 2104 | /* if program passed verifier, update used_maps in bpf_prog_info */ |
| 1986 | | − prog->aux->used_maps = kmalloc_array(env->used_map_cnt, |
| 1987 | | − sizeof(env->used_maps[0]), |
| 1988 | | − GFP_KERNEL); |
| 2105 | + env->prog->aux->used_maps = kmalloc_array(env->used_map_cnt, |
| 2106 | + sizeof(env->used_maps[0]), |
| 2107 | + GFP_KERNEL); |
| 1989 | 2108 | |
| 1990 | | − if (!prog->aux->used_maps) { |
| 2109 | + if (!env->prog->aux->used_maps) { |
| 1991 | 2110 | ret = -ENOMEM; |
| 1992 | 2111 | goto free_log_buf; |
| 1993 | 2112 | } |
| 1994 | 2113 | |
| 1995 | | − memcpy(prog->aux->used_maps, env->used_maps, |
| 2114 | + memcpy(env->prog->aux->used_maps, env->used_maps, |
| 1996 | 2115 | sizeof(env->used_maps[0]) * env->used_map_cnt); |
| 1997 | | − prog->aux->used_map_cnt = env->used_map_cnt; |
| 2116 | + env->prog->aux->used_map_cnt = env->used_map_cnt; |
| 1998 | 2117 | |
| 1999 | 2118 | /* program is valid. Convert pseudo bpf_ld_imm64 into generic |
| 2000 | 2119 | * bpf_ld_imm64 instructions |
| @@ -2006,11 +2125,12 @@ free_log_buf: · 5 unmodified lines |
| 2006 | 2125 | if (log_level) |
| 2007 | 2126 | vfree(log_buf); |
| 2008 | 2127 | free_env: |
| 2009 | | − if (!prog->aux->used_maps) |
| 2128 | + if (!env->prog->aux->used_maps) |
| 2010 | 2129 | /* if we didn't copy map pointers into bpf_prog_info, release |
| 2011 | 2130 | * them now. Otherwise free_bpf_prog_info() will release them. |
| 2012 | 2131 | */ |
| 2013 | 2132 | release_maps(env); |
| 2133 | + *prog = env->prog; |
| 2014 | 2134 | kfree(env); |
| 2015 | 2135 | mutex_unlock(&bpf_verifier_lock); |
| 2016 | 2136 | return ret; |