diff --git a/executor/executor.cc b/executor/executor.cc index ab8ae3d6c553..19aa45e814de 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -95,6 +95,7 @@ const int kOutFd = 4; static uint32* output_data; static uint32* output_pos; static uint32* write_output(uint32 v); +static uint32* write_output_64(uint64 v); static void write_completed(uint32 completed); static uint32 hash(uint32 a); static bool dedup(uint32 sig); @@ -1308,6 +1309,15 @@ uint32* write_output(uint32 v) return output_pos++; } +uint32* write_output_64(uint64 v) +{ + if (output_pos < output_data || (char*)(output_pos + 1) >= (char*)output_data + kMaxOutput) + fail("output overflow: pos=%p region=[%p:%p]", + output_pos, output_data, (char*)output_data + kMaxOutput); + *(uint64*)output_pos = v; + return output_pos + 2; +} + void write_completed(uint32 completed) { __atomic_store_n(output_data, completed, __ATOMIC_RELEASE); @@ -1344,13 +1354,10 @@ void kcov_comparison_t::write() if (!is_size_8) { write_output((uint32)arg1); write_output((uint32)arg2); - return; + } else { + write_output_64(arg1); + write_output_64(arg2); } - // If we have 64 bits arguments then write them in Little-endian. - write_output((uint32)(arg1 & 0xFFFFFFFF)); - write_output((uint32)(arg1 >> 32)); - write_output((uint32)(arg2 & 0xFFFFFFFF)); - write_output((uint32)(arg2 >> 32)); } bool kcov_comparison_t::ignore() const diff --git a/executor/executor_linux.h b/executor/executor_linux.h index 47804f4f4f73..98b89fc9a9d5 100644 --- a/executor/executor_linux.h +++ b/executor/executor_linux.h @@ -167,8 +167,10 @@ static void cover_reset(cover_t* cov) static void cover_collect(cover_t* cov) { - // Note: this assumes little-endian kernel. - cov->size = *(uint32*)cov->data; + if (is_kernel_64_bit) + cov->size = *(uint64*)cov->data; + else + cov->size = *(uint32*)cov->data; } static bool cover_check(uint32 pc) diff --git a/executor/test.h b/executor/test.h index 1f940eb714b5..0d3587b849f2 100644 --- a/executor/test.h +++ b/executor/test.h @@ -8,7 +8,7 @@ static int test_copyin() { static uint16 buf[3]; - STORE_BY_BITMASK(uint16, , &buf[1], 0x1234, 0, 16); + STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x1234, 0, 16); unsigned char x[sizeof(buf)]; memcpy(x, buf, sizeof(x)); if (x[0] != 0 || x[1] != 0 || @@ -18,7 +18,7 @@ static int test_copyin() x[0], x[1], x[2], x[3], x[4], x[5]); return 1; } - STORE_BY_BITMASK(uint16, , &buf[1], 0x555a, 5, 4); + STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x555a, 5, 4); memcpy(x, buf, sizeof(x)); if (x[0] != 0 || x[1] != 0 || x[2] != 0x54 || x[3] != 0x13 || diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go index f6aa20855e16..1abab7f5ef71 100644 --- a/pkg/ipc/ipc.go +++ b/pkg/ipc/ipc.go @@ -4,7 +4,6 @@ package ipc import ( - "encoding/binary" "fmt" "io" "io/ioutil" @@ -439,7 +438,7 @@ func readUint32(outp *[]byte) (uint32, bool) { if len(out) < 4 { return 0, false } - v := binary.LittleEndian.Uint32(out) + v := prog.HostEndian.Uint32(out) *outp = out[4:] return v, true } @@ -449,7 +448,7 @@ func readUint64(outp *[]byte) (uint64, bool) { if len(out) < 8 { return 0, false } - v := binary.LittleEndian.Uint64(out) + v := prog.HostEndian.Uint64(out) *outp = out[8:] return v, true } diff --git a/prog/big_endian.go b/prog/big_endian.go new file mode 100644 index 000000000000..1f9ebfffebd0 --- /dev/null +++ b/prog/big_endian.go @@ -0,0 +1,10 @@ +// Copyright 2020 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +// +build s390x + +package prog + +import "encoding/binary" + +var HostEndian = binary.BigEndian diff --git a/prog/decodeexec.go b/prog/decodeexec.go index 57f08d0fceae..e2ef2586c352 100644 --- a/prog/decodeexec.go +++ b/prog/decodeexec.go @@ -203,10 +203,7 @@ func (dec *execDecoder) read() uint64 { if dec.err != nil { return 0 } - var v uint64 - for i := 0; i < 8; i++ { - v |= uint64(dec.data[i]) << uint(i*8) - } + v := HostEndian.Uint64(dec.data) dec.data = dec.data[8:] return v } diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 78eae81ae888..2295bb72e1c6 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -20,6 +20,8 @@ package prog import ( + "bytes" + "encoding/binary" "fmt" "sort" ) @@ -221,14 +223,9 @@ func (w *execContext) write(v uint64) { w.eof = true return } - w.buf[0] = byte(v >> 0) - w.buf[1] = byte(v >> 8) - w.buf[2] = byte(v >> 16) - w.buf[3] = byte(v >> 24) - w.buf[4] = byte(v >> 32) - w.buf[5] = byte(v >> 40) - w.buf[6] = byte(v >> 48) - w.buf[7] = byte(v >> 56) + buf := new(bytes.Buffer) + binary.Write(buf, HostEndian, v) + copy(w.buf, buf.Bytes()) w.buf = w.buf[8:] } diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index 141cf5dda698..7cda63cc06bf 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -42,6 +42,18 @@ func TestSerializeForExec(t *testing.T) { } return uint64(c.ID) } + letoh64 := func(v uint64) uint64 { + buf := make([]byte, 8) + buf[0] = byte(v >> 0) + buf[1] = byte(v >> 8) + buf[2] = byte(v >> 16) + buf[3] = byte(v >> 24) + buf[4] = byte(v >> 32) + buf[5] = byte(v >> 40) + buf[6] = byte(v >> 48) + buf[7] = byte(v >> 56) + return HostEndian.Uint64(buf) + } tests := []struct { prog string serialized []uint64 @@ -204,7 +216,7 @@ func TestSerializeForExec(t *testing.T) { "test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})", []uint64{ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset + 1, execArgData, 5, 0x0504030201, + execInstrCopyin, dataOffset + 1, execArgData, 5, letoh64(0x0504030201), callID("test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, @@ -214,7 +226,7 @@ func TestSerializeForExec(t *testing.T) { "test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})", []uint64{ execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, - execInstrCopyin, dataOffset + 2, execArgData, 16, 0xbbbbbbbbaaaaaaaa, 0xddddddddcccccccc, + execInstrCopyin, dataOffset + 2, execArgData, 16, letoh64(0xbbbbbbbbaaaaaaaa), letoh64(0xddddddddcccccccc), execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43, callID("test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, @@ -436,8 +448,7 @@ func TestSerializeForExec(t *testing.T) { execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x1, execInstrCopyin, dataOffset + 6, execArgConst, 4 | 1<<8, 0x2, execInstrCopyin, dataOffset + 10, execArgConst, 2, 0x0, - execInstrCopyin, dataOffset + 12, execArgData, 1, 0xab, - + execInstrCopyin, dataOffset + 12, execArgData, 1, letoh64(0xab), execInstrCopyin, dataOffset + 10, execArgCsum, 2, ExecArgCsumInet, 5, ExecArgCsumChunkData, dataOffset + 2, 4, ExecArgCsumChunkData, dataOffset + 6, 4, @@ -466,11 +477,11 @@ func TestSerializeForExec(t *testing.T) { t.Fatalf("failed to serialize: %v", err) } w := new(bytes.Buffer) - binary.Write(w, binary.LittleEndian, test.serialized) + binary.Write(w, HostEndian, test.serialized) data := buf[:n] if !bytes.Equal(data, w.Bytes()) { got := make([]uint64, len(data)/8) - binary.Read(bytes.NewReader(data), binary.LittleEndian, &got) + binary.Read(bytes.NewReader(data), HostEndian, &got) t.Logf("want: %v", test.serialized) t.Logf("got: %v", got) t.Fatalf("mismatch") diff --git a/prog/little_endian.go b/prog/little_endian.go new file mode 100644 index 000000000000..4403926576f4 --- /dev/null +++ b/prog/little_endian.go @@ -0,0 +1,10 @@ +// Copyright 2020 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +// +build amd64 386 arm64 arm mips64le ppc64le + +package prog + +import "encoding/binary" + +var HostEndian = binary.LittleEndian