Skip to contentSkip to conversation

prctl: Deprecate non PR_SET_MM_MAP operations

PATCH Superseded Cyrill Gorcunov 4 participants 10 messages Apr 4, 2018 – Apr 5, 2018

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 prctl: Deprecate non PR_SET_MM_MAP operations

An ability to manipulate mm_struct fields was introduced in sake of CRIU in first place. Later we provide more suitable and safe operation PR_SET_MM_MAP where all fields to be modifed are passed in one structure which allows us to make more detailed verification.

Still old interface remains present for compatibility reason though CRIU itself already switched to PR_SET_MM_MAP on its own long ago.

Googling didn't reveal some other users of this operation so I think it should be safe to remove this interface.

CC Andrey Vagin <[email protected]>
CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC Michael Kerrisk <[email protected]>
CC Yang Shi <[email protected]>
CC Michal Hocko <[email protected]>
---
 kernel/sys.c |  146 -----------------------------------------------------------
 1 file changed, 2 insertions(+), 144 deletions(-)
kernel/sys.c +2 -144
Index: linux-ml.git/kernel/sys.c
===================================================================
@@ -2001,44 +2001,9 @@ static int prctl_set_mm_map(int opt, con
 }
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 
-static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,
-			  unsigned long len)
-{
-	/*
-	 * This doesn't move the auxiliary vector itself since it's pinned to
-	 * mm_struct, but it permits filling the vector with new values.  It's
-	 * up to the caller to provide sane values here, otherwise userspace
-	 * tools which use this vector might be unhappy.
-	 */
-	unsigned long user_auxv[AT_VECTOR_SIZE];
-
-	if (len > sizeof(user_auxv))
-		return -EINVAL;
-
-	if (copy_from_user(user_auxv, (const void __user *)addr, len))
-		return -EFAULT;
-
-	/* Make sure the last entry is always AT_NULL */
-	user_auxv[AT_VECTOR_SIZE - 2] = 0;
-	user_auxv[AT_VECTOR_SIZE - 1] = 0;
-
-	BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv));
-
-	task_lock(current);
-	memcpy(mm->saved_auxv, user_auxv, len);
-	task_unlock(current);
-
-	return 0;
-}
-
 static int prctl_set_mm(int opt, unsigned long addr,
 			unsigned long arg4, unsigned long arg5)
 {
-	struct mm_struct *mm = current->mm;
-	struct prctl_mm_map prctl_map;
-	struct vm_area_struct *vma;
-	int error;
-
 	if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV &&
 			      opt != PR_SET_MM_MAP &&
 			      opt != PR_SET_MM_MAP_SIZE)))
