* eina: fix possible race condition between opendir/readdir_r/pathconf.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 3 Nov 2010 10:19:55 +0000 (10:19 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 3 Nov 2010 10:19:55 +0000 (10:19 +0000)
See http://womble.decadent.org.uk/readdir_r-advisory.html .

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@54117 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

configure.ac
src/lib/eina_file.c

index f7031ac..d3720b0 100644 (file)
@@ -530,6 +530,7 @@ if test "x${dirfd}" = "xyes"; then
 fi
 AC_CHECK_FUNCS([openat], [AC_DEFINE(HAVE_OPENAT)], [])
 AC_CHECK_FUNCS([statat], [AC_DEFINE(HAVE_STATAT)], [])
+AC_CHECK_FUNCS([fpathconf], [AC_DEFINE(HAVE_FPATHCONF)], [])
 
 ### Modules
 
index b12431e..d62648b 100644 (file)
@@ -81,6 +81,45 @@ struct _Eina_File_Iterator
    char dir[1];
 };
 
+/*
+ * This complex piece of code is needed due to possible race condition.
+ * The code and description of the issue can be found at :
+ * http://womble.decadent.org.uk/readdir_r-advisory.html
+ */
+static size_t
+_eina_dirent_buffer_size(DIR * dirp)
+{
+   long name_max;
+   size_t name_end;
+
+#if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
+   name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
+
+   if (name_max == -1)
+     {
+# if defined(NAME_MAX)
+        name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
+# else
+        return PATH_MAX;
+# endif
+     }
+#else
+# if defined(NAME_MAX)
+   name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
+# else
+#  ifdef _PC_NAME_MAX
+#   warning "buffer size for readdir_r cannot be determined safely, best effort, but racy"
+   name_max = pathconf(dirp, _PC_NAME_MAX);
+#  else
+#   error "buffer size for readdir_r cannot be determined safely"
+# endif
+# endif
+#endif
+   name_end = (size_t) offsetof(struct dirent, d_name) + name_max + 1;
+
+   return (name_end > sizeof (struct dirent) ? name_end : sizeof (struct dirent));
+}
+
 static Eina_Bool
 _eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
 {
@@ -88,7 +127,7 @@ _eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
    char *name;
    size_t length;
 
-   dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
+   dp = alloca(_eina_dirent_buffer_size(it->dirp));
 
    do
      {
@@ -150,7 +189,7 @@ _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
    struct dirent *dp;
    size_t length;
 
-   dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
+   dp = alloca(_eina_dirent_buffer_size(it->dir));
 
    do
      {
@@ -336,8 +375,8 @@ eina_file_dir_list(const char *dir,
       return EINA_FALSE;
 
    dlength = strlen(dir);
-   de = alloca(offsetof(struct dirent, d_name) + pathconf(dir, _PC_NAME_MAX) + 1);
-  
+   de = alloca(_eina_dirent_buffer_size(dir));
+
    while ((!readdir_r(d, de, &de) && de))
      {
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))