Skip to content
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

ext/POSIX/t/wrappers.t fails when compiling on OpenLDAP user because of getgrgid() + fork() interaction #13779

Open
p5pRT opened this issue Apr 28, 2014 · 12 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 28, 2014

Migrated from rt.perl.org#121755 (status was 'open')

Searchable as RT121755$

@p5pRT
Copy link
Author

p5pRT commented Apr 28, 2014

From lvaliukas@cyber.law.harvard.edu

Created by lvaliukas@cyber.law.harvard.edu

When compiling Perl-blead with Perlbrew, the ext/POSIX/t/wrappers.t unit test fails with​:

  ext/POSIX/t/wrappers .......................................... # Failed test 'getc'
  # at t/wrappers.t line 217.
  # got​: undef
  # expected​: '1'
  FAILED at test 82

I suspect that the unit test doesn't pass because fork() silently fails right after the getgrgid() call. For example, when running this script​:

  use strict;
  use warnings;
 
  my $id = $(;
  say STDERR "group id​: $id";
  my $getgrgid_result = getgrgid $id;
  say STDERR "getgrgid​: $getgrgid_result";

  my $pid = fork();

  fail("fork failed​: $!") unless defined $pid;

  if ($pid) {
  say STDERR "MAIN PROCESS";
  } else {
  say STDERR "CHILD PROCESS";
  }

The *expected* output is​:

  group id​: 10018 113 10018
  getgrgid​: bcis-interns
  MAIN PROCESS
  CHILD PROCESS

But the *actual* output I get with Perl-blead is​:

  group id​: 10018 113 10018
  getgrgid​: bcis-interns
  MAIN PROCESS

I should also note that we're building Perl on an OpenLDAP user, and that the sample script (or the unit test) doesn't fail on a "normal" user (the one from /etc/passwd). Also, Perl v5.16.3 provides the *expected* output for the test script listed above.

I would be very thankful if you could provide me with any tips and hints on how I could debug / help you to fix this issue.

Perl Info

Flags:
    category=library
    severity=high
    module=POSIX

Site configuration information for perl 5.19.12:

Configured by lvaliukas at Mon Apr 28 11:20:18 EDT 2014.

Summary of my perl5 (revision 5 version 19 subversion 12) configuration:
  Snapshot of: 96258673547f51dc588c290d9c8ff3d9b2b93397
  Platform:
    osname=linux, osvers=3.11.0-19-generic, archname=x86_64-linux
    uname='linux new-chloe.law.harvard.edu 3.11.0-19-generic #33~precise1-ubuntu smp wed mar 12 21:16:27 utc 2014 x86_64 x86_64 x86_64 gnulinux '
    config_args='-de -Dprefix=/berkman/home/lvaliukas/perl5/perlbrew/perls/perl-blead -Dusedevel -Aeval:scriptdir=/berkman/home/lvaliukas/perl5/perlbrew/perls/perl-blead/bin'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.6.3', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
    libs=-lnsl -ldb -ldl -lm -lcrypt -lutil -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.15.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.15'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'



@INC for perl 5.19.12:
    /berkman/home/lvaliukas/perl5/perlbrew/perls/perl-blead/lib/site_perl/5.19.12/x86_64-linux
    /berkman/home/lvaliukas/perl5/perlbrew/perls/perl-blead/lib/site_perl/5.19.12
    /berkman/home/lvaliukas/perl5/perlbrew/perls/perl-blead/lib/5.19.12/x86_64-linux
    /berkman/home/lvaliukas/perl5/perlbrew/perls/perl-blead/lib/5.19.12
    .


Environment for perl 5.19.12:
    HOME=/berkman/home/lvaliukas
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/space/mediacloud/bin/bin:/mediacloud/data/mongoDB/mongodb-linux-x86_64-2.2.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented May 2, 2014

From @eserte

Dana Pon 28. Tra 2014, 09​:24​:40, lvaliukas@​cyber.law.harvard.edu reče​:

When compiling Perl-blead with Perlbrew, the ext/POSIX/t/wrappers.t
unit test fails with​:

ext/POSIX/t/wrappers .......................................... #
Failed test 'getc'
# at t/wrappers.t line 217.
# got​: undef
# expected​: '1'
FAILED at test 82

I suspect that the unit test doesn't pass because fork() silently
fails right after the getgrgid() call. For example, when running this
script​:

I also saw this problem in an environment where LDAP for user authentication is in use. My current workaround is​:

  if ($] >= 5.018) {
  warn "perl $], we need the LDAP hack :-(...\n";
  $SIG{PIPE}='IGNORE'; # XXX the ldap hack :-(
  }

