Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 688246 - sys-libs/glibc-2.29-r2: endgrent() sets errno if service 'db' is in nsswitch.conf, even if successful; breaks sys-apps/s6
Summary: sys-libs/glibc-2.29-r2: endgrent() sets errno if service 'db' is in nsswitch....
Status: CONFIRMED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: Current packages (show other bugs)
Hardware: AMD64 Linux
: Normal normal (vote)
Assignee: Gentoo Toolchain Maintainers
URL: https://sourceware.org/PR24696
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-06-17 18:51 UTC by Guillermo D. H.
Modified: 2019-07-10 21:50 UTC (History)
0 users

See Also:
Package list:
Runtime testing required: ---


Attachments
test-program.c (file_688246.txt,598 bytes, text/plain)
2019-06-17 18:51 UTC, Guillermo D. H.
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Guillermo D. H. 2019-06-17 18:51:19 UTC
Created attachment 580054 [details]
test-program.c

Gentoo's default /etc/nsswitch.conf has service 'db' configured for the group database, i.e.:

group: db files

With this configuration, endgrent(3) unexpectedly sets errno(3) to EINVAL, even when it is successful. POSIX specifies that setgrent(3) and endgrent() shall not change the setting of errno if successful, and, on error, shall set errno to indicate the error. Programs that expect the POSIX behaviour might break, and s6-envuidgid from package sys-apps/s6, does break:

# s6-envuidgid daemon sh -c 'echo $GIDLIST'
s6-envuidgid: fatal: unable to get supplementary groups for daemon: Invalid argument

If service 'db' is removed from the 'group:' line, i.e.

group: files

then endgrent(3) behaves as expected, and s6-envuidgid works:

# s6-envuidgid daemon sh -c 'echo $GIDLIST'
1,2,4

Attached test program demonstrates the problem. Last lines of output when 'db' is present:

End of file or error (errno = Success)
errno before endgrent() = Success
errno after endgrent() = Invalid argument

Last lines of output when 'db' is absent:

End of file or error (errno = Success)
errno before endgrent() = Success
errno after endgrent() = Success

$ emerge --info sys-libs/glibc

Portage 2.3.66 (python 3.6.5-final-0, default/linux/amd64/17.0/desktop, gcc-8.2.0, glibc-2.29-r2, 4.14.101-gentoo x86_64)
=================================================================
                         System Settings
=================================================================
System uname: Linux-4.14.101-gentoo-x86_64-Intel-R-_Core-TM-_i5-6200U_CPU_@_2.30GHz-with-gentoo-2.6
KiB Mem:     1020124 total,    892176 free
KiB Swap:     917496 total,    917496 free
Timestamp of repository gentoo: Sat, 25 May 2019 00:45:01 +0000
Head commit of repository gentoo: ae6dff15db1159f2969235aa8124ce96a7d03c58
sh bash 4.4_p23-r1
ld GNU ld (Gentoo 2.31.1 p7) 2.31.1
app-shells/bash:          4.4_p23-r1::gentoo
dev-lang/perl:            5.28.2-r1::gentoo
dev-lang/python:          2.7.15::gentoo, 3.6.5::gentoo
dev-util/pkgconfig:       0.29.2::gentoo
sys-apps/baselayout:      2.6-r1::gentoo
sys-apps/openrc:          0.41.2::gentoo
sys-apps/sandbox:         2.13::gentoo
sys-devel/autoconf:       2.69-r4::gentoo
sys-devel/automake:       1.16.1-r1::gentoo
sys-devel/binutils:       2.31.1-r6::gentoo
sys-devel/gcc:            8.2.0-r6::gentoo
sys-devel/gcc-config:     2.0::gentoo
sys-devel/libtool:        2.4.6-r3::gentoo
sys-devel/make:           4.2.1-r4::gentoo
sys-kernel/linux-headers: 4.14-r1::gentoo (virtual/os-headers)
sys-libs/glibc:           2.29-r2::gentoo
Repositories:

gentoo
    location: /var/db/repos/gentoo
    sync-type: rsync
    sync-uri: rsync://rsync.gentoo.org/gentoo-portage
    priority: 5
    sync-rsync-verify-max-age: 24
    sync-rsync-verify-jobs: 1
    sync-rsync-verify-metamanifest: yes
    sync-rsync-extra-opts: 

local
    location: /var/db/repos/local
    masters: gentoo
    priority: 10

ACCEPT_KEYWORDS="amd64"
ACCEPT_LICENSE="@FREE"
CBUILD="x86_64-pc-linux-gnu"
CFLAGS="-O2 -pipe"
CHOST="x86_64-pc-linux-gnu"
CONFIG_PROTECT="/etc /usr/share/gnupg/qualified.txt"
CONFIG_PROTECT_MASK="/etc/ca-certificates.conf /etc/env.d /etc/fonts/fonts.conf /etc/gconf /etc/gentoo-release /etc/revdep-rebuild /etc/sandbox.d /etc/terminfo"
CXXFLAGS="-O2 -pipe"
DISTDIR="/var/cache/distfiles"
ENV_UNSET="DBUS_SESSION_BUS_ADDRESS DISPLAY GOBIN PERL5LIB PERL5OPT PERLPREFIX PERL_CORE PERL_MB_OPT PERL_MM_OPT XAUTHORITY XDG_CACHE_HOME XDG_CONFIG_HOME XDG_DATA_HOME XDG_RUNTIME_DIR"
FCFLAGS="-O2 -pipe"
FEATURES="assume-digests binpkg-docompress binpkg-dostrip binpkg-logs config-protect-if-modified distlocks ebuild-locks fixlafiles ipc-sandbox merge-sync multilib-strict network-sandbox news parallel-fetch pid-sandbox preserve-libs protect-owned sandbox sfperms strict unknown-features-warn unmerge-logs unmerge-orphans userfetch userpriv usersandbox usersync xattr"
FFLAGS="-O2 -pipe"
GENTOO_MIRRORS="http://gentoo.gossamerhost.com/ http://gentoo.c3sl.ufpr.br/ http://gentoo.mirrors.ovh.net/gentoo-distfiles/"
LANG="en_US.utf8"
LDFLAGS="-Wl,-O1 -Wl,--as-needed"
LINGUAS="en en_US es es_AR"
MAKEOPTS="-j3"
PKGDIR="/var/cache/binpkgs"
PORTAGE_CONFIGROOT="/"
PORTAGE_RSYNC_OPTS="--recursive --links --safe-links --perms --times --omit-dir-times --compress --force --whole-file --delete --stats --human-readable --timeout=180 --exclude=/distfiles --exclude=/local --exclude=/packages --exclude=/.git"
PORTAGE_TMPDIR="/var/tmp"
USE="X a52 aac acl acpi alsa amd64 berkdb bindist bluetooth branding bzip2 cairo cdda cdr cli consolekit crypt cups cxx dbus dri dts dvd dvdr emboss encode exif fam flac fortran gdbm gif glamor gpm gtk iconv jpeg lcms ldap libnotify libtirpc mad mng mp3 mp4 mpeg multilib ncurses nls nptl ogg opengl openmp pam pango pcre pdf png policykit ppds qt5 readline sdl seccomp split-usr ssl startup-notification svg tcpd tiff truetype udev udisks unicode upower usb vorbis wxwidgets x264 xattr xcb xml xv xvid zlib" ABI_X86="64" ALSA_CARDS="ali5451 als4000 atiixp atiixp-modem bt87x ca0106 cmipci emu10k1x ens1370 ens1371 es1938 es1968 fm801 hda-intel intel8x0 intel8x0m maestro3 trident usb-audio via82xx via82xx-modem ymfpci" APACHE2_MODULES="authn_core authz_core socache_shmcb unixd actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgi cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias" CALLIGRA_FEATURES="karbon sheets words" COLLECTD_PLUGINS="df interface irq load memory rrdtool swap syslog" CPU_FLAGS_X86="aes avx mmx mmxext popcnt sse sse2 sse3 sse4_1 sse4_2 ssse3" ELIBC="glibc" GPSD_PROTOCOLS="ashtech aivdm earthmate evermore fv18 garmin garmintxt gpsclock isync itrax mtk3301 nmea ntrip navcom oceanserver oldstyle oncore rtcm104v2 rtcm104v3 sirf skytraq superstar2 timing tsip tripmate tnt ublox ubx" INPUT_DEVICES="evdev" KERNEL="linux" L10N="en en-US es es-AR" LCD_DEVICES="bayrad cfontz cfontz633 glk hd44780 lb216 lcdm001 mtxorb ncurses text" LIBREOFFICE_EXTENSIONS="presenter-console presenter-minimizer" NETBEANS_MODULES="apisupport cnd groovy gsf harness ide identity j2ee java mobility nb php profiler soa visualweb webcommon websvccommon xml" OFFICE_IMPLEMENTATION="libreoffice" PHP_TARGETS="php5-6 php7-1" POSTGRES_TARGETS="postgres9_5 postgres10" PYTHON_SINGLE_TARGET="python3_6" PYTHON_TARGETS="python2_7 python3_6" RUBY_TARGETS="ruby24" USERLAND="GNU" VIDEO_CARDS="fbdev" XTABLES_ADDONS="quota2 psd pknock lscan length2 ipv4options ipset ipp2p iface geoip fuzzy condition tee tarpit sysrq steal rawnat logmark ipmark dhcpmac delude chaos account"
Unset:  CC, CPPFLAGS, CTARGET, CXX, EMERGE_DEFAULT_OPTS, INSTALL_MASK, LC_ALL, PORTAGE_BINHOST, PORTAGE_BUNZIP2_COMMAND, PORTAGE_COMPRESS, PORTAGE_COMPRESS_FLAGS, PORTAGE_RSYNC_EXTRA_OPTS

