Messages in this thread Patch in this message |  | | From | "Fabio M. De Francesco" <> | Subject | [PATCH] watch_queue: Free the real number of allocated pages | Date | Mon, 21 Mar 2022 02:42:46 +0100 |
| |
In the "error_p" label, the code calls __free_page() in a loop from pages[0] to pages[nr_pages -1].
When pages[i] are allocated in a loop with calls to alloc_page() and one of these allocations fails, the code jumps to the "error_p" label without saving the real number of successful allocations and without using this as the limit of the free cycle.
For the above-mentioned reasons, Syzbot reports a bug: "[syzbot] KASAN: null-ptr-deref Read in __free_pages".[1]
Fix this bug by saving the real number of allocated pages and, in those cases where the inth iteration of alloc_page() fails and the code jumps to the "error_p" label, use that number as the upper limit for the index of the 'for' loop that calls __free_pages(pages[i]).
[1] https://lore.kernel.org/lkml/00000000000084e0cf05daafb25f@google.com/T/#m143407dade7ed9126253175728d6f38505d2393c
Reported-and-tested-by: syzbot+d55757faa9b80590767b@syzkaller.appspotmail.com Fixes: c73be61cede5 ("pipe: Add general notification queue support") Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com> --- kernel/watch_queue.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c index 00703444a219..5b0531020cf8 100644 --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -220,7 +220,7 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) struct page **pages; unsigned long *bitmap; unsigned long user_bufs; - int ret, i, nr_pages; + int ret, i, nr_pages, allocated_pages; if (!wqueue) return -ENODEV; @@ -254,6 +254,7 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) for (i = 0; i < nr_pages; i++) { pages[i] = alloc_page(GFP_KERNEL); + allocated_pages = i; if (!pages[i]) goto error_p; pages[i]->index = i * WATCH_QUEUE_NOTES_PER_PAGE; @@ -271,7 +272,7 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) return 0; error_p: - for (i = 0; i < nr_pages; i++) + for (i = 0; i < allocated_pages; i++) __free_page(pages[i]); kfree(pages); error: -- 2.34.1
|  |