2023-11-25 14:04:53

by Rong Tao

[permalink] [raw]
Subject: [PATCH] prctl: Get private anonymous memory region name

From: Rong Tao <[email protected]>

In commit 9a10064f5625 ("mm: add a field to store names for private anony-
mous memory") add PR_SET_VMA options and PR_SET_VMA_ANON_NAME for the prctl
system call, then the PR_GET_VMA interface should be provided accordingly,
which is necessary, as the userspace program usually wants to know what
VMA name it has configured for the anonymous page.

Userspace can set the name for a region of memory by calling:

prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, start, len, (unsigned long)name);

Then, Userspace can get the name of a memory region by calling:

char buf[80];
prctl(PR_GET_VMA, PR_GET_VMA_ANON_NAME, start, buf, 0);

Changes for prctl(2) manual page (in the options section):

PR_GET_VMA
Gets an attribute specified in arg2 for virtual memory areas
starting from the address specified in arg3 and spanning the
size specified in arg4. arg5 specifies the value of the attribute
to be set.

Currently, arg2 must be one of:

PR_GET_VMA_ANON_NAME
Get name of anonymous virtual memory areas. arg4 should be
a buffer in the user's program, and the size of the buffer
should not be less than 80 bytes, otherwise it is possible
that the prctl return will fail due to a copy failure
(unless you know the length of the name you set through
the PR_SET_VMA_ANON_NAME).

This feature is available only if the kernel is built with
the CONFIG_ANON_VMA_NAME option enabled.

Signed-off-by: Rong Tao <[email protected]>
---
include/linux/mm.h | 7 ++++++
include/uapi/linux/prctl.h | 3 +++
kernel/sys.c | 44 ++++++++++++++++++++++++++++++++++++++
mm/madvise.c | 18 ++++++++++++++++
4 files changed, 72 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 418d26608ece..2981c94c52f8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -4106,6 +4106,8 @@ static inline int seal_check_write(int seals, struct vm_area_struct *vma)
}

#ifdef CONFIG_ANON_VMA_NAME
+const struct anon_vma_name *madvise_get_anon_name(struct mm_struct *mm,
+ unsigned long start);
int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
unsigned long len_in,
struct anon_vma_name *anon_name);
@@ -4115,6 +4117,11 @@ madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
unsigned long len_in, struct anon_vma_name *anon_name) {
return 0;
}
+static inline
+const struct anon_vma_name *madvise_get_anon_name(struct mm_struct *mm,
+ unsigned long start) {
+ return NULL;
+}
#endif

#ifdef CONFIG_UNACCEPTED_MEMORY
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 370ed14b1ae0..8ba0016d77de 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -291,6 +291,9 @@ struct prctl_mm_map {
#define PR_SET_VMA 0x53564d41
# define PR_SET_VMA_ANON_NAME 0

+#define PR_GET_VMA 0x53564d42
+# define PR_GET_VMA_ANON_NAME 0
+
#define PR_GET_AUXV 0x41555856

#define PR_SET_MEMORY_MERGE 67
diff --git a/kernel/sys.c b/kernel/sys.c
index e219fcfa112d..f11eadd666d0 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2359,12 +2359,53 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
return error;
}

+static int prctl_get_vma(unsigned long opt, unsigned long addr,
+ unsigned long buf, unsigned long arg)
+{
+ struct mm_struct *mm = current->mm;
+ const char __user *u_buf;
+ int error;
+
+ switch (opt) {
+ case PR_GET_VMA_ANON_NAME:
+ const struct anon_vma_name *anon_name = NULL;
+
+ u_buf = (const char __user *)buf;
+ error = 0;
+
+ mmap_read_lock(mm);
+ anon_name = madvise_get_anon_name(mm, addr);
+ if (!anon_name) {
+ mmap_read_unlock(mm);
+ error = -EFAULT;
+ break;
+ }
+
+ if (copy_to_user((char __user *)u_buf, anon_name->name,
+ strlen(anon_name->name) + 1))
+ error = -EFAULT;
+
+ mmap_read_unlock(mm);
+ anon_vma_name_put(anon_name);
+ break;
+ default:
+ error = -EINVAL;
+ }
+ return error;
+}
+
#else /* CONFIG_ANON_VMA_NAME */
static int prctl_set_vma(unsigned long opt, unsigned long start,
unsigned long size, unsigned long arg)
{
return -EINVAL;
}
+
+static int prctl_get_vma(unsigned long opt, unsigned long start,
+ unsigned long u_buf, unsigned long arg)
+{
+ return -EINVAL;
+}
#endif /* CONFIG_ANON_VMA_NAME */

