diff --git a/include/linux/mm.h b/include/linux/mm.h index 58f2263de..50701adb9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -115,6 +115,7 @@ extern int mmap_rnd_compat_bits __read_mostly; #define DEFAULT_MAX_MAP_COUNT (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN) extern int sysctl_max_map_count; +extern int max_map_count_isolated; extern unsigned long sysctl_user_reserve_kbytes; extern unsigned long sysctl_admin_reserve_kbytes; diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 7b5ce005e..2c0e2d5b1 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -137,7 +137,8 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns ns->user_ns = get_user_ns(user_ns); ns->ucounts = ucounts; ns->nr_hashed = PIDNS_HASH_ADDING; - ns->max_map_count = parent_pid_ns->max_map_count; + ns->max_map_count = max_map_count_isolated ? + parent_pid_ns->max_map_count : sysctl_max_map_count; INIT_WORK(&ns->proc_work, proc_cleanup_work); set_bit(0, ns->pidmap[0].page); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a6cb9c1f9..b812bb89f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -343,6 +343,15 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "isolate_max_map_count", + .data = &max_map_count_isolated, + .maxlen = sizeof(max_map_count_isolated), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, #endif { .procname = "print-fatal-signals-src-dst", @@ -2693,7 +2702,8 @@ static int proc_dointvec_max_map_count(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { #ifdef CONFIG_PID_NS - table->data = &task_active_pid_ns(current)->max_map_count; + table->data = max_map_count_isolated ? + &task_active_pid_ns(current)->max_map_count : &sysctl_max_map_count; #endif return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL); } diff --git a/mm/madvise.c b/mm/madvise.c index ffb77f924..c87942f3a 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -148,7 +148,9 @@ static long madvise_behavior(struct vm_area_struct *vma, if (start != vma->vm_start) { #ifdef CONFIG_PID_NS - if (unlikely(mm->map_count >= task_active_pid_ns(current)->max_map_count)) + if (unlikely(mm->map_count >= (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count))) #else if (unlikely(mm->map_count >= sysctl_max_map_count)) #endif @@ -170,7 +172,9 @@ static long madvise_behavior(struct vm_area_struct *vma, if (end != vma->vm_end) { #ifdef CONFIG_PID_NS - if (unlikely(mm->map_count >= task_active_pid_ns(current)->max_map_count)) + if (unlikely(mm->map_count >= (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count))) #else if (unlikely(mm->map_count >= sysctl_max_map_count)) #endif diff --git a/mm/mmap.c b/mm/mmap.c index 6515645d1..86dc9b05e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1385,7 +1385,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, /* Too many mappings? */ #ifdef CONFIG_PID_NS - if (mm->map_count > task_active_pid_ns(current)->max_map_count) + if (mm->map_count > (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count)) #else if (mm->map_count > sysctl_max_map_count) #endif @@ -2642,7 +2644,9 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, int new_below) { #ifdef CONFIG_PID_NS - if (mm->map_count >= task_active_pid_ns(current)->max_map_count) + if (mm->map_count >= (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count)) #else if (mm->map_count >= sysctl_max_map_count) #endif @@ -2697,7 +2701,10 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len, * its limit temporarily, to help free resources as expected. */ #ifdef CONFIG_PID_NS - if (end < vma->vm_end && mm->map_count >= task_active_pid_ns(current)->max_map_count) + if (end < vma->vm_end && mm->map_count >= + (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count)) #else if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count) #endif @@ -2939,7 +2946,9 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla return -ENOMEM; #ifdef CONFIG_PID_NS - if (mm->map_count > task_active_pid_ns(current)->max_map_count) + if (mm->map_count > (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count)) #else if (mm->map_count > sysctl_max_map_count) #endif diff --git a/mm/mremap.c b/mm/mremap.c index ccc0e173a..10701f36f 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -278,7 +278,9 @@ static unsigned long move_vma(struct vm_area_struct *vma, * which may split one vma into three before unmapping. */ #ifdef CONFIG_PID_NS - if (mm->map_count >= task_active_pid_ns(current)->max_map_count - 3) + if (mm->map_count >= (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count) - 3) #else if (mm->map_count >= sysctl_max_map_count - 3) #endif diff --git a/mm/nommu.c b/mm/nommu.c index 33f987f57..6a0ce2075 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1488,7 +1488,9 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, return -ENOMEM; #ifdef CONFIG_PID_NS - if (mm->map_count >= task_active_pid_ns(current)->max_map_count) + if (mm->map_count >= (max_map_count_isolated ? + task_active_pid_ns(current)->max_map_count : + sysctl_max_map_count)) #else if (mm->map_count >= sysctl_max_map_count) #endif diff --git a/mm/util.c b/mm/util.c index 842ba5fb6..dbb7a92bb 100644 --- a/mm/util.c +++ b/mm/util.c @@ -516,6 +516,7 @@ EXPORT_SYMBOL_GPL(__page_mapcount); int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS; int sysctl_overcommit_ratio __read_mostly = 50; unsigned long sysctl_overcommit_kbytes __read_mostly; +int max_map_count_isolated = 1; int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */ unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */