Skip to content
This repository was archived by the owner on Oct 3, 2024. It is now read-only.

Commit c758781

Browse files
committed
Merge remote-tracking branch 'drm/topic/iomem-mmap-vs-gup' into drm-tip
2 parents d04fb07 + ac8b840 commit c758781

File tree

6 files changed

+68
-27
lines changed

6 files changed

+68
-27
lines changed

drivers/media/common/videobuf2/frame_vector.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
6969
break;
7070

7171
while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) {
72-
err = follow_pfn(vma, start, &nums[ret]);
72+
err = unsafe_follow_pfn(vma, start, &nums[ret]);
7373
if (err) {
7474
if (ret == 0)
7575
ret = err;

drivers/media/v4l2-core/videobuf-dma-contig.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
183183
user_address = untagged_baddr;
184184

185185
while (pages_done < (mem->size >> PAGE_SHIFT)) {
186-
ret = follow_pfn(vma, user_address, &this_pfn);
186+
ret = unsafe_follow_pfn(vma, user_address, &this_pfn);
187187
if (ret)
188188
break;
189189

include/linux/mm.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,8 +1744,8 @@ int follow_invalidate_pte(struct mm_struct *mm, unsigned long address,
17441744
pmd_t **pmdpp, spinlock_t **ptlp);
17451745
int follow_pte(struct mm_struct *mm, unsigned long address,
17461746
pte_t **ptepp, spinlock_t **ptlp);
1747-
int follow_pfn(struct vm_area_struct *vma, unsigned long address,
1748-
unsigned long *pfn);
1747+
int unsafe_follow_pfn(struct vm_area_struct *vma, unsigned long address,
1748+
unsigned long *pfn);
17491749
int follow_phys(struct vm_area_struct *vma, unsigned long address,
17501750
unsigned int flags, unsigned long *prot, resource_size_t *phys);
17511751
int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,

mm/memory.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4773,7 +4773,10 @@ int follow_invalidate_pte(struct mm_struct *mm, unsigned long address,
47734773
* should be taken for read.
47744774
*
47754775
* KVM uses this function. While it is arguably less bad than ``follow_pfn``,
4776-
* it is not a good general-purpose API.
4776+
* it is not a good general-purpose API: If callers use the pte after they've
4777+
* unlocked @ptlp they must ensure coherency with pte updates by using a
4778+
* &mmu_notifier to follow updates. Any caller not following these requirements
4779+
* must use unsafe_follow_pfn() instead.
47774780
*
47784781
* Return: zero on success, -ve otherwise.
47794782
*/
@@ -4784,20 +4787,7 @@ int follow_pte(struct mm_struct *mm, unsigned long address,
47844787
}
47854788
EXPORT_SYMBOL_GPL(follow_pte);
47864789

4787-
/**
4788-
* follow_pfn - look up PFN at a user virtual address
4789-
* @vma: memory mapping
4790-
* @address: user virtual address
4791-
* @pfn: location to store found PFN
4792-
*
4793-
* Only IO mappings and raw PFN mappings are allowed.
4794-
*
4795-
* This function does not allow the caller to read the permissions
4796-
* of the PTE. Do not use it.
4797-
*
4798-
* Return: zero and the pfn at @pfn on success, -ve otherwise.
4799-
*/
4800-
int follow_pfn(struct vm_area_struct *vma, unsigned long address,
4790+
static int follow_pfn(struct vm_area_struct *vma, unsigned long address,
48014791
unsigned long *pfn)
48024792
{
48034793
int ret = -EINVAL;
@@ -4814,7 +4804,31 @@ int follow_pfn(struct vm_area_struct *vma, unsigned long address,
48144804
pte_unmap_unlock(ptep, ptl);
48154805
return 0;
48164806
}
4817-
EXPORT_SYMBOL(follow_pfn);
4807+
4808+
/**
4809+
* unsafe_follow_pfn - look up PFN at a user virtual address
4810+
* @vma: memory mapping
4811+
* @address: user virtual address
4812+
* @pfn: location to store found PFN
4813+
*
4814+
* Only IO mappings and raw PFN mappings are allowed.
4815+
*
4816+
* Returns zero and the pfn at @pfn on success, -ve otherwise.
4817+
*/
4818+
int unsafe_follow_pfn(struct vm_area_struct *vma, unsigned long address,
4819+
unsigned long *pfn)
4820+
{
4821+
if (IS_ENABLED(CONFIG_STRICT_FOLLOW_PFN)) {
4822+
pr_info("unsafe follow_pfn usage rejected, see CONFIG_STRICT_FOLLOW_PFN\n");
4823+
return -EINVAL;
4824+
}
4825+
4826+
WARN_ONCE(1, "unsafe follow_pfn usage\n");
4827+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
4828+
4829+
return follow_pfn(vma, address, pfn);
4830+
}
4831+
EXPORT_SYMBOL(unsafe_follow_pfn);
48184832

48194833
#ifdef CONFIG_HAVE_IOREMAP_PROT
48204834
int follow_phys(struct vm_area_struct *vma,

mm/nommu.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,18 @@ unsigned int kobjsize(const void *objp)
111111
return page_size(page);
112112
}
113113

114+
static int follow_pfn(struct vm_area_struct *vma, unsigned long address,
115+
unsigned long *pfn)
116+
{
117+
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
118+
return -EINVAL;
119+
120+
*pfn = address >> PAGE_SHIFT;
121+
return 0;
122+
}
123+
114124
/**
115-
* follow_pfn - look up PFN at a user virtual address
125+
* unsafe_follow_pfn - look up PFN at a user virtual address
116126
* @vma: memory mapping
117127
* @address: user virtual address
118128
* @pfn: location to store found PFN
@@ -121,16 +131,20 @@ unsigned int kobjsize(const void *objp)
121131
*
122132
* Returns zero and the pfn at @pfn on success, -ve otherwise.
123133
*/
124-
int follow_pfn(struct vm_area_struct *vma, unsigned long address,
125-
unsigned long *pfn)
134+
int unsafe_follow_pfn(struct vm_area_struct *vma, unsigned long address,
135+
unsigned long *pfn)
126136
{
127-
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
137+
if (IS_ENABLED(CONFIG_STRICT_FOLLOW_PFN)) {
138+
pr_info("unsafe follow_pfn usage rejected, see CONFIG_STRICT_FOLLOW_PFN\n");
128139
return -EINVAL;
140+
}
129141

130-
*pfn = address >> PAGE_SHIFT;
131-
return 0;
142+
WARN_ONCE(1, "unsafe follow_pfn usage\n");
143+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
144+
145+
return follow_pfn(vma, address, pfn);
132146
}
133-
EXPORT_SYMBOL(follow_pfn);
147+
EXPORT_SYMBOL(unsafe_follow_pfn);
134148

135149
LIST_HEAD(vmap_area_list);
136150

security/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ config STATIC_USERMODEHELPER_PATH
230230
If you wish for all usermode helper programs to be disabled,
231231
specify an empty string here (i.e. "").
232232

233+
config STRICT_FOLLOW_PFN
234+
bool "Disable unsafe use of follow_pfn"
235+
depends on MMU
236+
help
237+
Some functionality in the kernel follows userspace mappings to iomem
238+
ranges in an unsafe matter. Examples include v4l userptr for zero-copy
239+
buffers sharing.
240+
241+
If this option is switched on, such access is rejected. Only disable
242+
this option when you must run userspace which requires this.
243+
244+
If in doubt, say Y.
245+
233246
source "security/selinux/Kconfig"
234247
source "security/smack/Kconfig"
235248
source "security/tomoyo/Kconfig"

0 commit comments

Comments
 (0)