Fix sendfile(2) error code

When output file is in append mode, sendfile(2) should fail
with EINVAL and not EBADF.

Closes #721

PiperOrigin-RevId: 265718958
This commit is contained in:
Fabricio Voznika 2019-08-27 10:51:23 -07:00 committed by gVisor bot
parent c39564332b
commit 8fd89fd7a2
2 changed files with 37 additions and 10 deletions

View File

@ -91,24 +91,31 @@ func Sendfile(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
}
// Get files.
outFile := t.GetFile(outFD)
if outFile == nil {
return 0, nil, syserror.EBADF
}
defer outFile.DecRef()
inFile := t.GetFile(inFD)
if inFile == nil {
return 0, nil, syserror.EBADF
}
defer inFile.DecRef()
// Verify that the outfile Append flag is not set. Note that fs.Splice
// itself validates that the output file is writable.
if outFile.Flags().Append {
if !inFile.Flags().Read {
return 0, nil, syserror.EBADF
}
outFile := t.GetFile(outFD)
if outFile == nil {
return 0, nil, syserror.EBADF
}
defer outFile.DecRef()
if !outFile.Flags().Write {
return 0, nil, syserror.EBADF
}
// Verify that the outfile Append flag is not set.
if outFile.Flags().Append {
return 0, nil, syserror.EINVAL
}
// Verify that we have a regular infile. This is a requirement; the
// same check appears in Linux (fs/splice.c:splice_direct_to_actor).
if !fs.IsRegular(inFile.Dirent.Inode.StableAttr) {

View File

@ -299,10 +299,30 @@ TEST(SendFileTest, DoNotSendfileIfOutfileIsAppendOnly) {
// Open the output file as append only.
const FileDescriptor outf =
ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_APPEND));
ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_WRONLY | O_APPEND));
// Send data and verify that sendfile returns the correct errno.
EXPECT_THAT(sendfile(outf.get(), inf.get(), nullptr, kDataSize),
SyscallFailsWithErrno(EINVAL));
}
TEST(SendFileTest, AppendCheckOrdering) {
constexpr char kData[] = "And by opposing end them: to die, to sleep";
constexpr int kDataSize = sizeof(kData) - 1;
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
GetAbsoluteTestTmpdir(), kData, TempPath::kDefaultFileMode));
const FileDescriptor read =
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY));
const FileDescriptor write =
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_WRONLY));
const FileDescriptor append =
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_APPEND));
// Check that read/write file mode is verified before append.
EXPECT_THAT(sendfile(append.get(), read.get(), nullptr, kDataSize),
SyscallFailsWithErrno(EBADF));
EXPECT_THAT(sendfile(write.get(), write.get(), nullptr, kDataSize),
SyscallFailsWithErrno(EBADF));
}