|
18 | 18 | #include <linux/sched.h>
|
19 | 19 | #include <linux/signal.h>
|
20 | 20 | #include <linux/slab.h>
|
| 21 | +#include <linux/time_namespace.h> |
21 | 22 | #include <linux/timekeeper_internal.h>
|
22 | 23 | #include <linux/vmalloc.h>
|
23 | 24 | #include <vdso/datapage.h>
|
@@ -164,15 +165,62 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
|
164 | 165 | mmap_read_unlock(mm);
|
165 | 166 | return 0;
|
166 | 167 | }
|
| 168 | + |
| 169 | +static struct page *find_timens_vvar_page(struct vm_area_struct *vma) |
| 170 | +{ |
| 171 | + if (likely(vma->vm_mm == current->mm)) |
| 172 | + return current->nsproxy->time_ns->vvar_page; |
| 173 | + |
| 174 | + /* |
| 175 | + * VM_PFNMAP | VM_IO protect .fault() handler from being called |
| 176 | + * through interfaces like /proc/$pid/mem or |
| 177 | + * process_vm_{readv,writev}() as long as there's no .access() |
| 178 | + * in special_mapping_vmops. |
| 179 | + * For more details check_vma_flags() and __access_remote_vm() |
| 180 | + */ |
| 181 | + WARN(1, "vvar_page accessed remotely"); |
| 182 | + |
| 183 | + return NULL; |
| 184 | +} |
| 185 | +#else |
| 186 | +static struct page *find_timens_vvar_page(struct vm_area_struct *vma) |
| 187 | +{ |
| 188 | + return NULL; |
| 189 | +} |
167 | 190 | #endif
|
168 | 191 |
|
169 | 192 | static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
|
170 | 193 | struct vm_area_struct *vma, struct vm_fault *vmf)
|
171 | 194 | {
|
172 |
| - if (vmf->pgoff == 0) |
173 |
| - return vmf_insert_pfn(vma, vmf->address, |
174 |
| - sym_to_pfn(vdso_data)); |
175 |
| - return VM_FAULT_SIGBUS; |
| 195 | + struct page *timens_page = find_timens_vvar_page(vma); |
| 196 | + unsigned long pfn; |
| 197 | + |
| 198 | + switch (vmf->pgoff) { |
| 199 | + case VVAR_DATA_PAGE_OFFSET: |
| 200 | + if (timens_page) |
| 201 | + pfn = page_to_pfn(timens_page); |
| 202 | + else |
| 203 | + pfn = sym_to_pfn(vdso_data); |
| 204 | + break; |
| 205 | +#ifdef CONFIG_TIME_NS |
| 206 | + case VVAR_TIMENS_PAGE_OFFSET: |
| 207 | + /* |
| 208 | + * If a task belongs to a time namespace then a namespace |
| 209 | + * specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and |
| 210 | + * the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET |
| 211 | + * offset. |
| 212 | + * See also the comment near timens_setup_vdso_data(). |
| 213 | + */ |
| 214 | + if (!timens_page) |
| 215 | + return VM_FAULT_SIGBUS; |
| 216 | + pfn = sym_to_pfn(vdso_data); |
| 217 | + break; |
| 218 | +#endif /* CONFIG_TIME_NS */ |
| 219 | + default: |
| 220 | + return VM_FAULT_SIGBUS; |
| 221 | + } |
| 222 | + |
| 223 | + return vmf_insert_pfn(vma, vmf->address, pfn); |
176 | 224 | }
|
177 | 225 |
|
178 | 226 | static int __setup_additional_pages(enum vdso_abi abi,
|
|
0 commit comments