mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 19:41:10 +00:00
fix: safely copy controller events to caller buffers
Stage ring and keyframe events before copying them with process_vm_writev. Return EFAULT for inaccessible destinations and advance the reader only for complete events delivered, preserving partial readv progress. Retested Factorio on the Thor with the exact ARM64 library.
This commit is contained in:
1 parent
a17a40db02
commit
c0359d1c8c
1 file changed
+26
-13
@@ -3577,6 +3577,21 @@ EXPORT int close(int fd) {
|
||||
static constexpr int kMaxRingWaitMs = 2;
|
||||
static constexpr int kLowLatencyRingWaitUs = 250;
|
||||
|
||||
static ssize_t copy_input_events(void *buf, const struct input_event *events, size_t count) {
|
||||
size_t bytes = count * sizeof(struct input_event);
|
||||
struct iovec local = {const_cast<struct input_event *>(events), bytes};
|
||||
struct iovec remote = {buf, bytes};
|
||||
ssize_t copied = syscall(SYS_process_vm_writev, getpid(), &local, 1, &remote, 1, 0);
|
||||
if (copied < 0) return -1;
|
||||
if (copied != static_cast<ssize_t>(bytes)) {
|
||||
errno = EFAULT;
|
||||
// evdev reads only report complete input_event records.
|
||||
copied -= copied % sizeof(struct input_event);
|
||||
if (!copied) return -1;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t read_input(int fd, void *buf, size_t count) {
|
||||
if (!watched(fd)) return syscall(SYS_read, fd, buf, count);
|
||||
std::unique_lock<std::recursive_mutex> guard(controller_mutex());
|
||||
@@ -3622,42 +3637,44 @@ static ssize_t read_input(int fd, void *buf, size_t count) {
|
||||
if (events == 0) break;
|
||||
const uint8_t *ring_events = reinterpret_cast<const uint8_t *>(fake.ring) +
|
||||
FAKE_INPUT_RING_HEADER_SIZE;
|
||||
std::vector<struct input_event> input_events(events);
|
||||
for (size_t i = 0; i < events; ++i) {
|
||||
size_t index = (fake.read_seq + i) % FAKE_INPUT_RING_CAPACITY;
|
||||
RingEvent stored;
|
||||
memcpy(&stored, ring_events + index * FAKE_INPUT_EVENT_SIZE, FAKE_INPUT_EVENT_SIZE);
|
||||
struct input_event ev = {};
|
||||
struct input_event &ev = input_events[i];
|
||||
ev.time.tv_sec = stored.sec;
|
||||
ev.time.tv_usec = stored.usec;
|
||||
ev.type = stored.type;
|
||||
ev.code = stored.code;
|
||||
ev.value = stored.value;
|
||||
if (ev.type == EV_ABS) ev.code = presented_abs_code(fake, ev.code);
|
||||
memcpy(static_cast<uint8_t *>(buf) + i * sizeof(ev), &ev, sizeof(ev));
|
||||
}
|
||||
__atomic_thread_fence(__ATOMIC_ACQUIRE);
|
||||
if (snap.sequence != __atomic_load_n(&fake.ring->snapshot_seq, __ATOMIC_RELAXED))
|
||||
continue;
|
||||
fake.read_seq += events;
|
||||
return static_cast<ssize_t>(events * sizeof(struct input_event));
|
||||
ssize_t copied = copy_input_events(buf, input_events.data(), events);
|
||||
if (copied > 0) fake.read_seq += copied / sizeof(struct input_event);
|
||||
return copied;
|
||||
}
|
||||
}
|
||||
|
||||
size_t events = std::min(requested, fake.keyframe_remaining);
|
||||
struct input_event input_events[kNeutralEventCount] = {};
|
||||
struct timeval now = {};
|
||||
gettimeofday(&now, nullptr);
|
||||
for (size_t i = 0; i < events; ++i) {
|
||||
size_t index = kNeutralEventCount - fake.keyframe_remaining;
|
||||
struct input_event ev = {};
|
||||
size_t index = kNeutralEventCount - fake.keyframe_remaining + i;
|
||||
struct input_event &ev = input_events[i];
|
||||
ev.time = now;
|
||||
ev.type = kNeutralEvents[index].type;
|
||||
ev.code = kNeutralEvents[index].code;
|
||||
ev.value = keyframe_value(fake, ev.type, ev.code);
|
||||
if (ev.type == EV_ABS) ev.code = presented_abs_code(fake, ev.code);
|
||||
memcpy(static_cast<uint8_t *>(buf) + i * sizeof(ev), &ev, sizeof(ev));
|
||||
--fake.keyframe_remaining;
|
||||
}
|
||||
return static_cast<ssize_t>(events * sizeof(struct input_event));
|
||||
ssize_t copied = copy_input_events(buf, input_events, events);
|
||||
if (copied > 0) fake.keyframe_remaining -= copied / sizeof(struct input_event);
|
||||
return copied;
|
||||
}
|
||||
if (nonblock) {
|
||||
errno = EAGAIN;
|
||||
@@ -3706,10 +3723,6 @@ EXPORT ssize_t readv(int fd, const struct iovec *iov, int iovcnt) {
|
||||
return -1;
|
||||
}
|
||||
size += iov[i].iov_len;
|
||||
if (iov[i].iov_len && !iov[i].iov_base) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// evdev's readv calls its read handler per vector; Steam's ARM64 overlay uses this path too.
|
||||
|
||||
Reference in new issue
Block a user