Bug 1165548
| Summary: | strace: broken output when io_submit has negative nr value | ||
|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | Martin Cermak <mcermak> |
| Component: | strace | Assignee: | DJ Delorie <dj> |
| Status: | CLOSED ERRATA | QA Contact: | Michal Kolar <mkolar> |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | 7.1 | CC: | ldv, mkolar, mnewsome, mpetlan |
| Target Milestone: | rc | ||
| Target Release: | --- | ||
| Hardware: | x86_64 | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | strace-4.12-1.el7 | Doc Type: | If docs needed, set a value |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2017-08-01 22:03:54 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
strace is just trying to write -1 (that means 4294967295 in this case, because it is considered as unsigned, it's the "nr" argument) times the "{...}" string.
The behaviour is expectable, although there should be some regulation for that kind of situations. Someone even mentioned it in comments... See desc.c line 886.
==== desc.c ====
879 int
880 sys_io_submit(struct tcb *tcp)
881 {
882 long nr;
883 if (entering(tcp)) {
884 tprintf("%lu, %ld, ", tcp->u_arg[0], tcp->u_arg[1]);
885 nr = tcp->u_arg[1];
886 /* and if nr is negative? */
887 if (nr == 0)
888 tprints("{}");
889 else {
890 #ifdef HAVE_LIBAIO_H
891 long i;
892 struct iocb *iocbp, **iocbs = (void *)tcp->u_arg[2];
893
894 for (i = 0; i < nr; i++, iocbs++) {
Interesting thing is that nr behaves like unsigned, but it is declared as signed.
I have rebuilt the strace with -Wconversion -Wsign-conversion -Wsign-promo and the thing is clearer a bit...
syscall.c:1881:30: warning: conversion to ‘long int’ from ‘long long unsigned int’ may change the sign of the result [-Wsign-conversion]
tcp->u_arg[1] = x86_64_regs.rsi;
==== syscall.c ====
1878 if (x86_io.iov_len != sizeof(i386_regs)) {
1879 /* x86-64 or x32 ABI */
1880 tcp->u_arg[0] = x86_64_regs.rdi;
1881 tcp->u_arg[1] = x86_64_regs.rsi;
1882 tcp->u_arg[2] = x86_64_regs.rdx;
1883 tcp->u_arg[3] = x86_64_regs.r10;
1884 tcp->u_arg[4] = x86_64_regs.r8;
1885 tcp->u_arg[5] = x86_64_regs.r9;
The evil value is converted here from unsigned to signed. The tcp->u_arg is signed. The problem is opposite, some signed->unsigned conversion precedes it probably somewhere.
...
io_submit(4294967295, 4294967295, {0}) = -1 EINVAL (Invalid argument)
...
upstream strace-4.9 has a fix for that
Another tip... 4294967295 == -1 in 32bit context... ... so the -1 gets converted into 4294967295 somewhere where it's treated 32bit-like, then no conversion is done, because this number can exist in 64bit signed int, so it is propagated into the signed long nr without any problems. (In reply to Michael Petlan from comment #3) > ... > io_submit(4294967295, 4294967295, {0}) = -1 EINVAL (Invalid argument) > ... > > upstream strace-4.9 has a fix for that Probably the fix is commit v4.8-77-gab24d51. this upstream commit could help: ab24d5182847b52095efb129bbd47dfdc1f21662 Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHBA-2017:2018 |
Following code makes x86_64 strace on RHEL[567] loop endlessly: ======= #include <sys/syscall.h> #include <linux/aio_abi.h> int main() { syscall(__NR_io_submit, -1, -1, 0); syscall(__NR_io_submit, (aio_context_t)-1, -1, 0); } ======= execve("./a.out", ["./a.out"], [/* 41 vars */]) = 0 brk(0) = 0x2153000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fac7984d000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=55634, ...}) = 0 mmap(NULL, 55634, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fac7983f000 close(3) = 0 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2107768, ...}) = 0 mmap(NULL, 3932736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fac7926d000 mprotect(0x7fac79423000, 2097152, PROT_NONE) = 0 mmap(0x7fac79623000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7fac79623000 mmap(0x7fac79629000, 16960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fac79629000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fac7983e000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fac7983c000 arch_prctl(ARCH_SET_FS, 0x7fac7983c740) = 0 mprotect(0x7fac79623000, 16384, PROT_READ) = 0 mprotect(0x600000, 4096, PROT_READ) = 0 mprotect(0x7fac7984e000, 4096, PROT_READ) = 0 munmap(0x7fac7983f000, 55634) = 0 io_submit(4294967295, 4294967295, {{...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, [ ... ] Reproducer itself runs as expected (without a loop): ======= 7.0 S x86_64 # cat test.c #include <sys/syscall.h> #include <linux/aio_abi.h> int main() { syscall(__NR_io_submit, -1, -1, 0); syscall(__NR_io_submit, (aio_context_t)-1, -1, 0); } 7.0 S x86_64 # gcc test.c 7.0 S x86_64 # ./a.out 7.0 S x86_64 # ======= Versions: - strace-4.5.18-18.el5.x86_64 - strace-4.5.19-1.17.el6.x86_64 - strace-4.8-7.el7.x86_64