From 98c41db239c52f97f865f6e6e8da2c310d7f29ae Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 6 Dec 2022 12:43:33 +0100 Subject: [PATCH] 5.10-stable patches added patches: v4l2-don-t-fall-back-to-follow_pfn-if-pin_user_pages_fast-fails.patch --- queue-5.10/series | 1 + ...low_pfn-if-pin_user_pages_fast-fails.patch | 114 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 queue-5.10/v4l2-don-t-fall-back-to-follow_pfn-if-pin_user_pages_fast-fails.patch diff --git a/queue-5.10/series b/queue-5.10/series index 272de4de34e..5354c18058c 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -92,3 +92,4 @@ input-raydium_ts_i2c-fix-memory-leak-in-raydium_i2c_send.patch block-unhash-blkdev-part-inode-when-the-part-is-deleted.patch proc-avoid-integer-type-confusion-in-get_proc_long.patch proc-proc_skip_spaces-shouldn-t-think-it-is-working-on-c-strings.patch +v4l2-don-t-fall-back-to-follow_pfn-if-pin_user_pages_fast-fails.patch diff --git a/queue-5.10/v4l2-don-t-fall-back-to-follow_pfn-if-pin_user_pages_fast-fails.patch b/queue-5.10/v4l2-don-t-fall-back-to-follow_pfn-if-pin_user_pages_fast-fails.patch new file mode 100644 index 00000000000..464c2910cb8 --- /dev/null +++ b/queue-5.10/v4l2-don-t-fall-back-to-follow_pfn-if-pin_user_pages_fast-fails.patch @@ -0,0 +1,114 @@ +From 6647e76ab623b2b3fb2efe03a86e9c9046c52c33 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Wed, 30 Nov 2022 16:10:52 -0800 +Subject: v4l2: don't fall back to follow_pfn() if pin_user_pages_fast() fails + +From: Linus Torvalds + +commit 6647e76ab623b2b3fb2efe03a86e9c9046c52c33 upstream. + +The V4L2_MEMORY_USERPTR interface is long deprecated and shouldn't be +used (and is discouraged for any modern v4l drivers). And Seth Jenkins +points out that the fallback to VM_PFNMAP/VM_IO is fundamentally racy +and dangerous. + +Note that it's not even a case that should trigger, since any normal +user pointer logic ends up just using the pin_user_pages_fast() call +that does the proper page reference counting. That's not the problem +case, only if you try to use special device mappings do you have any +issues. + +Normally I'd just remove this during the merge window, but since Seth +pointed out the problem cases, we really want to know as soon as +possible if there are actually any users of this odd special case of a +legacy interface. Neither Hans nor Mauro seem to think that such +mis-uses of the old legacy interface should exist. As Mauro says: + + "See, V4L2 has actually 4 streaming APIs: + - Kernel-allocated mmap (usually referred simply as just mmap); + - USERPTR mmap; + - read(); + - dmabuf; + + The USERPTR is one of the oldest way to use it, coming from V4L + version 1 times, and by far the least used one" + +And Hans chimed in on the USERPTR interface: + + "To be honest, I wouldn't mind if it goes away completely, but that's a + bit of a pipe dream right now" + +but while removing this legacy interface entirely may be a pipe dream we +can at least try to remove the unlikely (and actively broken) case of +using special device mappings for USERPTR accesses. + +This replaces it with a WARN_ONCE() that we can remove once we've +hopefully confirmed that no actual users exist. + +NOTE! Longer term, this means that a 'struct frame_vector' only ever +contains proper page pointers, and all the games we have with converting +them to pages can go away (grep for 'frame_vector_to_pages()' and the +uses of 'vec->is_pfns'). But this is just the first step, to verify +that this code really is all dead, and do so as quickly as possible. + +Reported-by: Seth Jenkins +Acked-by: Hans Verkuil +Acked-by: Mauro Carvalho Chehab +Cc: David Hildenbrand +Cc: Jan Kara +Signed-off-by: Linus Torvalds +Signed-off-by: Sergey Senozhatsky +Signed-off-by: Greg Kroah-Hartman +--- + mm/frame_vector.c | 31 ++++++------------------------- + 1 file changed, 6 insertions(+), 25 deletions(-) + +--- a/mm/frame_vector.c ++++ b/mm/frame_vector.c +@@ -37,7 +37,6 @@ int get_vaddr_frames(unsigned long start + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + int ret = 0; +- int err; + int locked; + + if (nr_frames == 0) +@@ -74,32 +73,14 @@ int get_vaddr_frames(unsigned long start + vec->is_pfns = false; + ret = pin_user_pages_locked(start, nr_frames, + gup_flags, (struct page **)(vec->ptrs), &locked); +- goto out; ++ if (likely(ret > 0)) ++ goto out; + } + +- vec->got_ref = false; +- vec->is_pfns = true; +- do { +- unsigned long *nums = frame_vector_pfns(vec); +- +- while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) { +- err = follow_pfn(vma, start, &nums[ret]); +- if (err) { +- if (ret == 0) +- ret = err; +- goto out; +- } +- start += PAGE_SIZE; +- ret++; +- } +- /* +- * We stop if we have enough pages or if VMA doesn't completely +- * cover the tail page. +- */ +- if (ret >= nr_frames || start < vma->vm_end) +- break; +- vma = find_vma_intersection(mm, start, start + 1); +- } while (vma && vma->vm_flags & (VM_IO | VM_PFNMAP)); ++ /* This used to (racily) return non-refcounted pfns. Let people know */ ++ WARN_ONCE(1, "get_vaddr_frames() cannot follow VM_IO mapping"); ++ vec->nr_frames = 0; ++ + out: + if (locked) + mmap_read_unlock(mm); -- 2.47.3