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. --