Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1381720 > unrolled thread
| Started by | Dmitry Safonov <dsafonov@virtuozzo.com> |
|---|---|
| First post | 2016-04-18 15:50 +0200 |
| Last post | 2016-04-24 01:20 +0200 |
| Articles | 7 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCHv5 2/3] x86/vdso: add mremap hook to vm_special_mapping Dmitry Safonov <dsafonov@virtuozzo.com> - 2016-04-18 15:50 +0200
Re: [PATCHv5 2/3] x86/vdso: add mremap hook to vm_special_mapping kbuild test robot <lkp@intel.com> - 2016-04-18 16:10 +0200
[PATCHv6 2/3] x86/vdso: add mremap hook to vm_special_mapping Dmitry Safonov <dsafonov@virtuozzo.com> - 2016-04-18 16:20 +0200
[PATCHv7 2/3] x86/vdso: add mremap hook to vm_special_mapping Dmitry Safonov <dsafonov@virtuozzo.com> - 2016-04-18 16:30 +0200
Re: [PATCHv7 2/3] x86/vdso: add mremap hook to vm_special_mapping Dmitry Safonov <dsafonov@virtuozzo.com> - 2016-04-20 18:40 +0200
Re: [PATCHv7 2/3] x86/vdso: add mremap hook to vm_special_mapping Andy Lutomirski <luto@amacapital.net> - 2016-04-21 22:00 +0200
Re: [PATCHv5 2/3] x86/vdso: add mremap hook to vm_special_mapping kbuild test robot <lkp@intel.com> - 2016-04-24 01:20 +0200
| From | Dmitry Safonov <dsafonov@virtuozzo.com> |
|---|---|
| Date | 2016-04-18 15:50 +0200 |
| Subject | [PATCHv5 2/3] x86/vdso: add mremap hook to vm_special_mapping |
| Message-ID | <rphIT-6ug-31@gated-at.bofh.it> |
Add possibility for userspace 32-bit applications to move
vdso mapping. Previously, when userspace app called
mremap for vdso, in return path it would land on previous
address of vdso page, resulting in segmentation violation.
Now it lands fine and returns to userspace with remapped vdso.
This will also fix context.vdso pointer for 64-bit, which does not
affect the user of vdso after mremap by now, but this may change.
As suggested by Andy, return EINVAL for mremap that splits vdso image.
Renamed and moved text_mapping structure declaration inside
map_vdso, as it used only there and now it complement
vvar_mapping variable.
There is still problem for remapping vdso in glibc applications:
linker relocates addresses for syscalls on vdso page, so
you need to relink with the new addresses. Or the next syscall
through glibc may fail:
Program received signal SIGSEGV, Segmentation fault.
#0 0xf7fd9b80 in __kernel_vsyscall ()
#1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
v5: as Andy suggested, add a check that new_vma->vm_mm and current->mm are
the same, also check not only in_ia32_syscall() but image == &vdso_image_32
v4: drop __maybe_unused & use image from mm->context instead vdso_image_32
v3: as Andy suggested, return EINVAL in case of splitting vdso blob on mremap;
used is_ia32_task instead of ifdefs
v2: added __maybe_unused for pt_regs in vdso_mremap
arch/x86/entry/vdso/vma.c | 39 ++++++++++++++++++++++++++++++++++-----
include/linux/mm_types.h | 3 +++
mm/mmap.c | 10 ++++++++++
3 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 10f704584922..ba133a9ab4f5 100644
--- a/arch/x86/entry/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
@@ -12,6 +12,7 @@
#include <linux/random.h>
#include <linux/elf.h>
#include <linux/cpu.h>
+#include <linux/ptrace.h>
#include <asm/pvclock.h>
#include <asm/vgtod.h>
#include <asm/proto.h>
@@ -98,10 +99,32 @@ static int vdso_fault(const struct vm_special_mapping *sm,
return 0;
}
-static const struct vm_special_mapping text_mapping = {
- .name = "[vdso]",
- .fault = vdso_fault,
-};
+static int vdso_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma)
+{
+ unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
+ const struct vdso_image *image = current->mm->context.vdso_image;
+
+ if (image->size != new_size)
+ return -EINVAL;
+
+ if (current->mm != new_vma->vm_mm)
+ return -EFAULT;
+
+ if (in_ia32_syscall() && image == &vdso_image_32) {
+ struct pt_regs *regs = current_pt_regs();
+ unsigned long vdso_land = image->sym_int80_landing_pad;
+ unsigned long old_land_addr = vdso_land +
+ (unsigned long)current->mm->context.vdso;
+
+ /* Fixing userspace landing - look at do_fast_syscall_32 */
+ if (regs->ip == old_land_addr)
+ regs->ip = new_vma->vm_start + vdso_land;
+ }
+ current->mm->context.vdso = (void __user *)new_vma->vm_start;
+
+ return 0;
+}
static int vvar_fault(const struct vm_special_mapping *sm,
struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -162,6 +185,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
struct vm_area_struct *vma;
unsigned long addr, text_start;
int ret = 0;
+
+ static const struct vm_special_mapping vdso_mapping = {
+ .name = "[vdso]",
+ .fault = vdso_fault,
+ .mremap = vdso_mremap,
+ };
static const struct vm_special_mapping vvar_mapping = {
.name = "[vvar]",
.fault = vvar_fault,
@@ -195,7 +224,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
image->size,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- &text_mapping);
+ &vdso_mapping);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index c2d75b4fa86c..4d16ab9287af 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -586,6 +586,9 @@ struct vm_special_mapping {
int (*fault)(const struct vm_special_mapping *sm,
struct vm_area_struct *vma,
struct vm_fault *vmf);
+
+ int (*mremap)(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma);
};
enum tlb_flush_reason {
diff --git a/mm/mmap.c b/mm/mmap.c
index bd2e1a533bc1..ba71658dd1a1 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2930,9 +2930,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma)
return ((struct vm_special_mapping *)vma->vm_private_data)->name;
}
+static int special_mapping_mremap(struct vm_area_struct *new_vma)
+{
+ struct vm_special_mapping *sm = new_vma->vm_private_data;
+
+ if (sm->mremap)
+ return sm->mremap(sm, new_vma);
+ return 0;
+}
+
static const struct vm_operations_struct special_mapping_vmops = {
.close = special_mapping_close,
.fault = special_mapping_fault,
+ .mremap = special_mapping_mremap,
.name = special_mapping_name,
};
--
2.8.0
[toc] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2016-04-18 16:10 +0200 |
| Message-ID | <rpi2e-6VB-35@gated-at.bofh.it> |
| In reply to | #1381720 |
[Multipart message — attachments visible in raw view] — view raw
Hi Dmitry,
[auto build test WARNING on v4.6-rc4]
[also build test WARNING on next-20160418]
[cannot apply to tip/x86/core tip/x86/vdso]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Dmitry-Safonov/x86-rename-is_-ia32-x32-_task-to-in_-ia32-x32-_syscall/20160418-214656
config: x86_64-randconfig-x000-201616 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All warnings (new ones prefixed by >>):
In file included from include/asm-generic/bug.h:4:0,
from arch/x86/include/asm/bug.h:35,
from include/linux/bug.h:4,
from include/linux/mmdebug.h:4,
from include/linux/mm.h:8,
from arch/x86/entry/vdso/vma.c:7:
arch/x86/entry/vdso/vma.c: In function 'vdso_mremap':
arch/x86/entry/vdso/vma.c:114:37: error: 'vdso_image_32' undeclared (first use in this function)
if (in_ia32_syscall() && image == &vdso_image_32) {
^
include/linux/compiler.h:151:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^
>> arch/x86/entry/vdso/vma.c:114:2: note: in expansion of macro 'if'
if (in_ia32_syscall() && image == &vdso_image_32) {
^
arch/x86/entry/vdso/vma.c:114:37: note: each undeclared identifier is reported only once for each function it appears in
if (in_ia32_syscall() && image == &vdso_image_32) {
^
include/linux/compiler.h:151:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^
>> arch/x86/entry/vdso/vma.c:114:2: note: in expansion of macro 'if'
if (in_ia32_syscall() && image == &vdso_image_32) {
^
vim +/if +114 arch/x86/entry/vdso/vma.c
1 /*
2 * Copyright 2007 Andi Kleen, SUSE Labs.
3 * Subject to the GPL, v.2
4 *
5 * This contains most of the x86 vDSO kernel-side code.
6 */
> 7 #include <linux/mm.h>
8 #include <linux/err.h>
9 #include <linux/sched.h>
10 #include <linux/slab.h>
11 #include <linux/init.h>
12 #include <linux/random.h>
13 #include <linux/elf.h>
14 #include <linux/cpu.h>
15 #include <linux/ptrace.h>
16 #include <asm/pvclock.h>
17 #include <asm/vgtod.h>
18 #include <asm/proto.h>
19 #include <asm/vdso.h>
20 #include <asm/vvar.h>
21 #include <asm/page.h>
22 #include <asm/hpet.h>
23 #include <asm/desc.h>
24 #include <asm/cpufeature.h>
25
26 #if defined(CONFIG_X86_64)
27 unsigned int __read_mostly vdso64_enabled = 1;
28 #endif
29
30 void __init init_vdso_image(const struct vdso_image *image)
31 {
32 BUG_ON(image->size % PAGE_SIZE != 0);
33
34 apply_alternatives((struct alt_instr *)(image->data + image->alt),
35 (struct alt_instr *)(image->data + image->alt +
36 image->alt_len));
37 }
38
39 struct linux_binprm;
40
41 /*
42 * Put the vdso above the (randomized) stack with another randomized
43 * offset. This way there is no hole in the middle of address space.
44 * To save memory make sure it is still in the same PTE as the stack
45 * top. This doesn't give that many random bits.
46 *
47 * Note that this algorithm is imperfect: the distribution of the vdso
48 * start address within a PMD is biased toward the end.
49 *
50 * Only used for the 64-bit and x32 vdsos.
51 */
52 static unsigned long vdso_addr(unsigned long start, unsigned len)
53 {
54 #ifdef CONFIG_X86_32
55 return 0;
56 #else
57 unsigned long addr, end;
58 unsigned offset;
59
60 /*
61 * Round up the start address. It can start out unaligned as a result
62 * of stack start randomization.
63 */
64 start = PAGE_ALIGN(start);
65
66 /* Round the lowest possible end address up to a PMD boundary. */
67 end = (start + len + PMD_SIZE - 1) & PMD_MASK;
68 if (end >= TASK_SIZE_MAX)
69 end = TASK_SIZE_MAX;
70 end -= len;
71
72 if (end > start) {
73 offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
74 addr = start + (offset << PAGE_SHIFT);
75 } else {
76 addr = start;
77 }
78
79 /*
80 * Forcibly align the final address in case we have a hardware
81 * issue that requires alignment for performance reasons.
82 */
83 addr = align_vdso_addr(addr);
84
85 return addr;
86 #endif
87 }
88
89 static int vdso_fault(const struct vm_special_mapping *sm,
90 struct vm_area_struct *vma, struct vm_fault *vmf)
91 {
92 const struct vdso_image *image = vma->vm_mm->context.vdso_image;
93
94 if (!image || (vmf->pgoff << PAGE_SHIFT) >= image->size)
95 return VM_FAULT_SIGBUS;
96
97 vmf->page = virt_to_page(image->data + (vmf->pgoff << PAGE_SHIFT));
98 get_page(vmf->page);
99 return 0;
100 }
101
102 static int vdso_mremap(const struct vm_special_mapping *sm,
103 struct vm_area_struct *new_vma)
104 {
105 unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
106 const struct vdso_image *image = current->mm->context.vdso_image;
107
108 if (image->size != new_size)
109 return -EINVAL;
110
111 if (current->mm != new_vma->vm_mm)
112 return -EFAULT;
113
> 114 if (in_ia32_syscall() && image == &vdso_image_32) {
115 struct pt_regs *regs = current_pt_regs();
116 unsigned long vdso_land = image->sym_int80_landing_pad;
117 unsigned long old_land_addr = vdso_land +
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [next] | [standalone]
| From | Dmitry Safonov <dsafonov@virtuozzo.com> |
|---|---|
| Date | 2016-04-18 16:20 +0200 |
| Subject | [PATCHv6 2/3] x86/vdso: add mremap hook to vm_special_mapping |
| Message-ID | <rpibU-6ZZ-17@gated-at.bofh.it> |
| In reply to | #1381720 |
Add possibility for userspace 32-bit applications to move
vdso mapping. Previously, when userspace app called
mremap for vdso, in return path it would land on previous
address of vdso page, resulting in segmentation violation.
Now it lands fine and returns to userspace with remapped vdso.
This will also fix context.vdso pointer for 64-bit, which does not
affect the user of vdso after mremap by now, but this may change.
As suggested by Andy, return EINVAL for mremap that splits vdso image.
Renamed and moved text_mapping structure declaration inside
map_vdso, as it used only there and now it complement
vvar_mapping variable.
There is still problem for remapping vdso in glibc applications:
linker relocates addresses for syscalls on vdso page, so
you need to relink with the new addresses. Or the next syscall
through glibc may fail:
Program received signal SIGSEGV, Segmentation fault.
#0 0xf7fd9b80 in __kernel_vsyscall ()
#1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
v6: moved vdso_image_32 check and fixup code into vdso_fix_landing function
with ifdefs around
v5: as Andy suggested, add a check that new_vma->vm_mm and current->mm are
the same, also check not only in_ia32_syscall() but image == &vdso_image_32
v4: drop __maybe_unused & use image from mm->context instead vdso_image_32
v3: as Andy suggested, return EINVAL in case of splitting vdso blob on mremap;
used is_ia32_task instead of ifdefs
v2: added __maybe_unused for pt_regs in vdso_mremap
arch/x86/entry/vdso/vma.c | 49 ++++++++++++++++++++++++++++++++++++++++++-----
include/linux/mm_types.h | 3 +++
mm/mmap.c | 10 ++++++++++
3 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 10f704584922..3385586f86a6 100644
--- a/arch/x86/entry/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
@@ -12,6 +12,7 @@
#include <linux/random.h>
#include <linux/elf.h>
#include <linux/cpu.h>
+#include <linux/ptrace.h>
#include <asm/pvclock.h>
#include <asm/vgtod.h>
#include <asm/proto.h>
@@ -98,10 +99,42 @@ static int vdso_fault(const struct vm_special_mapping *sm,
return 0;
}
-static const struct vm_special_mapping text_mapping = {
- .name = "[vdso]",
- .fault = vdso_fault,
-};
+#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
+static void vdso_fix_landing(const struct vdso_image *image,
+ struct vm_area_struct *new_vma)
+{
+ if (in_ia32_syscall() && image == &vdso_image_32) {
+ struct pt_regs *regs = current_pt_regs();
+ unsigned long vdso_land = image->sym_int80_landing_pad;
+ unsigned long old_land_addr = vdso_land +
+ (unsigned long)current->mm->context.vdso;
+
+ /* Fixing userspace landing - look at do_fast_syscall_32 */
+ if (regs->ip == old_land_addr)
+ regs->ip = new_vma->vm_start + vdso_land;
+ }
+}
+#else
+static void vdso_fix_landing(const struct vdso_image *image) {}
+#endif
+
+static int vdso_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma)
+{
+ unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
+ const struct vdso_image *image = current->mm->context.vdso_image;
+
+ if (image->size != new_size)
+ return -EINVAL;
+
+ if (current->mm != new_vma->vm_mm)
+ return -EFAULT;
+
+ vdso_fix_landing(image, new_vma);
+ current->mm->context.vdso = (void __user *)new_vma->vm_start;
+
+ return 0;
+}
static int vvar_fault(const struct vm_special_mapping *sm,
struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -162,6 +195,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
struct vm_area_struct *vma;
unsigned long addr, text_start;
int ret = 0;
+
+ static const struct vm_special_mapping vdso_mapping = {
+ .name = "[vdso]",
+ .fault = vdso_fault,
+ .mremap = vdso_mremap,
+ };
static const struct vm_special_mapping vvar_mapping = {
.name = "[vvar]",
.fault = vvar_fault,
@@ -195,7 +234,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
image->size,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- &text_mapping);
+ &vdso_mapping);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index c2d75b4fa86c..4d16ab9287af 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -586,6 +586,9 @@ struct vm_special_mapping {
int (*fault)(const struct vm_special_mapping *sm,
struct vm_area_struct *vma,
struct vm_fault *vmf);
+
+ int (*mremap)(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma);
};
enum tlb_flush_reason {
diff --git a/mm/mmap.c b/mm/mmap.c
index bd2e1a533bc1..ba71658dd1a1 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2930,9 +2930,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma)
return ((struct vm_special_mapping *)vma->vm_private_data)->name;
}
+static int special_mapping_mremap(struct vm_area_struct *new_vma)
+{
+ struct vm_special_mapping *sm = new_vma->vm_private_data;
+
+ if (sm->mremap)
+ return sm->mremap(sm, new_vma);
+ return 0;
+}
+
static const struct vm_operations_struct special_mapping_vmops = {
.close = special_mapping_close,
.fault = special_mapping_fault,
+ .mremap = special_mapping_mremap,
.name = special_mapping_name,
};
--
2.8.0
[toc] | [prev] | [next] | [standalone]
| From | Dmitry Safonov <dsafonov@virtuozzo.com> |
|---|---|
| Date | 2016-04-18 16:30 +0200 |
| Subject | [PATCHv7 2/3] x86/vdso: add mremap hook to vm_special_mapping |
| Message-ID | <rpilA-75e-15@gated-at.bofh.it> |
| In reply to | #1381720 |
Add possibility for userspace 32-bit applications to move
vdso mapping. Previously, when userspace app called
mremap for vdso, in return path it would land on previous
address of vdso page, resulting in segmentation violation.
Now it lands fine and returns to userspace with remapped vdso.
This will also fix context.vdso pointer for 64-bit, which does not
affect the user of vdso after mremap by now, but this may change.
As suggested by Andy, return EINVAL for mremap that splits vdso image.
Renamed and moved text_mapping structure declaration inside
map_vdso, as it used only there and now it complement
vvar_mapping variable.
There is still problem for remapping vdso in glibc applications:
linker relocates addresses for syscalls on vdso page, so
you need to relink with the new addresses. Or the next syscall
through glibc may fail:
Program received signal SIGSEGV, Segmentation fault.
#0 0xf7fd9b80 in __kernel_vsyscall ()
#1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
v7: that's just not my day: add new_vma parameter to vdso_fix_landing
sorry for the noise
v6: moved vdso_image_32 check and fixup code into vdso_fix_landing function
with ifdefs around
v5: as Andy suggested, add a check that new_vma->vm_mm and current->mm are
the same, also check not only in_ia32_syscall() but image == &vdso_image_32
v4: drop __maybe_unused & use image from mm->context instead vdso_image_32
v3: as Andy suggested, return EINVAL in case of splitting vdso blob on mremap;
used is_ia32_task instead of ifdefs
v2: added __maybe_unused for pt_regs in vdso_mremap
arch/x86/entry/vdso/vma.c | 50 ++++++++++++++++++++++++++++++++++++++++++-----
include/linux/mm_types.h | 3 +++
mm/mmap.c | 10 ++++++++++
3 files changed, 58 insertions(+), 5 deletions(-)
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 10f704584922..d94291a19b6e 100644
--- a/arch/x86/entry/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
@@ -12,6 +12,7 @@
#include <linux/random.h>
#include <linux/elf.h>
#include <linux/cpu.h>
+#include <linux/ptrace.h>
#include <asm/pvclock.h>
#include <asm/vgtod.h>
#include <asm/proto.h>
@@ -98,10 +99,43 @@ static int vdso_fault(const struct vm_special_mapping *sm,
return 0;
}
-static const struct vm_special_mapping text_mapping = {
- .name = "[vdso]",
- .fault = vdso_fault,
-};
+#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
+static void vdso_fix_landing(const struct vdso_image *image,
+ struct vm_area_struct *new_vma)
+{
+ if (in_ia32_syscall() && image == &vdso_image_32) {
+ struct pt_regs *regs = current_pt_regs();
+ unsigned long vdso_land = image->sym_int80_landing_pad;
+ unsigned long old_land_addr = vdso_land +
+ (unsigned long)current->mm->context.vdso;
+
+ /* Fixing userspace landing - look at do_fast_syscall_32 */
+ if (regs->ip == old_land_addr)
+ regs->ip = new_vma->vm_start + vdso_land;
+ }
+}
+#else
+static void vdso_fix_landing(const struct vdso_image *image,
+ struct vm_area_struct *new_vma) {}
+#endif
+
+static int vdso_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma)
+{
+ unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
+ const struct vdso_image *image = current->mm->context.vdso_image;
+
+ if (image->size != new_size)
+ return -EINVAL;
+
+ if (current->mm != new_vma->vm_mm)
+ return -EFAULT;
+
+ vdso_fix_landing(image, new_vma);
+ current->mm->context.vdso = (void __user *)new_vma->vm_start;
+
+ return 0;
+}
static int vvar_fault(const struct vm_special_mapping *sm,
struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -162,6 +196,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
struct vm_area_struct *vma;
unsigned long addr, text_start;
int ret = 0;
+
+ static const struct vm_special_mapping vdso_mapping = {
+ .name = "[vdso]",
+ .fault = vdso_fault,
+ .mremap = vdso_mremap,
+ };
static const struct vm_special_mapping vvar_mapping = {
.name = "[vvar]",
.fault = vvar_fault,
@@ -195,7 +235,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
image->size,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- &text_mapping);
+ &vdso_mapping);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index c2d75b4fa86c..4d16ab9287af 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -586,6 +586,9 @@ struct vm_special_mapping {
int (*fault)(const struct vm_special_mapping *sm,
struct vm_area_struct *vma,
struct vm_fault *vmf);
+
+ int (*mremap)(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma);
};
enum tlb_flush_reason {
diff --git a/mm/mmap.c b/mm/mmap.c
index bd2e1a533bc1..ba71658dd1a1 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2930,9 +2930,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma)
return ((struct vm_special_mapping *)vma->vm_private_data)->name;
}
+static int special_mapping_mremap(struct vm_area_struct *new_vma)
+{
+ struct vm_special_mapping *sm = new_vma->vm_private_data;
+
+ if (sm->mremap)
+ return sm->mremap(sm, new_vma);
+ return 0;
+}
+
static const struct vm_operations_struct special_mapping_vmops = {
.close = special_mapping_close,
.fault = special_mapping_fault,
+ .mremap = special_mapping_mremap,
.name = special_mapping_name,
};
--
2.8.0
[toc] | [prev] | [next] | [standalone]
| From | Dmitry Safonov <dsafonov@virtuozzo.com> |
|---|---|
| Date | 2016-04-20 18:40 +0200 |
| Subject | Re: [PATCHv7 2/3] x86/vdso: add mremap hook to vm_special_mapping |
| Message-ID | <rq3kt-2o0-1@gated-at.bofh.it> |
| In reply to | #1381752 |
On 04/18/2016 05:23 PM, Dmitry Safonov wrote:
> Add possibility for userspace 32-bit applications to move
> vdso mapping. Previously, when userspace app called
> mremap for vdso, in return path it would land on previous
> address of vdso page, resulting in segmentation violation.
> Now it lands fine and returns to userspace with remapped vdso.
> This will also fix context.vdso pointer for 64-bit, which does not
> affect the user of vdso after mremap by now, but this may change.
>
> As suggested by Andy, return EINVAL for mremap that splits vdso image.
>
> Renamed and moved text_mapping structure declaration inside
> map_vdso, as it used only there and now it complement
> vvar_mapping variable.
>
> There is still problem for remapping vdso in glibc applications:
> linker relocates addresses for syscalls on vdso page, so
> you need to relink with the new addresses. Or the next syscall
> through glibc may fail:
> Program received signal SIGSEGV, Segmentation fault.
> #0 0xf7fd9b80 in __kernel_vsyscall ()
> #1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6
>
> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
Andy, can I have an ack from you for this version?
If it looks fine for you, of course.
And for v5 test (3/3 patch)? (I did not resed it, as it hasn't changed)
> ---
> v7: that's just not my day: add new_vma parameter to vdso_fix_landing
> sorry for the noise
> v6: moved vdso_image_32 check and fixup code into vdso_fix_landing function
> with ifdefs around
> v5: as Andy suggested, add a check that new_vma->vm_mm and current->mm are
> the same, also check not only in_ia32_syscall() but image == &vdso_image_32
> v4: drop __maybe_unused & use image from mm->context instead vdso_image_32
> v3: as Andy suggested, return EINVAL in case of splitting vdso blob on mremap;
> used is_ia32_task instead of ifdefs
> v2: added __maybe_unused for pt_regs in vdso_mremap
>
> arch/x86/entry/vdso/vma.c | 50 ++++++++++++++++++++++++++++++++++++++++++-----
> include/linux/mm_types.h | 3 +++
> mm/mmap.c | 10 ++++++++++
> 3 files changed, 58 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
> index 10f704584922..d94291a19b6e 100644
> --- a/arch/x86/entry/vdso/vma.c
> +++ b/arch/x86/entry/vdso/vma.c
> @@ -12,6 +12,7 @@
> #include <linux/random.h>
> #include <linux/elf.h>
> #include <linux/cpu.h>
> +#include <linux/ptrace.h>
> #include <asm/pvclock.h>
> #include <asm/vgtod.h>
> #include <asm/proto.h>
> @@ -98,10 +99,43 @@ static int vdso_fault(const struct vm_special_mapping *sm,
> return 0;
> }
>
> -static const struct vm_special_mapping text_mapping = {
> - .name = "[vdso]",
> - .fault = vdso_fault,
> -};
> +#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
> +static void vdso_fix_landing(const struct vdso_image *image,
> + struct vm_area_struct *new_vma)
> +{
> + if (in_ia32_syscall() && image == &vdso_image_32) {
> + struct pt_regs *regs = current_pt_regs();
> + unsigned long vdso_land = image->sym_int80_landing_pad;
> + unsigned long old_land_addr = vdso_land +
> + (unsigned long)current->mm->context.vdso;
> +
> + /* Fixing userspace landing - look at do_fast_syscall_32 */
> + if (regs->ip == old_land_addr)
> + regs->ip = new_vma->vm_start + vdso_land;
> + }
> +}
> +#else
> +static void vdso_fix_landing(const struct vdso_image *image,
> + struct vm_area_struct *new_vma) {}
> +#endif
> +
> +static int vdso_mremap(const struct vm_special_mapping *sm,
> + struct vm_area_struct *new_vma)
> +{
> + unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
> + const struct vdso_image *image = current->mm->context.vdso_image;
> +
> + if (image->size != new_size)
> + return -EINVAL;
> +
> + if (current->mm != new_vma->vm_mm)
> + return -EFAULT;
> +
> + vdso_fix_landing(image, new_vma);
> + current->mm->context.vdso = (void __user *)new_vma->vm_start;
> +
> + return 0;
> +}
>
> static int vvar_fault(const struct vm_special_mapping *sm,
> struct vm_area_struct *vma, struct vm_fault *vmf)
> @@ -162,6 +196,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
> struct vm_area_struct *vma;
> unsigned long addr, text_start;
> int ret = 0;
> +
> + static const struct vm_special_mapping vdso_mapping = {
> + .name = "[vdso]",
> + .fault = vdso_fault,
> + .mremap = vdso_mremap,
> + };
> static const struct vm_special_mapping vvar_mapping = {
> .name = "[vvar]",
> .fault = vvar_fault,
> @@ -195,7 +235,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
> image->size,
> VM_READ|VM_EXEC|
> VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
> - &text_mapping);
> + &vdso_mapping);
>
> if (IS_ERR(vma)) {
> ret = PTR_ERR(vma);
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index c2d75b4fa86c..4d16ab9287af 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -586,6 +586,9 @@ struct vm_special_mapping {
> int (*fault)(const struct vm_special_mapping *sm,
> struct vm_area_struct *vma,
> struct vm_fault *vmf);
> +
> + int (*mremap)(const struct vm_special_mapping *sm,
> + struct vm_area_struct *new_vma);
> };
>
> enum tlb_flush_reason {
> diff --git a/mm/mmap.c b/mm/mmap.c
> index bd2e1a533bc1..ba71658dd1a1 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -2930,9 +2930,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma)
> return ((struct vm_special_mapping *)vma->vm_private_data)->name;
> }
>
> +static int special_mapping_mremap(struct vm_area_struct *new_vma)
> +{
> + struct vm_special_mapping *sm = new_vma->vm_private_data;
> +
> + if (sm->mremap)
> + return sm->mremap(sm, new_vma);
> + return 0;
> +}
> +
> static const struct vm_operations_struct special_mapping_vmops = {
> .close = special_mapping_close,
> .fault = special_mapping_fault,
> + .mremap = special_mapping_mremap,
> .name = special_mapping_name,
> };
>
--
Regards,
Dmitry Safonov
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-04-21 22:00 +0200 |
| Subject | Re: [PATCHv7 2/3] x86/vdso: add mremap hook to vm_special_mapping |
| Message-ID | <rqsVA-6gR-21@gated-at.bofh.it> |
| In reply to | #1381752 |
On Mon, Apr 18, 2016 at 7:23 AM, Dmitry Safonov <dsafonov@virtuozzo.com> wrote:
> Add possibility for userspace 32-bit applications to move
> vdso mapping. Previously, when userspace app called
> mremap for vdso, in return path it would land on previous
> address of vdso page, resulting in segmentation violation.
> Now it lands fine and returns to userspace with remapped vdso.
> This will also fix context.vdso pointer for 64-bit, which does not
> affect the user of vdso after mremap by now, but this may change.
>
> As suggested by Andy, return EINVAL for mremap that splits vdso image.
>
> Renamed and moved text_mapping structure declaration inside
> map_vdso, as it used only there and now it complement
> vvar_mapping variable.
>
> There is still problem for remapping vdso in glibc applications:
> linker relocates addresses for syscalls on vdso page, so
> you need to relink with the new addresses. Or the next syscall
> through glibc may fail:
> Program received signal SIGSEGV, Segmentation fault.
> #0 0xf7fd9b80 in __kernel_vsyscall ()
> #1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6
>
> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
> ---
> v7: that's just not my day: add new_vma parameter to vdso_fix_landing
> sorry for the noise
> v6: moved vdso_image_32 check and fixup code into vdso_fix_landing function
> with ifdefs around
> v5: as Andy suggested, add a check that new_vma->vm_mm and current->mm are
> the same, also check not only in_ia32_syscall() but image == &vdso_image_32
> v4: drop __maybe_unused & use image from mm->context instead vdso_image_32
> v3: as Andy suggested, return EINVAL in case of splitting vdso blob on mremap;
> used is_ia32_task instead of ifdefs
> v2: added __maybe_unused for pt_regs in vdso_mremap
>
> arch/x86/entry/vdso/vma.c | 50 ++++++++++++++++++++++++++++++++++++++++++-----
> include/linux/mm_types.h | 3 +++
> mm/mmap.c | 10 ++++++++++
> 3 files changed, 58 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
> index 10f704584922..d94291a19b6e 100644
> --- a/arch/x86/entry/vdso/vma.c
> +++ b/arch/x86/entry/vdso/vma.c
> @@ -12,6 +12,7 @@
> #include <linux/random.h>
> #include <linux/elf.h>
> #include <linux/cpu.h>
> +#include <linux/ptrace.h>
> #include <asm/pvclock.h>
> #include <asm/vgtod.h>
> #include <asm/proto.h>
> @@ -98,10 +99,43 @@ static int vdso_fault(const struct vm_special_mapping *sm,
> return 0;
> }
>
> -static const struct vm_special_mapping text_mapping = {
> - .name = "[vdso]",
> - .fault = vdso_fault,
> -};
> +#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
I think you mean defined(CONFIG_IA32_EMULATION). IIRC CONFIG_COMPAT
is set for X32, !IA32 kernels, too.
> +static void vdso_fix_landing(const struct vdso_image *image,
> + struct vm_area_struct *new_vma)
> +{
> + if (in_ia32_syscall() && image == &vdso_image_32) {
> + struct pt_regs *regs = current_pt_regs();
> + unsigned long vdso_land = image->sym_int80_landing_pad;
> + unsigned long old_land_addr = vdso_land +
> + (unsigned long)current->mm->context.vdso;
> +
> + /* Fixing userspace landing - look at do_fast_syscall_32 */
> + if (regs->ip == old_land_addr)
> + regs->ip = new_vma->vm_start + vdso_land;
> + }
> +}
> +#else
> +static void vdso_fix_landing(const struct vdso_image *image,
> + struct vm_area_struct *new_vma) {}
> +#endif
You could also define the function regardless and simply ifdef out the
body, thus saving a few lines of code.
> +
> +static int vdso_mremap(const struct vm_special_mapping *sm,
> + struct vm_area_struct *new_vma)
> +{
> + unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
> + const struct vdso_image *image = current->mm->context.vdso_image;
> +
> + if (image->size != new_size)
> + return -EINVAL;
> +
> + if (current->mm != new_vma->vm_mm)
> + return -EFAULT;
Can you make that if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))?
It should be impossible.
> +
> + vdso_fix_landing(image, new_vma);
> + current->mm->context.vdso = (void __user *)new_vma->vm_start;
> +
> + return 0;
> +}
>
> static int vvar_fault(const struct vm_special_mapping *sm,
> struct vm_area_struct *vma, struct vm_fault *vmf)
> @@ -162,6 +196,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
> struct vm_area_struct *vma;
> unsigned long addr, text_start;
> int ret = 0;
> +
> + static const struct vm_special_mapping vdso_mapping = {
> + .name = "[vdso]",
> + .fault = vdso_fault,
> + .mremap = vdso_mremap,
> + };
> static const struct vm_special_mapping vvar_mapping = {
> .name = "[vvar]",
> .fault = vvar_fault,
> @@ -195,7 +235,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
> image->size,
> VM_READ|VM_EXEC|
> VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
> - &text_mapping);
> + &vdso_mapping);
>
> if (IS_ERR(vma)) {
> ret = PTR_ERR(vma);
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index c2d75b4fa86c..4d16ab9287af 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -586,6 +586,9 @@ struct vm_special_mapping {
> int (*fault)(const struct vm_special_mapping *sm,
> struct vm_area_struct *vma,
> struct vm_fault *vmf);
> +
> + int (*mremap)(const struct vm_special_mapping *sm,
> + struct vm_area_struct *new_vma);
> };
>
> enum tlb_flush_reason {
> diff --git a/mm/mmap.c b/mm/mmap.c
> index bd2e1a533bc1..ba71658dd1a1 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -2930,9 +2930,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma)
> return ((struct vm_special_mapping *)vma->vm_private_data)->name;
> }
>
> +static int special_mapping_mremap(struct vm_area_struct *new_vma)
> +{
> + struct vm_special_mapping *sm = new_vma->vm_private_data;
> +
> + if (sm->mremap)
> + return sm->mremap(sm, new_vma);
> + return 0;
> +}
> +
> static const struct vm_operations_struct special_mapping_vmops = {
> .close = special_mapping_close,
> .fault = special_mapping_fault,
> + .mremap = special_mapping_mremap,
> .name = special_mapping_name,
> };
>
> --
> 2.8.0
>
--
Andy Lutomirski
AMA Capital Management, LLC
[toc] | [prev] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2016-04-24 01:20 +0200 |
| Message-ID | <rrf0d-2Qv-5@gated-at.bofh.it> |
| In reply to | #1381720 |
[Multipart message — attachments visible in raw view] — view raw
Hi,
[auto build test ERROR on v4.6-rc4]
[cannot apply to tip/x86/core tip/x86/vdso next-20160422]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Dmitry-Safonov/x86-rename-is_-ia32-x32-_task-to-in_-ia32-x32-_syscall/20160418-214656
config: x86_64-randconfig-s0-04240623 (attached as .config)
compiler: gcc-5 (Debian 5.3.1-14) 5.3.1 20160409
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
Note: the linux-review/Dmitry-Safonov/x86-rename-is_-ia32-x32-_task-to-in_-ia32-x32-_syscall/20160418-214656 HEAD aed83f1dd951908724a5ba564e2b03d68a9fc7b8 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
arch/x86/entry/vdso/vma.c: In function 'vdso_mremap':
>> arch/x86/entry/vdso/vma.c:114:37: error: 'vdso_image_32' undeclared (first use in this function)
if (in_ia32_syscall() && image == &vdso_image_32) {
^
arch/x86/entry/vdso/vma.c:114:37: note: each undeclared identifier is reported only once for each function it appears in
vim +/vdso_image_32 +114 arch/x86/entry/vdso/vma.c
108 if (image->size != new_size)
109 return -EINVAL;
110
111 if (current->mm != new_vma->vm_mm)
112 return -EFAULT;
113
> 114 if (in_ia32_syscall() && image == &vdso_image_32) {
115 struct pt_regs *regs = current_pt_regs();
116 unsigned long vdso_land = image->sym_int80_landing_pad;
117 unsigned long old_land_addr = vdso_land +
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web