@samitouri / QOSamiQemu / commits / 9b7d64686b

linux-user: update select timeout writeback

The Linux kernel writes back the remaining timeout for select-family syscalls in poll_select_finish(). If that writeback fails, it keeps the original return value. However, QEMU only writes back the timeout on success. If the writeback fails, QEMU returns -TARGET_EFAULT. This can lose the remaining timeout and change the return value. Update do_select(), do_pselect6(), and do_ppoll() to always write back the timeout to match the Linux kernel's behavior. If the timeout writeback fails, keep the original return value. Tested with the issue reproducer. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3343 Signed-off-by: Sun Haoyu <shyliuli@aosc.io> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260320111647.138984-1-shyliuli@aosc.io Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Sun Haoyu committed Mar 20, 2026 at 19:16 UTC 9b7d64686b82bb70315cc60e5630c70e27eef832
1 file changed +24 -21
linux-user/syscall.c
+24 -21
@@ -1384,14 +1384,15 @@ static abi_long do_select(int n,
1384 return -TARGET_EFAULT;
1385 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
1386 return -TARGET_EFAULT;
1387 -
1388 - if (target_tv_addr) {
1389 - tv.tv_sec = ts.tv_sec;
1390 - tv.tv_usec = ts.tv_nsec / 1000;
1391 - if (copy_to_user_timeval(target_tv_addr, &tv)) {
1392 - return -TARGET_EFAULT;
1393 - }
1394 - }
1387 + }
1388 + if (target_tv_addr) {
1389 + tv.tv_sec = ts.tv_sec;
1390 + tv.tv_usec = ts.tv_nsec / 1000;
1391 + /*
1392 + * Like the kernel, we deliberately ignore possible
1393 + * failures writing back to the timeout struct.
1394 + */
1395 + copy_to_user_timeval(target_tv_addr, &tv);
1396 }
1397
1398 return ret;
@@ -1519,14 +1520,16 @@ static abi_long do_pselect6(abi_long arg1, abi_long arg2, abi_long arg3,
1520 if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) {
1521 return -TARGET_EFAULT;
1522 }
1523 + }
1524 + if (ts_addr) {
1525 + /*
1526 + * Like the kernel, we deliberately ignore possible
1527 + * failures writing back to the timeout struct.
1528 + */
1529 if (time64) {
1523 - if (ts_addr && host_to_target_timespec64(ts_addr, &ts)) {
1524 - return -TARGET_EFAULT;
1525 - }
1530 + host_to_target_timespec64(ts_addr, &ts);
1531 } else {
1527 - if (ts_addr && host_to_target_timespec(ts_addr, &ts)) {
1528 - return -TARGET_EFAULT;
1529 - }
1532 + host_to_target_timespec(ts_addr, &ts);
1533 }
1534 }
1535 return ret;
@@ -1596,15 +1599,15 @@ static abi_long do_ppoll(abi_long arg1, abi_long arg2, abi_long arg3,
1599 if (set) {
1600 finish_sigsuspend_mask(ret);
1601 }
1599 - if (!is_error(ret) && arg3) {
1602 + if (arg3) {
1603 + /*
1604 + * Like the kernel, we deliberately ignore possible
1605 + * failures writing back to the timeout struct.
1606 + */
1607 if (time64) {
1601 - if (host_to_target_timespec64(arg3, timeout_ts)) {
1602 - return -TARGET_EFAULT;
1603 - }
1608 + host_to_target_timespec64(arg3, timeout_ts);
1609 } else {
1605 - if (host_to_target_timespec(arg3, timeout_ts)) {
1606 - return -TARGET_EFAULT;
1607 - }
1610 + host_to_target_timespec(arg3, timeout_ts);
1611 }
1612 }
1613 } else {