bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

strange bug, alloca suspected


From: Yann Droneaud
Subject: strange bug, alloca suspected
Date: Tue, 13 Feb 2001 22:10:27 +0100

Hi,

I found a strange bug with modprobe/glibc

I supposed this is a bad interaction between gcc alloca(), glibc and modprobe.

Modprobe don't use alloca() correctly, then glibc failed. (stack corruption ?)

This need more investigation.

This mail is sent to glibc, gcc and modutils maintainers.

>Submitter-Id:  net
>Originator:    Yann Droneaud <address@hidden>
>Organization:  no others than mine
>Confidential:  no
>Synopsis:      undetermined
>Severity:      non-critical
>Priority:      low
>Category:      libc
>Class:         sw-bug
>Release:       libc-2.1.3

>Environment: 

Host type: i586-pc-linux-gnu
System: Linux Corwin.Ambre 2.4.0-prerelease #1 Mon Jan 1 23:11:11 CET 2001 i586
unknown
Architecture: i586

Addons: crypt linuxthreads
Build CFLAGS: -g -O2 -march=i586
Build CC: gcc
Compiler version: 2.95.2 19991024 (release)
Kernel headers: 2.4.1
Symbol versioning: yes
Build static: yes
Build shared: yes
Build pic-default: no
Build profile: yes
Build omitfp: no
Build bounded: no
Build static-nss: no
Stdio: libio
compiled against linux 2.3.99-pre5 with gcc-2.95.2

Others:
modutils-2.4.2
  configured with './configure  --prefix=/usr --exec-prefix= --disable-combined
--enable-combined-rmmod --enable-combined-lsmod --disable-strip'
gcc 2.95.2
bash 2.03.0(1)-release

>Description:
>How-To-Repeat:

How to reproduce bug
--------------------
on shell prompt, as root type:
# /sbin/modprobe --help
just display help, no problem.

try this now:
# modprobe --help
display help,
 but finish by a Segmentation Fault

What a strange behaviour, isn't it ?


>Fix:

A little taste of debugging:
----------------------------
I decide to debug modprobe.
I added a signal handler for SIGSEGV.
The handler only wait for the debugger.

0x400951f1 in __libc_nanosleep () from /lib/libc.so.6
(gdb) bt
#0  0x400951f1 in __libc_nanosleep () from /lib/libc.so.6
#1  0x40095188 in __sleep (seconds=1) at ../sysdeps/unix/sysv/linux/sleep.c:82
#2  0x804ba3a in sighandler ()
#3  <signal handler called>
#4  tdestroy_recurse (root=0x0, freefct=0x400f1d20 <_IO_2_1_stderr_>) at
tsearch.c:637
#5  0x100 in ?? ()
(gdb) directory /tmp/glibc-2.1.3/misc
Source directories searched: /tmp/glibc-2.1.3/misc:$cdir:$cwd
(gdb) frame 4
#4  tdestroy_recurse (root=0x0, freefct=0x400f1d20 <_IO_2_1_stderr_>) at
tsearch.c:637
637       if (root->left != NULL)
(gdb) list
632        tree cannot be removed easily.  We provide a function to do this.  */
633     static void
634     internal_function
635     tdestroy_recurse (node root, __free_fn_t freefct)
636     {
637       if (root->left != NULL)
638         tdestroy_recurse (root->left, freefct);
639       if (root->right != NULL)
640         tdestroy_recurse (root->right, freefct);
641       (*freefct) ((void *) root->key);
(gdb) print root
$1 = 0x0

I wasn't able to find how/where this function could be call with a NULL
argument.

A little patch for glibc 2.1.3, misc/tsearch.c

=============================================================
--- tsearch.c   Thu Nov  6 00:18:09 1997
+++ tsearch-meuh.c      Sun Feb 11 23:54:37 2001
@@ -634,13 +634,22 @@
 internal_function
 tdestroy_recurse (node root, __free_fn_t freefct)
 {
-  if (root->left != NULL)
-    tdestroy_recurse (root->left, freefct);
-  if (root->right != NULL)
-    tdestroy_recurse (root->right, freefct);
-  (*freefct) ((void *) root->key);
-  /* Free the node itself.  */
-  free (root);
+  if (root != NULL)
+    {
+      if (root->left != NULL)
+       tdestroy_recurse (root->left, freefct);
+      if (root->right != NULL)
+       tdestroy_recurse (root->right, freefct);
+      (*freefct) ((void *) root->key);
+      /* Free the node itself.  */
+      free (root);
+    }
+#ifdef DEBUGGING
+  else
+    {
+      assert(root != NULL);
+    }
+#endif /* DEBUGGING */
 }

 void
===============================================================




For modprobe
I review the code before the getopt_long(), I found the alloca() call did not
reserve room for the last NUL char
The only thing important is the l++;

so the patch:
================================================================
--- modutils-2.4.2/insmod/modprobe.c    Fri Jan 19 07:26:33 2001
+++ modutils-2.4.2-debug/insmod/modprobe.c      Mon Feb 12 00:00:58 2001
@@ -33,6 +33,9 @@
 #include <limits.h>
 #include <sys/param.h>
 #include <sys/stat.h>

+#include <signal.h>

 #include "module.h"
 #include "obj.h"
 #include "modstat.h"
@@ -1476,6 +1479,25 @@
            );
 }

+#ifdef DEBUG
+void sighandler(int sig)
+{
+  int i;
+  static int wait_for_gdb;

+  printf("%d: signal SIGSEGV: %d, waiting for debugger\n", getpid(), sig);

+  while (wait_for_gdb == 0) 
+    sleep(1);

+  /* wait about 10 seconds */
+  for(i = 0; i < 10 ; i++)
+    sleep(1);

+  exit(1);
+}
+#endif

 int main(int argc, char *argv[])
 {
        int ret = 0;
@@ -1506,10 +1528,18 @@
        int i, l = 0;
        char *command;

+#ifdef DEBUG
+       signal(SIGSEGV, sighandler);
+#endif

        for (i = 0; i < argc; ++i)
                l += strlen(argv[i]) + 1;

+       l++; /* be sure to have room for last NUL char */

        command = alloca(l);
        *command = '\0';

        for (i = 0; i < argc; ++i) {
                strcat(command, argv[i]);
                strcat(command, " ");
==================================================================



-- 
Yann Droneaud <address@hidden>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]