=================================================================
                        Package Settings
=================================================================

sys-libs/glibc-2.29-r2::gentoo was built with the following:
USE="multiarch (multilib) ssp -audit -caps (-cet) (-compile-locales) -doc -gd -headers-only -nscd -profile (-selinux) -suid -systemtap -test (-vanilla)" ABI_X86="(64)"
CFLAGS="-pipe -ggdb -O2 -fno-strict-aliasing"
CXXFLAGS="-pipe -ggdb -O2 -fno-strict-aliasing"
FEATURES="assume-digests binpkg-docompress binpkg-dostrip binpkg-logs config-protect-if-modified distlocks ebuild-locks fixlafiles ipc-sandbox merge-sync multilib-strict network-sandbox news parallel-fetch pid-sandbox preserve-libs protect-owned sandbox sfperms splitdebug strict unknown-features-warn unmerge-logs unmerge-orphans userfetch userpriv usersandbox usersync xattr"
Comment 1 Guillermo D. H. 2019-06-17 18:59:29 UTC
Debugging the test program reveals that the setting of errno happens in function internal_endent() of file nss/nss_db/db-open.c. This function makes a munmap(2) call with a NULL argument (mapping->header). Function argument 'mapping' points to static variable 'state' defined in nss/nss_db/db-XXX.c), which is initialized to {.header = NULL, .len = 0}, and never modified if file /var/db/group.db does not exist and previously called function internal_setent() returned NSS_STATUS_UNAVAIL.

Relevant lines of strace output when executing the test program:

