eina mmap safety - only map zeropages if it's an eina file that sigbuses

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
This commit is contained in:
Carsten Haitzler 2017-08-30 12:03:41 +09:00
parent 15cdd9b71b
commit a5c8e883d8
3 changed files with 34 additions and 26 deletions

View 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;
}
/* ================================================================ *

View 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;
}

View 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;