Skip to content

copy_file_range and splice accept a negative offset #467

Open

Description

@xalestar

copy_file_range and splice read *off_in and *off_out from guest memory into an int64_t that starts at -1, and the copy code treats any negative value as "use the descriptor's position" (io_copy_chunked in src/syscall/io.c, and the same >= 0 tests in the splice path). A guest that passes a pointer to a negative offset therefore gets a copy from or to the file position instead of an error.

Linux rejects these calls. Measured with a static aarch64 probe that writes 8 bytes to a regular file and calls each syscall with a pointer to -1 and a count of 4:

Call Linux (qemu) elfuse
copy_file_range, *off_in = -1 -1, EOVERFLOW 4
copy_file_range, *off_out = -1 -1, EOVERFLOW 4
splice file to pipe, *off_in = -1 -1, EINVAL 4
splice pipe to file, *off_out = -1 -1, EINVAL 4

On Linux, copy_file_range gives EOVERFLOW because generic_copy_file_checks adds the size_t count to the loff_t position, the negative position promotes to a huge unsigned value, and the sum wraps. splice gives EINVAL from the rw_verify_area check on a negative position.

Goal: a negative offset passed by pointer is refused with the Linux errno before anything is copied, and the "no pointer" case keeps using the descriptor position. That means the sentinel would have to be "pointer was NULL" rather than "value is negative".

Found while answering review on #463; not changed there because it is outside RLIMIT_FSIZE.

Activity

  1. xalestar commented on Oct 24, 2026

    @xalestar
    CollaboratorAuthor

    The copy_file_range half is fixed on #463 in 7d0851f. copy_file_range now tests pos + len < pos as an unsigned sum at both ends, as generic_copy_file_checks does, so a negative *off_in or *off_out whose sum wraps returns EOVERFLOW, matching the qemu measurement above (-1 with a count of 4). A negative offset whose sum does not wrap, such as -4096 with a count of 10, gets EINVAL from rw_verify_area on qemu, and elfuse now returns EINVAL there too. An earlier version of this comment said every negative offset gives EOVERFLOW; that holds only when the sum wraps. The splice half (EINVAL for a negative offset) is still open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions