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

recv() with MSG_TRUNC flag kills perl with SEGV or glibc double-free #10377

Closed
p5pRT opened this issue May 13, 2010 · 4 comments
Closed

recv() with MSG_TRUNC flag kills perl with SEGV or glibc double-free #10377

p5pRT opened this issue May 13, 2010 · 4 comments

Comments

@p5pRT
Copy link

p5pRT commented May 13, 2010

Migrated from rt.perl.org#75082 (status was 'resolved')

Searchable as RT75082$

@p5pRT
Copy link
Author

p5pRT commented May 13, 2010

From @leonerd

Created by @leonerd

When using a PF_PACKET socket, the MSG_TRUNC flag can be useful on a recv()
call, to tell the kernel to truncate the message to the size of the given
buffer, but return its full size from the wire. For example, consider​:

#!/usr/bin/perl

use strict;
use warnings;

use Socket qw( SOCK_DGRAM );
use IO​::Socket​::Packet;

my $sock = IO​::Socket​::Packet->new(
  Type => SOCK_DGRAM,
  Protocol => 0x0800, # IPv4
) or die "Cannot create PF_PACKET socket - $!";

# 40 bytes is enough to extract the IPv4 addresses from the IPv4 header
while( my ( undef, undef, undef, $pkttype, undef ) = $sock->recv_unpack( my $buffer, 40, MSG_TRUNC ) ) {

  # Extract src and dst IP addresses
  my ( $src, $dst ) = unpack( "x12 a4 a4", $buffer );
  $_ = join ".", unpack "C*", $_ for $src, $dst;

  printf "Recieved a packet pkttype %d, length %d bytes from %s to %s\n", $pkttype, length $buffer, $src, $dst;
}

(this tested against Socket​::Packet 0.04)

This program captures IPv4 packets and prints their lengths and IP addresses.
It usually dies after about 20 packets or so (unreliably), such as​:

*** glibc detected *** /usr/bin/perl​: malloc()​: memory corruption (fast)​: 0x0000000001a355c0 ***
======= Backtrace​: =========
/lib/libc.so.6[0x7f002a3ebd16]
/lib/libc.so.6[0x7f002a3ef18e]
/lib/libc.so.6(__libc_malloc+0x70)[0x7f002a3f0aa0]
/usr/lib/libperl.so.5.10(Perl_safesysmalloc+0x36)[0x7f002ae04a76]
/usr/lib/libperl.so.5.10(Perl_sv_grow+0x6a)[0x7f002ae31c4a]
/usr/lib/libperl.so.5.10(Perl_sv_setsv_flags+0xd1b)[0x7f002ae2ddfb]
/usr/lib/libperl.so.5.10(Perl_sv_mortalcopy+0x50)[0x7f002ae2e3f0]
/usr/lib/libperl.so.5.10(Perl_pp_leavesub+0x32b)[0x7f002ae1dcab]
/usr/lib/libperl.so.5.10(Perl_runops_standard+0x16)[0x7f002ae1a9e6]
/usr/lib/libperl.so.5.10(perl_run+0x33c)[0x7f002adbf61c]
/usr/bin/perl(main+0xec)[0x400d3c]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f002a399abd]
/usr/bin/perl[0x400b89]

I believe this bug is caused by the following lines from pp_sys.c​:

(in PP(pp_sysread))​:

  buffer = SvGROW(bufsv, (STRLEN)(length+1));
  count = PerlSock_recvfrom(PerlIO_fileno(IoIFP(io)), buffer, length, offset,
  (struct sockaddr *)namebuf, &bufsize);
...
  SvCUR_set(bufsv, count);

This causes problems if the kernel's return value in count is larger than the
length value; such as is the case with the MSG_TRUNC flag.

As this is a fairly rare use case, I'm quite happy to provide a special
truncating recv() function in Socket​::Packet, allowing

  my ( $addr, $len ) = recv_len( $sock, my $buffer, $maxlen, $flags );

semantics. I think this would be sufficient to safely use the MSG_TRUNC flag.
Ideally perl's core recv() syscall function shouldn't fail in this manner,
though I don't have any firm suggestions or feelings for what it should do​:

* grow the buffer
* clamp the returned length, thus ignoring its oversizedness
* warn
* die
* ...?

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.10.1:

Configured by Debian Project at Sun Apr 11 20:09:49 UTC 2010.