static inline unsigned long get_current_mdwe(void)
@@ -2712,6 +2753,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;
+ case PR_GET_VMA:
+ error = prctl_get_vma(arg2, arg3, arg4, arg5);
+ break;
case PR_GET_AUXV:
if (arg4 || arg5)
return -EINVAL;
diff --git a/mm/madvise.c b/mm/madvise.c
index cf4d694280e9..a68f7a7d6389 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1287,6 +1287,24 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
return error;
}

+const struct anon_vma_name *madvise_get_anon_name(struct mm_struct *mm,
+ unsigned long start)
+{
+ struct vm_area_struct *vma;
+ struct anon_vma_name *anon_name;
+
+ vma = find_vma(mm, start);
+ if (vma) {
+ anon_name = anon_vma_name(vma);
+ if (anon_name) {
+ anon_vma_name_get(anon_name);
+ return anon_name;
+ }
+ }
+
+ return NULL;
+}
+
int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
unsigned long len_in, struct anon_vma_name *anon_name)
{
--
2.43.0


2023-11-25 15:58:20

by Oleg Nesterov

[permalink] [raw]
Subject: Re: [PATCH] prctl: Get private anonymous memory region name

On 11/25, Rong Tao wrote:
>
> +static int prctl_get_vma(unsigned long opt, unsigned long addr,
> + unsigned long buf, unsigned long arg)
> +{
> + struct mm_struct *mm = current->mm;
> + const char __user *u_buf;
> + int error;
> +
> + switch (opt) {
> + case PR_GET_VMA_ANON_NAME:
> + const struct anon_vma_name *anon_name = NULL;
> +
> + u_buf = (const char __user *)buf;
> + error = 0;
> +
> + mmap_read_lock(mm);
> + anon_name = madvise_get_anon_name(mm, addr);
> + if (!anon_name) {
> + mmap_read_unlock(mm);
> + error = -EFAULT;

may be another error code makes sense to distinguish this case from
the copy_to_user() failure?

> + break;
> + }
> +
> + if (copy_to_user((char __user *)u_buf, anon_name->name,
> + strlen(anon_name->name) + 1))
> + error = -EFAULT;

and I guess you can simplify this code a bit,

anon_name = madvise_get_anon_name(...);
if (!anon_name || copy_to_user(...))
error = -EFAULT;

mmap_read_unlock(mm);
anon_vma_name_put(anon_name); // safe if anon_name == NULL;

> +const struct anon_vma_name *madvise_get_anon_name(struct mm_struct *mm,
> + unsigned long start)
> +{
> + struct vm_area_struct *vma;
> + struct anon_vma_name *anon_name;
> +
> + vma = find_vma(mm, start);
> + if (vma) {
> + anon_name = anon_vma_name(vma);
> + if (anon_name) {
> + anon_vma_name_get(anon_name);
> + return anon_name;
> + }
> + }
> +
> + return NULL;

Again, afaics this can be simplified,

struct anon_vma_name *anon_name = NULL;

vma = find_vma(mm, start);
if (vma) {
anon_name = anon_vma_name(vma);
anon_vma_name_get(anon_name);
}

return anon_name;

Oleg.

2023-11-25 20:01:25

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] prctl: Get private anonymous memory region name

Hi Rong,

kernel test robot noticed the following build warnings:

[auto build test WARNING on akpm-mm/mm-everything]
[also build test WARNING on linus/master v6.7-rc2 next-20231124]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Rong-Tao/prctl-Get-private-anonymous-memory-region-name/20231125-220925
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/tencent_977CBF8E8CA6234A1B740A35655D5D7EAA0A%40qq.com
patch subject: [PATCH] prctl: Get private anonymous memory region name
config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20231126/[email protected]/config)
compiler: s390-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231126/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All warnings (new ones prefixed by >>):

kernel/sys.c: In function 'prctl_get_vma':
>> kernel/sys.c:2389:35: warning: passing argument 1 of 'anon_vma_name_put' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
2389 | anon_vma_name_put(anon_name);
| ^~~~~~~~~
In file included from kernel/sys.c:10:
include/linux/mm_inline.h:363:60: note: expected 'struct anon_vma_name *' but argument is of type 'const struct anon_vma_name *'
363 | static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~


vim +2389 kernel/sys.c

2361
2362 static int prctl_get_vma(unsigned long opt, unsigned long addr,
2363 unsigned long buf, unsigned long arg)
2364 {
2365 struct mm_struct *mm = current->mm;
2366 const char __user *u_buf;
2367 int error;
2368
2369 switch (opt) {
2370 case PR_GET_VMA_ANON_NAME:
2371 const struct anon_vma_name *anon_name = NULL;
2372
2373 u_buf = (const char __user *)buf;
2374 error = 0;
2375
2376 mmap_read_lock(mm);
2377 anon_name = madvise_get_anon_name(mm, addr);
2378 if (!anon_name) {
2379 mmap_read_unlock(mm);
2380 error = -EFAULT;
2381 break;
2382 }
2383
2384 if (copy_to_user((char __user *)u_buf, anon_name->name,
2385 strlen(anon_name->name) + 1))
2386 error = -EFAULT;
2387
2388 mmap_read_unlock(mm);
> 2389 anon_vma_name_put(anon_name);
2390 break;
2391 default:
2392 error = -EINVAL;
2393 }
2394 return error;
2395 }
2396

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-11-25 20:01:43

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] prctl: Get private anonymous memory region name

Hi Rong,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on linus/master v6.7-rc2 next-20231124]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Rong-Tao/prctl-Get-private-anonymous-memory-region-name/20231125-220925
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/tencent_977CBF8E8CA6234A1B740A35655D5D7EAA0A%40qq.com
patch subject: [PATCH] prctl: Get private anonymous memory region name
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20231126/[email protected]/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231126/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> kernel/sys.c:2371:3: error: expected expression
const struct anon_vma_name *anon_name = NULL;
^
>> kernel/sys.c:2377:3: error: use of undeclared identifier 'anon_name'
anon_name = madvise_get_anon_name(mm, addr);
^
kernel/sys.c:2378:8: error: use of undeclared identifier 'anon_name'
if (!anon_name) {
^
kernel/sys.c:2385:13: error: use of undeclared identifier 'anon_name'
strlen(anon_name->name) + 1))
^
kernel/sys.c:2384:42: error: use of undeclared identifier 'anon_name'
if (copy_to_user((char __user *)u_buf, anon_name->name,
^
kernel/sys.c:2389:21: error: use of undeclared identifier 'anon_name'
anon_vma_name_put(anon_name);
^
6 errors generated.


vim +2371 kernel/sys.c

2361
2362 static int prctl_get_vma(unsigned long opt, unsigned long addr,
2363 unsigned long buf, unsigned long arg)
2364 {
2365 struct mm_struct *mm = current->mm;
2366 const char __user *u_buf;
2367 int error;
2368
2369 switch (opt) {
2370 case PR_GET_VMA_ANON_NAME:
> 2371 const struct anon_vma_name *anon_name = NULL;
2372
2373 u_buf = (const char __user *)buf;
2374 error = 0;
2375
2376 mmap_read_lock(mm);
> 2377 anon_name = madvise_get_anon_name(mm, addr);
2378 if (!anon_name) {
2379 mmap_read_unlock(mm);
2380 error = -EFAULT;
2381 break;
2382 }
2383
2384 if (copy_to_user((char __user *)u_buf, anon_name->name,
2385 strlen(anon_name->name) + 1))
2386 error = -EFAULT;
2387
2388 mmap_read_unlock(mm);
2389 anon_vma_name_put(anon_name);
2390 break;
2391 default:
2392 error = -EINVAL;
2393 }
2394 return error;
2395 }
2396

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-11-25 22:27:28

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] prctl: Get private anonymous memory region name

Hi Rong,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on linus/master v6.7-rc2 next-20231124]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Rong-Tao/prctl-Get-private-anonymous-memory-region-name/20231125-220925
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/tencent_977CBF8E8CA6234A1B740A35655D5D7EAA0A%40qq.com
patch subject: [PATCH] prctl: Get private anonymous memory region name
config: x86_64-randconfig-122-20231126 (https://download.01.org/0day-ci/archive/20231126/[email protected]/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231126/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

kernel/sys.c: In function 'prctl_get_vma':
>> kernel/sys.c:2371:3: error: a label can only be part of a statement and a declaration is not a statement
2371 | const struct anon_vma_name *anon_name = NULL;
| ^~~~~
kernel/sys.c:2389:21: warning: passing argument 1 of 'anon_vma_name_put' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
2389 | anon_vma_name_put(anon_name);
| ^~~~~~~~~
In file included from kernel/sys.c:10:
include/linux/mm_inline.h:363:60: note: expected 'struct anon_vma_name *' but argument is of type 'const struct anon_vma_name *'
363 | static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~


vim +2371 kernel/sys.c

2361
2362 static int prctl_get_vma(unsigned long opt, unsigned long addr,
2363 unsigned long buf, unsigned long arg)
2364 {
2365 struct mm_struct *mm = current->mm;
2366 const char __user *u_buf;
2367 int error;
2368
2369 switch (opt) {
2370 case PR_GET_VMA_ANON_NAME:
> 2371 const struct anon_vma_name *anon_name = NULL;
2372
2373 u_buf = (const char __user *)buf;
2374 error = 0;
2375
2376 mmap_read_lock(mm);
2377 anon_name = madvise_get_anon_name(mm, addr);
2378 if (!anon_name) {
2379 mmap_read_unlock(mm);
2380 error = -EFAULT;
2381 break;
2382 }
2383
2384 if (copy_to_user((char __user *)u_buf, anon_name->name,
2385 strlen(anon_name->name) + 1))
2386 error = -EFAULT;
2387
2388 mmap_read_unlock(mm);
2389 anon_vma_name_put(anon_name);
2390 break;
2391 default:
2392 error = -EINVAL;
2393 }
2394 return error;
2395 }
2396

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-11-26 03:09:20

by Rong Tao

[permalink] [raw]
Subject: Re: [PATCH] prctl: Get private anonymous memory region name


On 11/25/23 23:56, Oleg Nesterov wrote:
> On 11/25, Rong Tao wrote:
>> +static int prctl_get_vma(unsigned long opt, unsigned long addr,
>> + unsigned long buf, unsigned long arg)
>> +{
>> + struct mm_struct *mm = current->mm;
>> + const char __user *u_buf;
>> + int error;
>> +
>> + switch (opt) {
>> + case PR_GET_VMA_ANON_NAME:
>> + const struct anon_vma_name *anon_name = NULL;
>> +
>> + u_buf = (const char __user *)buf;
>> + error = 0;
>> +
>> + mmap_read_lock(mm);
>> + anon_name = madvise_get_anon_name(mm, addr);
>> + if (!anon_name) {
>> + mmap_read_unlock(mm);
>> + error = -EFAULT;
> may be another error code makes sense to distinguish this case from
> the copy_to_user() failure?
>
>> + break;
>> + }
>> +
>> + if (copy_to_user((char __user *)u_buf, anon_name->name,
>> + strlen(anon_name->name) + 1))
>> + error = -EFAULT;
> and I guess you can simplify this code a bit,
>
> anon_name = madvise_get_anon_name(...);
> if (!anon_name || copy_to_user(...))
> error = -EFAULT;
Thanks a lot, I just modify the code, please review.
>
> mmap_read_unlock(mm);
> anon_vma_name_put(anon_name); // safe if anon_name == NULL;
>
>> +const struct anon_vma_name *madvise_get_anon_name(struct mm_struct *mm,
>> + unsigned long start)
>> +{
>> + struct vm_area_struct *vma;
>> + struct anon_vma_name *anon_name;
>> +
>> + vma = find_vma(mm, start);
>> + if (vma) {
>> + anon_name = anon_vma_name(vma);
>> + if (anon_name) {
>> + anon_vma_name_get(anon_name);
>> + return anon_name;
>> + }
>> + }
>> +
>> + return NULL;
> Again, afaics this can be simplified,
>
> struct anon_vma_name *anon_name = NULL;
>
> vma = find_vma(mm, start);
> if (vma) {
> anon_name = anon_vma_name(vma);
> anon_vma_name_get(anon_name);
> }
>
> return anon_name;
>
> Oleg.
Thanks again.

Rong Tao

>