vm:isolate max_map_count by pid namespace

Signed-off-by: Zhiguang Peng <zgpeng@tencent.com>
Signed-off-by: Liu Hua <shookliu@tencent.com>
This commit is contained in:
Liu Hua 2019-02-19 18:51:25 +08:00 committed by Xiaoming Gao
parent a9ab22a3dd
commit ec970f2dff
8 changed files with 54 additions and 3 deletions

View File

@ -53,6 +53,7 @@ struct pid_namespace {
int hide_pid;
int reboot; /* group exit code if this pidns was rebooted */
struct ns_common ns;
int max_map_count;
} __randomize_layout;
extern struct pid_namespace init_pid_ns;

View File

@ -39,6 +39,7 @@
#include <linux/proc_ns.h>
#include <linux/proc_fs.h>
#include <linux/sched/task.h>
#include <linux/sched/sysctl.h>
#define pid_hashfn(nr, ns) \
hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)
@ -78,6 +79,7 @@ struct pid_namespace init_pid_ns = {
.level = 0,
.child_reaper = &init_task,
.user_ns = &init_user_ns,
.max_map_count = DEFAULT_MAX_MAP_COUNT,
.ns.inum = PROC_PID_INIT_INO,
#ifdef CONFIG_PID_NS
.ns.ops = &pidns_operations,

View File

@ -21,6 +21,7 @@
#include <linux/export.h>
#include <linux/sched/task.h>
#include <linux/sched/signal.h>
#include <linux/sched/sysctl.h>
struct pid_cache {
int nr_ids;
@ -136,6 +137,7 @@ 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 = DEFAULT_MAX_MAP_COUNT;
INIT_WORK(&ns->proc_work, proc_cleanup_work);
set_bit(0, ns->pidmap[0].page);

View File

@ -208,6 +208,9 @@ static int proc_taint(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
static int proc_dointvec_max_map_count(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
#ifdef CONFIG_PRINTK
static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
@ -1509,7 +1512,7 @@ static struct ctl_table vm_table[] = {
.data = &sysctl_max_map_count,
.maxlen = sizeof(sysctl_max_map_count),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.proc_handler = proc_dointvec_max_map_count,
.extra1 = &zero,
},
#else
@ -2523,6 +2526,15 @@ int proc_douintvec(struct ctl_table *table, int write,
do_proc_douintvec_conv, NULL);
}
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;
#endif
return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL);
}
/*
* Taint values can only be increased
* This means we can safely use a temporary.

View File

@ -147,7 +147,12 @@ static long madvise_behavior(struct vm_area_struct *vma,
*prev = vma;
if (start != vma->vm_start) {
if (unlikely(mm->map_count >= sysctl_max_map_count)) {
#ifdef CONFIG_PID_NS
if (unlikely(mm->map_count >= task_active_pid_ns(current)->max_map_count))
#else
if (unlikely(mm->map_count >= sysctl_max_map_count))
#endif
{
error = -ENOMEM;
goto out;
}
@ -164,7 +169,12 @@ static long madvise_behavior(struct vm_area_struct *vma,
}
if (end != vma->vm_end) {
if (unlikely(mm->map_count >= sysctl_max_map_count)) {
#ifdef CONFIG_PID_NS
if (unlikely(mm->map_count >= task_active_pid_ns(current)->max_map_count))
#else
if (unlikely(mm->map_count >= sysctl_max_map_count))
#endif
{
error = -ENOMEM;
goto out;
}

View File

@ -1384,7 +1384,11 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
return -EOVERFLOW;
/* Too many mappings? */
#ifdef CONFIG_PID_NS
if (mm->map_count > task_active_pid_ns(current)->max_map_count)
#else
if (mm->map_count > sysctl_max_map_count)
#endif
return -ENOMEM;
/* Obtain the address to map to. we verify (or select) it and ensure
@ -2637,7 +2641,11 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
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)
#else
if (mm->map_count >= sysctl_max_map_count)
#endif
return -ENOMEM;
return __split_vma(mm, vma, addr, new_below);
@ -2688,7 +2696,11 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
* not exceed its limit; but let map_count go just above
* 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)
#else
if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count)
#endif
return -ENOMEM;
error = __split_vma(mm, vma, start, 0);
@ -2926,7 +2938,11 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla
if (!may_expand_vm(mm, flags, len >> PAGE_SHIFT))
return -ENOMEM;
#ifdef CONFIG_PID_NS
if (mm->map_count > task_active_pid_ns(current)->max_map_count)
#else
if (mm->map_count > sysctl_max_map_count)
#endif
return -ENOMEM;
if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))

View File

@ -277,7 +277,11 @@ static unsigned long move_vma(struct vm_area_struct *vma,
* We'd prefer to avoid failure later on in do_munmap:
* 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)
#else
if (mm->map_count >= sysctl_max_map_count - 3)
#endif
return -ENOMEM;
/*

View File

@ -1487,7 +1487,11 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
if (vma->vm_file)
return -ENOMEM;
#ifdef CONFIG_PID_NS
if (mm->map_count >= task_active_pid_ns(current)->max_map_count)
#else
if (mm->map_count >= sysctl_max_map_count)
#endif
return -ENOMEM;
region = kmem_cache_alloc(vm_region_jar, GFP_KERNEL);