Le Monday 03 July 2006 à 04:57:32, Colin Watson a écrit:
> On Sat, Jul 01, 2006 at 01:51:34PM +0200, Ludovic Rousseau wrote:
> > The bug is classic: off-by-one buffer overflow.
> > 
> > The function make_content() in libdb/db_lookup.c calculates the size
> > needed for cont.dptr but forget to include the final NUL byte.
> > 
> > Please apply this proposed patch.
> > 
> > diff -r --unified=10 man-db-2.4.3/libdb/db_lookup.c 
> > man-db-2.4.3.new/libdb/db_lookup.c
> > --- man-db-2.4.3/libdb/db_lookup.c  2003-11-16 19:46:47.000000000 +0100
> > +++ man-db-2.4.3.new/libdb/db_lookup.c      2006-07-01 13:40:12.000000000 
> > +0200
> > @@ -254,21 +254,21 @@
> >             in->whatis = dash + 1;
> >  
> >     cont.dsize = strlen (dash_if_unset (in->name)) +
> >                  strlen (in->ext) +
> >                  strlen (in->sec) +
> >               /* strlen (in->_st_mtime) */ + 11 +
> >               /* strlen (in->id) */ + 1 +
> >                  strlen (in->pointer) +
> >                  strlen (in->filter) +
> >                  strlen (in->comp) +
> > -                strlen (in->whatis) + 8;
> > +                strlen (in->whatis) + 8 +1;
> >     cont.dptr = (char *) xmalloc (cont.dsize);
> >  #ifdef ANSI_SPRINTF
> >     cont.dsize = 1 + sprintf (cont.dptr,
> >             "%s\t%s\t%s\t%ld\t%c\t%s\t%s\t%s\t%s",
> 
> Actually I'm not sure this is correct. Break down the string:
> 
>   name \t ext \t sec \t mtime \t id \t pointer \t filter \t comp \t whatis
> 
> Now the mtime is 10 digits long at most so the 11 in the code already
> includes its trailing tab. That means there are 7 tab characters not
> taken into account by the sum of the strlens, and the final NUL makes 8.
> The calculation seems correct to me. (I concede that the code is very
> confusingly arranged, and I just committed a change to upstream CVS to
> make it slightly less so.)

I think you are right.

> Presumably you've now dug into the problem somewhat; could you include
> some of your intermediate results? For example, is there a particular
> man page or package I can install that will allow me to reproduce the
> problem?

I used "mandb -d" but the generated trace is very long (more than 12,000 lines).

The end is:
[...]
ult_src: File /usr/share/man/man1/cpio.1.gz in mantree /usr/share/man
++priv_drop_count = 1
--priv_drop_count = 0
The following command done with dropped privs
/bin/gzip -dc /usr/share/man/man1/cpio.1.gz [input: 0, output: 9]
++priv_drop_count = 1
--priv_drop_count = 0
++priv_drop_count = 1
++priv_drop_count = 2
--priv_drop_count = 1
++priv_drop_count = 2
--priv_drop_count = 1
--priv_drop_count = 0
"cpio - copy files to and from archives"
record = 'cpio - copy files to and from archives'
base_name = 'cpio'
name = 'cpio', id = A

ult_src: File /usr/share/man/man1/mt-gnu.1.gz in mantree /usr/share/man
++priv_drop_count = 1
--priv_drop_count = 0
The following command done with dropped privs
/bin/gzip -dc /usr/share/man/man1/mt-gnu.1.gz [input: 0, output: 9]
++priv_drop_count = 1
--priv_drop_count = 0
++priv_drop_count = 1
++priv_drop_count = 2
--priv_drop_count = 1
++priv_drop_count = 2
--priv_drop_count = 1
--priv_drop_count = 0
"mt - control magnetic tape drive operation"
record = 'mt - control magnetic tape drive operation'
base_name = 'mt-gnu'
name = 'mt', id = C
name = 'mt-gnu', id = A

ult_src: File /usr/share/man/man1/crontab.1.gz in mantree /usr/share/man
++priv_drop_count = 1
--priv_drop_count = 0
The following command done with dropped privs
/bin/gzip -dc /usr/share/man/man1/crontab.1.gz [input: 0, output: 9]
++priv_drop_count = 1
--priv_drop_count = 0
++priv_drop_count = 1
++priv_drop_count = 2
--priv_drop_count = 1
++priv_drop_count = 2
--priv_drop_count = 1
--priv_drop_count = 0
"crontab - maintain crontab files for individual users (V3)"
record = 'crontab - maintain crontab files for individual users (V3)'
base_name = 'crontab'
name = 'crontab', id = A
found 2 names/extensions
multi key lookup (red   1)
"ed, red - text editor"
record = 'ed, red - text editor'
base_name = 'red'
name = 'ed', id = C
ignoring differing ids: ed
name = 'red', id = B
ignoring differing ids: red     1

ult_src: File /usr/share/man/man1/envsubst.1.gz in mantree /usr/share/man
++priv_drop_count = 1
*** glibc detected *** free(): invalid next size (normal): 0x0817c6e8 ***

Program received signal SIGABRT, Aborted.
0xffffe410 in __kernel_vsyscall ()
(gdb) bt
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x413386d1 in raise () from /lib/tls/i686/cmov/libc.so.6
#2  0x41339f9b in abort () from /lib/tls/i686/cmov/libc.so.6
#3  0x4136f157 in __fsetlocking () from /lib/tls/i686/cmov/libc.so.6
#4  0x41375727 in malloc_usable_size () from /lib/tls/i686/cmov/libc.so.6
#5  0x413772f5 in free () from /lib/tls/i686/cmov/libc.so.6
#6  0x41377f31 in realloc () from /lib/tls/i686/cmov/libc.so.6
#7  0x08058f8d in xrealloc (p=0x0, n=1094987764) at xmalloc.c:81
#8  0x08056604 in strappend (str=0x9 <Address 0x9 out of bounds>)
    at strappend.c:65
#9  0x08056781 in create_tempfile (template=0x0, created_filename=0x8061768)
    at tempfile.c:85
#10 0x08051898 in decompress (
    filename=0x817c3a8 "/usr/share/man/man1/envsubst.1.gz", comp=0x80616a0)
    at compression.c:75
#11 0x0804e4e3 in ult_src (name=0x817ae50 "/usr/share/man/man1/envsubst.1.gz",
    path=0x808d6e0 "/usr/share/man", buf=0xafd5eb6c,
    flags=<value optimized out>) at ult_src.c:320
#12 0x0804f640 in test_manfile (
    file=0x817ae50 "/usr/share/man/man1/envsubst.1.gz",
    path=0x808d6e0 "/usr/share/man") at check_mandirs.c:238
#13 0x0804fbe0 in testmandirs (path=0x808d6e0 "/usr/share/man", last=0)
    at check_mandirs.c:354
#14 0x0804fe8d in create_db (manpath=0x808d6e0 "/usr/share/man")
    at check_mandirs.c:529
#15 0x0804a0fb in mandb (catpath=0x808d780 "/var/cache/man",
    manpath=0x808d6e0 "/usr/share/man") at mandb.c:320
#16 0x0804a946 in main (argc=2, argv=0xafd5f264) at mandb.c:565
(gdb)





I also used electric-fence and I have a much shorter trace:
(I recompiled the program to have more debug info)

Starting program: /home/NoBackup/Debian/man-db/man-db-2.4.3/src/mandb -d
[Thread debugging using libthread_db enabled]
[New Thread -1476974912 (LWP 32461)]

  Electric Fence 2.1 Copyright (C) 1987-1998 Bruce Perens.
ruid=0, euid=0
++priv_drop_count = 1
>From the config file /etc/manpath.config:

Mandatory mandir `/usr/man'.
Mandatory mandir `/usr/share/man'.
Mandatory mandir `/usr/X11R6/man'.
Mandatory mandir `/usr/local/man'.
Path `/bin' mapped to mandir `/usr/share/man'.
Path `/usr/bin' mapped to mandir `/usr/share/man'.
Path `/sbin' mapped to mandir `/usr/share/man'.
Path `/usr/sbin' mapped to mandir `/usr/share/man'.
Path `/usr/local/bin' mapped to mandir `/usr/local/man'.
Path `/usr/local/bin' mapped to mandir `/usr/local/share/man'.
Path `/usr/local/sbin' mapped to mandir `/usr/local/man'.
Path `/usr/local/sbin' mapped to mandir `/usr/local/share/man'.
Path `/usr/X11R6/bin' mapped to mandir `/usr/X11R6/man'.
Path `/usr/bin/X11' mapped to mandir `/usr/X11R6/man'.
Path `/usr/games' mapped to mandir `/usr/share/man'.
Path `/opt/bin' mapped to mandir `/opt/man'.
Path `/opt/sbin' mapped to mandir `/opt/man'.
Global mandir `/usr/man', catdir `/var/cache/man/fsstnd'.
--priv_drop_count = 0
creating catdir hierarchy /var/cache/man/fsstnd
++priv_drop_count = 1
Global mandir `/usr/share/man', catdir `/var/cache/man'.
--priv_drop_count = 0
creating catdir hierarchy /var/cache/man
++priv_drop_count = 1
Global mandir `/usr/local/man', catdir `/var/cache/man/oldlocal'.
--priv_drop_count = 0
creating catdir hierarchy /var/cache/man/oldlocal
++priv_drop_count = 1
Global mandir `/usr/local/share/man', catdir `/var/cache/man/local'.
--priv_drop_count = 0
creating catdir hierarchy /var/cache/man/local
++priv_drop_count = 1
Global mandir `/usr/X11R6/man', catdir `/var/cache/man/X11R6'.
--priv_drop_count = 0
creating catdir hierarchy /var/cache/man/X11R6
++priv_drop_count = 1
Global mandir `/opt/man', catdir `/var/cache/man/opt'.
--priv_drop_count = 0
creating catdir hierarchy /var/cache/man/opt
++priv_drop_count = 1
Added section `1'.
Added section `n'.
Added section `l'.
Added section `8'.
Added section `3'.
Added section `2'.
Added section `3posix'.
Added section `3pm'.
Added section `3perl'.
Added section `5'.
Added section `4'.
Added section `9'.
Added section `6'.
Added section `7'.
`/usr/man'      `'      `1'
`/usr/share/man'        `'      `1'
`/usr/X11R6/man'        `'      `1'
`/usr/local/man'        `'      `1'
`/bin'  `/usr/share/man'        `0'
`/usr/bin'      `/usr/share/man'        `0'
`/sbin' `/usr/share/man'        `0'
`/usr/sbin'     `/usr/share/man'        `0'
`/usr/local/bin'        `/usr/local/man'        `0'
`/usr/local/bin'        `/usr/local/share/man'  `0'
`/usr/local/sbin'       `/usr/local/man'        `0'
`/usr/local/sbin'       `/usr/local/share/man'  `0'
`/usr/X11R6/bin'        `/usr/X11R6/man'        `0'
`/usr/bin/X11'  `/usr/X11R6/man'        `0'
`/usr/games'    `/usr/share/man'        `0'
`/opt/bin'      `/opt/man'      `0'
`/opt/sbin'     `/opt/man'      `0'
`/usr/man'      `/var/cache/man/fsstnd' `-1'
`/usr/share/man'        `/var/cache/man'        `-1'
`/usr/local/man'        `/var/cache/man/oldlocal'       `-1'
`/usr/local/share/man'  `/var/cache/man/local'  `-1'
`/usr/X11R6/man'        `/var/cache/man/X11R6'  `-1'
`/opt/man'      `/var/cache/man/opt'    `-1'
`1'     `'      `-5'
`n'     `'      `-5'
`l'     `'      `-5'
`8'     `'      `-5'
`3'     `'      `-5'
`2'     `'      `-5'
`3posix'        `'      `-5'
`3pm'   `'      `-5'
`3perl' `'      `-5'
`5'     `'      `-5'
`4'     `'      `-5'
`9'     `'      `-5'
`6'     `'      `-5'
`7'     `'      `-5'

path directory /usr/local/sbin is in the config file
adding /usr/local/man to manpath
adding /usr/local/share/man to manpath

path directory /usr/local/bin is in the config file
/usr/local/man is already in the manpath
/usr/local/share/man is already in the manpath

path directory /usr/sbin is in the config file
adding /usr/share/man to manpath

path directory /usr/bin is in the config file
/usr/share/man is already in the manpath

path directory /sbin is in the config file
/usr/share/man is already in the manpath

path directory /bin is in the config file
/usr/share/man is already in the manpath

path directory /usr/X11R6/bin is in the config file
mandb: warning: /usr/X11R6/man: No such file or directory

adding mandatory man directories

mandb: warning: /usr/man: No such file or directory
/usr/share/man is already in the manpath
mandb: warning: /usr/X11R6/man: No such file or directory
/usr/local/man is already in the manpath
manpath=/usr/man:/usr/share/man:/usr/local/man:/usr/local/share/man:/usr/X11R6/man:/opt/man
mandb: warning: /usr/man: No such file or directory
adding /usr/share/man to manpathlist
adding /usr/local/man to manpathlist
adding /usr/local/share/man to manpathlist
mandb: warning: /usr/X11R6/man: No such file or directory
mandb: warning: /opt/man: No such file or directory
--priv_drop_count = 0
Purging old database entries in /usr/share/man...

ElectricFence Exiting: mprotect() failed: Cannot allocate memory

Program exited with code 0377.
(gdb) bt
No stack.
(gdb) q


If I do not use the "-d" argument I have a very long backtrace and the end is:

#0  0xffffe410 in __kernel_vsyscall ()
#1  0x41338b16 in kill () from /lib/tls/i686/cmov/libc.so.6
#2  0xa7f0ddd5 in EF_Abort () from /usr/lib/libefence.so.0.0
#3  0xa7f0cdd0 in ?? () from /usr/lib/libefence.so.0.0
#4  0xa7f0e13d in ?? () from /usr/lib/libefence.so.0.0
#5  0xa7f0f438 in ?? () from /usr/lib/libefence.so.0.0
#6  0xaff686f8 in ?? ()
#7  0xa7f0d5af in memalign () from /usr/lib/libefence.so.0.0
#8  0xa7f0d5af in memalign () from /usr/lib/libefence.so.0.0
#9  0xa7f0d9ad in malloc () from /usr/lib/libefence.so.0.0
#10 0x4133562b in textdomain () from /lib/tls/i686/cmov/libc.so.6
#11 0x41333617 in ngettext () from /lib/tls/i686/cmov/libc.so.6
#12 0x41332fbe in gettext () from /lib/tls/i686/cmov/libc.so.6
#13 0x4133249d in dcgettext () from /lib/tls/i686/cmov/libc.so.6
#14 0x4137cb72 in strerror_r () from /lib/tls/i686/cmov/libc.so.6
#15 0xa7f0dbc7 in realloc () from /usr/lib/libefence.so.0.0
#16 0xa7f0dc87 in Page_Create () from /usr/lib/libefence.so.0.0
#17 0xa7f0d649 in memalign () from /usr/lib/libefence.so.0.0
[...]
#1153 0xa7f0d633 in memalign () from /usr/lib/libefence.so.0.0
#1154 0xa7f0d9ad in malloc () from /usr/lib/libefence.so.0.0
#1155 0x4133562b in textdomain () from /lib/tls/i686/cmov/libc.so.6
#1156 0x41333617 in ngettext () from /lib/tls/i686/cmov/libc.so.6
#1157 0x41332fbe in gettext () from /lib/tls/i686/cmov/libc.so.6
#1158 0x4133249d in dcgettext () from /lib/tls/i686/cmov/libc.so.6
#1159 0x4137cb72 in strerror_r () from /lib/tls/i686/cmov/libc.so.6
#1160 0xa7f0dbc7 in realloc () from /usr/lib/libefence.so.0.0
#1161 0xa7f0dc87 in Page_Create () from /usr/lib/libefence.so.0.0
#1162 0xa7f0d633 in memalign () from /usr/lib/libefence.so.0.0
#1163 0xa7f0d9ad in malloc () from /usr/lib/libefence.so.0.0
#1164 0x4133562b in textdomain () from /lib/tls/i686/cmov/libc.so.6
#1165 0x41333617 in ngettext () from /lib/tls/i686/cmov/libc.so.6
#1166 0x41332fbe in gettext () from /lib/tls/i686/cmov/libc.so.6
#1167 0x4133249d in dcgettext () from /lib/tls/i686/cmov/libc.so.6
#1168 0x4137cb72 in strerror_r () from /lib/tls/i686/cmov/libc.so.6
#1169 0xa7f0dbc7 in realloc () from /usr/lib/libefence.so.0.0
#1170 0xa7f0dc87 in Page_Create () from /usr/lib/libefence.so.0.0
#1171 0xa7f0d633 in memalign () from /usr/lib/libefence.so.0.0
#1172 0xa7f0d9ad in malloc () from /usr/lib/libefence.so.0.0
#1173 0x4133562b in textdomain () from /lib/tls/i686/cmov/libc.so.6
#1174 0x41333617 in ngettext () from /lib/tls/i686/cmov/libc.so.6
#1175 0x41332fbe in gettext () from /lib/tls/i686/cmov/libc.so.6
---Type <return> to continue, or q <return> to quit---
#1176 0x4133249d in dcgettext () from /lib/tls/i686/cmov/libc.so.6
#1177 0x4137cb72 in strerror_r () from /lib/tls/i686/cmov/libc.so.6
#1178 0xa7f0dbc7 in realloc () from /usr/lib/libefence.so.0.0
#1179 0xa7f0dc87 in Page_Create () from /usr/lib/libefence.so.0.0
#1180 0xa7f0d633 in memalign () from /usr/lib/libefence.so.0.0
#1181 0xa7f0d9ad in malloc () from /usr/lib/libefence.so.0.0
#1182 0x08058f52 in xmalloc (n=12) at xmalloc.c:66
#1183 0x08056a0f in hash_install (ht=0x9ebb1ff0,
    name=0xa0ff9ff0 "vga_setreadpage", len=16, defn=0x0) at hashtable.c:125
#1184 0x08055e4c in man_gdbm_firstkey (wrap=0xa6ba7ff8) at db_gdbm.c:139
#1185 0x0804ef63 in purge_missing (manpath=0xa7c30ff0 "/usr/share/man",
    catpath=0xa7c3eff0 "/var/cache/man") at check_mandirs.c:826
#1186 0x0804a915 in main (argc=1, argv=0xaff83c64) at mandb.c:556
(gdb)


Using "set environment EF_PROTECT_BELOW 1" I have a different backtrace:

#1181 0xa7f399ad in malloc () from /usr/lib/libefence.so.0.0
#1182 0x4133562b in textdomain () from /lib/tls/i686/cmov/libc.so.6
#1183 0x41333617 in ngettext () from /lib/tls/i686/cmov/libc.so.6
#1184 0x41332fbe in gettext () from /lib/tls/i686/cmov/libc.so.6
#1185 0x4133249d in dcgettext () from /lib/tls/i686/cmov/libc.so.6
#1186 0x4137cb72 in strerror_r () from /lib/tls/i686/cmov/libc.so.6
#1187 0xa7f39bc7 in realloc () from /usr/lib/libefence.so.0.0
#1188 0xa7f39c87 in Page_Create () from /usr/lib/libefence.so.0.0
#1189 0xa7f397dd in memalign () from /usr/lib/libefence.so.0.0
#1190 0xa7f399ad in malloc () from /usr/lib/libefence.so.0.0
#1191 0x08058f52 in xmalloc (n=14) at xmalloc.c:66
#1192 0x08058ed1 in xstrndup (string=0xa3718000 "vga_setpalvec", size=0)
    at xstrndup.c:46
#1193 0x08056a1d in hash_install (ht=0x9ebde000,
    name=0xa3718000 "vga_setpalvec", len=14, defn=0x0) at hashtable.c:126
#1194 0x08055e4c in man_gdbm_firstkey (wrap=0xa6bd4000) at db_gdbm.c:139
#1195 0x0804ef63 in purge_missing (manpath=0xa7c5d000 "/usr/share/man",
    catpath=0xa7c6b000 "/var/cache/man") at check_mandirs.c:826
#1196 0x0804a915 in main (argc=1, argv=0xafa99f64) at mandb.c:556
(gdb)

It now crashes in hashtable.c:126 (np->name = xstrndup (name, len);)
instead of hashtable.c:125 (np = (struct nlist *) xmalloc (sizeof
(struct nlist));) and with a different manpage.


It really looks like a memory corruption somewhere.

I tried in a sid chroot I have and can't reproduce the bug.
I can send you the list of the 1138 packages I have installed if you
want.

What alse can I do for you?

Bye,

-- 
 Dr. Ludovic Rousseau                        [EMAIL PROTECTED]
 -- Normaliser Unix c'est comme pasteuriser le camembert, L.R. --

Reply via email to