[PATCH v2] prctl: Get private anonymous memory region name

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Rong Tao <rongtao@xxxxxxxx>

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 <rongtao@xxxxxxxx>
---
v2: Simplify code implementation.
v1: https://lore.kernel.org/all/tencent_977CBF8E8CA6234A1B740A35655D5D7EAA0A@xxxxxx/
---
 include/linux/mm.h         |  7 +++++++
 include/uapi/linux/prctl.h |  3 +++
 kernel/sys.c               | 39 ++++++++++++++++++++++++++++++++++++++
 mm/madvise.c               | 15 +++++++++++++++
 4 files changed, 64 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 418d26608ece..f7c242f1bceb 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
+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
+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..b1cbcb276e1a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2359,12 +2359,48 @@ 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;
+	char __user *u_buf;
+	int error;
+
+	switch (opt) {
+	case PR_GET_VMA_ANON_NAME:
+		struct anon_vma_name *anon_name = NULL;
+
+		u_buf = (char __user *)buf;
+		error = 0;
+
+		mmap_read_lock(mm);
+		anon_name = madvise_get_anon_name(mm, addr);
+
+		if (!anon_name || copy_to_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 +2748,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..bad7b4167d2c 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1287,6 +1287,21 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
 	return error;
 }
 
+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 = NULL;
+
+	vma = find_vma(mm, start);
+	if (vma) {
+		anon_name = anon_vma_name(vma);
+		anon_vma_name_get(anon_name);
+	}
+
+	return anon_name;
+}
+
 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





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux