Re: [bug report] mm: huge_memory: enable debugfs to split huge pages to any order

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 7 Mar 2024, at 8:49, Dan Carpenter wrote:

> Hello Zi Yan,
>
> Commit fc4d182316bd ("mm: huge_memory: enable debugfs to split huge
> pages to any order") from Feb 26, 2024 (linux-next), leads to the
> following Smatch static checker warning:
>
> 	mm/huge_memory.c:2898 __split_huge_page()
> 	error: undefined (user controlled) shift '1 << new_order'
>
> mm/huge_memory.c
>     2889 static void __split_huge_page(struct page *page, struct list_head *list,
>     2890                 pgoff_t end, unsigned int new_order)
>     2891 {
>     2892         struct folio *folio = page_folio(page);
>     2893         struct page *head = &folio->page;
>     2894         struct lruvec *lruvec;
>     2895         struct address_space *swap_cache = NULL;
>     2896         unsigned long offset = 0;
>     2897         int i, nr_dropped = 0;
> --> 2898         unsigned int new_nr = 1 << new_order;
>                                             ^^^^^^^^^
> The new_order variable comes from the user via debugfs.
>
>     2899         int order = folio_order(folio);
>     2900         unsigned int nr = 1 << order;
>     2901
>     2902         /* complete memcg works before add pages to LRU */
>     2903         split_page_memcg(head, order, new_order);
>     2904
>     2905         if (folio_test_anon(folio) && folio_test_swapcache(folio)) {
>     2906                 offset = swp_offset(folio->swap);
>     2907                 swap_cache = swap_address_space(folio->swap);
>
> Here is the debugfs code in split_huge_pages_write()
>
> mm/huge_memory.c
>   3628
>   3629          ret = sscanf(input_buf, "%d,0x%lx,0x%lx,%d", &pid, &vaddr_start, &vaddr_end, &new_order);
>                                                                                              ^^^^^^^^^^
> We just read new_order
>
>   3630          if (ret == 1 && pid == 1) {
>   3631                  split_huge_pages_all();
>   3632                  ret = strlen(input_buf);
>   3633                  goto out;
>   3634          } else if (ret != 3 && ret != 4) {
>   3635                  ret = -EINVAL;
>   3636                  goto out;
>   3637          }
>   3638
>   3639          ret = split_huge_pages_pid(pid, vaddr_start, vaddr_end, new_order);
>                                                                         ^^^^^^^^^
> And pass it directly with no bounds checking.  Debugfs code is root
> only...  We used to take a view that if root does something stupid then
> they get what they deserve.  But these days syzbot is fuzz testing stuff
> even when it's root only and complaining about shift wraps or other
> undefined behavior.  So I feel like it might be easiest to silence this
> undefined behavior warning now instead of waiting for the syzbot reports
> to come back to bite us in a couple years.

Sure. Thank you for reporting this.

Can you check if the patch below fixes the issue? I checked the inputs from
debugfs and also inside split_huge_page_to_list_to_order().

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index a81a09236c16..4d21e57a7d07 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3052,6 +3052,9 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
        VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
        VM_BUG_ON_FOLIO(!folio_test_large(folio), folio);

+       if (new_order >= folio_order(folio))
+               return -EINVAL;
+
        /* Cannot split anonymous THP to order-1 */
        if (new_order == 1 && folio_test_anon(folio)) {
                VM_WARN_ONCE(1, "Cannot split to order-1 folio");
@@ -3484,6 +3487,9 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
                        goto next;

                total++;
+
+               if (new_order >= folio_order(folio))
+                       goto next;
                /*
                 * For folios with private, split_huge_page_to_list_to_order()
                 * will try to drop it before split and then check if the folio
@@ -3550,6 +3556,9 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
                total++;
                nr_pages = folio_nr_pages(folio);

+               if (new_order >= folio_order(folio))
+                       goto next;
+
                if (!folio_trylock(folio))
                        goto next;
--
Best Regards,
Yan, Zi

Attachment: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux