aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOkash Khawaja <osk@fb.com>2018-07-10 17:33:07 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-07-11 16:36:08 -0400
commitb65f370d0671c4980ffe866c41e327b88893245c (patch)
tree6f2c9bc4ce56c7d0f63b7754d5cb34bb3960b4a4 /kernel
parent61d769807f273fda962866f3d4c677cda9974d3c (diff)
bpf: btf: Fix bitfield extraction for big endian
When extracting bitfield from a number, btf_int_bits_seq_show() builds a mask and accesses least significant byte of the number in a way specific to little-endian. This patch fixes that by checking endianness of the machine and then shifting left and right the unneeded bits. Thanks to Martin Lau for the help in navigating potential pitfalls when dealing with endianess and for the final solution. Fixes: b00b8daec828 ("bpf: btf: Add pretty print capability for data with BTF type info") Signed-off-by: Okash Khawaja <osk@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/btf.c30
1 files changed, 13 insertions, 17 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 2d49d18b793a..e016ac3afa24 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -991,16 +991,13 @@ static void btf_int_bits_seq_show(const struct btf *btf,
991 void *data, u8 bits_offset, 991 void *data, u8 bits_offset,
992 struct seq_file *m) 992 struct seq_file *m)
993{ 993{
994 u16 left_shift_bits, right_shift_bits;
994 u32 int_data = btf_type_int(t); 995 u32 int_data = btf_type_int(t);
995 u16 nr_bits = BTF_INT_BITS(int_data); 996 u16 nr_bits = BTF_INT_BITS(int_data);
996 u16 total_bits_offset; 997 u16 total_bits_offset;
997 u16 nr_copy_bytes; 998 u16 nr_copy_bytes;
998 u16 nr_copy_bits; 999 u16 nr_copy_bits;
999 u8 nr_upper_bits; 1000 u64 print_num;
1000 union {
1001 u64 u64_num;
1002 u8 u8_nums[8];
1003 } print_num;
1004 1001
1005 total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data); 1002 total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
1006 data += BITS_ROUNDDOWN_BYTES(total_bits_offset); 1003 data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
@@ -1008,21 +1005,20 @@ static void btf_int_bits_seq_show(const struct btf *btf,
1008 nr_copy_bits = nr_bits + bits_offset; 1005 nr_copy_bits = nr_bits + bits_offset;
1009 nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits); 1006 nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
1010 1007
1011 print_num.u64_num = 0; 1008 print_num = 0;
1012 memcpy(&print_num.u64_num, data, nr_copy_bytes); 1009 memcpy(&print_num, data, nr_copy_bytes);
1013 1010
1014 /* Ditch the higher order bits */ 1011#ifdef __BIG_ENDIAN_BITFIELD
1015 nr_upper_bits = BITS_PER_BYTE_MASKED(nr_copy_bits); 1012 left_shift_bits = bits_offset;
1016 if (nr_upper_bits) { 1013#else
1017 /* We need to mask out some bits of the upper byte. */ 1014 left_shift_bits = BITS_PER_U64 - nr_copy_bits;
1018 u8 mask = (1 << nr_upper_bits) - 1; 1015#endif
1016 right_shift_bits = BITS_PER_U64 - nr_bits;
1019 1017
1020 print_num.u8_nums[nr_copy_bytes - 1] &= mask; 1018 print_num <<= left_shift_bits;
1021 } 1019 print_num >>= right_shift_bits;
1022
1023 print_num.u64_num >>= bits_offset;
1024 1020
1025 seq_printf(m, "0x%llx", print_num.u64_num); 1021 seq_printf(m, "0x%llx", print_num);
1026} 1022}
1027 1023
1028static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t, 1024static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t,