From owner-freebsd-hackers Mon Nov 15 20:55:17 1999 Delivered-To: freebsd-hackers@freebsd.org Received: from kronos.alcnet.com (kronos.alcnet.com [63.69.28.22]) by hub.freebsd.org (Postfix) with ESMTP id 40BEA14E5B for ; Mon, 15 Nov 1999 20:55:13 -0800 (PST) (envelope-from kbyanc@posi.net) X-Provider: ALC Communications, Inc. http://www.alcnet.com/ Received: from localhost (kbyanc@localhost) by kronos.alcnet.com (8.9.3/8.9.3/antispam) with ESMTP id XAA74824 for ; Mon, 15 Nov 1999 23:55:12 -0500 (EST) Date: Mon, 15 Nov 1999 23:55:12 -0500 (EST) From: Kelly Yancey X-Sender: kbyanc@kronos.alcnet.com To: freebsd-hackers@freebsd.org Subject: Portable way to compare struct stat's? Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG Is there a portable method for determining if the contents of two struct stat's are identical? I believe there is not. The problem is that while Posix defines a base set of fields for the stat structure, it appears that most implementations (including FreeBSD's) extend the structure with additional fields. Comparing all of the Posix fields will only determine the relationship between the Posix subset of the structures. My first inclination was to do a memcmp() which in theory should work across all stat structure definitions. But being that my development box runs FreeBSD, I quickly discovered that at least on FreeBSD, memcmp won't work. The reason? Because the FreeBSD struct stat defines 2 spare fields: st_lspare and st_qspare. The kernel never initializes the values of these fields when returning structures back to userland. So the values are more or less random contents that were on the kernel stack. Besides the possible security implications of passing random kernel stack contents into userland (I am no security expert, so there may not be any problem with this, it just doesn't seem right), there is the nasty side effect the memcmp cannot be used to compare 2 stat structures for equality. I have made a small set of changes to my local kernel source which addresses the problem by bzero'ing the struct stat memory in the kernel before filling it (which ensures that the spare fields get reset to a known state). I've attached the patches below (they need to be applied in the /sys/kern directory). So, back to my original question: is there a better way for comparing stat structures? Or, should memcmp work on other platforms (as well as FreeBSD given the attached patch)? -- Kelly Yancey - kbyanc@posi.net - Richmond, VA Director of Technical Services, ALC Communications http://www.alcnet.com/ Maintainer, BSD Driver Database http://www.posi.net/freebsd/drivers/ Coordinator, Team FreeBSD http://www.posi.net/freebsd/Team-FreeBSD/ --- kern_descrip.c.orig Mon Nov 15 22:11:57 1999 +++ kern_descrip.c Mon Nov 15 22:27:43 1999 @@ -548,9 +548,11 @@ panic("ofstat"); /*NOTREACHED*/ } - cvtstat(&ub, &oub); - if (error == 0) + if (error == 0) { + bzero(&oub, sizeof (oub)); + cvtstat(&ub, &oub); error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub)); + } return (error); } #endif /* COMPAT_43 || COMPAT_SUNOS */ @@ -578,6 +580,7 @@ if ((unsigned)uap->fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[uap->fd]) == NULL) return (EBADF); + bzero(&ub, sizeof (ub)); switch (fp->f_type) { case DTYPE_FIFO: @@ -646,6 +649,7 @@ /*NOTREACHED*/ } if (error == 0) { + bzero(&nub, sizeof (nub)); cvtnstat(&ub, &nub); error = copyout((caddr_t)&nub, (caddr_t)uap->sb, sizeof (nub)); } --- vfs_syscalls.c.orig Mon Nov 15 23:25:48 1999 +++ vfs_syscalls.c Mon Nov 15 23:29:08 1999 @@ -1514,6 +1514,7 @@ vput(nd.ni_vp); if (error) return (error); + bzero(&osb, sizeof (osb)); cvtstat(&sb, &osb); error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); return (error); @@ -1552,6 +1553,7 @@ vput(vp); if (error) return (error); + bzero(&osb, sizeof (osb)); cvtstat(&sb, &osb); error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); return (error); @@ -1613,6 +1615,7 @@ SCARG(uap, path), p); if (error = namei(&nd)) return (error); + bzero(&sb, sizeof (sb)); error = vn_stat(nd.ni_vp, &sb, p); vput(nd.ni_vp); if (error) @@ -1648,6 +1651,7 @@ SCARG(uap, path), p); if (error = namei(&nd)) return (error); + bzero(&sb, sizeof (sb)); vp = nd.ni_vp; error = vn_stat(vp, &sb, p); vput(vp); @@ -1707,6 +1711,7 @@ vput(nd.ni_vp); if (error) return (error); + bzero(&nsb, sizeof (nsb)); cvtnstat(&sb, &nsb); error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb)); return (error); @@ -1745,6 +1750,7 @@ vput(vp); if (error) return (error); + bzero(&nsb, sizeof (nsb)); cvtnstat(&sb, &nsb); error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb)); return (error); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message