@@ -2049,115 +2014,8 @@ static int prctl_set_mm(int opt, unsigne
 		return prctl_set_mm_map(opt, (const void __user *)addr, arg4);
 #endif
 
-	if (!capable(CAP_SYS_RESOURCE))
-		return -EPERM;
-
-	if (opt == PR_SET_MM_EXE_FILE)
-		return prctl_set_mm_exe_file(mm, (unsigned int)addr);
-
-	if (opt == PR_SET_MM_AUXV)
-		return prctl_set_auxv(mm, addr, arg4);
-
-	if (addr >= TASK_SIZE || addr < mmap_min_addr)
-		return -EINVAL;
-
-	error = -EINVAL;
-
-	down_write(&mm->mmap_sem);
-	vma = find_vma(mm, addr);
-
-	prctl_map.start_code	= mm->start_code;
-	prctl_map.end_code	= mm->end_code;
-	prctl_map.start_data	= mm->start_data;
-	prctl_map.end_data	= mm->end_data;
-	prctl_map.start_brk	= mm->start_brk;
-	prctl_map.brk		= mm->brk;
-	prctl_map.start_stack	= mm->start_stack;
-	prctl_map.arg_start	= mm->arg_start;
-	prctl_map.arg_end	= mm->arg_end;
-	prctl_map.env_start	= mm->env_start;
-	prctl_map.env_end	= mm->env_end;
-	prctl_map.auxv		= NULL;
-	prctl_map.auxv_size	= 0;
-	prctl_map.exe_fd	= -1;
-
-	switch (opt) {
-	case PR_SET_MM_START_CODE:
-		prctl_map.start_code = addr;
-		break;
-	case PR_SET_MM_END_CODE:
-		prctl_map.end_code = addr;
-		break;
-	case PR_SET_MM_START_DATA:
-		prctl_map.start_data = addr;
-		break;
-	case PR_SET_MM_END_DATA:
-		prctl_map.end_data = addr;
-		break;
-	case PR_SET_MM_START_STACK:
-		prctl_map.start_stack = addr;
-		break;
-	case PR_SET_MM_START_BRK:
-		prctl_map.start_brk = addr;
-		break;
-	case PR_SET_MM_BRK:
-		prctl_map.brk = addr;
-		break;
-	case PR_SET_MM_ARG_START:
-		prctl_map.arg_start = addr;
-		break;
-	case PR_SET_MM_ARG_END:
-		prctl_map.arg_end = addr;
-		break;
-	case PR_SET_MM_ENV_START:
-		prctl_map.env_start = addr;
-		break;
-	case PR_SET_MM_ENV_END:
-		prctl_map.env_end = addr;
-		break;
-	default:
-		goto out;
-	}
-
-	error = validate_prctl_map(&prctl_map);
-	if (error)
-		goto out;
-
-	switch (opt) {
-	/*
-	 * If command line arguments and environment
-	 * are placed somewhere else on stack, we can
-	 * set them up here, ARG_START/END to setup
-	 * command line argumets and ENV_START/END
-	 * for environment.
-	 */
-	case PR_SET_MM_START_STACK:
-	case PR_SET_MM_ARG_START:
-	case PR_SET_MM_ARG_END:
-	case PR_SET_MM_ENV_START:
-	case PR_SET_MM_ENV_END:
-		if (!vma) {
-			error = -EFAULT;
-			goto out;
-		}
-	}
-
-	mm->start_code	= prctl_map.start_code;
-	mm->end_code	= prctl_map.end_code;
-	mm->start_data	= prctl_map.start_data;
-	mm->end_data	= prctl_map.end_data;
-	mm->start_brk	= prctl_map.start_brk;
-	mm->brk		= prctl_map.brk;
-	mm->start_stack	= prctl_map.start_stack;
-	mm->arg_start	= prctl_map.arg_start;
-	mm->arg_end	= prctl_map.arg_end;
-	mm->env_start	= prctl_map.env_start;
-	mm->env_end	= prctl_map.env_end;
-
-	error = 0;
-out:
-	up_write(&mm->mmap_sem);
-	return error;
+	pr_warn_once("Non PR_SET_MM_MAP operations are deprecated\n");
+	return -EINVAL;
 }
 
 #ifdef CONFIG_CHECKPOINT_RESTORE
#1 lore raw

Hi,

kernel/sys.c static int prctl_set_mm(int opt, unsigne · line 2019

Quoted 12 lines · Cyrill Gorcunov
---
 kernel/sys.c |  146 -----------------------------------------------------------
 1 file changed, 2 insertions(+), 144 deletions(-)

Index: linux-ml.git/kernel/sys.c
===================================================================

kernel/sys.c +2 -0
 
+	pr_warn_once("Non PR_SET_MM_MAP operations are deprecated\n");
+	return -EINVAL;
 }

I'm not against removing such functionality, but I think that it's more than "deprecated." It's gone.

Signature · 1 line
~Randy
#2 lore raw
Quoted 7 lines · Randy Dunlap

kernel/sys.c static int prctl_set_mm(int opt, unsigne · line 2019

Quoted 4 lines
kernel/sys.c +2 -0
+	pr_warn_once("Non PR_SET_MM_MAP operations are deprecated\n");
+	return -EINVAL;
 }

I'm not against removing such functionality, but I think that it's more than "deprecated." It's gone.

