diff options
| author | Alexei Starovoitov <ast@plumgrid.com> | 2015-03-13 14:57:42 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-03-15 22:02:28 -0400 |
| commit | 9bac3d6d548e5cc925570b263f35b70a00a00ffd (patch) | |
| tree | 00ae5c37fb877d7c2b4fdf5ee0b8fe4837b1d476 /kernel/bpf | |
| parent | a498cfe990f569dd3766bfc9bfd2a5ee04468cd2 (diff) | |
bpf: allow extended BPF programs access skb fields
introduce user accessible mirror of in-kernel 'struct sk_buff':
struct __sk_buff {
__u32 len;
__u32 pkt_type;
__u32 mark;
__u32 queue_mapping;
};
bpf programs can do:
int bpf_prog(struct __sk_buff *skb)
{
__u32 var = skb->pkt_type;
which will be compiled to bpf assembler as:
dst_reg = *(u32 *)(src_reg + 4) // 4 == offsetof(struct __sk_buff, pkt_type)
bpf verifier will check validity of access and will convert it to:
dst_reg = *(u8 *)(src_reg + offsetof(struct sk_buff, __pkt_type_offset))
dst_reg &= 7
since skb->pkt_type is a bitfield.
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/syscall.c | 2 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 152 |
2 files changed, 137 insertions, 17 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 669719ccc9ee..ea75c654af1b 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
| @@ -519,7 +519,7 @@ static int bpf_prog_load(union bpf_attr *attr) | |||
| 519 | goto free_prog; | 519 | goto free_prog; |
| 520 | 520 | ||
| 521 | /* run eBPF verifier */ | 521 | /* run eBPF verifier */ |
| 522 | err = bpf_check(prog, attr); | 522 | err = bpf_check(&prog, attr); |
| 523 | if (err < 0) | 523 | if (err < 0) |
| 524 | goto free_used_maps; | 524 | goto free_used_maps; |
| 525 | 525 | ||
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e6b522496250..c22ebd36fa4b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -1620,11 +1620,10 @@ static int do_check(struct verifier_env *env) | |||
| 1620 | return err; | 1620 | return err; |
| 1621 | 1621 | ||
| 1622 | } else if (class == BPF_LDX) { | 1622 | } else if (class == BPF_LDX) { |
| 1623 | if (BPF_MODE(insn->code) != BPF_MEM || | 1623 | enum bpf_reg_type src_reg_type; |
| 1624 | insn->imm != 0) { | 1624 | |
| 1625 | verbose("BPF_LDX uses reserved fields\n"); | 1625 | /* check for reserved fields is already done */ |
| 1626 | return -EINVAL; | 1626 | |
| 1627 | } | ||
| 1628 | /* check src operand */ | 1627 | /* check src operand */ |
| 1629 | err = check_reg_arg(regs, insn->src_reg, SRC_OP); | 1628 | err = check_reg_arg(regs, insn->src_reg, SRC_OP); |
| 1630 | if (err) | 1629 | if (err) |
| @@ -1643,6 +1642,29 @@ static int do_check(struct verifier_env *env) | |||
| 1643 | if (err) | 1642 | if (err) |
| 1644 | return err; | 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 | } else if (class == BPF_STX) { | 1668 | } else if (class == BPF_STX) { |
| 1647 | if (BPF_MODE(insn->code) == BPF_XADD) { | 1669 | if (BPF_MODE(insn->code) == BPF_XADD) { |
| 1648 | err = check_xadd(env, insn); | 1670 | err = check_xadd(env, insn); |
| @@ -1790,6 +1812,13 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) | |||
| 1790 | int i, j; | 1812 | int i, j; |
| 1791 | 1813 | ||
| 1792 | for (i = 0; i < insn_cnt; i++, insn++) { | 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 | if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) { | 1822 | if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) { |
| 1794 | struct bpf_map *map; | 1823 | struct bpf_map *map; |
| 1795 | struct fd f; | 1824 | struct fd f; |
| @@ -1881,6 +1910,92 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env) | |||
| 1881 | insn->src_reg = 0; | 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 | static void free_states(struct verifier_env *env) | 1999 | static void free_states(struct verifier_env *env) |
| 1885 | { | 2000 | { |
| 1886 | struct verifier_state_list *sl, *sln; | 2001 | struct verifier_state_list *sl, *sln; |
| @@ -1903,13 +2018,13 @@ static void free_states(struct verifier_env *env) | |||
| 1903 | kfree(env->explored_states); | 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 | char __user *log_ubuf = NULL; | 2023 | char __user *log_ubuf = NULL; |
| 1909 | struct verifier_env *env; | 2024 | struct verifier_env *env; |
| 1910 | int ret = -EINVAL; | 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 | return -E2BIG; | 2028 | return -E2BIG; |
| 1914 | 2029 | ||
| 1915 | /* 'struct verifier_env' can be global, but since it's not small, | 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) | |||
| 1919 | if (!env) | 2034 | if (!env) |
| 1920 | return -ENOMEM; | 2035 | return -ENOMEM; |
| 1921 | 2036 | ||
| 1922 | env->prog = prog; | 2037 | env->prog = *prog; |
| 1923 | 2038 | ||
| 1924 | /* grab the mutex to protect few globals used by verifier */ | 2039 | /* grab the mutex to protect few globals used by verifier */ |
| 1925 | mutex_lock(&bpf_verifier_lock); | 2040 | mutex_lock(&bpf_verifier_lock); |
| @@ -1951,7 +2066,7 @@ int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) | |||
| 1951 | if (ret < 0) | 2066 | if (ret < 0) |
| 1952 | goto skip_full_check; | 2067 | goto skip_full_check; |
| 1953 | 2068 | ||
| 1954 | env->explored_states = kcalloc(prog->len, | 2069 | env->explored_states = kcalloc(env->prog->len, |
| 1955 | sizeof(struct verifier_state_list *), | 2070 | sizeof(struct verifier_state_list *), |
| 1956 | GFP_USER); | 2071 | GFP_USER); |
| 1957 | ret = -ENOMEM; | 2072 | ret = -ENOMEM; |
| @@ -1968,6 +2083,10 @@ skip_full_check: | |||
| 1968 | while (pop_stack(env, NULL) >= 0); | 2083 | while (pop_stack(env, NULL) >= 0); |
| 1969 | free_states(env); | 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 | if (log_level && log_len >= log_size - 1) { | 2090 | if (log_level && log_len >= log_size - 1) { |
| 1972 | BUG_ON(log_len >= log_size); | 2091 | BUG_ON(log_len >= log_size); |
| 1973 | /* verifier log exceeded user supplied buffer */ | 2092 | /* verifier log exceeded user supplied buffer */ |
| @@ -1983,18 +2102,18 @@ skip_full_check: | |||
| 1983 | 2102 | ||
| 1984 | if (ret == 0 && env->used_map_cnt) { | 2103 | if (ret == 0 && env->used_map_cnt) { |
| 1985 | /* if program passed verifier, update used_maps in bpf_prog_info */ | 2104 | /* if program passed verifier, update used_maps in bpf_prog_info */ |
| 1986 | prog->aux->used_maps = kmalloc_array(env->used_map_cnt, | 2105 | env->prog->aux->used_maps = kmalloc_array(env->used_map_cnt, |
| 1987 | sizeof(env->used_maps[0]), | 2106 | sizeof(env->used_maps[0]), |
| 1988 | GFP_KERNEL); | 2107 | GFP_KERNEL); |
| 1989 | 2108 | ||
| 1990 | if (!prog->aux->used_maps) { | 2109 | if (!env->prog->aux->used_maps) { |
| 1991 | ret = -ENOMEM; | 2110 | ret = -ENOMEM; |
| 1992 | goto free_log_buf; | 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 | sizeof(env->used_maps[0]) * env->used_map_cnt); | 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 | /* program is valid. Convert pseudo bpf_ld_imm64 into generic | 2118 | /* program is valid. Convert pseudo bpf_ld_imm64 into generic |
| 2000 | * bpf_ld_imm64 instructions | 2119 | * bpf_ld_imm64 instructions |
| @@ -2006,11 +2125,12 @@ free_log_buf: | |||
| 2006 | if (log_level) | 2125 | if (log_level) |
| 2007 | vfree(log_buf); | 2126 | vfree(log_buf); |
| 2008 | free_env: | 2127 | free_env: |
| 2009 | if (!prog->aux->used_maps) | 2128 | if (!env->prog->aux->used_maps) |
| 2010 | /* if we didn't copy map pointers into bpf_prog_info, release | 2129 | /* if we didn't copy map pointers into bpf_prog_info, release |
| 2011 | * them now. Otherwise free_bpf_prog_info() will release them. | 2130 | * them now. Otherwise free_bpf_prog_info() will release them. |
| 2012 | */ | 2131 | */ |
| 2013 | release_maps(env); | 2132 | release_maps(env); |
| 2133 | *prog = env->prog; | ||
| 2014 | kfree(env); | 2134 | kfree(env); |
| 2015 | mutex_unlock(&bpf_verifier_lock); | 2135 | mutex_unlock(&bpf_verifier_lock); |
| 2016 | return ret; | 2136 | return ret; |
