-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ipc: fix endianness issues #1854
Conversation
Codecov Report
|
executor/executor.cc
Outdated
if (output_pos < output_data || (char*)output_pos >= (char*)output_data + kMaxOutput) | ||
fail("output overflow: pos=%p region=[%p:%p]", | ||
output_pos, output_data, (char*)output_data + kMaxOutput); | ||
*output_pos = v; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in pkg/ipc/ipc.go we do:
func readUint64(outp *[]byte) (uint64, bool) {
out := *outp
if len(out) < 8 {
return 0, false
}
v := binary.LittleEndian.Uint64(out)
*outp = out[8:]
return v, true
}
that's native endianess, right.
Or, do you plan more changes to pkg/ipc as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added more ipc fixes to the commit, i wanted first to separate them but ok
executor/executor_linux.h
Outdated
@@ -167,8 +167,11 @@ 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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please no braces {} around single-statement blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
A meta comment to this and previous changes: |
Later i will provide support for IBM's s390x 64-bit big-endian architecture which can be run in QEMU on x86 w/o KVM or with on IBM/Z. |
@@ -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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the name. Maybe we should use function overloading here but i decided against because
it is easy to misuse and pass uint32 instead of uint64 and compiler will not warn about it. What do you think ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with this version for now. I don't see significant reasons to switch to something else now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
37bfd94
to
ebdc38a
Compare
NB: Tests like sys/test/test/align0 are going to be the next block on the road to the first big-endian architecture. It also assumes little-endian architecture, sigh. Any ideas how to better address that ? But otherwise, all unit tests run now in my s390x syzkaller setup. Thank you for feedback |
34bfe4a
to
457ef1b
Compare
@@ -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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with this version for now. I don't see significant reasons to switch to something else now.
executor/executor.cc
Outdated
@@ -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 >= (char*)output_data + kMaxOutput) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We now need some adjustment to the check I think. It assumes we write a single element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good finding, thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
prog/encodingexec_test.go
Outdated
@@ -204,7 +210,8 @@ 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, | |||
convDataToUint64([]byte{0x01, 0x02, 0x03, 0x04, 0x05}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite verbose and convoluted way to represent numbers. I will need some additional brain cycles to decode this while reading. Will it work if we add letoh64
and then do letoh64(0x0504030201)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, i must disagree here because i find it more readable if i do not have to swap bytes every time i look at this code :) But i do not mind changing it, no big deal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
prog/encodingexec_test.go
Outdated
for _, v := range test.serialized { | ||
tmp := make([]byte, 8) | ||
*(*uint64)(unsafe.Pointer(&tmp[0])) = v | ||
w.Write(tmp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these changes... here, in prog package and in ipc package... it's not that I am opposed to every single use of unsafe... but we are adding lots of them throughout and new imports of "unsafe". Since this is now something we need to care about throughout the codebase, I am trying to consider alternatives.
For example, if we would have binary.NativeEndian
(or HostEndian
), it seems that it would allow to quite nice solution. Say, here, we just change s/LittleEndian/HostEndian. What do you think?
I am surprised binary package does not have it... is there something I am missing?.. whatever... we can add it ourselves.
We need to add it in some low-level enough package to avoid circular dependencies. That's probably sys/targets
for now.
I think we can even avoid any additional overhead and indirection by doing (for each arch:
// little_endian.go
// +build amd64 386 arm ...
package targets
import "encdoing/binary"
var HostEndian = binary.LittleEndian
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great idea, i like it :) I also find it abhorrent to add all those casting statements, it feels dirty. I also was surprised as i discovered that Go doesn't offer something like binary.NativeEndian.
Let me rework it then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re Go, that's:
golang/go#35398
golang/go#36040
and:
golang/go#37658
So it's probably not going to happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A problem. targets package uses prog package already but i need HostEndian in the prog package, cycle. Any suggestion ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we make Endianness a field of Target ? I will need it anyways later for extractFromELF ?
type Target struct { ... ByteOrder binary.ByteOrder ... }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- You are right re cycle. Then I guess we need to put it into prog package.
- I would prefer both standalone
prog.HostEndianess
and optionally as field of target. The reason for standalone is that it will allow inlining and not forcing arguments to escape.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Oh, you are running these tests. That's good. |
Cool! We would also like to run some non-x86 arches on syzbot using qemu tcg. |
I run all unit tests but those which hardcode data in little-endian format fail of course on s390x big-endian arch. I must say i find the idea of adding littleendian flag on the one side very good because it will allow me to disable failing little-endian tests quickly and proceed with my port. But on the other side i find it's not good disabling tests because they fail. Which leaves me the option of duplicating the same tests and fixing byte-order, which is better but not quite because duplication is bad. What do you think ? Could you elaborate your idea with new 'syz_*' functions please ? |
That's the only option that I see now. I am fine adding few basic tests and tests for bugs/regressions.
No. Because I don't have any details :) |
You probably mean the binfmt_misc file system and /proc/sys/fs/binfmt_misc. What you mean (correct me if i'm wrong) is cross-compiling Go unit tests for s390x arch on x86 arch and run the produced binary with qemu-system-s390x. Let me test it and then report back, right now i cannot say anything about it. But otherwise qemu tcg s390x was fine on my x86 machine. Slow but it worked :) BTW, i also ported s390x to buildroot and will upstream it soon. I use it now for syzkaller testing. Hmm, half hour booting, that's very long. I need maybe a couple of minutes to boot my buildroot kernel + rootfs prepared for syzakller. |
You are right.
Good. Yes, buildroot should produce something much more thin than a modern Debian with systemd. |
I will address !littleendian in the next PR. |
Use native byte-order for IPC and program serialization. This way we will be able to support both little- and big-endian architectures. Signed-off-by: Alexander Egorenkov <Alexander.Egorenkov@ibm.com>
Nice! |
Small followup: 8e0c064 |
Use native byte-order for IPC and program serialization.
This way we will be able to support both little- and big-endian
architectures.
Signed-off-by: Alexander Egorenkov Alexander.Egorenkov@ibm.com
Before sending a pull request, please review Contribution Guidelines:
https://github.com/google/syzkaller/blob/master/docs/contributing.md