vlc | branch: master | Rémi Denis-Courmont <[email protected]> | Fri Sep 17 06:10:17 2010 +0300| [1c1a4e41611e1802b60a3ceddcc1f4e1c3eb7f4e] | committer: Rémi Denis-Courmont
Fix potential overflow in vlc_readdir() > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=1c1a4e41611e1802b60a3ceddcc1f4e1c3eb7f4e --- src/text/filesystem.c | 39 ++++++++++++++++++++++++++------------- 1 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/text/filesystem.c b/src/text/filesystem.c index ff08e1e..f83a4fc 100644 --- a/src/text/filesystem.c +++ b/src/text/filesystem.c @@ -38,9 +38,6 @@ #include <stdio.h> #include <limits.h> /* NAME_MAX */ -#if !defined(NAME_MAX) && defined(_POSIX_NAME_MAX) -# define NAME_MAX _POSIX_NAME_MAX -#endif #include <errno.h> #include <sys/types.h> #include <dirent.h> @@ -324,19 +321,35 @@ char *vlc_readdir( DIR *dir ) return FromWide (ent->d_name); #else + /* Beware that readdir_r() assumes <buf> is large enough to hold the result + * dirent including the file name. A buffer overflow could occur otherwise. + * In particular, pathconf() and _POSIX_NAME_MAX cannot be used here. */ struct dirent *ent; - struct - { - struct dirent ent; - char buf[NAME_MAX + 1]; - } buf; - int val = readdir_r (dir, &buf.ent, &ent); - if (val) + char *path = NULL; + + long len = fpathconf (dirfd (dir), _PC_NAME_MAX); + if (len == -1) { - errno = val; - return NULL; +#ifdef NAME_MAX + len = NAME_MAX; +#else + errno = ENOMEM; + return NULL; // OS is broken. There is no sane way to fix this. +#endif } - return ent ? vlc_fix_readdir( ent->d_name ) : NULL; + len += offsetof (struct dirent, d_name) + 1; + + struct dirent *buf = malloc (len); + if (unlikely(buf == NULL)) + return NULL; + + int val = readdir_r (dir, buf, &ent); + if (val != 0) + errno = val; + else if (ent != NULL) + path = vlc_fix_readdir (ent->d_name); + free (buf); + return path; #endif } _______________________________________________ vlc-commits mailing list [email protected] http://mailman.videolan.org/listinfo/vlc-commits