At first this was plain warning without code removal but I've been advised that dropping it completely may be a better idea which I agree https://lkml.org/lkml/2018/4/4/31 Or you mean the warning message itsef? We aready have similars, for example in kernel/auditfilter.c

printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n");

#3 lore raw
Quoted 9 lines · Cyrill Gorcunov
Quoted 7 lines · Randy Dunlap

kernel/sys.c static int prctl_set_mm(int opt, unsigne · line 2019

Quoted 4 lines
kernel/sys.c +2 -0
+	pr_warn_once("Non PR_SET_MM_MAP operations are deprecated\n");
+	return -EINVAL;
 }

I'm not against removing such functionality, but I think that it's more than "deprecated." It's gone.

Quoted 5 lines

At first this was plain warning without code removal but I've been advised that dropping it completely may be a better idea which I agree https://lkml.org/lkml/2018/4/4/31 Or you mean the warning message itsef? We aready have similars, for example in kernel/auditfilter.c

The traditional way (eons ago) to deprecate something was to add a printk() and then delete the feature a few years later. Still, I have no objection to dropping that prctl.

Sorry if I wasn't clear. I was objecting to the "language", i.e., to the word "deprecated." Deprecated means frowned on, advised against, etc. It does not mean "deleted."

Quoted 1 line

printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n");

Yeah, that one's wrong also. :)

Signature · 1 line
~Randy
#4 lore raw
Quoted 7 lines · Randy Dunlap
Quoted 6 lines

At first this was plain warning without code removal but I've been advised that dropping it completely may be a better idea which I agree https://lkml.org/lkml/2018/4/4/31 Or you mean the warning message itsef? We aready have similars, for example in kernel/auditfilter.c

Quoted 7 lines

The traditional way (eons ago) to deprecate something was to add a printk() and then delete the feature a few years later. Still, I have no objection to dropping that prctl.

Sorry if I wasn't clear. I was objecting to the "language", i.e., to the word "deprecated." Deprecated means frowned on, advised against, etc. It does not mean "deleted."

True. I remember this rule of deprecation. But when I dropped the code I though which message to put here (or should I put it at all) and since "deprecated" was the first word came into mind I decided to grep sources, the result you see by its own :)

Quoted 4 lines
Quoted 2 lines

printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n");

Yeah, that one's wrong also. :)

So, maybe just get rid of any warning message at all?

#5 lore raw
Quoted 22 lines · Cyrill Gorcunov
Quoted 7 lines · Randy Dunlap
Quoted 6 lines

At first this was plain warning without code removal but I've been advised that dropping it completely may be a better idea which I agree https://lkml.org/lkml/2018/4/4/31 Or you mean the warning message itsef? We aready have similars, for example in kernel/auditfilter.c

Quoted 7 lines

The traditional way (eons ago) to deprecate something was to add a printk() and then delete the feature a few years later. Still, I have no objection to dropping that prctl.

Sorry if I wasn't clear. I was objecting to the "language", i.e., to the word "deprecated." Deprecated means frowned on, advised against, etc. It does not mean "deleted."

True. I remember this rule of deprecation. But when I dropped the code I though which message to put here (or should I put it at all) and since "deprecated" was the first word came into mind I decided to grep sources, the result you see by its own :)

Quoted 1 line
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n");

Yeah, that one's wrong also. :)

So, maybe just get rid of any warning message at all?

That would be OK since -EINVAL or something similar is being returned.

Signature · 1 line
~Randy
#6 lore raw
Quoted 4 lines · Randy Dunlap
Quoted 2 lines

So, maybe just get rid of any warning message at all?

That would be OK since -EINVAL or something similar is being returned.

Thanks for feedback! Will do tomorrow and send it out.

#7 lore raw
In reply to Cyrill Gorcunov
Quoted 1 line · Cyrill Gorcunov

On Wed, Apr 04, 2018 at 01:53:08PM -0700, Randy Dunlap wrote:

[...]

Quoted 3 lines
Quoted 1 line

Yeah, that one's wrong also. :)