The problem does not appear with perl 5.16.3 on the same system.

Regards,
  Slaven

@p5pRT
Copy link
Author

p5pRT commented May 2, 2014

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented May 2, 2014

From lvaliukas@cyber.law.harvard.edu

On Fri May 02 07​:01​:31 2014, slaven@​rezic.de wrote​:

I also saw this problem in an environment where LDAP for user
authentication is in use. My current workaround is​:

if ($] >= 5.018) {
warn "perl $], we need the LDAP hack :-(...\n";
$SIG{PIPE}='IGNORE'; # XXX the ldap hack :-(
}

The problem does not appear with perl 5.16.3 on the same system.

Regards,
Slaven

Thanks Slaven! It's good to see that we're not the only ones who encounter this bug!

The workaround would probably do fine in our own code (at least temporary), but I'm worried that dependency CPAN modules (which we do not control) might be using getgrgid() themselves and potentially crashing Perl / introducing security issues to the rest of the system.

Would you be able to comment on your OpenLDAP infrastructure? In other words, have you found a way to replicate a bug on a "clean" system?

@p5pRT
Copy link
Author

p5pRT commented May 2, 2014

From @eserte

Dana Pet 02. Svibanj 2014, 11​:22​:19, lvaliukas@​cyber.law.harvard.edu reče​:

On Fri May 02 07​:01​:31 2014, slaven@​rezic.de wrote​:

I also saw this problem in an environment where LDAP for user
authentication is in use. My current workaround is​:

if ($] >= 5.018) {
warn "perl $], we need the LDAP hack :-(...\n";
$SIG{PIPE}='IGNORE'; # XXX the ldap hack :-(
}

The problem does not appear with perl 5.16.3 on the same system.

Regards,
Slaven

Thanks Slaven! It's good to see that we're not the only ones who
encounter this bug!

The workaround would probably do fine in our own code (at least
temporary), but I'm worried that dependency CPAN modules (which we do
not control) might be using getgrgid() themselves and potentially
crashing Perl / introducing security issues to the rest of the system.

Would you be able to comment on your OpenLDAP infrastructure? In other
words, have you found a way to replicate a bug on a "clean" system?

I am just a user in a company LDAP setup. Actually I wasn't aware that LDAP was in use, until I stumbled over this problem and tried to find out what's going on using strace. I found out that some Linux component was opening the LDAP connection when the perl process was calling getpwuid(). After a fork() strange things happen to the (also forked) LDAP connection, leading to a SIGPIPE and the child being killed.

This smells like a bug in the LDAP implementation. But nevertheless it would be a good thing if it could be workaround in the Perl interpreter.

Regards,
  Slaven

@p5pRT
Copy link
Author

p5pRT commented May 2, 2014

From @Leont

On Fri, May 2, 2014 at 11​:34 PM, slaven@​rezic.de via RT <
perlbug-followup@​perl.org> wrote​:

Thanks Slaven! It's good to see that we're not the only ones who
encounter this bug!

The workaround would probably do fine in our own code (at least
temporary), but I'm worried that dependency CPAN modules (which we do
not control) might be using getgrgid() themselves and potentially
crashing Perl / introducing security issues to the rest of the system.

Would you be able to comment on your OpenLDAP infrastructure? In other
words, have you found a way to replicate a bug on a "clean" system?

I am just a user in a company LDAP setup. Actually I wasn't aware that
LDAP was in use, until I stumbled over this problem and tried to find out
what's going on using strace. I found out that some Linux component was
opening the LDAP connection when the perl process was calling getpwuid().
After a fork() strange things happen to the (also forked) LDAP connection,
leading to a SIGPIPE and the child being killed.

This smells like a bug in the LDAP implementation. But nevertheless it
would be a good thing if it could be workaround in the Perl interpreter.

Indeed it does. I'm guessing the a shutdown(2) is involved. This is a
sensible thing to do if your process actually owns the connection but
unlike close it's actually global so if the other process.

Swapping libnss-ldap/libnss-ldapd might help (but may not be an option in
production).

Leon

@p5pRT
Copy link
Author

p5pRT commented May 5, 2014

From bitcard@larochelle.name

According to The Open Group Specification getpwuid() is not thread safe.

( See http​://pubs.opengroup.org/onlinepubs/009695399/functions/getpwuid.html).

I realize the fork()ing is very different from threads but I wonder if getpwuid_r(), the thread-safe version of getpwuid() should be used instead.

On Fri May 02 14​:34​:40 2014, slaven@​rezic.de wrote​:

I am just a user in a company LDAP setup. Actually I wasn't aware that
LDAP was in use, until I stumbled over this problem and tried to find
out what's going on using strace. I found out that some Linux
component was opening the LDAP connection when the perl process was
calling getpwuid(). After a fork() strange things happen to the (also
forked) LDAP connection, leading to a SIGPIPE and the child being
killed.

@p5pRT
Copy link
Author

p5pRT commented May 6, 2014

From @Leont

On Mon, May 5, 2014 at 11​:57 PM, dlarochelle via RT <
perlbug-followup@​perl.org> wrote​:

According to The Open Group Specification getpwuid() is not thread safe.

( See
http​://pubs.opengroup.org/onlinepubs/009695399/functions/getpwuid.html).

I realize the fork()ing is very different from threads but I wonder if
getpwuid_r(), the thread-safe version of getpwuid() should be used instead.

The reentrant APIs are already used on threaded perls (in a rather
confusing manner), and are not relevant to fork() anyway.

Leon

@p5pRT
Copy link
Author

p5pRT commented May 6, 2014

From @lizmat

On 06 May 2014, at 12​:09, Leon Timmermans <fawaka@​gmail.com> wrote​:

On Mon, May 5, 2014 at 11​:57 PM, dlarochelle via RT <perlbug-followup@​perl.org> wrote​:
According to The Open Group Specification getpwuid() is not thread safe.

( See http​://pubs.opengroup.org/onlinepubs/009695399/functions/getpwuid.html).

I realize the fork()ing is very different from threads but I wonder if getpwuid_r(), the thread-safe version of getpwuid() should be used instead.

The reentrant APIs are already used on threaded perls (in a rather confusing manner), and are not relevant to fork() anyway.

Still, some XS might want to do threads on a non-threaded perl​: for those cases it would make sense to also use the re-entrant versions. And are we talking about hot paths here?

Liz

@p5pRT
Copy link
Author

p5pRT commented May 6, 2014

From @Leont

On Tue, May 6, 2014 at 12​:46 PM, Elizabeth Mattijsen <liz@​dijkmat.nl> wrote​:

Still, some XS might want to do threads on a non-threaded perl​: for those
cases it would make sense to also use the re-entrant versions. And are we
talking about hot paths here?

Agreed. It can be enabled on non-threaded perls with the -Dusereentrant
option. Another issue is that these wrappers are not exposed to XS modules
by default (though it seems a «#define PERL_REENTR_API 1» would fix that).
Path hotness isn't really a factor, I don't expect the functions to be
slower (they just use an explicit buffer instead of an implicit static one,
otherwise they're the same), but it does increase the size of the
interpreter struct (not that I personally care much about that).

Leon

@p5pRT
Copy link
Author

p5pRT commented May 13, 2014

From lvaliukas@cyber.law.harvard.edu

On Tue May 06 05​:16​:26 2014, LeonT wrote​:

Agreed. It can be enabled on non-threaded perls with the -Dusereentrant
option.

I've recompiled Perl-blead with "-Dusereentrant", but the bug is still present.

@p5pRT
Copy link
Author

p5pRT commented May 13, 2014

From @Leont

On Tue, May 13, 2014 at 5​:39 PM, Linas Valiukas via RT <
perlbug-followup@​perl.org> wrote​:

On Tue May 06 05​:16​:26 2014, LeonT wrote​:

Agreed. It can be enabled on non-threaded perls with the -Dusereentrant
option.

I've recompiled Perl-blead with "-Dusereentrant", but the bug is still
present.

We were getting side-tracked, of course that didn't fix it. Everything
points at the bug being in your ldap nss implementation, not in Perl. One
could test this with a simple C program.

Leon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants