| Debugging information: |
The bug has been found using the BSD version of fsfuzzer on a
FreeBSD 6.1 installation with a kernel
compiled from sources available in ftp.freebsd.org. No operation except mount itself, is necessary to
trigger the bug. The architecture used to conduct the tests is IA32/x86.
kgdb) shell uname -a
FreeBSD freebsdvm.info-pull.com 6.1-RELEASE FreeBSD 6.1-RELEASE #1: Thu Nov 2 21:15:59 UTC 2006
root@freebsdvm.info-pull.com:/usr/obj/usr/src/sys/GENERIC i386
The following 'output' is a detailed analysis of the bug using kgdb and the crash dump with a kernel
image containing debug symbols:
[root@freebsdvm /sys/i386/include]# kgdb -d /usr/crash/ -n 6 /usr/obj/usr/src/sys/GENERIC/kernel.debug
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so: Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Unread portion of the kernel message buffer:
WARNING: : multilabel flag on fs but no MAC support
panic: kmem_malloc(-1912602624): kmem_map too small: 4636672 total allocated
Uptime: 1m57s
Dumping 255 MB (3 chunks)
chunk 0: 1MB (159 pages) ... ok
chunk 1: 254MB (65008 pages) 238 222 206 190 174 158 142 126 110 94 78 62 46 30 14 ... ok
chunk 2: 1MB (256 pages)
#0 doadump () at pcpu.h:165
165 __asm __volatile("movl %%fs:0,%0" : "=r" (td));
(kgdb) bt
#0 doadump () at pcpu.h:165
#1 0xc064dee1 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:402
#2 0xc064e178 in panic (fmt=0xc08baffd ) at /usr/src/sys/kern/kern_shutdown.c:558
#3 0xc07bc3a1 in kmem_malloc (map=0xc10430c0, size=2382364672, flags=2) at /usr/src/sys/vm/vm_kern.c:299
#4 0xc07b3c6e in page_alloc (zone=0x0, bytes=-1912602624, pflag=0x0, wait=2) at /usr/src/sys/vm/uma_core.c:958
#5 0xc07b5fc7 in uma_large_malloc (size=-1912602624, wait=2) at /usr/src/sys/vm/uma_core.c:2702
#6 0xc0643815 in malloc (size=2382364672, mtp=0xc0916fc0, flags=2) at /usr/src/sys/kern/kern_malloc.c:329
#7 0xc07a43e6 in ffs_rdextattr (p=0x0, vp=0xc2598110, td=0x0, extra=0) at /usr/src/sys/ufs/ffs/ffs_vnops.c:1137
#8 0xc07a4487 in ffs_open_ea (vp=0x0, cred=0x0, td=0xc257f480) at /usr/src/sys/ufs/ffs/ffs_vnops.c:1170
#9 0xc07a48c2 in ffs_getextattr (ap=0xd135983c) at /usr/src/sys/ufs/ffs/ffs_vnops.c:1423
#10 0xc08539c5 in VOP_GETEXTATTR_APV (vop=0x0, a=0x0) at vnode_if.c:2431
#11 0xc06b1ef5 in vn_extattr_get (vp=0xc2598110, ioflg=8, attrnamespace=0, attrname=0x0, buflen=0xd13598ac, buf=0x0, td=0xc257f480)
at vnode_if.h:1282
#12 0xc07a4f87 in ufs_getacl (ap=0xd13598dc) at /usr/src/sys/ufs/ufs/ufs_acl.c:183
#13 0xc0853825 in VOP_GETACL_APV (vop=0x0, a=0x0) at vnode_if.c:2218
#14 0xc07abb22 in ufs_access (ap=0xd135993c) at vnode_if.h:1151
#15 0xc0852a44 in VOP_ACCESS_APV (vop=0x0, a=0x0) at vnode_if.c:480
#16 0xc0698cd6 in vfs_cache_lookup (ap=0x0) at vnode_if.h:256
#17 0xc085278b in VOP_LOOKUP_APV (vop=0xc0952520, a=0xd13599c8) at vnode_if.c:99
#18 0xc069d345 in lookup (ndp=0xd1359bcc) at vnode_if.h:56
#19 0xc069cbe6 in namei (ndp=0xd1359bcc) at /usr/src/sys/kern/vfs_lookup.c:203
#20 0xc06b033b in vn_open_cred (ndp=0xd1359bcc, flagp=0xd1359ccc, cmode=420, cred=0xc2506780, fdidx=3) at /usr/src/sys/kern/vfs_vnops.c:125
#21 0xc06b02de in vn_open (ndp=0x0, flagp=0xd1359ccc, cmode=420, fdidx=3) at /usr/src/sys/kern/vfs_vnops.c:91
#22 0xc06a8d22 in kern_open (td=0xc257f480, path=0x0, pathseg=UIO_USERSPACE, flags=1538, mode=438) at /usr/src/sys/kern/vfs_syscalls.c:1002
#23 0xc06a8c36 in open (td=0xc257f480, uap=0xd1359d04) at /usr/src/sys/kern/vfs_syscalls.c:968
#24 0xc08420ab in syscall (frame=
{tf_fs = 59, tf_es = 59, tf_ds = 59, tf_edi = 0, tf_esi = 135282928, tf_ebp = -1077951192, tf_isp = -785015452,
tf_ebx = 1537, tf_edx = 135053297, tf_ecx = 135053307, tf_eax= 5, tf_trapno = 12, tf_err = 2, tf_eip = 674081515, tf_cs = 51,
tf_eflags = 582, tf_esp = -1077951556, tf_ss = 59}) at /usr/src/sys/i386/i386/trap.c:981
#25 0xc0830cef in Xint0x80_syscall () at /usr/src/sys/i386/i386/exception.s:200
#26 0x00000033 in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb) info registers
eax 0x0 0
ecx 0x0 0
edx 0x0 0
ebx 0xc2316480 -1036950400
esp 0xd13596a0 0xd13596a0
ebp 0xd13596a8 0xd13596a8
esi 0x0 0
edi 0x4 4
eip 0xc064da16 0xc064da16
eflags 0x0 0
cs 0x0 0
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(kgdb) list *0xc07a43e6
0xc07a43e6 is in ffs_rdextattr (/usr/src/sys/ufs/ffs/ffs_vnops.c:1137).
1132
1133 ip = VTOI(vp);
1134 dp = ip->i_din2;
1135 easize = dp->di_extsize;
1136
1137 eae = malloc(easize + extra, M_TEMP, M_WAITOK);
1138
1139 liovec.iov_base = eae;
1140 liovec.iov_len = easize;
1141 luio.uio_iov = &liovec;
(kgdb) select-frame 7
(kgdb) info locals
ip = (struct inode *) 0x0
dp = (struct ufs2_dinode *) 0x0
luio = {uio_iov = 0xc12f61c8, uio_iovcnt = -1063583904, uio_offset = -3371621792048218112,
uio_resid = -1065101227, uio_segflg = 3231383392, uio_rw = 3260669952,
uio_td = 0xc104e640}
liovec = {iov_base = 0xc098ec40, iov_len = 3238265580}
easize = -1912602624
error = -1912602624
eae = (u_char *) 0xc241ddec ""
(kgdb) list *0xc07a4487 <---- #8
0xc07a4487 is in ffs_open_ea (/usr/src/sys/ufs/ffs/ffs_vnops.c:1171).
1166
1167 if (ip->i_ea_area != NULL)
1168 return (EBUSY);
1169 dp = ip->i_din2;
1170 error = ffs_rdextattr(&ip->i_ea_area, vp, td, 0); <--- to #7
1171 if (error)
1172 return (error);
1173 ip->i_ea_len = dp->di_extsize;
1174 ip->i_ea_error = 0;
1175 return (0);
(kgdb) select-frame 8
(kgdb) info locals
ip = (struct inode *) 0xc241ddec
dp = (struct ufs2_dinode *) 0xc259c100
error = 0
------------- ufs/ufs/inode.h
50 /*
51 * The inode is used to describe each active (or recently active) file in the
52 * UFS filesystem. It is composed of two types of information. The first part
53 * is the information that is needed only while the file is active (such as
54 * the identity of the file and linkage to speed its lookup). The second part
55 * is the permanent meta-data associated with the file which is read in
56 * from the permanent dinode from long term storage when the file becomes
57 * active, and is put back when the file is no longer being used.
58 */
59 struct inode {
60 TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
61 struct vnode *i_vnode;/* Vnode associated with this inode. */
62 struct ufsmount *i_ump;/* Ufsmount point associated with this inode. */
63 u_int32_t i_flag; /* flags, see below */
64 struct cdev *i_dev; /* Device associated with the inode. */
65 ino_t i_number; /* The identity of the inode. */
66 int i_effnlink; /* i_nlink when I/O completes */
67
68 struct fs *i_fs; /* Associated filesystem superblock. */
69 struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
70 u_quad_t i_modrev; /* Revision level for NFS lease. */
71 struct lockf *i_lockf;/* Head of byte-level lock list. */
(...)
111 };
--------- ufs/ufs/inode.h
(kgdb) frame
#8 0xc07a4487 in ffs_open_ea (vp=0x0, cred=0x0, td=0xc257f480) at /usr/src/sys/ufs/ffs/ffs_vnops.c:1170
1170 error = ffs_rdextattr(&ip->i_ea_area, vp, td, 0);
(kgdb) list 1123,1176
1123 static int
1124 ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td, int extra)
1125 {
1126 struct inode *ip;
1127 struct ufs2_dinode *dp;
1128 struct uio luio;
1129 struct iovec liovec;
1130 int easize, error;
1131 u_char *eae;
1132
1133 ip = VTOI(vp);
1134 dp = ip->i_din2;
1135 easize = dp->di_extsize;
1136
1137 eae = malloc(easize + extra, M_TEMP, M_WAITOK);
1138
1139 liovec.iov_base = eae;
1140 liovec.iov_len = easize;
1141 luio.uio_iov = &liovec;
1142 luio.uio_iovcnt = 1;
1143 luio.uio_offset = 0;
1144 luio.uio_resid = easize;
1145 luio.uio_segflg = UIO_SYSSPACE;
1146 luio.uio_rw = UIO_READ;
1147 luio.uio_td = td;
1148
1149 error = ffs_extread(vp, &luio, IO_EXT | IO_SYNC);
1150 if (error) {
1151 free(eae, M_TEMP);
1152 return(error);
1153 }
1154 *p = eae;
1155 return (0);
1156 }
1157
1158 static int
1159 ffs_open_ea(struct vnode *vp, struct ucred *cred, struct thread *td)
---Type to continue, or q to quit---
1160 {
1161 struct inode *ip;
1162 struct ufs2_dinode *dp;
1163 int error;
1164
1165 ip = VTOI(vp);
1166
1167 if (ip->i_ea_area != NULL)
1168 return (EBUSY);
1169 dp = ip->i_din2;
1170 error = ffs_rdextattr(&ip->i_ea_area, vp, td, 0); <--- to #7
1171 if (error)
1172 return (error);
1173 ip->i_ea_len = dp->di_extsize;
1174 ip->i_ea_error = 0;
1175 return (0);
1176 }
(kgdb) printf "%p\n",ip->i_fs->fs_magic
0x19540119 <------ = FS_UFS2_MAGIC
(kgdb) p dp
$43 = (struct ufs2_dinode *) 0xc259c100
(kgdb) p dp->di_extsize
$44 = -1912602624
(kgdb) p ip->i_fs
$51 = (struct fs *) 0xc2325000
(kgdb) list 1390,1440
1390 */
1391 static int
1392 ffs_getextattr(struct vop_getextattr_args *ap)
1393 /*
1394 vop_getextattr {
1395 IN struct vnode *a_vp;
1396 IN int a_attrnamespace;
1397 IN const char *a_name;
1398 INOUT struct uio *a_uio;
1399 OUT size_t *a_size;
1400 IN struct ucred *a_cred;
1401 IN struct thread *a_td;
1402 };
1403 */
1404 {
1405 struct inode *ip;
1406 struct fs *fs;
1407 u_char *eae, *p;
1408 unsigned easize;
1409 int error, ealen, stand_alone;
1410
1411 ip = VTOI(ap->a_vp);
1412 fs = ip->i_fs;
1413
1414 if (ap->a_vp->v_type == VCHR)
1415 return (EOPNOTSUPP);
1416
1417 error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1418 ap->a_cred, ap->a_td, IREAD);
1419 if (error)
1420 return (error);
1421
1422 if (ip->i_ea_area == NULL) {
1423 error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); <------------- to #8
1424 if (error)
1425 return (error);
1426 stand_alone = 1;
1427 } else {
1428 stand_alone = 0;
1429 }
1430 eae = ip->i_ea_area;
1431 easize = ip->i_ea_len;
1432
1433 ealen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
1434 NULL, &p);
1435 if (ealen >= 0) {
1436 error = 0;
1437 if (ap->a_size != NULL)
1438 *ap->a_size = ealen;
1439 else if (ap->a_uio != NULL)
1440 error = uiomove(p, ealen, ap->a_uio);
(kgdb) info locals
ip = (struct inode *) 0xc241ddec
p = (u_char *) 0x0
error = -1034321648
ealen = 0
stand_alone = 0
(kgdb) p ip->dinode_u->din2->di_extsize
$72 = -1912602624
-------------------------------- ufs/ufs/dinode.h
125 struct ufs2_dinode {
126 u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
127 int16_t di_nlink; /* 2: File link count. */
128 u_int32_t di_uid; /* 4: File owner. */
129 u_int32_t di_gid; /* 8: File group. */
130 u_int32_t di_blksize; /* 12: Inode blocksize. */
131 u_int64_t di_size; /* 16: File byte count. */
132 u_int64_t di_blocks; /* 24: Bytes actually held. */
(...)
144 int32_t di_extsize; /* 92: External attributes block. */
(...)
-------------------------------- ufs/ufs/dinode.h
(kgdb) select-frame 12
(kgdb) frame
#12 0xc07a4f87 in ufs_getacl (ap=0xd13598dc) at /usr/src/sys/ufs/ufs/ufs_acl.c:183
183 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
(kgdb) list
178 * EA, as they are in fact a combination of the inode
179 * ownership/permissions and the EA contents. If the
180 * EA is present, merge the two in a temporary ACL
181 * storage, otherwise just return the inode contents.
182 */
183 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
184 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
185 POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp,
186 ap->a_td);
187 switch (error) {
(kgdb) list -
168
169 /*
170 * Attempt to retrieve the ACL based on the ACL type.
171 */
172 bzero(ap->a_aclp, sizeof(*ap->a_aclp));
173 len = sizeof(*ap->a_aclp);
174 switch(ap->a_type) {
175 case ACL_TYPE_ACCESS:
176 /*
177 * ACL_TYPE_ACCESS ACLs may or may not be stored in the
(kgdb) list -
158 {
159 struct inode *ip = VTOI(ap->a_vp);
160 int error, len;
161
162 /*
163 * XXX: If ufs_getacl() should work on file systems not supporting
164 * ACLs, remove this check.
165 */
166 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
167 return (EOPNOTSUPP);
(kgdb) p ip->dinode_u->din2->di_extsize
$76 = -1912602624
(kgdb) select-frame 19
(kgdb) info locals
fdp = (struct filedesc *) 0xc24eec00
cp = 0xc24eec00 ""
dp = (struct vnode *) 0xc233fbb0 <---------
aiov = {iov_base = 0xfffebff4, iov_len = 0}
auio = {uio_iov = 0x0, uio_iovcnt = -785016152, uio_offset = -4577691262870250712, uio_resid = -1036395872,
uio_segflg = 4294885364, uio_rw = 4294967295, uio_td = 0x4000}
error = -1036780624 <---------
linklen = -1036780624 <---------
cnp = (struct componentname *) 0xd1359bf4
td = (struct thread *) 0xc257f480
p = (struct proc *) 0x0
vfslocked = 0
(kgdb) frame
#19 0xc069cbe6 in namei (ndp=0xd1359bcc) at /usr/src/sys/kern/vfs_lookup.c:203
203 error = lookup(ndp);
(kgdb) list
198 VREF(dp);
199 }
200 if (vfslocked)
201 ndp->ni_cnd.cn_flags |= GIANTHELD;
202 ndp->ni_startdir = dp;
203 error = lookup(ndp);
204 if (error) {
205 uma_zfree(namei_zone, cnp->cn_pnbuf);
206 #ifdef DIAGNOSTIC
207 cnp->cn_pnbuf = NULL;
(kgdb) ptype linklen
type = int
------------ kern/vfs_lookup.c
203 error = lookup(ndp);
204 if (error) {
205 uma_zfree(namei_zone, cnp->cn_pnbuf);
206 #ifdef DIAGNOSTIC
207 cnp->cn_pnbuf = NULL;
208 cnp->cn_nameptr = NULL;
209 #endif
210 return (error);
211 }
------------- kern/vfs_lookup.c
|