kern/117010: [linux] linux_getdents() get something like buffer
overflow or else
sam
samflanker at gmail.com
Wed Sep 10 08:07:41 UTC 2008
On Mon, Sep 08, 2008 at 01:12:28AM +0400, Chagin Dmitry wrote:
>/ 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!
Hello
Iam tested this patch on my old testing pack (with source)
http://cs.udmvt.ru/files/temp/linux_getdents.tar.bz2
(bin.file linux_getdents_static compiled on system Linux 2.6.9 with old glibc version)
# uname -a
FreeBSD damascus 7.0-STABLE FreeBSD 7.0-STABLE #0: Mon Aug 25 12:41:55 MSD 2008 root at static:/usr/obj/usr/src/sys/DAMASCUS i386
# sysctl compat.linux.osrelease
compat.linux.osrelease: 2.6.16
# pkg_info|grep linux
linux_base-fc-4_13 Base set of packages needed in Linux mode (for i386/amd64)
/before patch
-------------------------------------------------------------------
# ./linux_getdents_static ./temp/
Reading...
.
..
ak47-1.wav
ak47-2.wav
***
sliderelease1.wav
Closing...
*** glibc detected *** ./linux_getdents_static: double free or corruption (!prev): 0x080c7688 ***
======= Backtrace: =========
[0x80515fe]
[0x8054cdb]
[0x80564b8]
[0x804828b]
[0x80484ab]
[0x8048151]
======= Memory map: ========
08048000-080c3000 r-xp 0008d000 00:00 4168734 /usr/home/venom/temp/temp/devel/linux/linux_getdents_static
080c3000-080c6000 rw-p 00025000 00:00 0
080c6000-080e8000 rwxp 00025000 00:00 0
480c3000-480c4000 rwxp 0013d000 00:00 0
48100000-48121000 rwxp 0013d000 00:00 0
48121000-48200000 ---p 0013d000 00:00 0
bfbe0000-bfc00000 rwxp 00020000 00:00 0
Abort trap: 6 (core dumped)
-------------------------------------------------------------------
after patch
-------------------------------------------------------------------
# ./linux_getdents_static ./temp/
Reading...
.
..
ak47-1.wav
ak47-2.wav
***
sliderelease1.wav
Closing...Done!
-------------------------------------------------------------------
thanks
/Vladimir Ermakov
More information about the freebsd-emulation
mailing list