summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-09-15 15:56:17 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-09-18 11:58:53 +0900
commit05c051405e89ef595f117f637dbbb0104262c218 (patch)
tree2dd20d3f3c96265ef38927d76cc1f665e136305a /src/lib
parentb2ea60691e45674a4e283e0535634bdd699544ea (diff)
eina file: Ensure populate is safe to call
This makes sure that the call to madvise is safe. On Linux it's not too much of an issue as checks are made inside madvise, and the worst that can happen is an error is returned (EINVAL). Not great. But if MAP_POPULATE is not present, as is the case on *BSD, then the internal function _eina_file_map_populate() is used for the populate rule. In that case actual data is read and we should make sure not to trigger a segfault or bus error. Also, this makes sure that in case of HugeTLB we actually populate all pages, rather than one page out of 8 (we were jumping by 16Mb instead of 2Mb). Note: Can we get the size of a HugeTLB at runtime? We're assuming 2Mb which might very well not be the case! See: https://wiki.debian.org/Hugepages Tested by disabling MAP_POPULATE and observing crashes :) @fix
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/eina/eina_file.c60
1 files changed, 42 insertions, 18 deletions
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index 97dec3e..e458269 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -68,7 +68,10 @@
68 */ 68 */
69 69
70#define EINA_SMALL_PAGE eina_cpu_page_size() 70#define EINA_SMALL_PAGE eina_cpu_page_size()
71#define EINA_HUGE_PAGE 16 * 1024 * 1024 71
72// FIXME: This assumes HugeTLB size of 2Mb. How to get this information at runtime?
73#define EINA_HUGE_PAGE (2 * 1024 * 1024)
74#define EINA_HUGE_PAGE_MIN (8 * EINA_HUGE_PAGE)
72 75
73#ifdef HAVE_DIRENT_H 76#ifdef HAVE_DIRENT_H
74typedef struct _Eina_File_Iterator Eina_File_Iterator; 77typedef struct _Eina_File_Iterator Eina_File_Iterator;
@@ -331,11 +334,24 @@ _eina_file_map_populate(char *map, unsigned long int size, Eina_Bool hugetlb)
331} 334}
332#endif 335#endif
333 336
337static char *
338_page_aligned_address(const char *map, unsigned long int offset, Eina_Bool hugetlb)
339{
340 const uintptr_t align = hugetlb ? EINA_HUGE_PAGE : EINA_SMALL_PAGE;
341 uintptr_t pmap = (uintptr_t) map;
342
343 pmap = (pmap + offset) - ((pmap + offset) & (align - 1));
344
345 return (char *) pmap;
346}
347
334static int 348static int
335_eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned long int size, Eina_Bool hugetlb) 349_eina_file_map_rule_apply(Eina_File_Populate rule, const void *map, unsigned long int offset,
350 unsigned long int size, unsigned long long maplen, Eina_Bool hugetlb)
336{ 351{
337 int tmp = 42; 352 int tmp = 42;
338 int flag = MADV_RANDOM; 353 int flag = MADV_RANDOM;
354 char *addr;
339 355
340 switch (rule) 356 switch (rule)
341 { 357 {
@@ -354,6 +370,21 @@ _eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned long int
354 default: return tmp; break; 370 default: return tmp; break;
355 } 371 }
356 372
373 if (offset >= maplen) return tmp;
374
375 // Align address, clamp size
376 addr = _page_aligned_address(map, offset, hugetlb);
377 if (size > 0)
378 {
379 size += ((char *) map + offset) - addr;
380 offset -= ((char *) map + offset) - addr;
381 if ((offset + size) > maplen)
382 {
383 if (offset > maplen) return tmp;
384 size = maplen - offset;
385 }
386 }
387
357 madvise(addr, size, flag); 388 madvise(addr, size, flag);
358 389
359#ifndef MAP_POPULATE 390#ifndef MAP_POPULATE
@@ -914,7 +945,7 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
914 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; 945 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
915#endif 946#endif
916#ifdef MAP_HUGETLB 947#ifdef MAP_HUGETLB
917 if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB; 948 if (file->length >= EINA_HUGE_PAGE_MIN) flags |= MAP_HUGETLB;
918#endif 949#endif
919 950
920 eina_mmap_safety_enabled_set(EINA_TRUE); 951 eina_mmap_safety_enabled_set(EINA_TRUE);
@@ -941,7 +972,7 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
941 else 972 else
942 hugetlb = file->global_hugetlb; 973 hugetlb = file->global_hugetlb;
943 974
944 _eina_file_map_rule_apply(rule, file->global_map, file->length, hugetlb); 975 _eina_file_map_rule_apply(rule, file->global_map, 0, file->length, file->length, hugetlb);
945 file->global_refcount++; 976 file->global_refcount++;
946 ret = file->global_map; 977 ret = file->global_map;
947 } 978 }
@@ -986,7 +1017,7 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
986 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; 1017 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
987#endif 1018#endif
988#ifdef MAP_HUGETLB 1019#ifdef MAP_HUGETLB
989 if (length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB; 1020 if (length >= EINA_HUGE_PAGE_MIN) flags |= MAP_HUGETLB;
990#endif 1021#endif
991 1022
992 map = malloc(sizeof (Eina_File_Map)); 1023 map = malloc(sizeof (Eina_File_Map));
@@ -1016,7 +1047,7 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
1016 1047
1017 map->refcount++; 1048 map->refcount++;
1018 1049
1019 _eina_file_map_rule_apply(rule, map->map, length, map->hugetlb); 1050 _eina_file_map_rule_apply(rule, map->map, 0, length, map->length, map->hugetlb);
1020 1051
1021 eina_lock_release(&file->lock); 1052 eina_lock_release(&file->lock);
1022 1053
@@ -1064,21 +1095,14 @@ EAPI void
1064eina_file_map_populate(Eina_File *file, Eina_File_Populate rule, const void *map, 1095eina_file_map_populate(Eina_File *file, Eina_File_Populate rule, const void *map,
1065 unsigned long int offset, unsigned long int length) 1096 unsigned long int offset, unsigned long int length)
1066{ 1097{
1098 Eina_File_Map *em;
1099
1067 EINA_SAFETY_ON_NULL_RETURN(file); 1100 EINA_SAFETY_ON_NULL_RETURN(file);
1068 eina_lock_take(&file->lock); 1101 eina_lock_take(&file->lock);
1069 if (map == file->global_map) 1102 if (map == file->global_map)
1070 { 1103 _eina_file_map_rule_apply(rule, map, offset, length, file->length, file->global_hugetlb);
1071 _eina_file_map_rule_apply(rule, ((char*) map) + offset, length, 1104 else if ((em = eina_hash_find(file->rmap, &map)) != NULL)
1072 file->global_hugetlb); 1105 _eina_file_map_rule_apply(rule, map, offset, length, em->length, em->hugetlb);
1073 }
1074 else
1075 {
1076 Eina_File_Map *em;
1077
1078 em = eina_hash_find(file->rmap, &map);
1079 if (em) _eina_file_map_rule_apply(rule, ((char *) em->map) + offset,
1080 length, em->hugetlb);
1081 }
1082 eina_lock_release(&file->lock); 1106 eina_lock_release(&file->lock);
1083} 1107}
1084 1108