List Info

Thread: Buffer overflow in win32_select() (PATCH included)




Buffer overflow in win32_select() (PATCH included)
user name
2007-10-10 04:44:13
# New Ticket Created by  Risto Kankkunen 
# Please include the string:  [perl #46309]
# in the subject line of all future correspondence about
this issue. 
# <URL: h
ttp://rt.perl.org/rt3/Ticket/Display.html?id=46309 >


This is a bug report for perl from risto.kankkunenf-secure.com,
generated with the help of perlbug 1.35 running under perl
v5.8.7.


------------------------------------------------------------
-----
I've found a nasty buffer overflow problem in win32_select()
function
that has made our product, which is using embedded Perl,
very
unreliable. We are currently using version 5.8.7, but I have
checked
that the problematic code is the same in 5.8.8.

The problem happens, when some of the select() sets are not
specified.
In this case the code uses a dummy variable in place of the
actual bit
vector:

win32/win32sck.c:282:
> int
> win32_select(int nfds, Perl_fd_set* rd, Perl_fd_set*
wr, Perl_fd_set* ex,
> const struct timeval* timeout)
> {
>     int r;
> #ifdef USE_SOCKETS_AS_HANDLES
>    Perl_fd_set dummy;


win32/win32sck.c:304:
>     if (!rd)
> 	rd = &dummy, prd = NULL;


Perl_fd_set is defined in win32/include/sys/socket.h:26 as:

> #ifndef PERL_FD_SETSIZE
> #define PERL_FD_SETSIZE		64
> #endif
>
> #define PERL_BITS_PER_BYTE	8
>
#define	PERL_NFDBITS		(sizeof(Perl_fd_mask)*PERL_BITS_PER_BY
TE)
>
> typedef int			Perl_fd_mask;
>
> typedef struct	Perl_fd_set {
>     Perl_fd_mask
bits[(PERL_FD_SETSIZE+PERL_NFDBITS-1)/PERL_NFDBITS];
> }				Perl_fd_set;


If a socket number exceeds 63, this code writes over the end
of dummy,
destroying some local variables, the return address and so
on:


