From 2e15d5dcadfff3796358a344fa1819196f85c4d9 Mon Sep 17 00:00:00 2001 From: Sung-hun Kim Date: Thu, 19 May 2022 20:53:02 +0900 Subject: [PATCH] mm: LKSM: fix a bug in the filter length calculation Since type of a size variable in the calculation of the filter length is signed integer, it can make a buggy situation when the size of a vma is bigger than a range of a signed integer variable. In this case, the size is treated as a negative number. As a result, it incurs a kernel bug at BUG_ON(size < 0). This patch changes types of variables and members in lksm_region data structure from signed integer to unsigned long. Additionally, remove an assertion BUG_ON(size < 0) because the size never be a negative number. Change-Id: I822a2ba5d372596ee55dcbec90a019fdf1dc2416 Signed-off-by: Sung-hun Kim --- mm/lksm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mm/lksm.c b/mm/lksm.c index 31d8601..ff9fdd0 100644 --- a/mm/lksm.c +++ b/mm/lksm.c @@ -550,12 +550,12 @@ static int region_share[LKSM_REGION_UNKNOWN + 1]; struct lksm_region { enum lksm_region_type type; - int len; int ino; int merge_cnt; int filter_cnt; int scan_round; int conflict; + unsigned long len; atomic_t refcount; struct hlist_node hnode; struct lksm_region *next; @@ -582,7 +582,7 @@ static unsigned int lksm_nr_regions; /* the upper limit for region lookup */ #define LKSM_REGION_ITER_MAX 8 -#define lksm_region_size(start, end) ((int)(end - start) >> PAGE_SHIFT) +#define lksm_region_size(start, end) ((end - start) >> PAGE_SHIFT) #define lksm_bitmap_size(size) ((size >> 6) + ((size % BITS_PER_LONG) ? 1 : 0)) /* all processes share one lksm_region for their heaps */ @@ -2915,9 +2915,9 @@ static void lksm_insert_mm_slot_ordered(struct mm_slot *slot) */ static inline void __lksm_copy_filter -(unsigned long *orig, unsigned long *newer, int size) +(unsigned long *orig, unsigned long *newer, unsigned long size) { - while (--size >= 0) + while (size-- > 0) *(newer++) = *(orig++); } @@ -2964,8 +2964,8 @@ static struct vm_area_struct *lksm_find_next_vma else if (region->type != LKSM_REGION_HEAP && region->type != LKSM_REGION_CONFLICT && region->type != LKSM_REGION_UNKNOWN) { - int size = lksm_region_size(vma->vm_start, vma->vm_end); - int len = (size > BITS_PER_LONG) ? lksm_bitmap_size(size) + unsigned long size = lksm_region_size(vma->vm_start, vma->vm_end); + unsigned long len = (size > BITS_PER_LONG) ? lksm_bitmap_size(size) : SINGLE_FILTER_LEN; if (len > SINGLE_FILTER_LEN && unlikely(region->len != len)) { @@ -2982,7 +2982,7 @@ static struct vm_area_struct *lksm_find_next_vma } if (region->len < len) { unsigned long *filter; - ksm_debug("size of region(%p) is changed: %d -> %d (size: %d)", + ksm_debug("size of region(%p) is changed: %lu -> %lu (size: %lu)", region, region->len, len, size); filter = kcalloc(len, sizeof(long), GFP_KERNEL); if (!filter) { @@ -4815,7 +4815,7 @@ static const struct attribute_group ksm_attr_group = { #ifdef CONFIG_LKSM_FILTER static inline void init_lksm_region -(struct lksm_region *region, unsigned long ino, int type, int len) +(struct lksm_region *region, unsigned long ino, int type, unsigned long len) { region->ino = ino; region->type = type; @@ -4827,12 +4827,12 @@ static void lksm_insert_region (struct lksm_region **region, unsigned long ino, struct vm_area_struct *vma, int type) { - int size, len, need_hash_add = 0; + int need_hash_add = 0; + unsigned long len, size; struct lksm_region *next = NULL; unsigned long flags; size = lksm_region_size(vma->vm_start, vma->vm_end); - BUG_ON(size < 0); len = (size > BITS_PER_LONG) ? lksm_bitmap_size(size) : SINGLE_FILTER_LEN; if (!(*region)) { -- 2.7.4