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 | |
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')
-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; |