Summary of my perl5 (revision 5 version 10 subversion 1) configuration:
   
  Platform:
    osname=linux, osvers=2.6.32-3-amd64, archname=x86_64-linux-gnu-thread-multi
    uname='linux madeleine 2.6.32-3-amd64 #1 smp wed feb 24 18:07:42 utc 2010 x86_64 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr -Dprivlib=/usr/share/perl/5.10 -Darchlib=/usr/lib/perl/5.10 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.10.1 -Dsitearch=/usr/local/lib/perl/5.10.1 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm -DDEBUGGING=-g -Doptimize=-O2 -Duseshrplib -Dlibperl=libperl.so.5.10.1 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.4.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 /lib /usr/lib /lib64 /usr/lib64
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.10.2.so, so=so, useshrplib=true, libperl=libperl.so.5.10.1
    gnulibc_version='2.10.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib -fstack-protector'

Locally applied patches:
    DEBPKG:debian/arm_thread_stress_timeout - http://bugs.debian.org/501970 Raise the timeout of ext/threads/shared/t/stress.t to accommodate slower build hosts
    DEBPKG:debian/cpan_config_path - Set location of CPAN::Config to /etc/perl as /usr may not be writable.
    DEBPKG:debian/cpan_definstalldirs - Provide a sensible INSTALLDIRS default for modules installed from CPAN.
    DEBPKG:debian/db_file_ver - http://bugs.debian.org/340047 Remove overly restrictive DB_File version check.
    DEBPKG:debian/doc_info - Replace generic man(1) instructions with Debian-specific information.
    DEBPKG:debian/enc2xs_inc - http://bugs.debian.org/290336 Tweak enc2xs to follow symlinks and ignore missing @INC directories.
    DEBPKG:debian/errno_ver - http://bugs.debian.org/343351 Remove Errno version check due to upgrade problems with long-running processes.
    DEBPKG:debian/extutils_hacks - Various debian-specific ExtUtils changes
    DEBPKG:debian/fakeroot - Postpone LD_LIBRARY_PATH evaluation to the binary targets.
    DEBPKG:debian/instmodsh_doc - Debian policy doesn't install .packlist files for core or vendor.
    DEBPKG:debian/ld_run_path - Remove standard libs from LD_RUN_PATH as per Debian policy.
    DEBPKG:debian/libnet_config_path - Set location of libnet.cfg to /etc/perl/Net as /usr may not be writable.
    DEBPKG:debian/m68k_thread_stress - http://bugs.debian.org/495826 Disable some threads tests on m68k for now due to missing TLS.
    DEBPKG:debian/mod_paths - Tweak @INC ordering for Debian
    DEBPKG:debian/module_build_man_extensions - http://bugs.debian.org/479460 Adjust Module::Build manual page extensions for the Debian Perl policy
    DEBPKG:debian/perl_synopsis - http://bugs.debian.org/278323 Rearrange perl.pod
    DEBPKG:debian/prune_libs - http://bugs.debian.org/128355 Prune the list of libraries wanted to what we actually need.
    DEBPKG:debian/use_gdbm - Explicitly link against -lgdbm_compat in ODBM_File/NDBM_File. 
    DEBPKG:fixes/assorted_docs - http://bugs.debian.org/443733 [384f06a] Math::BigInt::CalcEmu documentation grammar fix
    DEBPKG:fixes/net_smtp_docs - http://bugs.debian.org/100195 [rt.cpan.org #36038] Document the Net::SMTP 'Port' option
    DEBPKG:fixes/processPL - http://bugs.debian.org/357264 [rt.cpan.org #17224] Always use PERLRUNINST when building perl modules.
    DEBPKG:debian/perlivp - http://bugs.debian.org/510895 Make perlivp skip include directories in /usr/local
    DEBPKG:fixes/pod2man-index-backslash - http://bugs.debian.org/521256 Escape backslashes in .IX entries
    DEBPKG:debian/disable-zlib-bundling - Disable zlib bundling in Compress::Raw::Zlib
    DEBPKG:fixes/kfreebsd_cppsymbols - http://bugs.debian.org/533098 [3b910a0] Add gcc predefined macros to $Config{cppsymbols} on GNU/kFreeBSD.
    DEBPKG:debian/cpanplus_definstalldirs - http://bugs.debian.org/533707 Configure CPANPLUS to use the site directories by default.
    DEBPKG:debian/cpanplus_config_path - Save local versions of CPANPLUS::Config::System into /etc/perl.
    DEBPKG:fixes/kfreebsd-filecopy-pipes - http://bugs.debian.org/537555 [16f708c] Fix File::Copy::copy with pipes on GNU/kFreeBSD
    DEBPKG:fixes/anon-tmpfile-dir - http://bugs.debian.org/528544 [perl #66452] Honor TMPDIR when open()ing an anonymous temporary file
    DEBPKG:fixes/abstract-sockets - http://bugs.debian.org/329291 [89904c0] Add support for Abstract namespace sockets.
    DEBPKG:fixes/hurd_cppsymbols - http://bugs.debian.org/544307 [eeb92b7] Add gcc predefined macros to $Config{cppsymbols} on GNU/Hurd.
    DEBPKG:fixes/autodie-flock - http://bugs.debian.org/543731 Allow for flock returning EAGAIN instead of EWOULDBLOCK on linux/parisc
    DEBPKG:fixes/archive-tar-instance-error - http://bugs.debian.org/539355 [rt.cpan.org #48879] Separate Archive::Tar instance error strings from each other
    DEBPKG:fixes/positive-gpos - http://bugs.debian.org/545234 [perl #69056] [c584a96] Fix \\G crash on first match
    DEBPKG:debian/devel-ppport-ia64-optim - http://bugs.debian.org/548943 Work around an ICE on ia64
    DEBPKG:fixes/trie-logic-match - http://bugs.debian.org/552291 [perl #69973] [0abd0d7] Fix a DoS in Unicode processing [CVE-2009-3626]
    DEBPKG:fixes/hppa-thread-eagain - http://bugs.debian.org/554218 make the threads-shared test suite more robust, fixing failures on hppa
    DEBPKG:fixes/crash-on-undefined-destroy - http://bugs.debian.org/564074 [perl #71952] [1f15e67] Fix a NULL pointer dereference when looking for a DESTROY method
    DEBPKG:fixes/tainted-errno - http://bugs.debian.org/574129 [perl #61976] [be1cf43] fix an errno stringification bug in taint mode
    DEBPKG:patchlevel - http://bugs.debian.org/567489 List packaged patches for 5.10.1-12 in patchlevel.h


