On 6/24/25 17:37, Rob Landley wrote:
Ok, just to be PEDANTIC I'll add the stupid consts to my function it's redirecting to (that CAN'T be it, ELF doesn't annotate at that level.) Yup, made no difference.

Did ASAN special case the name "crypt" somehow? This seems unlikely...

Can I strip down a smaller reproduction test case? Hmmm,

$ gcc -lcrypt -fsanitize=address -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls -static-libasan -Wl,--gc-sections -Wl,--as-needed -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-strict-aliasing -xc - <<<$'#include<crypt.h>\nint main(void){crypt("one", "two");}' && ASAN_OPTIONS=detect_leaks=0 ./a.out

Produces a 1.4 megabyte binary, which runs with no complaint. (Please don't tell me this is one of those things that cares about the order of options on the command line...)

Ok, clean checkout, "ASAN=1 V=1 make clean test_mkpasswd" reproduces it, and... wait, what? One of the V=1 lines normally silent output is:

/usr/bin/ld: cannot find -lcrypto: No such file or directory

The compile time probe didn't find -lcrypto? It's /usr/lib/x86_64-linux-gnu/libcrypto.so.3 and the other one found it. I'm not telling it NOT to search the usual paths. The glibc guys are the ones who moved it to an external library! How did it LINK if it couldn't FIND it?

$ gcc -xc - <<<$'#include <crypt.h>\nint main(void){crypt("a","b");}'
/usr/bin/ld: /tmp/cclzm7N3.o: in function `main':
<stdin>:(.text+0x19): undefined reference to `crypt'
collect2: error: ld returned 1 exit status

It doesn't! The glibc guys moved it to an external library! That's the first thing I hit building that big long... wait.

If I remove "-lcrypt" from the big long test, it compiles and the binary reproduces the failure. I have no idea WHY it links with a MISSING SYMBOL, but it does, because ASAN, somehow.

Ok, why didn't the compile time probe find this? Ah, it did. The probe list has both "crypt" and "crypto" in it (that was a mac or bsd thing, wasn't it)?

BUT, I reproduced the issue! If you link without -lcrypt but with asan, the build succeeds and the resulting binary fails. And the mkpasswd build is doing:

cc -Wall -Wundef -Werror=implicit-function-declaration -Wno-char-subscripts -Wno-pointer-sign -funsigned-char -Wno-restrict -Wno-format-overflow -fsanitize=address -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls -static-libasan -Wno-restrict -Wno-format-overflow -I . -Os -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-strict-aliasing -DTOYBOX_VERSION="0.8.12-62-g70157e71bb2c" generated/obj/lib_args.o generated/obj/lib_commas.o generated/obj/lib_deflate.o generated/obj/lib_dirtree.o generated/obj/lib_elf.o generated/obj/lib_env.o generated/obj/lib_hash.o generated/obj/lib_lib.o generated/obj/lib_llist.o generated/obj/lib_net.o generated/obj/lib_password.o generated/obj/lib_portability.o generated/obj/lib_tty.o generated/obj/lib_utf8.o generated/obj/lib_xwrap.o generated/obj/main.o generated/obj/mkpasswd.o -Wl,--gc-sections -Wl,--as-needed -lcrypt -lm -lresolv -lselinux -lutil -lz -o generated/unstripped/mkpasswd
chmod 555 mkpasswd

Which has -lcrypt right there as the first symbol after --as-needed. So let's reorder the symbols:

$ gcc -fsanitize=address -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls -static-libasan -Wl,--gc-sections -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-strict-aliasing -xc - -Wl,--as-needed -lcrypt <<<$'#include<crypt.h>\nint main(void){crypt("one", "two");}' && ASAN_OPTIONS=detect_leaks=0 ./a.out
AddressSanitizer:DEADLYSIGNAL
=================================================================
==32558==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7ffd12d94be0 sp 0x7ffd12d94bd8 T0)
==32558==Hint: pc points to the zero page.
==32558==The signal is caused by a READ memory access.
==32558==Hint: address points to the zero page.
    #0 0x0  (<unknown module>)
    #1 0x7fe4159fa249  (/lib/x86_64-linux-gnu/libc.so.6+0x27249)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (<unknown module>)
==32558==ABORTING

So it's grabbing -lcrypt, using that to bump the weak symbol, and then when the library is --as-needed it's --gc-symbol-ing it away again, despite that succeeding to link the binary, and null pointer dereferencing when you try to run it. But only when ASAN is enabled.

I am so very tired. And have no idea what to do with that information.

Yes I _could_ try to engage with gcc, but I've been subscribed to the coreutils mailing list for something over 3 years now, which has gone https://lists.gnu.org/archive/html/coreutils/2022-01/msg00007.html to https://lists.gnu.org/archive/html/coreutils/2023-08/msg00009.html and https://lists.gnu.org/archive/html/coreutils/2023-08/msg00100.html and... Sigh. I mean, glass houses, but still.

Rob

P.S. I should probably go back to dumping these big long rants into my blog and not here. I should edit and post my last month+ of blog entries...
_______________________________________________
Toybox mailing list
Toybox@lists.landley.net
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to