diff options
Diffstat (limited to 'pkg/sentry/syscalls/linux/sys_write.go')
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_write.go | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/pkg/sentry/syscalls/linux/sys_write.go b/pkg/sentry/syscalls/linux/sys_write.go index 08e263112..750a098cd 100644 --- a/pkg/sentry/syscalls/linux/sys_write.go +++ b/pkg/sentry/syscalls/linux/sys_write.go @@ -187,6 +187,72 @@ func Pwritev(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysca return uintptr(n), nil, handleIOError(t, n != 0, err, kernel.ERESTARTSYS, "pwritev", file) } +// Pwritev2 implements linux syscall pwritev2(2). +// TODO: Implement RWF_HIPRI functionality. +// TODO: Implement O_SYNC and D_SYNC functionality. +func Pwritev2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + // While the syscall is + // pwritev2(int fd, struct iovec* iov, int iov_cnt, off_t offset, int flags) + // the linux internal call + // (https://elixir.bootlin.com/linux/v4.18/source/fs/read_write.c#L1354) + // splits the offset argument into a high/low value for compatibility with + // 32-bit architectures. The flags argument is the 5th argument. + + fd := kdefs.FD(args[0].Int()) + addr := args[1].Pointer() + iovcnt := int(args[2].Int()) + offset := args[3].Int64() + flags := int(args[5].Int()) + + if int(args[4].Int())&0x4 == 1 { + return 0, nil, syserror.EACCES + } + + file := t.FDMap().GetFile(fd) + if file == nil { + return 0, nil, syserror.EBADF + } + defer file.DecRef() + + // Check that the offset is legitimate. + if offset < -1 { + return 0, nil, syserror.EINVAL + } + + // Is writing at an offset supported? + if offset > -1 && !file.Flags().Pwrite { + return 0, nil, syserror.ESPIPE + } + + if flags&^linux.RWF_VALID != 0 { + return uintptr(flags), nil, syserror.EOPNOTSUPP + } + + // Check that the file is writeable. + if !file.Flags().Write { + return 0, nil, syserror.EBADF + } + + // Read the iovecs that specify the source of the write. + src, err := t.IovecsIOSequence(addr, iovcnt, usermem.IOOpts{ + AddressSpaceActive: true, + }) + if err != nil { + return 0, nil, err + } + + // If pwritev2 is called with an offset of -1, writev is called. + if offset == -1 { + n, err := writev(t, file, src) + t.IOUsage().AccountWriteSyscall(n) + return uintptr(n), nil, handleIOError(t, n != 0, err, kernel.ERESTARTSYS, "pwritev2", file) + } + + n, err := pwritev(t, file, src, offset) + t.IOUsage().AccountWriteSyscall(n) + return uintptr(n), nil, handleIOError(t, n != 0, err, kernel.ERESTARTSYS, "pwritev2", file) +} + func writev(t *kernel.Task, f *fs.File, src usermem.IOSequence) (int64, error) { n, err := f.Writev(t, src) if err != syserror.ErrWouldBlock || f.Flags().NonBlocking { |