@@ -3797,7 +3797,8 @@ static Switchable did_emulate_read(int syscallno, RecordTask* t,
37973797{
37983798 syscall_state.emulate_result (result);
37993799 record_ranges (t, ranges, result);
3800- if (syscallno == Arch::pread64 || syscallno == Arch::preadv || result <= 0 ) {
3800+ if (syscallno == Arch::pread64 || syscallno == Arch::preadv ||
3801+ syscallno == Arch::preadv2 || result <= 0 ) {
38013802 // Don't perform this syscall.
38023803 Registers r = t->regs ();
38033804 r.set_arg1 (-1 );
@@ -3823,6 +3824,42 @@ static ParamSize select_param_size(intptr_t nfds, SupportedArch arch) {
38233824 return ParamSize (size);
38243825}
38253826
3827+ // RWF_* flags we know rr records correctly. Reject unknown flags so
3828+ // that a future kernel addition whose semantics break rr (e.g. affecting
3829+ // the offset or bytes we record) cannot silently go wrong; the tracee
3830+ // simply sees EINVAL as if running on an older kernel.
3831+ // RWF_APPEND is excluded from the write mask: when set, the kernel
3832+ // ignores the user's offset and uses/updates the current file position,
3833+ // but FileMonitor::retrieve_offset would compute the explicit offset
3834+ // argument and get it wrong.
3835+ enum {
3836+ RR_RWF_HIPRI = 0x00000001 ,
3837+ RR_RWF_DSYNC = 0x00000002 ,
3838+ RR_RWF_SYNC = 0x00000004 ,
3839+ RR_RWF_NOWAIT = 0x00000008 ,
3840+ RR_RWF_APPEND = 0x00000010 ,
3841+ RR_RWF_NOAPPEND = 0x00000020 ,
3842+ RR_RWF_ATOMIC = 0x00000040 ,
3843+ RR_RWF_DONTCACHE = 0x00000080 ,
3844+ };
3845+ static const uint32_t RR_KNOWN_PREADV2_FLAGS =
3846+ RR_RWF_HIPRI | RR_RWF_DSYNC | RR_RWF_SYNC | RR_RWF_NOWAIT |
3847+ RR_RWF_APPEND | RR_RWF_NOAPPEND | RR_RWF_ATOMIC | RR_RWF_DONTCACHE;
3848+ static const uint32_t RR_KNOWN_PWRITEV2_FLAGS =
3849+ RR_KNOWN_PREADV2_FLAGS & ~RR_RWF_APPEND;
3850+
3851+ template <typename Arch>
3852+ static Switchable reject_preadv2_pwritev2 (RecordTask* t,
3853+ TaskSyscallState& syscall_state) {
3854+ syscall_state.emulate_result (-EINVAL);
3855+ // Point fd at -1 so the kernel short-circuits the syscall with -EBADF;
3856+ // emulate_result overrides the tracee-visible result to -EINVAL.
3857+ Registers r = t->regs ();
3858+ r.set_arg1 (-1 );
3859+ t->set_regs (r);
3860+ return PREVENT_SWITCH;
3861+ }
3862+
38263863template <typename Arch>
38273864static Switchable rec_prepare_syscall_arch (RecordTask* t,
38283865 TaskSyscallState& syscall_state,
@@ -4556,7 +4593,14 @@ static Switchable rec_prepare_syscall_arch(RecordTask* t,
45564593 case Arch::readv:
45574594 /* ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
45584595 off_t offset); */
4559- case Arch::preadv: {
4596+ case Arch::preadv:
4597+ /* ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt,
4598+ off_t offset, int flags); */
4599+ case Arch::preadv2: {
4600+ if (syscallno == Arch::preadv2 &&
4601+ ((uint32_t )regs.arg6 () & ~RR_KNOWN_PREADV2_FLAGS)) {
4602+ return reject_preadv2_pwritev2<Arch>(t, syscall_state);
4603+ }
45604604 int fd = (int )regs.arg1_signed ();
45614605 int iovcnt = (int )regs.arg3_signed ();
45624606 remote_ptr<void > iovecsp_void = syscall_state.reg_parameter (
@@ -4583,6 +4627,15 @@ static Switchable rec_prepare_syscall_arch(RecordTask* t,
45834627 return ALLOW_SWITCH;
45844628 }
45854629
4630+ /* ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt,
4631+ off_t offset, int flags); */
4632+ case Arch::pwritev2: {
4633+ if ((uint32_t )regs.arg6 () & ~RR_KNOWN_PWRITEV2_FLAGS) {
4634+ return reject_preadv2_pwritev2<Arch>(t, syscall_state);
4635+ }
4636+ return ALLOW_SWITCH;
4637+ }
4638+
45864639 /* pid_t waitpid(pid_t pid, int *status, int options); */
45874640 /* pid_t wait4(pid_t pid, int *status, int options, struct rusage
45884641 * *rusage);
@@ -7282,6 +7335,8 @@ static void rec_process_syscall_arch(RecordTask* t,
72827335 case Arch::pkey_mprotect:
72837336 case Arch::pread64:
72847337 case Arch::preadv:
7338+ case Arch::preadv2:
7339+ case Arch::pwritev2:
72857340 case Arch::ptrace:
72867341 case Arch::read:
72877342 case Arch::readv:
0 commit comments