Created attachment 198079 [details] Please use the pull request instead. While doing some digging around the syscall, I noticed (via code inspection) that it doesn't percolate issues with copyout back to userspace. This means that failures to call copyout might result in incorrectly communicated values for sbytes. The attached patch percolates up the EFAULT issues from copyout.
(In reply to Enji Cooper from comment #0) I thought about the proposed patch and I don't think it was a good complete solution. I have submitted https://github.com/freebsd/freebsd/pull/169 instead for the issue.
That's a good catch, but I don't fully agree on the patch. Some return values of sendfile aren't errors, and the patch doesn't cover them. If sendfile returns EAGAIN, which is normal for non-blocking socket, we again ignore copyout error. I think we should take in copyout error always.
A commit references this bug: Author: ngie Date: Wed Jan 23 22:00:18 UTC 2019 New revision: 343362 URL: https://svnweb.freebsd.org/changeset/base/343362 Log: Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625 Changes: head/lib/libc/tests/sys/Makefile head/lib/libc/tests/sys/sendfile_test.c
A commit references this bug: Author: ngie Date: Fri Jan 25 19:56:02 UTC 2019 New revision: 343444 URL: https://svnweb.freebsd.org/changeset/base/343444 Log: Document that `sendfile` will return an invalid value for `sbytes` if provided an invalid address This is meant to clarify the fact that the system call will not fail with -1/EFAULT, as one might expect, when reading the sendfile(2) manpage today. While here, pet the mandoc linter, when dealing with the section that describes valid values for `flags`. PR: 232210 MFC after: 2 weeks Approved by: emaste (mentor) Reviewed by: glebius, 0mp Differential Revision: https://reviews.freebsd.org/D18949 Changes: head/lib/libc/sys/sendfile.2
A commit references this bug: Author: ngie Date: Tue Feb 12 02:57:29 UTC 2019 New revision: 344037 URL: https://svnweb.freebsd.org/changeset/base/344037 Log: MFC r343444: Document that `sendfile` will return an invalid value for `sbytes` if provided an invalid address This is meant to clarify the fact that the system call will not fail with -1/EFAULT, as one might expect, when reading the sendfile(2) manpage today. While here, pet the mandoc linter, when dealing with the section that describes valid values for `flags`. PR: 232210 Approved by: jtl (mentor) Differential Revision: https://reviews.freebsd.org/D19151 Changes: _U stable/12/ stable/12/lib/libc/sys/sendfile.2
A commit references this bug: Author: ngie Date: Tue Feb 12 02:57:35 UTC 2019 New revision: 344038 URL: https://svnweb.freebsd.org/changeset/base/344038 Log: MFC r339343,r343444: r339343 (by allanjude): Document that sendfile(2) can return ENOTCAPABLE PR: 232207 r343444: Document that `sendfile` will return an invalid value for `sbytes` if provided an invalid address This is meant to clarify the fact that the system call will not fail with -1/EFAULT, as one might expect, when reading the sendfile(2) manpage today. While here, pet the mandoc linter, when dealing with the section that describes valid values for `flags`. PR: 232210 Approved by: jtl (mentor) Differential Revision: https://reviews.freebsd.org/D19150 Changes: _U stable/11/ stable/11/lib/libc/sys/sendfile.2
A commit references this bug: Author: ngie Date: Sun Mar 10 16:13:01 UTC 2019 New revision: 344977 URL: https://svnweb.freebsd.org/changeset/base/344977 Log: MFC r343362,r343365,r343367,r343368,r343461,r343751,r344310: r343362: Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. PR: 232210 r343365: Unbreak the gcc build with sendfile_test after r343362 gcc 8.x is more pedantic than clang 7.x with format strings and the tests passed `void*` variables while supplying `%s` (which is technically incorrect). Make the affected `void*` variables use `char*` storage instead to address this issue, as the compiler will upcast the values to `char*`. MFC with: r343362 r343367: Unbreak the build on architectures where size_t isn't synonymous with uintmax_t I should have used `%zu` instead of `%ju` with `size_t` types. MFC with: r343362, r343365 Pointyhat to: ngie r343368: Fix up r343367 I should have only changed the format qualifier with the `size_t` value, `length`, not the other [`off_t`] value, `dest_file_size`. MFC with: r343362, r343365, r343367 r343461: Fix reporting errors with `gai_strerror(..)` The return value (`err`) should be checked; not the `errno` value. PR: 235200 MFC with: r343362, r343365, r343367-r343368 r343751: Avoid the DNS lookup for "localhost" ci.FreeBSD.org does not have access to a DNS resolver/network (unlike my test VM), so in order for the test to pass on the host, it needs to avoid the DNS lookup by using the numeric host address representation. PR: 235200 MFC with: r343362, r343365, r343367-r343368, r343461 r344310: Make `server_cat(..)` handle short receives In short, the prior code was far too simplistic when it came to calling recv(2) and failed intermittently (or in the case of Jenkins, deterministically). Handle short recv(2)s by checking the return code and incrementing the window into the buffer by the number of received bytes. If the number of received bytes <= 0, then bail out of the loop, and test the total number of received bytes vs the expected number of bytes sent for equality, and base whether or not the test passes/fails on that fact. Remove the expected failure, now that the hdtr testcases deterministically pass on my host after this change [1]. PR: 234809 [1], 235200 Approved by: emaste (mentor) Differential Revision: https://reviews.freebsd.org/D19524 Changes: _U stable/11/ stable/11/lib/libc/tests/sys/Makefile stable/11/lib/libc/tests/sys/sendfile_test.c
A commit references this bug: Author: ngie Date: Sun Mar 10 16:14:43 UTC 2019 New revision: 344978 URL: https://svnweb.freebsd.org/changeset/base/344978 Log: MFC r343362,r343365,r343367,r343368,r343461,r343751,r344310: r343362: Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. PR: 232210 r343365: Unbreak the gcc build with sendfile_test after r343362 gcc 8.x is more pedantic than clang 7.x with format strings and the tests passed `void*` variables while supplying `%s` (which is technically incorrect). Make the affected `void*` variables use `char*` storage instead to address this issue, as the compiler will upcast the values to `char*`. MFC with: r343362 r343367: Unbreak the build on architectures where size_t isn't synonymous with uintmax_t I should have used `%zu` instead of `%ju` with `size_t` types. MFC with: r343362, r343365 Pointyhat to: ngie r343368: Fix up r343367 I should have only changed the format qualifier with the `size_t` value, `length`, not the other [`off_t`] value, `dest_file_size`. MFC with: r343362, r343365, r343367 r343461: Fix reporting errors with `gai_strerror(..)` The return value (`err`) should be checked; not the `errno` value. PR: 235200 MFC with: r343362, r343365, r343367-r343368 r343751: Avoid the DNS lookup for "localhost" ci.FreeBSD.org does not have access to a DNS resolver/network (unlike my test VM), so in order for the test to pass on the host, it needs to avoid the DNS lookup by using the numeric host address representation. PR: 235200 MFC with: r343362, r343365, r343367-r343368, r343461 r344310: Make `server_cat(..)` handle short receives In short, the prior code was far too simplistic when it came to calling recv(2) and failed intermittently (or in the case of Jenkins, deterministically). Handle short recv(2)s by checking the return code and incrementing the window into the buffer by the number of received bytes. If the number of received bytes <= 0, then bail out of the loop, and test the total number of received bytes vs the expected number of bytes sent for equality, and base whether or not the test passes/fails on that fact. Remove the expected failure, now that the hdtr testcases deterministically pass on my host after this change [1]. PR: 234809 [1], 235200 Approved by: emaste (mentor, implicit: MFC to ^/stable/11 in r344977) Differential Revision: https://reviews.freebsd.org/D19523 Changes: _U stable/12/ stable/12/lib/libc/tests/sys/Makefile stable/12/lib/libc/tests/sys/sendfile_test.c