diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 10 | 
1 files changed, 8 insertions, 2 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index d1b2b8d934bb..38509dc1f77b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2018,7 +2018,11 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data  			return error;  	} -	down_write(&mm->mmap_sem); +	/* +	 * arg_lock protects concurent updates but we still need mmap_sem for +	 * read to exclude races with sys_brk. +	 */ +	down_read(&mm->mmap_sem);  	/*  	 * We don't validate if these members are pointing to @@ -2032,6 +2036,7 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data  	 *    to any problem in kernel itself  	 */ +	spin_lock(&mm->arg_lock);  	mm->start_code	= prctl_map.start_code;  	mm->end_code	= prctl_map.end_code;  	mm->start_data	= prctl_map.start_data; @@ -2043,6 +2048,7 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data  	mm->arg_end	= prctl_map.arg_end;  	mm->env_start	= prctl_map.env_start;  	mm->env_end	= prctl_map.env_end; +	spin_unlock(&mm->arg_lock);  	/*  	 * Note this update of @saved_auxv is lockless thus @@ -2055,7 +2061,7 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data  	if (prctl_map.auxv_size)  		memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); -	up_write(&mm->mmap_sem); +	up_read(&mm->mmap_sem);  	return 0;  }  #endif /* CONFIG_CHECKPOINT_RESTORE */  |