So, maybe just get rid of any warning message at all?

or simply do

	pr_warn("PR_SET_MM_MAP has been removed. Use <ALTERNATIVE> instead\n");
Signature · 2 lines
Michal Hocko
SUSE Labs
#8 lore raw
In reply to Cyrill Gorcunov
Quoted 61 lines · Cyrill Gorcunov

An ability to manipulate mm_struct fields was introduced in sake of CRIU in first place. Later we provide more suitable and safe operation PR_SET_MM_MAP where all fields to be modifed are passed in one structure which allows us to make more detailed verification.

Still old interface remains present for compatibility reason though CRIU itself already switched to PR_SET_MM_MAP on its own long ago.

Googling didn't reveal some other users of this operation so I think it should be safe to remove this interface.

CC Andrey Vagin <[email protected]>
CC Andrew Morton <[email protected]>
CC Pavel Emelyanov <[email protected]>
CC Michael Kerrisk <[email protected]>
CC Yang Shi <[email protected]>
CC Michal Hocko <[email protected]>
---
  kernel/sys.c |  146 -----------------------------------------------------------
  1 file changed, 2 insertions(+), 144 deletions(-)

Index: linux-ml.git/kernel/sys.c
===================================================================

kernel/sys.c +0 -29
@@ -2001,44 +2001,9 @@ static int prctl_set_mm_map(int opt, con
  }
  #endif /* CONFIG_CHECKPOINT_RESTORE */
 
-static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,
-			  unsigned long len)
-{
-	/*
-	 * This doesn't move the auxiliary vector itself since it's pinned to
-	 * mm_struct, but it permits filling the vector with new values.  It's
-	 * up to the caller to provide sane values here, otherwise userspace
-	 * tools which use this vector might be unhappy.
-	 */
-	unsigned long user_auxv[AT_VECTOR_SIZE];
-
-	if (len > sizeof(user_auxv))
-		return -EINVAL;
-
-	if (copy_from_user(user_auxv, (const void __user *)addr, len))
-		return -EFAULT;
-
-	/* Make sure the last entry is always AT_NULL */
-	user_auxv[AT_VECTOR_SIZE - 2] = 0;
-	user_auxv[AT_VECTOR_SIZE - 1] = 0;
-
-	BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv));
-
-	task_lock(current);
-	memcpy(mm->saved_auxv, user_auxv, len);
-	task_unlock(current);
-
-	return 0;
-}

kernel/sys.c static int prctl_set_mm_map(int opt, con · line 2007

Quoted 10 lines
kernel/sys.c +0 -6
-
  static int prctl_set_mm(int opt, unsigned long addr,
  			unsigned long arg4, unsigned long arg5)
  {
-	struct mm_struct *mm = current->mm;
-	struct prctl_mm_map prctl_map;
-	struct vm_area_struct *vma;
-	int error;
-
  	if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV &&

This PR_SET_MM_AUXV should be removed too? There is not callsite to prctl_set_auxv() anymore.

Thanks,
Yang

Quoted 120 lines
kernel/sys.c +2 -109
  			      opt != PR_SET_MM_MAP &&
  			      opt != PR_SET_MM_MAP_SIZE)))
