[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#928769: libc6: upgrade to glibc >=2.28 can cause relocation error in libnss_files.so.2 __libc_readline_unlocked



Package: libc6
Version: 2.28-1
Severity: normal

Typical message:

relocation error: /lib/x86_64-linux-gnu/libnss_files.so.2: symbol __libc_readline_unlocked, version GLIBC_PRIVATE not defined in file libc.so.6 with link time reference

I looked into this a bit and have put together a small reproduction
case.

$ cat repro.c
#include <pwd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

int main(int argc, char **argv) {
  printf("press enter after upgrading glibc...");
  getchar();
  setpwent();
  for (;getpwent(););
  endpwent();
  printf("if you made it this far nothing broke, congrats!\n");
  exit(0);
}
$ cc repro.c -o repro
$ ./repro
press enter after upgrading glibc...
./repro: relocation error: /lib/x86_64-linux-gnu/libnss_files.so.2: symbol __libc_readline_unlocked, version GLIBC_PRIVATE not defined in file libc.so.6 with link time reference

In the above case if you start the binary, upgrade to glibc >= 2.28, and
have it continue after the upgrade the setpwent call will dlopen
libnss_files.so.2 (assuming you have "passwd: files" in your
nsswitch.conf). The problem is that the newer version of
libnss_files.so.2 references __libc_readline_unlocked in the
GLIBC_PRIVATE part of libc6, but since the older version of libc6 is
already loaded it can't find it.

I have verified that I can reproduce the issue by debootstrapping a
stable chroot and performing the glibc upgrade by switching to testing.

The use of the function in nss_files seems to have been introduced in:

commit 916124ed841745b7a1e0fbc43f9909340b47d373
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Jul 6 14:23:15 2018 +0200

    nss_files: Fix re-reading of long lines [BZ #18991]
    
    Use the new __libc_readline_unlocked function to pick up
    reading at the same line in case the buffer needs to be enlarged.

And the func was added to libc6 the very same day.

commit 3f5e3f5d066dcffb80af48ae2cf35a01a85a8f10
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Jul 6 16:53:48 2018 +0200

    libio: Implement internal function __libc_readline_unlocked
    
    This is a variant of fgets which fails with ERANGE if the
    buffer is too small, and the buffer length is given as an
    argument of type size_t.
    
    This function will be useful for implementing NSS file reading
    operations.  Compared to a direct implementation using the public API,
    it avoids an lseek system call in case the line terminator can be
    found in the internal read buffer.

And if my git-fu is strong enough both of these commits were new in
2.28, which means any binary started before an upgrade to 2.28 can
potentially run into this problem (I have not verified this).

Attachment: signature.asc
Description: PGP signature


Reply to: