Merge tag 'vfs-5.8-merge-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / mm / debug.c
index 2189357..f2ede2d 100644 (file)
@@ -110,13 +110,57 @@ void __dump_page(struct page *page, const char *reason)
        else if (PageAnon(page))
                type = "anon ";
        else if (mapping) {
-               if (mapping->host && mapping->host->i_dentry.first) {
-                       struct dentry *dentry;
-                       dentry = container_of(mapping->host->i_dentry.first, struct dentry, d_u.d_alias);
-                       pr_warn("%ps name:\"%pd\"\n", mapping->a_ops, dentry);
-               } else
-                       pr_warn("%ps\n", mapping->a_ops);
+               const struct inode *host;
+               const struct address_space_operations *a_ops;
+               const struct hlist_node *dentry_first;
+               const struct dentry *dentry_ptr;
+               struct dentry dentry;
+
+               /*
+                * mapping can be invalid pointer and we don't want to crash
+                * accessing it, so probe everything depending on it carefully
+                */
+               if (probe_kernel_read_strict(&host, &mapping->host,
+                                               sizeof(struct inode *)) ||
+                   probe_kernel_read_strict(&a_ops, &mapping->a_ops,
+                               sizeof(struct address_space_operations *))) {
+                       pr_warn("failed to read mapping->host or a_ops, mapping not a valid kernel address?\n");
+                       goto out_mapping;
+               }
+
+               if (!host) {
+                       pr_warn("mapping->a_ops:%ps\n", a_ops);
+                       goto out_mapping;
+               }
+
+               if (probe_kernel_read_strict(&dentry_first,
+                       &host->i_dentry.first, sizeof(struct hlist_node *))) {
+                       pr_warn("mapping->a_ops:%ps with invalid mapping->host inode address %px\n",
+                               a_ops, host);
+                       goto out_mapping;
+               }
+
+               if (!dentry_first) {
+                       pr_warn("mapping->a_ops:%ps\n", a_ops);
+                       goto out_mapping;
+               }
+
+               dentry_ptr = container_of(dentry_first, struct dentry, d_u.d_alias);
+               if (probe_kernel_read_strict(&dentry, dentry_ptr,
+                                                       sizeof(struct dentry))) {
+                       pr_warn("mapping->aops:%ps with invalid mapping->host->i_dentry.first %px\n",
+                               a_ops, dentry_ptr);
+               } else {
+                       /*
+                        * if dentry is corrupted, the %pd handler may still
+                        * crash, but it's unlikely that we reach here with a
+                        * corrupted struct page
+                        */
+                       pr_warn("mapping->aops:%ps dentry name:\"%pd\"\n",
+                                                               a_ops, &dentry);
+               }
        }
+out_mapping:
        BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
 
        pr_warn("%sflags: %#lx(%pGp)%s\n", type, page->flags, &page->flags,