New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
t/Image/Transform.t aborts on memmove() in img_2d_transform() if compiled with -D_FORTIFY_SOURCE=3 and glibc-2.36.9000 #78
Comments
Thank you for great anaysis! One thing bothers me though: for decades I knew that if one suspects that memory areas overlap, memmove is the safer approach than memcpy. Now you are saying the reverse. I shall check the bug later no matter what, but could you corroborate the statement about glibc.memmove's area that cannot overlap? |
You are right, memove() can overlap. I got confused by the valgrind output. Maybe glibc fortification does not play well with valgrind instrumentation, or valgrind prints a misnomer. Here is a backtrace from GDB when Prima built with -D_FORTIFY_SOURCE=3 and glibc aborts the program:
It points to the same memove() call at img/rotate.c:1171. There are lot of local variables. Interesting ones from frame #7:
Frame #6 does not show anything interesting because all arguments were optimized out. Problem with _FORTIFY_SOURCE is that it requires enabled optimizations. |
If I recompile without fortification and optimizations, valgrind does not catch anything. |
This is all quite mystical I must say... if I compile with these flags, nothing is happening, neither coredumps nor valgrind alerts. Is it a specific glibc version and/or architecture? I tried this on Ubuntu GLIBC 2.35-0ubuntu3.1 . One thing though, my compiler warns during the compilation:
I wonder if _FORTIFY_SOURCE=3 has any effect here? I'd hate to call it a glibc bug but it looks like one. There are no direct google hits, but there is some vague info on google that memcpy and memmove were one until some version, and I see that in the stack trace you've got there is this line
hinting that valgrind uses its own memcpy_chk to test, well, memcpy, and not necessarily memmove. Anyway more details needed - I'd be curious too to recompile glibc version to dig down to the real problem. |
( btw I just tried to play with the latest glibc 5.36 but that didn't work for me, caused coredumps for every command...) |
I observe this on current Fedora 38. It has glibc-2.36.9000, a snapshot of development glibc newer than 2.36 release. I added few debugging printf()s and this what it prints:
If did the math correctly, than none of the two memmove() calls reads or writes out of the iop structure memory. It's ridiculous that first memmove() of size 24 passes fortification, but subsequent memmove() of size 12 fails the fortification check. The corresponding initial iop content is:
I conclude it's a bug in glibc or gcc. I will try to minimize the code and report to glibc developers. |
This is gets more and more interesting ... let's though keep this bug open for the reference |
I reported it to glibc together with a minimal reproducer https://bugzilla.redhat.com/show_bug.cgi?id=2160682. |
Yeah, valgrind can report spurious warnings with fortified functions: https://bugs.kde.org/show_bug.cgi?id=453084 I'm trying to figure out out to fix this in gcc, the In the meantime, I've suggested a workaround in the fedora bug Petr filed for the reproducer, hopefully that helps work around this in actual code too. Basically the intent is to ensure that |
I don't see the patch you mention but i"m ok to change the code. I cannot reproduce it though so i depend here on whoever can. Replace io + 1 to iop[steps + 1] or something similar, I would guess? |
I've sent a PR that ought to resolve this. |
When building Prima with -D_FORTIFY_SOURCE=3:
t/Image/Transform.t test aborts:
$ perl -Iblib/{lib,arch} t/Image/Transform.t
ok 1 - rotate(90) width ok
ok 2 - rotate(90) height ok
ok 3 - rotate(90) data ok
ok 4 - rotate(270) width ok
ok 5 - rotate(270) height ok
ok 6 - rotate(270) data ok
ok 7 - rotate(180) width ok
ok 8 - rotate(180) height ok
ok 9 - rotate(180) data ok
ok 10 - short: rotate(90) data ok
ok 11 - short: rotate(270) data ok
ok 12 - short: rotate(180) data ok
ok 13 - byte: vertical mirroring ok
ok 14 - byte: horizontal mirroring ok
ok 15 - short: vertical mirroring ok
ok 16 - short: horizontal mirroring ok
ok 17 - rotation 360 seems performing
ok 18 - rotation 360 is correct
ok 19 - rotation 360 by transform2d seems performing
ok 20 - rotation 360 transform2d is correct
ok 21 - xshear(2) integral data
ok 22 - xshear(2) integral mask
*** buffer overflow detected ***: terminated
Aborted (core dumped)
This can be reduced to:
Valgrind reports:
It is this code:
This happens both with Prima-1.67 as well as with current head (8a0c8bc).
memove() is requires that source and target memory areas cannot overlap. Modern glibc scrutinizes the calls if a program is compiled with -D_FORTIFY_SOURCE=3 -O2 cflags and aborts the program when it detects overlapping memory areas.
Please note that I have not yet verified that this is a genuine bug in Prima and not a bug in glibc.
The text was updated successfully, but these errors were encountered: