• Bug#1089636: libcap2: FTBFS due to test suite failure on powerpc

    From Aurelien Jarno@21:1/5 to Christian Kastner on Fri Mar 21 23:10:01 2025
    control: reassign -1 libcap2
    control: retitle -1 libcap.so.2 lacks a _IO_stdin_used symbol
    control: tag -1 + patch

    Hi,

    On 2025-03-20 23:04, Christian Kastner wrote:
    Control: reassign -1 glibc
    Control: retitle -1 glibc-2.40 printf() segfaults on mips64el, powerpc Control: notforwarded -1
    Control: tags -1 - ftbfs

    Dear glibc maintainers,

    A change introduced in glibc-2.40 seems to have introduced an
    I/O-related bug on mips64el and powerpc. With mips64el being an official architecture, this was made an RC bug.

    This bug was discovered by src:libcap2 starting to FTBFS last October
    because tests were segfaulting on the aforementioned architectures. The segfault occurs during calls to printf().

    The segfault is reproducible even with the libcap2 version in bookworm.
    In a bookworm mips64el container image, I verified that everything was
    still fine with glibc-2.39 from snapshots.d.o, and that the breakage
    appears with glibc-2.40.

    A bisect determined that the breaking commit is:

    2a99e23: Use a doubly-linked list for _IO_list_all (bug 27777)

    A crude attempt at reverting this commit (crude because it cannot be
    reverted cleanly) resolved the issue.

    The problem can is easily reproduced in a mips64el container or chroot
    where libcap2 is installed:

    # libcap2.so is runnable by itself, so we make a copy executable
    $ sudo apt-get install libcap2
    $ cp /usr/lib/mips*/libcap.so.2.* .
    $ chmod +x libcap.so.2.*
    # calls usage(), which calls printf(), which segfaults
    $ ./libcap.so.2.* --usage

    The relevant code [1] is fairly simple: the call to usage() triggers the segfault on its sole printf(). Interestingly, the call to summary() does
    not trigger the segfault on the first printf(), but one of the later
    ones.

    No, it is not that simple given libcap.so.2 is a library that is
    executable, and the way it is done is a bit tricky. The problem actually
    comes from there...

    The breaking commit looks simple enough that this might be an issue with
    how the padding for struct _IO_FILE_complete changed. However I don't
    have enough background to be confident in this assessment, and I was
    hoping that you might be able to pass this on upstream.

    Yep, I confirm this is indeed linked with that. The problem is that the libcap.so.2 library lacks the _IO_stdin_used symbols that is provided by Scrt1.o for executables. This symbol is used by the GNU libc determine
    which version of the I/O functions should be used. When this symbol is
    absent, it means that the "old" version is used, leading to possible
    crashes or other issues on architectures that were supported by glibc
    2.0. That is for debian: i386 and mips64el for official architectures
    and alpha, hppa, m68k, powerpc, sh4 and sparc64 for ports
    architectures.

    With time the differences with the original structure increased. While
    very basic functions were still working until recently, the commit you
    pointed that went in glibc 2.40 changed the format of the libio
    structures even more.

    The solution is to get that symbol defined in libcap.so.2, like any
    other executable. Given it is a both a library and executable, it is not possible to link with Scrt1.o like it's done with normal binaries, as
    this requires a main symbol. The following patch should do that, and
    that indeed fixes the issue, although I guess there might be better ways
    to do that:

    --- libcap2-2.75.orig/libcap/Makefile
    +++ libcap2-2.75/libcap/Makefile
    @@ -14,9 +14,9 @@ PSXLIBNAME=$(PSXTITLE).so
    STAPSXLIBNAME=$(PSXTITLE).a

    CAPFILES=cap_alloc cap_proc cap_extint cap_flag cap_text cap_file cap_syscalls -CAPMAGICOBJ=cap_magic.o
    +CAPMAGICOBJ=cap_magic.o _IO_stdin_used.o
    PSXFILES=../psx/psx ../psx/psx_calls ../psx/wrap/psx_wrap -PSXMAGICOBJ=psx_magic.o
    +PSXMAGICOBJ=psx_magic.o _IO_stdin_used.o

    # hardening=+all adds this universally, but we don't want this for the lib
    CFLAGS := $(filter-out -fPIE,$(CFLAGS))
    @@ -122,6 +122,9 @@ empty: empty.c
    loader.txt: empty
    $(OBJCOPY) --dump-section .interp=$@ $< /dev/null

    +_IO_stdin_used.o: $(shell $(CC) -print-file-name=Scrt1.o)
    + $(OBJCOPY) --strip-all --keep-symbol=_IO_stdin_used $< $@
    +
    cap_magic.o: execable.h execable.c loader.txt libcap.h
    $(CC) $(CFLAGS) $(CPPFLAGS) -DLIBRARY_VERSION=\"$(LIBTITLE)-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat loader.txt)\" -include ./libcap.h -c execable.c -o $@


    Note th