Commit e07b98d9bffe410019dfcf62c3428d4a96c56a2c
1 parent
c5fc9692d1
Exists in
smarc_imx_lf-5.15.y
and in
20 other branches
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>
Showing 6 changed files with 40 additions and 9 deletions Side-by-side Diff
include/linux/bpf_verifier.h
... | ... | @@ -90,6 +90,7 @@ |
90 | 90 | struct bpf_prog *prog; /* eBPF program being verified */ |
91 | 91 | struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */ |
92 | 92 | int stack_size; /* number of states to be processed */ |
93 | + bool strict_alignment; /* perform strict pointer alignment checks */ | |
93 | 94 | struct bpf_verifier_state cur_state; /* current verifier state */ |
94 | 95 | struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ |
95 | 96 | const struct bpf_ext_analyzer_ops *analyzer_ops; /* external analyzer ops */ |
include/uapi/linux/bpf.h
... | ... | @@ -132,6 +132,13 @@ |
132 | 132 | */ |
133 | 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 | 142 | #define BPF_PSEUDO_MAP_FD 1 |
136 | 143 | |
137 | 144 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
... | ... | @@ -177,6 +184,7 @@ |
177 | 184 | __u32 log_size; /* size of user buffer */ |
178 | 185 | __aligned_u64 log_buf; /* user supplied buffer */ |
179 | 186 | __u32 kern_version; /* checked when prog_type=kprobe */ |
187 | + __u32 prog_flags; | |
180 | 188 | }; |
181 | 189 | |
182 | 190 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
kernel/bpf/syscall.c
... | ... | @@ -783,7 +783,7 @@ |
783 | 783 | EXPORT_SYMBOL_GPL(bpf_prog_get_type); |
784 | 784 | |
785 | 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 | 788 | static int bpf_prog_load(union bpf_attr *attr) |
789 | 789 | { |
... | ... | @@ -794,6 +794,9 @@ |
794 | 794 | bool is_gpl; |
795 | 795 | |
796 | 796 | if (CHECK_ATTR(BPF_PROG_LOAD)) |
797 | + return -EINVAL; | |
798 | + | |
799 | + if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) | |
797 | 800 | return -EINVAL; |
798 | 801 | |
799 | 802 | /* copy eBPF program license from user space */ |
kernel/bpf/verifier.c
... | ... | @@ -791,6 +791,7 @@ |
791 | 791 | static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, |
792 | 792 | int off, int size, bool strict) |
793 | 793 | { |
794 | + int ip_align; | |
794 | 795 | int reg_off; |
795 | 796 | |
796 | 797 | /* Byte size accesses are always allowed. */ |
797 | 798 | |
... | ... | @@ -807,10 +808,14 @@ |
807 | 808 | reg_off += reg->aux_off; |
808 | 809 | } |
809 | 810 | |
810 | - /* skb->data is NET_IP_ALIGN-ed */ | |
811 | - if ((NET_IP_ALIGN + reg_off + off) % size != 0) { | |
811 | + /* skb->data is NET_IP_ALIGN-ed, but for strict alignment checking | |
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 | 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 | 819 | return -EACCES; |
815 | 820 | } |
816 | 821 | |
817 | 822 | |
... | ... | @@ -828,10 +833,11 @@ |
828 | 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 | 838 | int off, int size) |
833 | 839 | { |
834 | - bool strict = false; | |
840 | + bool strict = env->strict_alignment; | |
835 | 841 | |
836 | 842 | if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) |
837 | 843 | strict = true; |
... | ... | @@ -873,7 +879,7 @@ |
873 | 879 | if (size < 0) |
874 | 880 | return size; |
875 | 881 | |
876 | - err = check_ptr_alignment(reg, off, size); | |
882 | + err = check_ptr_alignment(env, reg, off, size); | |
877 | 883 | if (err) |
878 | 884 | return err; |
879 | 885 | |
... | ... | @@ -3568,6 +3574,10 @@ |
3568 | 3574 | } else { |
3569 | 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 | 3582 | ret = replace_map_fd_with_map_ptr(env); |
3573 | 3583 | if (ret < 0) |
... | ... | @@ -3673,6 +3683,7 @@ |
3673 | 3683 | mutex_lock(&bpf_verifier_lock); |
3674 | 3684 | |
3675 | 3685 | log_level = 0; |
3686 | + env->strict_alignment = false; | |
3676 | 3687 | |
3677 | 3688 | env->explored_states = kcalloc(env->prog->len, |
3678 | 3689 | sizeof(struct bpf_verifier_state_list *), |
tools/build/feature/test-bpf.c
tools/include/uapi/linux/bpf.h
... | ... | @@ -132,6 +132,13 @@ |
132 | 132 | */ |
133 | 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 | 142 | #define BPF_PSEUDO_MAP_FD 1 |
136 | 143 | |
137 | 144 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
... | ... | @@ -177,6 +184,7 @@ |
177 | 184 | __u32 log_size; /* size of user buffer */ |
178 | 185 | __aligned_u64 log_buf; /* user supplied buffer */ |
179 | 186 | __u32 kern_version; /* checked when prog_type=kprobe */ |
187 | + __u32 prog_flags; | |
180 | 188 | }; |
181 | 189 | |
182 | 190 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
... | ... | @@ -481,8 +489,7 @@ |
481 | 489 | * u32 bpf_get_socket_uid(skb) |
482 | 490 | * Get the owner uid of the socket stored inside sk_buff. |
483 | 491 | * @skb: pointer to skb |
484 | - * Return: uid of the socket owner on success or 0 if the socket pointer | |
485 | - * inside sk_buff is NULL | |
492 | + * Return: uid of the socket owner on success or overflowuid if failed. | |
486 | 493 | */ |
487 | 494 | #define __BPF_FUNC_MAPPER(FN) \ |
488 | 495 | FN(unspec), \ |