aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/task_mmu.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 98ba9ea96b19..bc651644b1b2 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -939,6 +939,7 @@ typedef struct {
939struct pagemapread { 939struct pagemapread {
940 int pos, len; /* units: PM_ENTRY_BYTES, not bytes */ 940 int pos, len; /* units: PM_ENTRY_BYTES, not bytes */
941 pagemap_entry_t *buffer; 941 pagemap_entry_t *buffer;
942 bool show_pfn;
942}; 943};
943 944
944#define PAGEMAP_WALK_SIZE (PMD_SIZE) 945#define PAGEMAP_WALK_SIZE (PMD_SIZE)
@@ -1015,7 +1016,8 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
1015 struct page *page = NULL; 1016 struct page *page = NULL;
1016 1017
1017 if (pte_present(pte)) { 1018 if (pte_present(pte)) {
1018 frame = pte_pfn(pte); 1019 if (pm->show_pfn)
1020 frame = pte_pfn(pte);
1019 flags |= PM_PRESENT; 1021 flags |= PM_PRESENT;
1020 page = vm_normal_page(vma, addr, pte); 1022 page = vm_normal_page(vma, addr, pte);
1021 if (pte_soft_dirty(pte)) 1023 if (pte_soft_dirty(pte))
@@ -1065,8 +1067,9 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
1065 */ 1067 */
1066 if (pmd_present(pmd)) { 1068 if (pmd_present(pmd)) {
1067 flags |= PM_PRESENT; 1069 flags |= PM_PRESENT;
1068 frame = pmd_pfn(pmd) + 1070 if (pm->show_pfn)
1069 ((addr & ~PMD_MASK) >> PAGE_SHIFT); 1071 frame = pmd_pfn(pmd) +
1072 ((addr & ~PMD_MASK) >> PAGE_SHIFT);
1070 } 1073 }
1071 1074
1072 for (; addr != end; addr += PAGE_SIZE) { 1075 for (; addr != end; addr += PAGE_SIZE) {
@@ -1075,7 +1078,7 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
1075 err = add_to_pagemap(addr, &pme, pm); 1078 err = add_to_pagemap(addr, &pme, pm);
1076 if (err) 1079 if (err)
1077 break; 1080 break;
1078 if (flags & PM_PRESENT) 1081 if (pm->show_pfn && (flags & PM_PRESENT))
1079 frame++; 1082 frame++;
1080 } 1083 }
1081 spin_unlock(ptl); 1084 spin_unlock(ptl);
@@ -1129,8 +1132,9 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask,
1129 flags |= PM_FILE; 1132 flags |= PM_FILE;
1130 1133
1131 flags |= PM_PRESENT; 1134 flags |= PM_PRESENT;
1132 frame = pte_pfn(pte) + 1135 if (pm->show_pfn)
1133 ((addr & ~hmask) >> PAGE_SHIFT); 1136 frame = pte_pfn(pte) +
1137 ((addr & ~hmask) >> PAGE_SHIFT);
1134 } 1138 }
1135 1139
1136 for (; addr != end; addr += PAGE_SIZE) { 1140 for (; addr != end; addr += PAGE_SIZE) {
@@ -1139,7 +1143,7 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask,
1139 err = add_to_pagemap(addr, &pme, pm); 1143 err = add_to_pagemap(addr, &pme, pm);
1140 if (err) 1144 if (err)
1141 return err; 1145 return err;
1142 if (flags & PM_PRESENT) 1146 if (pm->show_pfn && (flags & PM_PRESENT))
1143 frame++; 1147 frame++;
1144 } 1148 }
1145 1149
@@ -1198,6 +1202,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
1198 if (!count) 1202 if (!count)
1199 goto out_mm; 1203 goto out_mm;
1200 1204
1205 /* do not disclose physical addresses: attack vector */
1206 pm.show_pfn = file_ns_capable(file, &init_user_ns, CAP_SYS_ADMIN);
1207
1201 pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); 1208 pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
1202 pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY); 1209 pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY);
1203 ret = -ENOMEM; 1210 ret = -ENOMEM;
@@ -1267,10 +1274,6 @@ static int pagemap_open(struct inode *inode, struct file *file)
1267{ 1274{
1268 struct mm_struct *mm; 1275 struct mm_struct *mm;
1269 1276
1270 /* do not disclose physical addresses: attack vector */
1271 if (!capable(CAP_SYS_ADMIN))
1272 return -EPERM;
1273
1274 mm = proc_mem_open(inode, PTRACE_MODE_READ); 1277 mm = proc_mem_open(inode, PTRACE_MODE_READ);
1275 if (IS_ERR(mm)) 1278 if (IS_ERR(mm))
1276 return PTR_ERR(mm); 1279 return PTR_ERR(mm);