mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Require pread/pwrite for splice file offsets
If there is an offset, the file must support pread/pwrite. See fs/splice.c:do_splice. PiperOrigin-RevId: 261944932
This commit is contained in:
committed by
gVisor bot
parent
fb996668e4
commit
704f9610f3
@@ -207,6 +207,10 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
|
||||
return 0, nil, syserror.ESPIPE
|
||||
}
|
||||
if outOffset != 0 {
|
||||
if !outFile.Flags().Pwrite {
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
|
||||
var offset int64
|
||||
if _, err := t.CopyIn(outOffset, &offset); err != nil {
|
||||
return 0, nil, err
|
||||
@@ -220,6 +224,10 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
|
||||
return 0, nil, syserror.ESPIPE
|
||||
}
|
||||
if inOffset != 0 {
|
||||
if !inFile.Flags().Pread {
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
|
||||
var offset int64
|
||||
if _, err := t.CopyIn(inOffset, &offset); err != nil {
|
||||
return 0, nil, err
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -135,6 +136,80 @@ TEST(SpliceTest, PipeOffsets) {
|
||||
SyscallFailsWithErrno(ESPIPE));
|
||||
}
|
||||
|
||||
// Event FDs may be used with splice without an offset.
|
||||
TEST(SpliceTest, FromEventFD) {
|
||||
// Open the input eventfd with an initial value so that it is readable.
|
||||
constexpr uint64_t kEventFDValue = 1;
|
||||
int efd;
|
||||
ASSERT_THAT(efd = eventfd(kEventFDValue, 0), SyscallSucceeds());
|
||||
const FileDescriptor inf(efd);
|
||||
|
||||
// Create a new pipe.
|
||||
int fds[2];
|
||||
ASSERT_THAT(pipe(fds), SyscallSucceeds());
|
||||
const FileDescriptor rfd(fds[0]);
|
||||
const FileDescriptor wfd(fds[1]);
|
||||
|
||||
// Splice 8-byte eventfd value to pipe.
|
||||
constexpr int kEventFDSize = 8;
|
||||
EXPECT_THAT(splice(inf.get(), nullptr, wfd.get(), nullptr, kEventFDSize, 0),
|
||||
SyscallSucceedsWithValue(kEventFDSize));
|
||||
|
||||
// Contents should be equal.
|
||||
std::vector<char> rbuf(kEventFDSize);
|
||||
ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()),
|
||||
SyscallSucceedsWithValue(kEventFDSize));
|
||||
EXPECT_EQ(memcmp(rbuf.data(), &kEventFDValue, rbuf.size()), 0);
|
||||
}
|
||||
|
||||
// Event FDs may not be used with splice with an offset.
|
||||
TEST(SpliceTest, FromEventFDOffset) {
|
||||
int efd;
|
||||
ASSERT_THAT(efd = eventfd(0, 0), SyscallSucceeds());
|
||||
const FileDescriptor inf(efd);
|
||||
|
||||
// Create a new pipe.
|
||||
int fds[2];
|
||||
ASSERT_THAT(pipe(fds), SyscallSucceeds());
|
||||
const FileDescriptor rfd(fds[0]);
|
||||
const FileDescriptor wfd(fds[1]);
|
||||
|
||||
// Attempt to splice 8-byte eventfd value to pipe with offset.
|
||||
//
|
||||
// This is not allowed because eventfd doesn't support pread.
|
||||
constexpr int kEventFDSize = 8;
|
||||
loff_t in_off = 0;
|
||||
EXPECT_THAT(splice(inf.get(), &in_off, wfd.get(), nullptr, kEventFDSize, 0),
|
||||
SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
// Event FDs may not be used with splice with an offset.
|
||||
TEST(SpliceTest, ToEventFDOffset) {
|
||||
// Create a new pipe.
|
||||
int fds[2];
|
||||
ASSERT_THAT(pipe(fds), SyscallSucceeds());
|
||||
const FileDescriptor rfd(fds[0]);
|
||||
const FileDescriptor wfd(fds[1]);
|
||||
|
||||
// Fill with a value.
|
||||
constexpr int kEventFDSize = 8;
|
||||
std::vector<char> buf(kEventFDSize);
|
||||
buf[0] = 1;
|
||||
ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
|
||||
SyscallSucceedsWithValue(kEventFDSize));
|
||||
|
||||
int efd;
|
||||
ASSERT_THAT(efd = eventfd(0, 0), SyscallSucceeds());
|
||||
const FileDescriptor outf(efd);
|
||||
|
||||
// Attempt to splice 8-byte eventfd value to pipe with offset.
|
||||
//
|
||||
// This is not allowed because eventfd doesn't support pwrite.
|
||||
loff_t out_off = 0;
|
||||
EXPECT_THAT(splice(rfd.get(), nullptr, outf.get(), &out_off, kEventFDSize, 0),
|
||||
SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
TEST(SpliceTest, ToPipe) {
|
||||
// Open the input file.
|
||||
const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
|
||||
|
||||
Reference in New Issue
Block a user