openat(AT_FDCWD, "/var/db/group.db", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/group", O_RDONLY|O_CLOEXEC) = 3
...
write(1, "End of file or error (errno = Su"..., 39) = 39
write(1, "errno before endgrent() = Succes"..., 34) = 34
munmap(NULL, 0)                         = -1 EINVAL (Invalid argument)
close(3)                                = 0
write(1, "errno after endgrent() = Invalid"..., 42) = 42
exit_group(0)                           = ?
+++ exited with 0 +++

Relevant output of a GDB session for debugging the test program, showing backtraces, and variable and function argument values, when executing getgrent() for the first time, and when executing endgrent():

(gdb) bt
#0  __GI___open64_nocancel (file=0x7ffff7def03a "/var/db/group.db", oflag=oflag@entry=524288) at ../sysdeps/unix/sysv/linux/open64_nocancel.c:34
#1  0x00007ffff7dee013 in internal_setent (file=<optimized out>, mapping=0x7ffff7df1230 <state>) at nss_db/db-open.c:39
#2  0x00007ffff7deb573 in _nss_db_getgrent_r (result=0x7ffff7fbed40 <resbuf>, buffer=0x555555559260 "", buflen=1024, errnop=0x7ffff7fc3480)
    at ./nss_files/../nss_db/db-XXX.c:249
#3  0x00007ffff7f1f1da in __nss_getent_r (getent_func_name=getent_func_name@entry=0x7ffff7f8698b "getgrent_r", 
    setent_func_name=setent_func_name@entry=0x7ffff7f86996 "setgrent", lookup_fct=<optimized out>, nip=nip@entry=0x7ffff7fbee08 <nip>, 
    startp=startp@entry=0x7ffff7fbedf8 <startp>, last_nip=last_nip@entry=0x7ffff7fbee00 <last_nip>, stayopen_tmp=0x0, res=0, 
    resbuf=0x7ffff7fbed40 <resbuf>, buffer=0x555555559260 "", buflen=1024, result=0x7fffffffe070, h_errnop=0x0) at getnssent_r.c:194
#4  0x00007ffff7ebf6d6 in __getgrent_r (resbuf=<optimized out>, buffer=<optimized out>, buflen=<optimized out>, result=<optimized out>)
    at ../nss/getXXent_r.c:160
#5  0x00007ffff7f1ecb3 in __nss_getent (func=0x7ffff7ebf640 <__getgrent_r>, resbuf=resbuf@entry=0x7ffff7fbed40 <resbuf>, 
    buffer=buffer@entry=0x7ffff7fbd898 <buffer>, buflen=buflen@entry=1024, buffer_size=buffer_size@entry=0x7ffff7fbed20 <buffer_size>, 
    h_errnop=h_errnop@entry=0x0) at getnssent.c:50
#6  0x00007ffff7ebedba in getgrent () at ../nss/getXXent.c:83
#7  0x00005555555551ad in main () at prueba.c:10
...
(gdb) next
_nss_db_getgrent_r (result=0x7ffff7fbed40 <resbuf>, buffer=0x555555559260 "", buflen=1024, errnop=0x7ffff7fc3480)
    at ./nss_files/../nss_db/db-XXX.c:250
(gdb) print status
$2 = NSS_STATUS_UNAVAIL
(gdb) print state
$3 = {header = 0x0, len = 0}
...
(gdb) bt
#0  internal_endent (mapping=0x7ffff7df1230 <state>) at nss_db/db-open.c:65
#1  0x00007ffff7deb396 in _nss_db_endgrent () at ./nss_files/../nss_db/db-XXX.c:95
#2  0x00007ffff7f1f043 in __nss_endent (func_name=func_name@entry=0x7ffff7f8699f "endgrent", lookup_fct=0x7ffff7f1feb0 <__GI___nss_group_lookup2>, 
    nip=nip@entry=0x7ffff7fbee08 <nip>, startp=startp@entry=0x7ffff7fbedf8 <startp>, last_nip=last_nip@entry=0x7ffff7fbee00 <last_nip>, 
    res=res@entry=0) at getnssent_r.c:139
