diff options
| author | David S. Miller <davem@davemloft.net> | 2017-05-10 14:38:07 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-05-11 14:19:00 -0400 |
| commit | e07b98d9bffe410019dfcf62c3428d4a96c56a2c (patch) | |
| tree | 52a3aede39b1bac6a409586bcdd272d9aa958868 | |
| parent | c5fc9692d101d1318b0f53f9f691cd88ac029317 (diff) | |
bpf: Add strict alignment flag for BPF_PROG_LOAD.
Add a new field, "prog_flags", and an initial flag value
BPF_F_STRICT_ALIGNMENT.
When set, the verifier will enforce strict pointer alignment
regardless of the setting of CONFIG_EFFICIENT_UNALIGNED_ACCESS.
The verifier, in this mode, will also use a fixed value of "2" in
place of NET_IP_ALIGN.
This facilitates test cases that will exercise and validate this part
of the verifier even when run on architectures where alignment doesn't
matter.
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
| -rw-r--r-- | include/linux/bpf_verifier.h | 1 | ||||
| -rw-r--r-- | include/uapi/linux/bpf.h | 8 | ||||
| -rw-r--r-- | kernel/bpf/syscall.c | 5 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 23 | ||||
| -rw-r--r-- | tools/build/feature/test-bpf.c | 1 | ||||
| -rw-r--r-- | tools/include/uapi/linux/bpf.h | 11 |
6 files changed, 40 insertions, 9 deletions
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 7c6a51924afc..d5093b52b485 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h | |||
| @@ -90,6 +90,7 @@ struct bpf_verifier_env { | |||
| 90 | struct bpf_prog *prog; /* eBPF program being verified */ | 90 | struct bpf_prog *prog; /* eBPF program being verified */ |
| 91 | struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */ | 91 | struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */ |
| 92 | int stack_size; /* number of states to be processed */ | 92 | int stack_size; /* number of states to be processed */ |
| 93 | bool strict_alignment; /* perform strict pointer alignment checks */ | ||
| 93 | struct bpf_verifier_state cur_state; /* current verifier state */ | 94 | struct bpf_verifier_state cur_state; /* current verifier state */ |
| 94 | struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ | 95 | struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ |
| 95 | const struct bpf_ext_analyzer_ops *analyzer_ops; /* external analyzer ops */ | 96 | const struct bpf_ext_analyzer_ops *analyzer_ops; /* external analyzer ops */ |
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 945a1f5f63c5..94dfa9def355 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
| @@ -132,6 +132,13 @@ enum bpf_attach_type { | |||
| 132 | */ | 132 | */ |
| 133 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) | 133 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) |
| 134 | 134 | ||
| 135 | /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the | ||
| 136 | * verifier will perform strict alignment checking as if the kernel | ||
| 137 | * has been built with CONFIG_EFFICIENT_UNALIGNED_ACCESS not set, | ||
| 138 | * and NET_IP_ALIGN defined to 2. | ||
| 139 | */ | ||
| 140 | #define BPF_F_STRICT_ALIGNMENT (1U << 0) | ||
| 141 | |||
| 135 | #define BPF_PSEUDO_MAP_FD 1 | 142 | #define BPF_PSEUDO_MAP_FD 1 |
| 136 | 143 | ||
| 137 | /* flags for BPF_MAP_UPDATE_ELEM command */ | 144 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
| @@ -177,6 +184,7 @@ union bpf_attr { | |||
| 177 | __u32 log_size; /* size of user buffer */ | 184 | __u32 log_size; /* size of user buffer */ |
| 178 | __aligned_u64 log_buf; /* user supplied buffer */ | 185 | __aligned_u64 log_buf; /* user supplied buffer */ |
| 179 | __u32 kern_version; /* checked when prog_type=kprobe */ | 186 | __u32 kern_version; /* checked when prog_type=kprobe */ |
| 187 | __u32 prog_flags; | ||
| 180 | }; | 188 | }; |
| 181 | 189 | ||
| 182 | struct { /* anonymous struct used by BPF_OBJ_* commands */ | 190 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index fd2411fd6914..265a0d854e33 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
| @@ -783,7 +783,7 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type) | |||
| 783 | EXPORT_SYMBOL_GPL(bpf_prog_get_type); | 783 | EXPORT_SYMBOL_GPL(bpf_prog_get_type); |
| 784 | 784 | ||
| 785 | /* last field in 'union bpf_attr' used by this command */ | 785 | /* last field in 'union bpf_attr' used by this command */ |
| 786 | #define BPF_PROG_LOAD_LAST_FIELD kern_version | 786 | #define BPF_PROG_LOAD_LAST_FIELD prog_flags |
| 787 | 787 | ||
| 788 | static int bpf_prog_load(union bpf_attr *attr) | 788 | static int bpf_prog_load(union bpf_attr *attr) |
| 789 | { | 789 | { |
| @@ -796,6 +796,9 @@ static int bpf_prog_load(union bpf_attr *attr) | |||
| 796 | if (CHECK_ATTR(BPF_PROG_LOAD)) | 796 | if (CHECK_ATTR(BPF_PROG_LOAD)) |
| 797 | return -EINVAL; | 797 | return -EINVAL; |
| 798 | 798 | ||
| 799 | if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) | ||
| 800 | return -EINVAL; | ||
| 801 | |||
| 799 | /* copy eBPF program license from user space */ | 802 | /* copy eBPF program license from user space */ |
| 800 | if (strncpy_from_user(license, u64_to_user_ptr(attr->license), | 803 | if (strncpy_from_user(license, u64_to_user_ptr(attr->license), |
| 801 | sizeof(license) - 1) < 0) | 804 | sizeof(license) - 1) < 0) |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ff2bfe1d656a..e74fb1b87855 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -791,6 +791,7 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) | |||
| 791 | static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, | 791 | static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, |
| 792 | int off, int size, bool strict) | 792 | int off, int size, bool strict) |
| 793 | { | 793 | { |
| 794 | int ip_align; | ||
| 794 | int reg_off; | 795 | int reg_off; |
| 795 | 796 | ||
| 796 | /* Byte size accesses are always allowed. */ | 797 | /* Byte size accesses are always allowed. */ |
| @@ -807,10 +808,14 @@ static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, | |||
| 807 | reg_off += reg->aux_off; | 808 | reg_off += reg->aux_off; |
| 808 | } | 809 | } |
| 809 | 810 | ||
| 810 | /* skb->data is NET_IP_ALIGN-ed */ | 811 | /* skb->data is NET_IP_ALIGN-ed, but for strict alignment checking |
| 811 | if ((NET_IP_ALIGN + reg_off + off) % size != 0) { | 812 | * we force this to 2 which is universally what architectures use |
| 813 | * when they don't set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS. | ||
| 814 | */ | ||
| 815 | ip_align = strict ? 2 : NET_IP_ALIGN; | ||
| 816 | if ((ip_align + reg_off + off) % size != 0) { | ||
| 812 | verbose("misaligned packet access off %d+%d+%d size %d\n", | 817 | verbose("misaligned packet access off %d+%d+%d size %d\n", |
| 813 | NET_IP_ALIGN, reg_off, off, size); | 818 | ip_align, reg_off, off, size); |
| 814 | return -EACCES; | 819 | return -EACCES; |
| 815 | } | 820 | } |
| 816 | 821 | ||
| @@ -828,10 +833,11 @@ static int check_val_ptr_alignment(const struct bpf_reg_state *reg, | |||
| 828 | return 0; | 833 | return 0; |
| 829 | } | 834 | } |
| 830 | 835 | ||
| 831 | static int check_ptr_alignment(const struct bpf_reg_state *reg, | 836 | static int check_ptr_alignment(struct bpf_verifier_env *env, |
| 837 | const struct bpf_reg_state *reg, | ||
| 832 | int off, int size) | 838 | int off, int size) |
| 833 | { | 839 | { |
| 834 | bool strict = false; | 840 | bool strict = env->strict_alignment; |
| 835 | 841 | ||
| 836 | if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) | 842 | if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) |
| 837 | strict = true; | 843 | strict = true; |
| @@ -873,7 +879,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off, | |||
| 873 | if (size < 0) | 879 | if (size < 0) |
| 874 | return size; | 880 | return size; |
| 875 | 881 | ||
| 876 | err = check_ptr_alignment(reg, off, size); | 882 | err = check_ptr_alignment(env, reg, off, size); |
| 877 | if (err) | 883 | if (err) |
| 878 | return err; | 884 | return err; |
| 879 | 885 | ||
| @@ -3568,6 +3574,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) | |||
| 3568 | } else { | 3574 | } else { |
| 3569 | log_level = 0; | 3575 | log_level = 0; |
| 3570 | } | 3576 | } |
| 3577 | if (attr->prog_flags & BPF_F_STRICT_ALIGNMENT) | ||
| 3578 | env->strict_alignment = true; | ||
| 3579 | else | ||
| 3580 | env->strict_alignment = false; | ||
| 3571 | 3581 | ||
| 3572 | ret = replace_map_fd_with_map_ptr(env); | 3582 | ret = replace_map_fd_with_map_ptr(env); |
| 3573 | if (ret < 0) | 3583 | if (ret < 0) |
| @@ -3673,6 +3683,7 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, | |||
| 3673 | mutex_lock(&bpf_verifier_lock); | 3683 | mutex_lock(&bpf_verifier_lock); |
| 3674 | 3684 | ||
| 3675 | log_level = 0; | 3685 | log_level = 0; |
| 3686 | env->strict_alignment = false; | ||
| 3676 | 3687 | ||
| 3677 | env->explored_states = kcalloc(env->prog->len, | 3688 | env->explored_states = kcalloc(env->prog->len, |
| 3678 | sizeof(struct bpf_verifier_state_list *), | 3689 | sizeof(struct bpf_verifier_state_list *), |
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c index ebc6dceddb58..7598361ef1f1 100644 --- a/tools/build/feature/test-bpf.c +++ b/tools/build/feature/test-bpf.c | |||
| @@ -29,6 +29,7 @@ int main(void) | |||
| 29 | attr.log_size = 0; | 29 | attr.log_size = 0; |
| 30 | attr.log_level = 0; | 30 | attr.log_level = 0; |
| 31 | attr.kern_version = 0; | 31 | attr.kern_version = 0; |
| 32 | attr.prog_flags = 0; | ||
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * Test existence of __NR_bpf and BPF_PROG_LOAD. | 35 | * Test existence of __NR_bpf and BPF_PROG_LOAD. |
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e553529929f6..94dfa9def355 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
| @@ -132,6 +132,13 @@ enum bpf_attach_type { | |||
| 132 | */ | 132 | */ |
| 133 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) | 133 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) |
| 134 | 134 | ||
| 135 | /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the | ||
| 136 | * verifier will perform strict alignment checking as if the kernel | ||
| 137 | * has been built with CONFIG_EFFICIENT_UNALIGNED_ACCESS not set, | ||
| 138 | * and NET_IP_ALIGN defined to 2. | ||
| 139 | */ | ||
| 140 | #define BPF_F_STRICT_ALIGNMENT (1U << 0) | ||
| 141 | |||
| 135 | #define BPF_PSEUDO_MAP_FD 1 | 142 | #define BPF_PSEUDO_MAP_FD 1 |
| 136 | 143 | ||
| 137 | /* flags for BPF_MAP_UPDATE_ELEM command */ | 144 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
| @@ -177,6 +184,7 @@ union bpf_attr { | |||
| 177 | __u32 log_size; /* size of user buffer */ | 184 | __u32 log_size; /* size of user buffer */ |
| 178 | __aligned_u64 log_buf; /* user supplied buffer */ | 185 | __aligned_u64 log_buf; /* user supplied buffer */ |
| 179 | __u32 kern_version; /* checked when prog_type=kprobe */ | 186 | __u32 kern_version; /* checked when prog_type=kprobe */ |
| 187 | __u32 prog_flags; | ||
| 180 | }; | 188 | }; |
| 181 | 189 | ||
| 182 | struct { /* anonymous struct used by BPF_OBJ_* commands */ | 190 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
| @@ -481,8 +489,7 @@ union bpf_attr { | |||
| 481 | * u32 bpf_get_socket_uid(skb) | 489 | * u32 bpf_get_socket_uid(skb) |
