diff options
| -rw-r--r-- | include/linux/bpf.h | 5 | ||||
| -rw-r--r-- | include/uapi/linux/bpf.h | 10 | ||||
| -rw-r--r-- | kernel/bpf/syscall.c | 2 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 152 | ||||
| -rw-r--r-- | net/core/filter.c | 100 |
5 files changed, 234 insertions, 35 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 30bfd331882a..280a315de8d6 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h | |||
| @@ -103,6 +103,9 @@ struct bpf_verifier_ops { | |||
| 103 | * with 'type' (read or write) is allowed | 103 | * with 'type' (read or write) is allowed |
| 104 | */ | 104 | */ |
| 105 | bool (*is_valid_access)(int off, int size, enum bpf_access_type type); | 105 | bool (*is_valid_access)(int off, int size, enum bpf_access_type type); |
| 106 | |||
| 107 | u32 (*convert_ctx_access)(int dst_reg, int src_reg, int ctx_off, | ||
| 108 | struct bpf_insn *insn); | ||
| 106 | }; | 109 | }; |
| 107 | 110 | ||
| 108 | struct bpf_prog_type_list { | 111 | struct bpf_prog_type_list { |
| @@ -133,7 +136,7 @@ struct bpf_map *bpf_map_get(struct fd f); | |||
| 133 | void bpf_map_put(struct bpf_map *map); | 136 | void bpf_map_put(struct bpf_map *map); |
| 134 | 137 | ||
| 135 | /* verify correctness of eBPF program */ | 138 | /* verify correctness of eBPF program */ |
| 136 | int bpf_check(struct bpf_prog *fp, union bpf_attr *attr); | 139 | int bpf_check(struct bpf_prog **fp, union bpf_attr *attr); |
| 137 | #else | 140 | #else |
| 138 | static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl) | 141 | static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl) |
| 139 | { | 142 | { |
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index de1f63668daf..929545a27546 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
| @@ -170,4 +170,14 @@ enum bpf_func_id { | |||
| 170 | __BPF_FUNC_MAX_ID, | 170 | __BPF_FUNC_MAX_ID, |
| 171 | }; | 171 | }; |
| 172 | 172 | ||
| 173 | /* user accessible mirror of in-kernel sk_buff. | ||
| 174 | * new fields can only be added to the end of this structure | ||
| 175 | */ | ||
| 176 | struct __sk_buff { | ||
| 177 | __u32 len; | ||
| 178 | __u32 pkt_type; | ||
| 179 | __u32 mark; | ||
| 180 | __u32 queue_mapping; | ||
| 181 | }; | ||
| 182 | |||
| 173 | #endif /* _UAPI__LINUX_BPF_H__ */ | 183 | #endif /* _UAPI__LINUX_BPF_H__ */ |
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 - | ||
