When converting a siginfo_t from waitid(), the interpretation of si_status
depends on the value of si_code: For CLD_EXITED, it is an exit code and
should be copied verbatim. For other codes, it is a signal number
(possibly with additional high bits from ptrace) that should be mapped.
This code was previously changed in commit
1c3dfb506ea3
("linux-user/signal: Decode waitid si_code"), but the fix was
incomplete.
Tested with the following test program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
exit(12);
} else {
siginfo_t siginfo = {};
waitid(P_PID, pid, &siginfo, WEXITED);
printf("Code: %d, status: %d\n", (int)siginfo.si_code, (int)siginfo.si_status);
}
pid = fork();
if (pid == 0) {
raise(SIGUSR2);
} else {
siginfo_t siginfo = {};
waitid(P_PID, pid, &siginfo, WEXITED);
printf("Code: %d, status: %d\n", (int)siginfo.si_code, (int)siginfo.si_status);
}
}
Output with an x86_64 host and mips64el target before
1c3dfb506ea3
(incorrect: exit code 12 is translated like a signal):
Code: 1, status: 17
Code: 2, status: 17
After
1c3dfb506ea3 (incorrect: signal number is not translated):
Code: 1, status: 12
Code: 2, status: 12
With this patch:
Code: 1, status: 12
Code: 2, status: 17
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <
81534fde7cdfc6acea4889d886fbefdd606630fb.
1635019124.git.mschiffer@universe-factory.net>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
case TARGET_SIGCHLD:
tinfo->_sifields._sigchld._pid = info->si_pid;
tinfo->_sifields._sigchld._uid = info->si_uid;
- tinfo->_sifields._sigchld._status = info->si_status;
+ if (si_code == CLD_EXITED)
+ tinfo->_sifields._sigchld._status = info->si_status;
+ else
+ tinfo->_sifields._sigchld._status
+ = host_to_target_signal(info->si_status & 0x7f)
+ | (info->si_status & ~0x7f);
tinfo->_sifields._sigchld._utime = info->si_utime;
tinfo->_sifields._sigchld._stime = info->si_stime;
si_type = QEMU_SI_CHLD;