@INC for perl 5.10.1:
    /home/paul/lib/perl5/x86_64-linux-gnu-thread-multi
    /home/paul/lib/perl5
    /etc/perl
    /usr/local/lib/perl/5.10.1
    /usr/local/share/perl/5.10.1
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.10
    /usr/share/perl/5.10
    /usr/local/lib/site_perl
    /usr/local/lib/perl/5.10.0
    /usr/local/share/perl/5.10.0
    .


Environment for perl 5.10.1:
    HOME=/home/paul
    LANG=en_GB.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/home/paul/lib
    LOGDIR (unset)
    PATH=/home/paul/bin:/usr/local/bin:/usr/bin:/bin:/usr/games
    PERL5LIB=/home/paul/lib/perl5
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2010

From @iabyn

On Thu, May 13, 2010 at 10​:18​:37AM -0700, Paul LeoNerd Evans wrote​:

When using a PF_PACKET socket, the MSG_TRUNC flag can be useful on a recv()
call, to tell the kernel to truncate the message to the size of the given
buffer, but return its full size from the wire.
[snip]
This program captures IPv4 packets and prints their lengths and IP addresses.
It usually dies after about 20 packets or so (unreliably), such as​:
[snip]
I believe this bug is caused by the following lines from pp_sys.c​:

(in PP(pp_sysread))​:

    buffer = SvGROW\(bufsv\, \(STRLEN\)\(length\+1\)\);
    count = PerlSock\_recvfrom\(PerlIO\_fileno\(IoIFP\(io\)\)\, buffer\, length\, offset\,
                              \(struct sockaddr \*\)namebuf\, &bufsize\);

...
SvCUR_set(bufsv, count);

This causes problems if the kernel's return value in count is larger than the
length value; such as is the case with the MSG_TRUNC flag.
[snip]
Ideally perl's core recv() syscall function shouldn't fail in this manner,
though I don't have any firm suggestions or feelings for what it should do​:

* grow the buffer
* clamp the returned length, thus ignoring its oversizedness
* warn
* die
* ...?

Thanks for the report. I've gone with the 'clamp the returned length'
option, as commit 8eb023a

--
You never really learn to swear until you learn to drive.

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2010

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

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2010

@iabyn - Status changed from 'open' to 'resolved'

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

1 participant