x86/mm/dump_pagetables: Allow dumping current pagetables
authorThomas Gleixner <tglx@linutronix.de>
Mon, 4 Dec 2017 14:08:06 +0000 (15:08 +0100)
committerIngo Molnar <mingo@kernel.org>
Sat, 23 Dec 2017 20:13:01 +0000 (21:13 +0100)
Add two debugfs files which allow to dump the pagetable of the current
task.

current_kernel dumps the regular page table. This is the page table which
is normally shared between kernel and user space. If kernel page table
isolation is enabled this is the kernel space mapping.

If kernel page table isolation is enabled the second file, current_user,
dumps the user space page table.

These files allow to verify the resulting page tables for page table
isolation, but even in the normal case its useful to be able to inspect
user space page tables of current for debugging purposes.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Laight <David.Laight@aculab.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Eduardo Valentin <eduval@amazon.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: aliguori@amazon.com
Cc: daniel.gruss@iaik.tugraz.at
Cc: hughd@google.com
Cc: keescook@google.com
Cc: linux-mm@kvack.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/pgtable.h
arch/x86/mm/debug_pagetables.c
arch/x86/mm/dump_pagetables.c

index 03780d5c41c55037bfbd9c19d58767454cdf42d1..6b43d677f8ca743f09f64a92b21a5b2976c49c29 100644 (file)
@@ -28,7 +28,7 @@ extern pgd_t early_top_pgt[PTRS_PER_PGD];
 int __init __early_make_pgtable(unsigned long address, pmdval_t pmd);
 
 void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
-void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd);
+void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd, bool user);
 void ptdump_walk_pgd_level_checkwx(void);
 
 #ifdef CONFIG_DEBUG_WX
index 8e70c1599e517f5b78c2fb957b91e8baa474dae9..421f2664ffa06e6cd4b31e5d6521648add3e2c4e 100644 (file)
@@ -5,7 +5,7 @@
 
 static int ptdump_show(struct seq_file *m, void *v)
 {
-       ptdump_walk_pgd_level_debugfs(m, NULL);
+       ptdump_walk_pgd_level_debugfs(m, NULL, false);
        return 0;
 }
 
@@ -22,7 +22,57 @@ static const struct file_operations ptdump_fops = {
        .release        = single_release,
 };
 
-static struct dentry *dir, *pe;
+static int ptdump_show_curknl(struct seq_file *m, void *v)
+{
+       if (current->mm->pgd) {
+               down_read(&current->mm->mmap_sem);
+               ptdump_walk_pgd_level_debugfs(m, current->mm->pgd, false);
+               up_read(&current->mm->mmap_sem);
+       }
+       return 0;
+}
+
+static int ptdump_open_curknl(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, ptdump_show_curknl, NULL);
+}
+
+static const struct file_operations ptdump_curknl_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ptdump_open_curknl,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+static struct dentry *pe_curusr;
+
+static int ptdump_show_curusr(struct seq_file *m, void *v)
+{
+       if (current->mm->pgd) {
+               down_read(&current->mm->mmap_sem);
+               ptdump_walk_pgd_level_debugfs(m, current->mm->pgd, true);
+               up_read(&current->mm->mmap_sem);
+       }
+       return 0;
+}
+
+static int ptdump_open_curusr(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, ptdump_show_curusr, NULL);
+}
+
+static const struct file_operations ptdump_curusr_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ptdump_open_curusr,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
+static struct dentry *dir, *pe_knl, *pe_curknl;
 
 static int __init pt_dump_debug_init(void)
 {
@@ -30,9 +80,22 @@ static int __init pt_dump_debug_init(void)
        if (!dir)
                return -ENOMEM;
 
-       pe = debugfs_create_file("kernel", 0400, dir, NULL, &ptdump_fops);
-       if (!pe)
+       pe_knl = debugfs_create_file("kernel", 0400, dir, NULL,
+                                    &ptdump_fops);
+       if (!pe_knl)
+               goto err;
+
+       pe_curknl = debugfs_create_file("current_kernel", 0400,
+                                       dir, NULL, &ptdump_curknl_fops);
+       if (!pe_curknl)
+               goto err;
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       pe_curusr = debugfs_create_file("current_user", 0400,
+                                       dir, NULL, &ptdump_curusr_fops);
+       if (!pe_curusr)
                goto err;
+#endif
        return 0;
 err:
        debugfs_remove_recursive(dir);
index 17f5b417f95e9e869aca7c07cadccf9e4c0c9890..f56902c1f04b94e1543710dee75d2d7dee19b7c9 100644 (file)
@@ -530,8 +530,12 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
        ptdump_walk_pgd_level_core(m, pgd, false, true);
 }
 
-void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd)
+void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd, bool user)
 {
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       if (user && static_cpu_has(X86_FEATURE_PTI))
+               pgd = kernel_to_user_pgdp(pgd);
+#endif
        ptdump_walk_pgd_level_core(m, pgd, false, false);
 }
 EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level_debugfs);