-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
bpo-33871: Fix os.sendfile(), os.writev(), os.readv(), etc. #7931
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
Merged
serhiy-storchaka
merged 2 commits into
python:master
from
serhiy-storchaka:sendfile-macos-overflow
Jul 31, 2018
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
Misc/NEWS.d/next/Library/2018-06-26-19-03-56.bpo-33871.XhlrGU.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Fixed integer overflow in :func:`os.readv`, :func:`os.writev`, | ||
:func:`os.preadv` and :func:`os.pwritev` and in :func:`os.sendfile` with | ||
*headers* or *trailers* arguments (on BSD-based OSes and macOS). |
3 changes: 3 additions & 0 deletions
3
Misc/NEWS.d/next/Security/2018-06-26-19-35-33.bpo-33871.S4HR9n.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Fixed sending the part of the file in :func:`os.sendfile` on macOS. Using | ||
the *trailers* argument could cause sending more bytes from the input file | ||
than was specified. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 this. Is
off_t
always 64-bit on macOS?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.
According to
pymacconfig.h
,off_t
is equal tolong long
on 32-bit, andlong
on 64-bit. E.g. it is always 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.
I've checked the SDK headers to be sure, and off_t is indeed always 64-bit (off_t is a typedef for __darwin_off_t, and that in turn is a typedef for __int64_t).
The manpage for sendfile(2) doesn't mention this, but the one for writev(2) says:
Furthermore we have had problems with write(2) in the past when writing more than INT_MAX bytes at a time (see the implementation of _Py_write_impl). I think it is therefore better to limit the maximum size to INT_MAX, unless we explicitly test that sendfile can send more than INT_MAX bytes in one go.
BTW. Instead of OFF_T_MAX you could use OFF_MAX here, that should be defined to the maximum value of off_t.
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.
Is OFF_MAX a macOS specific constant?
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 have not just the sum of the iov_len values, but also added the length of the data sent from a file. The total sum can exceed 32-bit limit even if the sum of the iov_len values is in 32-bit limit.
I think it is better to use a 64-bit limit and allow OS to return an error if this is not supported. We should guard only from integer overflows occurred on the border between Python and OS.
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 _PyWrite_impl we explicitly guard against overflowing a 32-bit integer to avoid problems. IIRC this was done because this gives a nicer user experience (and hoping that Apple will fix this in the kernel is not really useful).
I'll see if I can create a simple test to check if sendfile suffers from the same limitation on 10.13 and 10.14.
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 _PyWrite_impl there is a different situation. We guard against overflowing
int
on Windows becausewrite()
accepts onlyunsigned int
as the count argument on Windows, and because it is allowed to write less bytes then requested inwrite()
. This is a border between Python and OS.readv()
,writev()
andsendfile()
acceptsize_t
as the length of every chunk on all supported OSes even if OS doesn't support writing too large total size. I'm not sure that it is better to silently truncate the output than raise OSError. At leastsendfile()
with headers and trailers will produce corrupted output in this case: headers, than truncated content, than trailers.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.
_Py_write_impl does indeed not limit writes, I was confused because I have a local patch for issue 24658 that I never pushed...
sendfile like write can write less bytes than requested (at least, that's what the API suggests as it returns the amount of bytes written), limiting the amount of data written to avoid misbehaviour of the OS shouldn't be a problem.
That said: limiting is only necessary when there is a reason to do so. I guess I'll really have to write a test program that checks what the system does when trying to write more than 2GB of data.
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 test sending 2 GiB with headers and trailers.
If truncate the total size to INT_MAX, then this can send
b"[begin]"
, then2**31-1-7
bytes from the file (instead of expected2**31-1
bytes) and thenb"[end]"
. This is a wrong result.