Merge tag 'linux-user-next-pull-request' of https://github.com/hdeller/qemu-hppa into staging Pull request for linux-user Please pull 4 fixes for the linux-user target. Two patches fix open bug reports regarding return error codes and allowed parameters. One adds missing CDROM ioctls (and fixes a few), and the last patch is a leftover from the previous pull request and helps flushing error strings at exit. # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCafMCcAAKCRD3ErUQojoP # XxaVAPsEXGQiK8DSTXx6h0FQ8wUkhCTOXCECVTjydYhk2kA0BwD+PXXBaODFLJwR # b2Mtt0A7il8W5Iclvy/FCa6Pkm9vFw4= # =zPZb # -----END PGP SIGNATURE----- # gpg: Signature made Thu 30 Apr 2026 03:19:12 EDT # gpg: using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F # gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown] # gpg: aka "Helge Deller <deller@kernel.org>" [unknown] # gpg: aka "Helge Deller <deller@debian.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 4544 8228 2CD9 10DB EF3D 25F8 3E5F 3D04 A7A2 4603 # Subkey fingerprint: BCE9 123E 1AD2 9F07 C049 BBDE F712 B510 A23A 0F5F * tag 'linux-user-next-pull-request' of https://github.com/hdeller/qemu-hppa: linux-user: Translate errno in IP_RECVERR and IPV6_RECVERR linux-user: Allow getsockopt() with NULL optval address linux-user: Flush errors by using exit() instead of _exit() in error path linux-user: Add missing CDROM ioctls Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 5b7d00e..aa485ee 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h
@@ -416,19 +416,18 @@ #endif IOCTL(CDROMPAUSE, 0, TYPE_NULL) - IOCTL(CDROMSTART, 0, TYPE_NULL) - IOCTL(CDROMSTOP, 0, TYPE_NULL) IOCTL(CDROMRESUME, 0, TYPE_NULL) - IOCTL(CDROMEJECT, 0, TYPE_NULL) - IOCTL(CDROMEJECT_SW, 0, TYPE_INT) - IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL) - IOCTL(CDROMRESET, 0, TYPE_NULL) IOCTL(CDROMPLAYMSF, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMPLAYTRKIND, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMREADTOCHDR, IOC_R, MK_PTR(TYPE_INT)) IOCTL(CDROMREADTOCENTRY, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMSTOP, 0, TYPE_NULL) + IOCTL(CDROMSTART, 0, TYPE_NULL) + IOCTL(CDROMEJECT, 0, TYPE_NULL) IOCTL(CDROMVOLCTRL, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMSUBCHNL, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMEJECT_SW, IOC_W, TYPE_INT) + IOCTL(CDROMRESET, 0, TYPE_NULL) /* XXX: incorrect (need specific handling) */ IOCTL(CDROMREADAUDIO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_cdrom_read_audio))) IOCTL(CDROMREADCOOKED, IOC_RW, MK_PTR(TYPE_INT)) @@ -438,16 +437,22 @@ IOCTL(CDROMREADALL, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(CDROMMULTISESSION, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(CDROM_GET_UPC, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(CDROM_LAST_WRITTEN, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(CDROMVOLREAD, IOC_R, MK_PTR(TYPE_INT)) IOCTL(CDROMSEEK, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMPLAYBLK, IOC_W, MK_PTR(TYPE_INT)) - IOCTL(CDROM_MEDIA_CHANGED, 0, TYPE_NULL) - IOCTL(CDROM_SET_OPTIONS, 0, TYPE_INT) - IOCTL(CDROM_CLEAR_OPTIONS, 0, TYPE_INT) - IOCTL(CDROM_SELECT_SPEED, 0, TYPE_INT) - IOCTL(CDROM_SELECT_DISC, 0, TYPE_INT) - IOCTL(CDROM_DRIVE_STATUS, 0, TYPE_NULL) + IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL) + IOCTL(CDROM_SET_OPTIONS, IOC_W, TYPE_INT) + IOCTL(CDROM_CLEAR_OPTIONS, IOC_W, TYPE_INT) + IOCTL(CDROM_SELECT_SPEED, IOC_W, TYPE_INT) + IOCTL(CDROM_SELECT_DISC, IOC_W, TYPE_INT) + IOCTL(CDROM_MEDIA_CHANGED, IOC_W, TYPE_INT) + IOCTL(CDROM_DRIVE_STATUS, IOC_W, TYPE_INT) IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL) + IOCTL(CDROM_CHANGER_NSLOTS, 0, TYPE_NULL) + IOCTL(CDROM_LOCKDOOR, IOC_W, TYPE_INT) + IOCTL(CDROM_DEBUG, IOC_W, TYPE_INT) + IOCTL(CDROM_GET_CAPABILITY, 0, TYPE_NULL) IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT) #if 0
diff --git a/linux-user/main.c b/linux-user/main.c index 84e110d..86d04cc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c
@@ -975,7 +975,7 @@ info, &bprm); if (ret != 0) { printf("Error while loading %s: %s\n", exec_path, strerror(-ret)); - _exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } for (wrk = target_environ; *wrk; wrk++) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4594909..d3d9fff 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c
@@ -2008,7 +2008,8 @@ tgt_len != sizeof(struct errhdr_t)) { goto unimplemented; } - __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno); + __put_user(host_to_target_errno(errh->ee.ee_errno), + &target_errh->ee.ee_errno); __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin); __put_user(errh->ee.ee_type, &target_errh->ee.ee_type); __put_user(errh->ee.ee_code, &target_errh->ee.ee_code); @@ -2062,7 +2063,8 @@ tgt_len != sizeof(struct errhdr6_t)) { goto unimplemented; } - __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno); + __put_user(host_to_target_errno(errh->ee.ee_errno), + &target_errh->ee.ee_errno); __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin); __put_user(errh->ee.ee_type, &target_errh->ee.ee_type); __put_user(errh->ee.ee_code, &target_errh->ee.ee_code); @@ -2644,6 +2646,10 @@ if (ret < 0) { return ret; } + /* special case: destination address is NULL, return 0 */ + if (optval_addr) { + len = 0; + } if (len == sizeof(struct target__kernel_sock_timeval)) { if (copy_to_user_timeval64(optval_addr, &tv)) { return -TARGET_EFAULT; @@ -2844,7 +2850,10 @@ } if (len > lv) len = lv; - if (len == 4) { + if (!optval_addr) { + /* writing to NULL does not give error */ + len = 0; + } else if (len == 4) { if (put_user_u32(val, optval_addr)) return -TARGET_EFAULT; } else { @@ -2877,18 +2886,24 @@ return -TARGET_EINVAL; lv = sizeof(lv); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); +write_ret: if (ret < 0) return ret; - if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { + if (!optval_addr) { + len = 0; + } else if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { len = 1; - if (put_user_u32(len, optlen) - || put_user_u8(val, optval_addr)) + if (put_user_u8(val, optval_addr)) { return -TARGET_EFAULT; + } } else { if (len > sizeof(int)) len = sizeof(int); - if (put_user_u32(len, optlen) - || put_user_u32(val, optval_addr)) + if (put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } + if (put_user_u32(len, optlen)) { return -TARGET_EFAULT; } break; @@ -2939,20 +2954,7 @@ return -TARGET_EINVAL; lv = sizeof(lv); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); - if (ret < 0) - return ret; - if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { - len = 1; - if (put_user_u32(len, optlen) - || put_user_u8(val, optval_addr)) - return -TARGET_EFAULT; - } else { - if (len > sizeof(int)) - len = sizeof(int); - if (put_user_u32(len, optlen) - || put_user_u32(val, optval_addr)) - return -TARGET_EFAULT; - } + goto write_ret; break; default: ret = -TARGET_ENOPROTOOPT; @@ -2986,8 +2988,14 @@ if (ret < 0) { return ret; } - if (put_user_u32(lv, optlen) - || put_user_u32(val, optval_addr)) { + if (optval_addr) { + if (put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } else { + lv = 0; + } + if (put_user_u32(lv, optlen)) { return -TARGET_EFAULT; } break;