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.
Unified · Split
| @@ -90,6 +90,7 @@ struct bpf_verifier_env { · 89 unmodified lines | ||
| 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 */ |
| @@ -132,6 +132,13 @@ enum bpf_attach_type { · 131 unmodified lines | ||
| 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 @@ union bpf_attr { · 39 unmodified lines | ||
| 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 */ |
| @@ -783,7 +783,7 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type) · 782 unmodified lines | ||
| 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 | { |
| @@ -796,6 +796,9 @@ static int bpf_prog_load(union bpf_attr *attr) · 6 unmodified lines | ||
| 796 | 796 | if (CHECK_ATTR(BPF_PROG_LOAD)) |
| 797 | 797 | return -EINVAL; |
| 798 | 798 | |
| 799 | + if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) | |
| 800 | + return -EINVAL; | |
| 801 | + | |
| 799 | 802 | /* copy eBPF program license from user space */ |
| 800 | 803 | if (strncpy_from_user(license, u64_to_user_ptr(attr->license), |
| 801 | 804 | sizeof(license) - 1) < 0) |
| @@ -791,6 +791,7 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) · 790 unmodified lines | ||
| 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. */ |
| @@ -807,10 +808,14 @@ static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, · 10 unmodified lines | ||
| 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 | |
| @@ -828,10 +833,11 @@ static int check_val_ptr_alignment(const struct bpf_reg_state *reg, · 11 unmodified lines | ||
| 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 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off, · 35 unmodified lines | ||
| 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 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) · 2688 unmodified lines | ||
| 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 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, · 99 unmodified lines | ||
| 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 *), |
| @@ -29,6 +29,7 @@ int main(void) · 28 unmodified lines | ||
| 29 | 29 | attr.log_size = 0; |
| 30 | 30 | attr.log_level = 0; |
| 31 | 31 | attr.kern_version = 0; |
| 32 | + attr.prog_flags = 0; | |
| 32 | 33 | |
| 33 | 34 | /* |
| 34 | 35 | * Test existence of __NR_bpf and BPF_PROG_LOAD. |
| @@ -132,6 +132,13 @@ enum bpf_attach_type { · 131 unmodified lines | ||
| 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 @@ union bpf_attr { · 39 unmodified lines | ||
| 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 @@ union bpf_attr { · 298 unmodified lines | ||
| 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), \ |