win32/win32sck.c:334:
>     for (i = 0; i < nfds; i++) {
> 	fd = TO_SOCKET(i);
> 	if (PERL_FD_ISSET(i,rd) && !FD_ISSET(fd,
&nrd))
> 	    PERL_FD_CLR(i,rd);


You can easily repro the problem with the attached
socketcrash.pl script.

I have attached a patch that fixes the buffer overflow by
eliminating
the dummy
variable.

Regards,
Risto Kankkunen

~~~ socketcrash.pl
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
use strict;
use warnings;

use IO::Socket;

sub fhbits {
	my fhlist = _;

	my($bits)="";
	vec($bits,fileno($_),1) = 1 for (fhlist);
	return $bits;
}

my handles = ();
	for (1..2000) {
	my $handle = new IO::Socket(
		Domain=>AF_INET,
		Proto=>"udp",
		PeerAddr=>"127.0.0.2:8888"
	) or die;
	
	push(handles, $handle);
}
printf "handles=%d-%dn", fileno($handles[0]),
fileno($handles[-1]);

my $rin = fhbits(handles);
my ($rout, $wout, $eout);

my ($count, $timeleft) = select($rout=$rin, $wout=undef,
$eout=undef, 1);

print "count=$countn";
print "timeleft=$timeleftn";
printf "rin =%*v08bn", " " , $rin;
printf "rout=%*v08bn", " " , $rout ||
0;
printf "wout=%*v08bn", " " , $wout ||
0;
printf "eout=%*v08bn", " " , $eout ||
0;
~~~ win32_select.patch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Index: perl/src/win32/win32sck.c
============================================================
=======
--- perl/src/win32/win32sck.c	(revision 3794)
+++ perl/src/win32/win32sck.c	(working copy)
 -287,9
+287,8 
  {
      int r;
  #ifdef USE_SOCKETS_AS_HANDLES
-    Perl_fd_set dummy;
      int i, fd, save_errno = errno;
-    FD_SET nrd, nwr, nex, *prd, *pwr, *pex;
+    FD_SET nrd, nwr, nex;

      /* winsock seems incapable of dealing with all three
null fd_sets,
       * so do the (millisecond) sleep as a special case
 -303,44
+302,31 
  	return 0;
      }
      StartSockets();
-    PERL_FD_ZERO(&dummy);
-    if (!rd)
-	rd = &dummy, prd = NULL;
-    else
-	prd = &nrd;
-    if (!wr)
-	wr = &dummy, pwr = NULL;
-    else
-	pwr = &nwr;
-    if (!ex)
-	ex = &dummy, pex = NULL;
-    else
-	pex = &nex;

      FD_ZERO(&nrd);
      FD_ZERO(&nwr);
      FD_ZERO(&nex);
      for (i = 0; i < nfds; i++) {
  	fd = TO_SOCKET(i);
-	if (PERL_FD_ISSET(i,rd))
+	if (rd && PERL_FD_ISSET(i,rd))
  	    FD_SET((unsigned)fd, &nrd);
-	if (PERL_FD_ISSET(i,wr))
+	if (wr && PERL_FD_ISSET(i,wr))
  	    FD_SET((unsigned)fd, &nwr);
-	if (PERL_FD_ISSET(i,ex))
+	if (ex && PERL_FD_ISSET(i,ex))
  	    FD_SET((unsigned)fd, &nex);
      }

      errno = save_errno;
-    SOCKET_TEST_ERROR(r = select(nfds, prd, pwr, pex,
timeout));
+    SOCKET_TEST_ERROR(r = select(nfds, &nrd, &nwr,
&nex, timeout));
      save_errno = errno;

      for (i = 0; i < nfds; i++) {
  	fd = TO_SOCKET(i);
-	if (PERL_FD_ISSET(i,rd) && !FD_ISSET(fd,
&nrd))
+	if (rd && PERL_FD_ISSET(i,rd) &&
!FD_ISSET(fd, &nrd))
  	    PERL_FD_CLR(i,rd);
-	if (PERL_FD_ISSET(i,wr) && !FD_ISSET(fd,
&nwr))
+	if (wr && PERL_FD_ISSET(i,wr) &&
!FD_ISSET(fd, &nwr))
  	    PERL_FD_CLR(i,wr);
-	if (PERL_FD_ISSET(i,ex) && !FD_ISSET(fd,
&nex))
+	if (ex && PERL_FD_ISSET(i,ex) &&
!FD_ISSET(fd, &nex))
  	    PERL_FD_CLR(i,ex);
      }
      errno = save_errno;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~

------------------------------------------------------------
-----
---
Flags:
     category=core
     severity=high
---
Site configuration information for perl v5.8.7:

Configured by kankri at Mon Oct 30 15:14:16 2006.

Summary of my perl5 (revision 5 version 8 subversion 7)
configuration:
   Platform:
     osname=MSWin32, osvers=5.1,
archname=MSWin32-x86-multi-thread
     uname=''
     config_args='undef'
     hint=recommended, useposix=true, d_sigaction=undef
     usethreads=define use5005threads=undef
useithreads=define usemultiplicity=define
     useperlio=define d_sfio=undef uselargefiles=define
usesocks=undef
     use64bitint=undef use64bitall=undef
uselongdouble=undef
     usemymalloc=n, bincompat5005=undef
   Compiler:
     cc='cl', ccflags ='-nologo -Gf -W3 -MD -Zi -DNDEBUG -O1
-DWIN32
-D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT  -DPERL_NO_EXIT
-DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO
-DPERL_MSVCRT_READFIX',
     optimize='-MD -Zi -DNDEBUG -O1',
     cppflags='-DWIN32'
     ccversion='12.00.8804', gccversion='', gccosandvers=''
     intsize=4, longsize=4, ptrsize=4, doublesize=8,
byteorder=1234
     d_longlong=undef, longlongsize=8, d_longdbl=define,
longdblsize=10
     ivtype='long', ivsize=4, nvtype='double', nvsize=8,
Off_t='__int64', lseeksize=8
     alignbytes=8, prototype=define
   Linker and Libraries:
     ld='link', ldflags ='-nologo -nodefaultlib -debug
-opt:ref,icf -libpath:"c:fs-perllibCORE" 
-machine86'
     libpth=lib
     libs=  oldnames.lib kernel32.lib user32.lib gdi32.lib
winspool.lib
  comdlg32.lib advapi32.lib shell32.lib ole32.lib
oleaut32.lib
netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib 
version.lib
odbc32.lib odbccp32.lib msvcrt.lib
     perllibs=  oldnames.lib kernel32.lib user32.lib
gdi32.lib
winspool.lib  comdlg32.lib advapi32.lib shell32.lib
ole32.lib
oleaut32.lib  netapi32.lib uuid.lib ws2_32.lib mpr.lib
winmm.lib
version.lib odbc32.lib odbccp32.lib msvcrt.lib
     libc=msvcrt.lib, so=dll, useshrplib=yes,
libperl=fspl58.lib
     gnulibc_version='undef'
   Dynamic Linking:
     dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef,
ccdlflags=' '
     cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib
-debug -opt:ref,icf 
-libpath:"c:fs-perllibCORE"  -machine86'

Locally applied patches:


---
INC
for perl v5.8.7:
     C:/fs-perl/lib
     C:/fs-perl/site/lib
     .

---
Environment for perl v5.8.7:
     HOME (unset)
     LANG (unset)
     LANGUAGE (unset)
     LD_LIBRARY_PATH (unset)
     LOGDIR (unset)
     PATH=<undisclosed>
     PERL_BADLANG (unset)
     SHELL (unset)


Re: Buffer overflow in win32_select() (PATCH included)
user name
2007-10-19 05:25:48
On 10/10/2007, via RT Risto Kankkunen
<perlbug-followupperl.org> wrote:
> I've found a nasty buffer overflow problem in
win32_select() function
> that has made our product, which is using embedded
Perl, very
> unreliable. We are currently using version 5.8.7, but I
have checked
> that the problematic code is the same in 5.8.8.

No feedback on this from our Win32 experts ?

[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )