Ticket #117 (closed defect: fixed)
Opened 21 months ago
Last modified 18 months ago
[PATCH] darwin_async_io_callback data truncation
| Reported by: | rogueresearch | Owned by: | hjelmn |
|---|---|---|---|
| Milestone: | Component: | libusb-1.0 | |
| Keywords: | Cc: | ||
| Blocked By: | Blocks: |
Description
The private function darwin_async_io_callback() has a bug.
It is correctly declared with the IOAsyncCallback1 signature:
static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0)
Note the last param is a pointer and thus either 32 or 64 bit in size, depending on architecture.
The last lines of code in the function are:
write (priv->fds[1], &message, sizeof (message));
write (priv->fds[1], &itransfer, sizeof (itransfer));
write (priv->fds[1], &result, sizeof (IOReturn));
write (priv->fds[1], &arg0, sizeof (UInt32));
The last line is wrong on 64 bit architectures. And a wonderful example of why it is preferable to use sizeof() on a variable, and not on a type. That's done for the first 2, but not the last two.
Attached is an *untested* patch that fixes the above. I also reviewed use of sizeof() in the same file and fixed a few others.
I'm hoping this is why libusb is broken for me on ppc64 but working on x86_64. On big endian, only the most significant (likely 0) bytes are written.
Attachments
Change History
Changed 21 months ago by rogueresearch
comment:1 Changed 21 months ago by rogueresearch
- Owner set to hjelmn
- Status changed from new to assigned
comment:2 follow-up: ↓ 3 Changed 21 months ago by stuge
comment:3 in reply to: ↑ 2 Changed 21 months ago by stuge
Replying to stuge:
The question is if it is better to write 64 bits and truncate into UInt32 io_size on the receiving end, or if it is better to truncated void *arg0 into an UInt32 before it gets written
..or the third option of course: to always write and read UInt64, which would require darwin_handle_callback() to change the io_size parameter from UInt32. I'm not sure if UInt64 would be relevant?
comment:4 Changed 21 months ago by rogueresearch
stuge, thanks for noticing the omission in my patch. As I said, it's untested.
Option 3 would quickly morph into ticket #85 I suspect.
Perhaps it would be best to truncate 64 -> 32 (the value, not the pointer, of course) until #85 can be thoroughly dealt with.
But I don't know libusb well, and defer to Nathan and you.
comment:5 follow-up: ↓ 6 Changed 21 months ago by vlovich
I think it's best to assign arg0 to a 32-bit value that is written but also put in an assert in darwin_async_io_callback that arg0 <= UINT32_MAX (or instead of assert make it an explicit check that prints an error). Also, it should send the full 64-bit value across the pipe & do the truncation in op_handle_events.
comment:6 in reply to: ↑ 5 Changed 21 months ago by stuge
Replying to vlovich:
I think it's best to assign arg0 to a 32-bit value that is written
..
Also, it should send the full 64-bit value across the pipe
I think these are directly opposing statements? :)
comment:7 Changed 21 months ago by hjelmn
comment:8 Changed 21 months ago by hjelmn
- Status changed from assigned to accepted
comment:9 Changed 21 months ago by rogueresearch
The just attached patch does as Nathan suggests, which, given the imminent release, is probably best. It introduces a compiler warning about truncating a pointer to a smaller integer (which indeed should not be done), but at run time this is better than what was there previously.
I've only tested that it builds.
comment:10 Changed 20 months ago by rogueresearch
OK, I've tested this on ppc64, i386, and x86_64. Works great for me. Can we please get it in 1.0.9, thanks!
comment:11 Changed 20 months ago by hjelmn
Should have noted I fixed this in libusb-darwin. Should make it into 1.0.9.
comment:12 Changed 18 months ago by Nathan Hjelm <hjelmn@…>
- Resolution set to fixed
- Status changed from accepted to closed
The patch is not quite complete, because it will write 64 bits but only read 32 on the other end.
The question is if it is better to write 64 bits and truncate into UInt32 io_size on the receiving end, or if it is better to truncated void *arg0 into an UInt32 before it gets written over the pipe. What's your take, Nathan?