[PATCH] Fix a buffer overflow in libgfortran

Jakub Jelinek jakub@redhat.com
Mon Apr 7 15:37:00 GMT 2008


On Mon, Apr 07, 2008 at 09:11:23AM -0400, Jakub Jelinek wrote:
> Still, even with this patch I fear e.g. that nl->var_name doesn't have any
> upper bound, so at least wherever you put that snprintf should be used.

Apparently the frontend limits all symbols to 63 chars, still libgfortran
shouldn't assume it silently, unless it verifies that.  Even then 100 bytes
for e.g. up to 36 chars message from nml_parse_identifier + strlen
(nl->var_name) (up to 63) + 24 is too short.  Testcase that still overflows
the stack is e.g.:

! { dg-do run }

module global
  type             ::  mt
    character(len=2) ::  c012345678901234567890123456789012345678901234567890123456789h(2) = (/"aa","bb"/)
  end type mt
  type             ::  bt
    integer        ::  i(2) = (/1,2/)
    type(mt)       ::  m(2)
  end type bt
end module global

program namelist_47
  use global
  type(bt)         ::  x(2)
  character(140)    ::  teststring 
  namelist /mynml/ x

  teststring = " x(2)%m%c012345678901234567890123456789012345678901234567890123456789h(:)(2:2) = 'z','z',"
  call writenml (teststring)
  teststring = " x(2)%m(2)%c012345678901234567890123456789012345678901234567890123456789h(:)(2) = 'z','z',"
  call writenml (teststring)
  teststring = " x(2)%m(2)%c012345678901234567890123456789012345678901234567890123456789h(:)(:3) = 'z','z',"
  call writenml (teststring)
  teststring = " x(2)%m(2)%c012345678901234567890123456789012345678901234567890123456789h(1:2)(k:) = 'z','z',"
  call writenml (teststring)
  
contains

subroutine writenml (astring)
  character(140), intent(in)  :: astring
  character(300)   :: errmessage
  integer          :: ierror

  open (10, status="scratch", delim='apostrophe')
  write (10, '(A)') "&MYNML"
  write (10, '(A)') astring
  write (10, '(A)') "/"
  rewind (10)
  read (10, nml = mynml, iostat=ierror, iomsg=errmessage)
  if (ierror == 0) call abort
  print '(a)', trim(errmessage)
  close (10)

end subroutine writenml

end program namelist_47
! { dg-final { cleanup-modules "global" } }

So, snprintf should be used plus the nml_err_msg size bumped to
at least 150 on branches where generate_error/internal_error isn't
changed into vararg function.

OT, while looking at list_read.c, I've noticed inefficiencies, e.g.
I don't see any point to allocate memory in nml_touch_nodes and
nml_read_obj, all the following code then does is
strncmp (something, orig_nl->var_name with "%" appended to it, ...)
That can very well be done e.g. in nml_touch_nodes with
--- list_read.c 2008-04-07 15:48:44.000000000 +0200
+++ list_read.c    2008-04-07 16:06:35.000000000 +0200
@@ -2136,14 +2136,13 @@ find_nml_node (st_parameter_dt *dtp, cha
 static void
 nml_touch_nodes (namelist_info * nl)
 {
-  index_type len = strlen (nl->var_name) + 1;
+  char * ext_name = nl->var_name;
+  index_type len = strlen (ext_name);
   int dim;
-  char * ext_name = (char*)get_mem (len + 1);
-  memcpy (ext_name, nl->var_name, len-1);
-  memcpy (ext_name + len - 1, "%", 2);
   for (nl = nl->next; nl; nl = nl->next)
     {
-      if (strncmp (nl->var_name, ext_name, len) == 0)
+      if (strncmp (nl->var_name, ext_name, len) == 0
+         && nl->var_name[len] == '%')
        {
          nl->touched = 1;
          for (dim=0; dim < nl->var_rank; dim++)
@@ -2157,7 +2156,6 @@ nml_touch_nodes (namelist_info * nl)
       else
        break;
     }
-  free_mem (ext_name);
   return;
 }
 

	Jakub



More information about the Gcc-patches mailing list