#3  0x00007ffff7ebf5da in endgrent () at ../nss/getXXent_r.c:143
#4  0x000055555555527e in main () at prueba.c:24
(gdb) next
66	in nss_db/db-open.c
(gdb) print *mapping
$5 = {header = 0x0, len = 0}
(gdb) next
0x00007ffff7dea120 in munmap@plt () from /lib64/libnss_db.so.2
Comment 2 Sergei Trofimovich gentoo-dev 2019-06-17 19:50:46 UTC
Confirmed, will try to reproduce on vanilla glibc and try to bisect.

Do you know which last version of glibc worked for you if ever?
Comment 3 Guillermo D. H. 2019-06-17 20:06:11 UTC
(In reply to Sergei Trofimovich from comment #2)
> Confirmed, will try to reproduce on vanilla glibc and try to bisect.
> 
> Do you know which last version of glibc worked for you if ever?

Thanks. Last version that worked for me was the last sys-libs/glibc-2.27 package that was in the stable amd64 branch before it was masked. I think last upgrade on May 25th went straight from 2.27 to 2.29.
Comment 4 Sergei Trofimovich gentoo-dev 2019-06-17 21:10:37 UTC
(In reply to Guillermo D. H. from comment #3)
> (In reply to Sergei Trofimovich from comment #2)
> > Confirmed, will try to reproduce on vanilla glibc and try to bisect.
> > 
> > Do you know which last version of glibc worked for you if ever?
> 
> Thanks. Last version that worked for me was the last sys-libs/glibc-2.27
> package that was in the stable amd64 branch before it was masked. I think
> last upgrade on May 25th went straight from 2.27 to 2.29.

Aha!

I tried vanilla glibc for master, 2.29, 2.28, 2.27, 2.26. All have the same EINVAL. Could it be that you (or glibc) updated /etc/nsswitch.conf at the same time?

I think glibc added munmap() call to glibc-2.25 in 2666d441c2d8107b1987b869714189af64b954c6.
Comment 5 Sergei Trofimovich gentoo-dev 2019-06-17 21:17:38 UTC
This fix seems to be enough to preserve errno. I'll file upstream bug.

--- a/nss/nss_db/db-open.c
+++ b/nss/nss_db/db-open.c
@@ -63,5 +63,9 @@ internal_setent (const char *file, struct nss_db_map *mapping)
 void
 internal_endent (struct nss_db_map *mapping)
 {
-  munmap (mapping->header, mapping->len);
+  /* Avoid clobbering errno if 'header' was never allocated.  */
+  if (mapping->header != NULL)
+    {
+      munmap (mapping->header, mapping->len);
+    }
 }
Comment 6 Sergei Trofimovich gentoo-dev 2019-06-17 21:26:45 UTC
Reported as https://sourceware.org/PR24696
Comment 7 Guillermo D. H. 2019-06-17 22:56:49 UTC
(In reply to Sergei Trofimovich from comment #4)
> I tried vanilla glibc for master, 2.29, 2.28, 2.27, 2.26. All have the same
> EINVAL. Could it be that you (or glibc) updated /etc/nsswitch.conf at the
> same time?

I think I know what happened. My /var/log/emerge.log says I had sys-libs/glibc-2.27-r6 before the upgrade. The corresponding patch set, glibc-2.27-patches-3.tar.bz2, shipped with an /etc/nsswitch.conf (in directory extra/etc) that said:

group: compat files

(i.e. no 'db' service), whereas the patch set for sys-libs/glibc-2.29-r2, glibc-2.29-patches-3.tar.xz, does not, so the ebuild installs upstream's example file, nss/nsswitch.conf.

This EINVAL thing might have been present since version 2.26, but Gentoo's default nsswitch.conf did not expose it. Let's see what upstream says about it.

I don't remember ever modifying that file.
Comment 8 Sergei Trofimovich gentoo-dev 2019-07-10 21:50:47 UTC
Upstream applied a patch to 2.30 as:
    https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=99135114ba23c3110b7e4e650fabdc5e639746b7