@@ -2049,115 +2014,8 @@ static int prctl_set_mm(int opt, unsigne
  		return prctl_set_mm_map(opt, (const void __user *)addr, arg4);
  #endif
 
-	if (!capable(CAP_SYS_RESOURCE))
-		return -EPERM;
-
-	if (opt == PR_SET_MM_EXE_FILE)
-		return prctl_set_mm_exe_file(mm, (unsigned int)addr);
-
-	if (opt == PR_SET_MM_AUXV)
-		return prctl_set_auxv(mm, addr, arg4);
-
-	if (addr >= TASK_SIZE || addr < mmap_min_addr)
-		return -EINVAL;
-
-	error = -EINVAL;
-
-	down_write(&mm->mmap_sem);
-	vma = find_vma(mm, addr);
-
-	prctl_map.start_code	= mm->start_code;
-	prctl_map.end_code	= mm->end_code;
-	prctl_map.start_data	= mm->start_data;
-	prctl_map.end_data	= mm->end_data;
-	prctl_map.start_brk	= mm->start_brk;
-	prctl_map.brk		= mm->brk;
-	prctl_map.start_stack	= mm->start_stack;
-	prctl_map.arg_start	= mm->arg_start;
-	prctl_map.arg_end	= mm->arg_end;
-	prctl_map.env_start	= mm->env_start;
-	prctl_map.env_end	= mm->env_end;
-	prctl_map.auxv		= NULL;
-	prctl_map.auxv_size	= 0;
-	prctl_map.exe_fd	= -1;
-
-	switch (opt) {
-	case PR_SET_MM_START_CODE:
-		prctl_map.start_code = addr;
-		break;
-	case PR_SET_MM_END_CODE:
-		prctl_map.end_code = addr;
-		break;
-	case PR_SET_MM_START_DATA:
-		prctl_map.start_data = addr;
-		break;
-	case PR_SET_MM_END_DATA:
-		prctl_map.end_data = addr;
-		break;
-	case PR_SET_MM_START_STACK:
-		prctl_map.start_stack = addr;
-		break;
-	case PR_SET_MM_START_BRK:
-		prctl_map.start_brk = addr;
-		break;
-	case PR_SET_MM_BRK:
-		prctl_map.brk = addr;
-		break;
-	case PR_SET_MM_ARG_START:
-		prctl_map.arg_start = addr;
-		break;
-	case PR_SET_MM_ARG_END:
-		prctl_map.arg_end = addr;
-		break;
-	case PR_SET_MM_ENV_START:
-		prctl_map.env_start = addr;
-		break;
-	case PR_SET_MM_ENV_END:
-		prctl_map.env_end = addr;
-		break;
-	default:
-		goto out;
-	}
-
-	error = validate_prctl_map(&prctl_map);
-	if (error)
-		goto out;
-
-	switch (opt) {
-	/*
-	 * If command line arguments and environment
-	 * are placed somewhere else on stack, we can
-	 * set them up here, ARG_START/END to setup
-	 * command line argumets and ENV_START/END
-	 * for environment.
-	 */
-	case PR_SET_MM_START_STACK:
-	case PR_SET_MM_ARG_START:
-	case PR_SET_MM_ARG_END:
-	case PR_SET_MM_ENV_START:
-	case PR_SET_MM_ENV_END:
-		if (!vma) {
-			error = -EFAULT;
-			goto out;
-		}
-	}
-
-	mm->start_code	= prctl_map.start_code;
-	mm->end_code	= prctl_map.end_code;
-	mm->start_data	= prctl_map.start_data;
-	mm->end_data	= prctl_map.end_data;
-	mm->start_brk	= prctl_map.start_brk;
-	mm->brk		= prctl_map.brk;
-	mm->start_stack	= prctl_map.start_stack;
-	mm->arg_start	= prctl_map.arg_start;
-	mm->arg_end	= prctl_map.arg_end;
-	mm->env_start	= prctl_map.env_start;
-	mm->env_end	= prctl_map.env_end;
-
-	error = 0;
-out:
-	up_write(&mm->mmap_sem);
-	return error;
+	pr_warn_once("Non PR_SET_MM_MAP operations are deprecated\n");
+	return -EINVAL;
  }
 
  #ifdef CONFIG_CHECKPOINT_RESTORE
#9 lore raw
Quoted 7 lines · Yang Shi
Quoted 6 lines · Cyrill Gorcunov

An ability to manipulate mm_struct fields was introduced in sake of CRIU in first place. Later we provide more suitable and safe operation PR_SET_MM_MAP where all fields to be modifed are passed in one structure which allows us to make more detailed verification.

Quoted 5 lines
Quoted 2 lines

-
if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV &&

This PR_SET_MM_AUXV should be removed too? There is not callsite to prctl_set_auxv() anymore.

Yeah, good point. Will update.