eina mmap safety - only map zeropages if it's an eina file that sigbuses
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Wed, 30 Aug 2017 03:03:41 +0000 (12:03 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Wed, 30 Aug 2017 03:03:41 +0000 (12:03 +0900)
restrict mapping /dev/zero to only eina files having a sigbus
reported. the mmap was before all our file access used eina_file i
think thus the raw mmap of it. now walk all eina files and find the
candidate and only then if it exists flag is as having a faulty i/o
backing and map the zerto pages then return, otherwise call abort.
more restricted mapping and perhaps a fix for not trapping non-efl
issues.

@fix

src/lib/eina/eina_file.c
src/lib/eina/eina_mmap.c
src/lib/eina/eina_private.h

index 7e154db..c2c7f8f 100644 (file)
@@ -418,30 +418,28 @@ _eina_file_mmap_faulty_one(void *addr, long page_size,
    return EINA_FALSE;
 }
 
-void
+Eina_Bool
 eina_file_mmap_faulty(void *addr, long page_size)
 {
    Eina_File_Map *m;
    Eina_File *f;
    Eina_Iterator *itf;
    Eina_Iterator *itm;
+   Eina_Bool faulty = EINA_FALSE;
 
-   /* NOTE: I actually don't know if other thread are running, I will try to take the lock.
-      It may be possible that if other thread are not running and they were in the middle of
-      accessing an Eina_File this lock are still taken and we will result as a deadlock. */
    eina_lock_take(&_eina_file_lock_cache);
 
    itf = eina_hash_iterator_data_new(_eina_file_cache);
    EINA_ITERATOR_FOREACH(itf, f)
      {
-        Eina_Bool faulty = EINA_FALSE;
-
         eina_lock_take(&f->lock);
 
         if (f->global_map != MAP_FAILED)
           {
-             if ((unsigned char *) addr < (((unsigned char *)f->global_map) + f->length) &&
-                 (((unsigned char *) addr) + page_size) >= (unsigned char *) f->global_map)
+             if ((unsigned char *)addr <
+                 (((unsigned char *)f->global_map) + f->length) &&
+                 (((unsigned char *)addr) + page_size) >=
+                  (unsigned char *)f->global_map)
                {
                   f->global_faulty = EINA_TRUE;
                   faulty = EINA_TRUE;
@@ -477,6 +475,7 @@ eina_file_mmap_faulty(void *addr, long page_size)
    eina_iterator_free(itf);
 
    eina_lock_release(&_eina_file_lock_cache);
+   return faulty;
 }
 
 /* ================================================================ *
index d6d5281..11d8804 100644 (file)
@@ -129,26 +129,35 @@ _eina_mmap_safe_sigbus(int sig, siginfo_t *siginfo, void *ptr)
                }
           }
      }
-   /* send this to stderr - not eina_log. Specifically want this on stderr */
-   fprintf(stderr,
-           "EINA: Data at address 0x%lx is invalid. Replacing with zero page.\n",
-           (unsigned long)addr);
-   /* align address to the lower page boundary */
-   addr = (unsigned char *)((long)addr & (~(_eina_mmap_pagesize - 1)));
-   /* mmap a pzge of zero's from /dev/zero in there */
-   if (mmap(addr, _eina_mmap_pagesize,
-            PROT_READ | PROT_WRITE | PROT_EXEC,
-            MAP_PRIVATE | MAP_FIXED,
-            _eina_mmap_zero_fd, 0) == MAP_FAILED)
+   // Look into mmaped Eina_File if it was one of them, mark it as having
+   // I/O errors and then mmap a zero page in place here
+   if (eina_file_mmap_faulty(addr, _eina_mmap_pagesize))
      {
-        /* mmap of /dev/zero failed :( */
-        perror("mmap");
-        ERR("Failed to mmap() /dev/zero in place of page. SIGBUS!!!");
-        errno = perrno;
+        // Send this to stderr not eina_log. Specifically want this on stderr
+        fprintf(stderr,
+                "EINA: Data at address 0x%lx is invalid. "
+                "Replacing with zero page.\n",
+                (unsigned long)addr);
+        /* align address to the lower page boundary */
+        addr = (unsigned char *)((long)addr & (~(_eina_mmap_pagesize - 1)));
+        /* mmap a pzge of zero's from /dev/zero in there */
+        if (mmap(addr, _eina_mmap_pagesize,
+                 PROT_READ | PROT_WRITE | PROT_EXEC,
+                 MAP_PRIVATE | MAP_FIXED,
+                 _eina_mmap_zero_fd, 0) == MAP_FAILED)
+          {
+             /* mmap of /dev/zero failed :( */
+             perror("mmap");
+             ERR("Failed to mmap() /dev/zero in place of page. SIGBUS!!!");
+             errno = perrno;
+             abort();
+          }
+     }
+   else
+     {
+        ERR("Regular SIGBUS not in an eina_file mmaped file");
         abort();
      }
-   /* Look into mmaped Eina_File if it was one of them, just to remember for later request */
-   eina_file_mmap_faulty(addr, _eina_mmap_pagesize);
    /* restore previous errno */
    errno = perrno;
 }
index d032f84..745364a 100644 (file)
@@ -136,7 +136,7 @@ void eina_log_threads_shutdown(void);
 
 void eina_cpu_count_internal(void);
 
-void eina_file_mmap_faulty(void *addr, long page_size);
+Eina_Bool eina_file_mmap_faulty(void *addr, long page_size);
 
 #ifndef EINA_FREEQ_H_
 typedef struct _Eina_FreeQ Eina_FreeQ;