Date: Mon, 8 Sep 2008 11:30:14 +0400 From: Chagin Dmitry <dchagin@freebsd.org> To: Roman Divacky <rdivacky@freebsd.org> Cc: freebsd-emulation@freebsd.org, MITA Yoshio <mita@ee.t.u-tokyo.ac.jp> Subject: Re: kern/117010: [linux] linux_getdents() get something like buffer overflow or else Message-ID: <20080908073014.GA1429@dchagin.dialup.corbina.ru> In-Reply-To: <20080908070505.GA20963@freebsd.org> References: <200809072030.m87KU44I064646@freefall.freebsd.org> <20080907211228.GA51816@dchagin.dialup.corbina.ru> <20080908070505.GA20963@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Sep 08, 2008 at 09:05:05AM +0200, Roman Divacky wrote: > On Mon, Sep 08, 2008 at 01:12:28AM +0400, Chagin Dmitry wrote: > > On Sun, Sep 07, 2008 at 08:30:04PM +0000, MITA Yoshio wrote: > > > The following reply was made to PR kern/117010; it has been noted by GNATS. > > > > > > From: MITA Yoshio <mita@ee.t.u-tokyo.ac.jp> > > > To: bug-followup@FreeBSD.org,samflanker@gmail.com, > > > Chagin Dmitry <chagin.dmitry@gmail.com>, > > > beech@FreeBSD.org > > > Cc: > > > Subject: Re: kern/117010: [linux] linux_getdents() get something like buffer overflow or else > > > Date: Sun, 07 Sep 2008 21:42:15 +0200 > > > > > > Hello, > > > > > > I've tested a patch from Mr. Dmitry concerning Mr. Ermakov's PR: > > > > > > http://www.freebsd.org/cgi/query-pr.cgi?pr=117010 > > > > > > Patch: > > > >From: Chagin Dmitry <chagin.dmitry@gmail.com> > > > >Date: Fri, 25 Jul 2008 10:22:46 +0400 (MSD) > > > > > > This worked!!! to make skype2 work. > > > Otherwise skype2 dumped core as Mr. reported. > > > > > > Regards, > > > ----- > > > Tested Environment: > > > FreeBSD 7.0-RELEASE > > > linux_base-fc6-6_5 > > > linux-glib2-2.6.6 > > > skype-2.0.0.68,1 > > > > > > /etc/sysctl.conf: > > > compat.linux.osrelease=2.6.16 > > > > > > /etc/make.conf: > > > OVERRIDE_LINUX_BASE_PORT=fc6 > > > > Please, try a patch bellow: > > > > diff --git a/src/sys/compat/linux/linux_file.c b/src/sys/compat/linux/linux_file.c > > index 303bc3f..413e597 100644 > > --- a/src/sys/compat/linux/linux_file.c > > +++ b/src/sys/compat/linux/linux_file.c > > @@ -303,9 +303,20 @@ struct l_dirent64 { > > char d_name[LINUX_NAME_MAX + 1]; > > }; > > > > -#define LINUX_RECLEN(de,namlen) \ > > - ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) > > +/* > > + * Linux uses the last byte in the dirent buffer to store d_type, > > + * at least glibc-2.7 requires it. For what l_dirent padded on 2 bytes. > > + */ > > +#define LINUX_RECLEN(namlen) \ > > + roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2), \ > > + sizeof(l_ulong)) > > + > > +#define LINUX_RECLEN64(namlen) \ > > + roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1), \ > > + sizeof(uint64_t)) > > > > +#define LINUX_MAXRECLEN max(LINUX_RECLEN(LINUX_NAME_MAX), \ > > + LINUX_RECLEN64(LINUX_NAME_MAX)) > > #define LINUX_DIRBLKSIZ 512 > > > > static int > > @@ -318,12 +329,13 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args, > > int len, reclen; /* BSD-format */ > > caddr_t outp; /* Linux-format */ > > int resid, linuxreclen=0; /* Linux-format */ > > + caddr_t lbuf; /* Linux-format */ > > struct file *fp; > > struct uio auio; > > struct iovec aiov; > > off_t off; > > - struct l_dirent linux_dirent; > > - struct l_dirent64 linux_dirent64; > > + struct l_dirent *linux_dirent; > > + struct l_dirent64 *linux_dirent64; > > int buflen, error, eofflag, nbytes, justone; > > u_long *cookies = NULL, *cookiep; > > int ncookies, vfslocked; > > @@ -359,6 +371,7 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args, > > buflen = max(LINUX_DIRBLKSIZ, nbytes); > > buflen = min(buflen, MAXBSIZE); > > buf = malloc(buflen, M_TEMP, M_WAITOK); > > + lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO); > > vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); > > > > again: > > @@ -436,8 +449,8 @@ again: > > } > > > > linuxreclen = (is64bit) > > - ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) > > - : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); > > + ? LINUX_RECLEN64(bdp->d_namlen) > > + : LINUX_RECLEN(bdp->d_namlen); > > > > if (reclen > len || resid < linuxreclen) { > > outp++; > > @@ -446,34 +459,41 @@ again: > > > > if (justone) { > > /* readdir(2) case. */ > > - linux_dirent.d_ino = bdp->d_fileno; > > - linux_dirent.d_off = (l_off_t)linuxreclen; > > - linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; > > - strcpy(linux_dirent.d_name, bdp->d_name); > > - error = copyout(&linux_dirent, outp, linuxreclen); > > - } else { > > - if (is64bit) { > > - linux_dirent64.d_ino = bdp->d_fileno; > > - linux_dirent64.d_off = (cookiep) > > - ? (l_off_t)*cookiep > > - : (l_off_t)(off + reclen); > > - linux_dirent64.d_reclen = > > - (l_ushort)linuxreclen; > > - linux_dirent64.d_type = bdp->d_type; > > - strcpy(linux_dirent64.d_name, bdp->d_name); > > - error = copyout(&linux_dirent64, outp, > > - linuxreclen); > > - } else { > > - linux_dirent.d_ino = bdp->d_fileno; > > - linux_dirent.d_off = (cookiep) > > - ? (l_off_t)*cookiep > > - : (l_off_t)(off + reclen); > > - linux_dirent.d_reclen = (l_ushort)linuxreclen; > > - strcpy(linux_dirent.d_name, bdp->d_name); > > - error = copyout(&linux_dirent, outp, > > - linuxreclen); > > - } > > + linux_dirent = (struct l_dirent*)lbuf; > > + linux_dirent->d_ino = bdp->d_fileno; > > + linux_dirent->d_off = (l_off_t)linuxreclen; > > + linux_dirent->d_reclen = (l_ushort)bdp->d_namlen; > > + strlcpy(linux_dirent->d_name, bdp->d_name, > > + linuxreclen - offsetof(struct l_dirent, d_name)); > > + error = copyout(linux_dirent, outp, linuxreclen); > > } > > + if (is64bit) { > > + linux_dirent64 = (struct l_dirent64*)lbuf; > > + linux_dirent64->d_ino = bdp->d_fileno; > > + linux_dirent64->d_off = (cookiep) > > + ? (l_off_t)*cookiep > > + : (l_off_t)(off + reclen); > > + linux_dirent64->d_reclen = (l_ushort)linuxreclen; > > + linux_dirent64->d_type = bdp->d_type; > > + strlcpy(linux_dirent64->d_name, bdp->d_name, > > + linuxreclen - offsetof(struct l_dirent64, d_name)); > > + error = copyout(linux_dirent64, outp, linuxreclen); > > + } else if (!justone) { > > + linux_dirent = (struct l_dirent*)lbuf; > > + linux_dirent->d_ino = bdp->d_fileno; > > + linux_dirent->d_off = (cookiep) > > + ? (l_off_t)*cookiep > > + : (l_off_t)(off + reclen); > > + linux_dirent->d_reclen = (l_ushort)linuxreclen; > > + /* > > + * Copy d_type to last byte of l_dirent buffer > > + */ > > + lbuf[linuxreclen-1] = bdp->d_type; > > + strlcpy(linux_dirent->d_name, bdp->d_name, > > + linuxreclen - offsetof(struct l_dirent, d_name)-1); > > + error = copyout(linux_dirent, outp, linuxreclen); > > + } > > + > > if (error) > > goto out; > > > > @@ -509,6 +529,7 @@ out: > > VFS_UNLOCK_GIANT(vfslocked); > > fdrop(fp, td); > > free(buf, M_TEMP); > > + free(lbuf, M_TEMP); > > return (error); > > } > > > > > > Roman, I think that this patch can be commited (if testing passes :)) > > thnx! > > yes.... this is the version of the patch I posted to you + the comment changed, right? yes -- Have fun! chd
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080908073014.GA1429>