diff options
author | David S. Miller <davem@davemloft.net> | 2017-04-01 15:36:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-01 15:36:38 -0400 |
commit | 0989bd034a125cef29bd6351514d588fc616b39a (patch) | |
tree | 9098a803f81125ec916cbb36610b45ddd6731f51 /kernel | |
parent | d5b07ccc1bf5fd2ccc6bf9da5677fc448a972e32 (diff) | |
parent | 02ea80b1850e48abbce77878896229d7cc5cb230 (diff) |
Merge branch 'bpf-map_value_adj-reg-types-fixes'
Daniel Borkmann says:
====================
BPF fixes on map_value_adj reg types
This set adds two fixes for map_value_adj register type in the
verifier and user space tests along with them for the BPF self
test suite. For details, please see individual patches.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/bpf/verifier.c | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5e6202e62265..a834068a400e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -765,38 +765,56 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) | |||
765 | } | 765 | } |
766 | } | 766 | } |
767 | 767 | ||
768 | static int check_ptr_alignment(struct bpf_verifier_env *env, | 768 | static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, |
769 | struct bpf_reg_state *reg, int off, int size) | 769 | int off, int size) |
770 | { | 770 | { |
771 | if (reg->type != PTR_TO_PACKET && reg->type != PTR_TO_MAP_VALUE_ADJ) { | ||
772 | if (off % size != 0) { | ||
773 | verbose("misaligned access off %d size %d\n", | ||
774 | off, size); | ||
775 | return -EACCES; | ||
776 | } else { | ||
777 | return 0; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) | ||
782 | /* misaligned access to packet is ok on x86,arm,arm64 */ | ||
783 | return 0; | ||
784 | |||
785 | if (reg->id && size != 1) { | 771 | if (reg->id && size != 1) { |
786 | verbose("Unknown packet alignment. Only byte-sized access allowed\n"); | 772 | verbose("Unknown alignment. Only byte-sized access allowed in packet access.\n"); |
787 | return -EACCES; | 773 | return -EACCES; |
788 | } | 774 | } |
789 | 775 | ||
790 | /* skb->data is NET_IP_ALIGN-ed */ | 776 | /* skb->data is NET_IP_ALIGN-ed */ |
791 | if (reg->type == PTR_TO_PACKET && | 777 | if ((NET_IP_ALIGN + reg->off + off) % size != 0) { |
792 | (NET_IP_ALIGN + reg->off + off) % size != 0) { | ||
793 | verbose("misaligned packet access off %d+%d+%d size %d\n", | 778 | verbose("misaligned packet access off %d+%d+%d size %d\n", |
794 | NET_IP_ALIGN, reg->off, off, size); | 779 | NET_IP_ALIGN, reg->off, off, size); |
795 | return -EACCES; | 780 | return -EACCES; |
796 | } | 781 | } |
782 | |||
797 | return 0; | 783 | return 0; |
798 | } | 784 | } |
799 | 785 | ||
786 | static int check_val_ptr_alignment(const struct bpf_reg_state *reg, | ||
787 | int size) | ||
788 | { | ||
789 | if (size != 1) { | ||
790 | verbose("Unknown alignment. Only byte-sized access allowed in value access.\n"); | ||
791 | return -EACCES; | ||
792 | } | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static int check_ptr_alignment(const struct bpf_reg_state *reg, | ||
798 | int off, int size) | ||
799 | { | ||
800 | switch (reg->type) { | ||
801 | case PTR_TO_PACKET: | ||
802 | return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 : | ||
803 | check_pkt_ptr_alignment(reg, off, size); | ||
804 | case PTR_TO_MAP_VALUE_ADJ: | ||
805 | return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 : | ||
806 | check_val_ptr_alignment(reg, size); | ||
807 | default: | ||
808 | if (off % size != 0) { | ||
809 | verbose("misaligned access off %d size %d\n", | ||
810 | off, size); | ||
811 | return -EACCES; | ||
812 | } | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | } | ||
817 | |||
800 | /* check whether memory at (regno + off) is accessible for t = (read | write) | 818 | /* check whether memory at (regno + off) is accessible for t = (read | write) |
801 | * if t==write, value_regno is a register which value is stored into memory | 819 | * if t==write, value_regno is a register which value is stored into memory |
802 | * if t==read, value_regno is a register which will receive the value from memory | 820 | * if t==read, value_regno is a register which will receive the value from memory |
@@ -818,7 +836,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off, | |||
818 | if (size < 0) | 836 | if (size < 0) |
819 | return size; | 837 | return size; |
820 | 838 | ||
821 | err = check_ptr_alignment(env, reg, off, size); | 839 | err = check_ptr_alignment(reg, off, size); |
822 | if (err) | 840 | if (err) |
823 | return err; | 841 | return err; |
824 | 842 | ||
@@ -1925,6 +1943,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
1925 | * register as unknown. | 1943 | * register as unknown. |
1926 | */ | 1944 | */ |
1927 | if (env->allow_ptr_leaks && | 1945 | if (env->allow_ptr_leaks && |
1946 | BPF_CLASS(insn->code) == BPF_ALU64 && opcode == BPF_ADD && | ||
1928 | (dst_reg->type == PTR_TO_MAP_VALUE || | 1947 | (dst_reg->type == PTR_TO_MAP_VALUE || |
1929 | dst_reg->type == PTR_TO_MAP_VALUE_ADJ)) | 1948 | dst_reg->type == PTR_TO_MAP_VALUE_ADJ)) |
1930 | dst_reg->type = PTR_TO_MAP_VALUE_ADJ; | 1949 | dst_reg->type = PTR_TO_MAP_VALUE_ADJ; |