"value":"In the Linux kernel, the following vulnerability has been resolved:\n\nubifs: Fix to add refcount once page is set private\n\nMM defined the rule [1] very clearly that once page was set with PG_private\nflag, we should increment the refcount in that page, also main flows like\npageout(), migrate_page() will assume there is one additional page\nreference count if page_has_private() returns true. Otherwise, we may\nget a BUG in page migration:\n\n page:0000000080d05b9d refcount:-1 mapcount:0 mapping:000000005f4d82a8\n index:0xe2 pfn:0x14c12\n aops:ubifs_file_address_operations [ubifs] ino:8f1 dentry name:\"f30e\"\nflags:0x1fffff80002405(locked|uptodate|owner_priv_1|private|node=0|\nzone=1|lastcpupid=0x1fffff)\npagedumpedbecause:VM_BUG_ON_PAGE(page_count(page)!=0)\n------------[cuthere]------------\nkernelBUGatinclude/linux/page_ref.h:184!\ninvalidopcode:0000[#1]SMP\nCPU:3PID:38Comm:kcompactd0Nottainted5.15.0-rc5\nRIP:0010:migrate_page_move_mapping+0xac3/0xe70\nCallTrace:\nubifs_migrate_page+0x22/0xc0[ubifs]\nmove_to_new_page+0xb4/0x600\nmigrate_pages+0x1523/0x1cc0\ncompact_zone+0x8c5/0x14b0\nkcompactd+0x2bc/0x560\nkthread+0x18c/0x1e0\nret_from_fork+0x1f/0x30\n\nBeforethetime,weshouldmakecleanaconcept,whatdoesrefcountmeans\ninpagegottenfromgrab_cache_page_write_begin().Thereare2situations:\nSituation1:refcountis3,pageiscreatedby__page_cache_alloc.\nTYPE_A-thewriteprocessisusingthispage\nTYPE_B-pageisassignedtoonecertainmappingbycalling\n\t__add_to_page_cache_locked()\nTYPE_C-pageisaddedintopageveclistcorrespondingcurrentcpuby\n\tcallinglru_cache_add()\nSituation2:refcountis2,pageisgottenfromthemapping'stree\nTYPE_B-pagehasbeenassignedtoonecertainmapping\nTYPE_A-thewriteprocessisusingthispage(bycalling\n\tpage_cache_get_speculative())\nFilesystemreleasesonerefcountbycallingput_page()inxxx_write_end(),\nthereleasedrefcountcorrespondstoTYPE_A(writetaskisusingit).If\nthereareanyprocessesusingapage,pagemigrationprocesswillskipthe\npagebyjudgingwhetherexpected_page_refs()equalstopagerefcount.\n\nTheBUGiscausedbyfollowingprocess:\nPA(cpu0)kcompactd(cpu1)\n\t\t\t\tcompact_zone\nubifs_write_begin\npage_a=grab_cache_page_write_begin\nadd_to_page_cache_lru\nlru_cache_add\npagevec_add// put page into cpu 0's pagevec\n (refcnf = 3, for page creation process)\nubifs_write_end\n SetPagePrivate(page_a) // doesn't increase page count !\n unlock_page(page_a)\n put_page(page_a) // refcnt = 2\n\t\t\t\t[...]\n\n PB(cpu 0)\nfilemap_read\n filemap_get_pages\n add_to_page_cache_lru\n lru_cache_add\n __pagevec_lru_add // traverse all pages in cpu 0's pagevec\n\t __pagevec_lru_add_fn\n\t SetPageLRU(page_a)\n\t\t\t\tisolate_migratepages\n isolate_migratepages_block\n\t\t\t\t get_page_unless_zero(page_a)\n\t\t\t\t // refcnt = 3\n list_add(page_a, from_list)\n\t\t\t\tmigrate_pages(from_list)\n\t\t\t\t __unmap_and_move\n\t\t\t\t move_to_new_page\n\t\t\t\t ubifs_migrate_page(page_a)\n\t\t\t\t migrate_page_move_mapping\n\t\t\t\t\t expected_page_refs get 3\n (migration[1] + mapping[1] + private[1])\n\t release_pages\n\t put_page_testzero(page_a) // refcnt = 3\n page_ref_freeze // refcnt = 0\n\t page_ref_dec_and_test(0 - 1 = -1)\n page_ref_unfreeze\n VM_BUG_ON_PAGE(-1 != 0, page)\n\nUBIFS doesn't increase the page refcount after setting private flag, which\nleads to page migration task believes the page is not used by any other\nprocesses, so the page is migrated. This causes concurrent accessing on\npage refcount between put_page() called by other process(eg. read process\ncalls
"value":"En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: ubifs: Correcci\u00f3n para agregar refcount una vez que la p\u00e1gina se establece como privada MM defini\u00f3 la regla [1] muy claramente que una vez que la p\u00e1gina se establece con el indicador PG_private, debemos incrementar el refcount en esa p\u00e1gina, tambi\u00e9n los flujos principales como pageout(), migrants_page() asumir\u00e1n que hay un recuento de referencia de p\u00e1gina adicional si page_has_private() devuelve verdadero. De lo contrario, podemos obtener un ERROR en la migraci\u00f3n de la p\u00e1gina: page:0000000080d05b9d refcount:-1 mapcount:0 mapping:000000005f4d82a8 index:0xe2 pfn:0x14c12 aops:ubifs_file_address_operations [ubifs] ino:8f1 dentry name:\"f30e\"flags:0x1fffff80002405(locked|uptodate|owner_priv_1|private|node=0|zone=1|lastcpupid=0x1fffff)p\u00e1ginavolcadaporque:VM_BUG_ON_PAGE(page_count(page)!=0)------------[cortaraqu\u00ed]------------\u00a1ERRORdelkerneleninclude/linux/page_ref.h:184!c\u00f3digodeoperaci\u00f3nnov\u00e1lido:0000[#1]CPUSMP:3PID:38Comm:kcompactd0Nocontaminado5.15.0-rc5RIP:0010:migrate_page_move_mapping+0xac3/0xe70Rastreodellamadas:ubifs_migrate_page+0x22/0xc0[ubifs]move_to_new_page+0xb4/0x600migrants_pages+0x1523/0x1cc0compact_zone+0x8c5/0x14b0kcompactd+0x2bc/0x560kthread+0x18c/0x1e0ret_from_fork+0x1f/0x30Antesdetiempo,deber\u00edamosaclararunconcepto,qu\u00e9significarefcountenlap\u00e1ginaobtenidadegrab_cache_page_write_begin().Hay2situaciones:Situaci\u00f3n1:refcountes3,lap\u00e1ginaescreadapor__page_cache_alloc.TYPE_A-elprocesodeescrituraest\u00e1usandoestap\u00e1ginaTYPE_B-lap\u00e1ginaesasignadaaunciertomapeollamandoa__add_to_page_cache_locked()TYPE_C-lap\u00e1ginaesagregadaalalistapageveccorrespondientealaCPUactualllamandoalru_cache_add()Situaci\u00f3n2:refcountes2,lap\u00e1ginaesobtenidadel\u00e1rboldelmapeoTYPE_B-lap\u00e1ginahasidoasignadaaunciertomapeoTYPE_A-elprocesodeescrituraest\u00e1usandoestap\u00e1gina(llamandoapage_cache_get_speculative())Elsistemadearchivosliberaunrefcountllamandoaput_page()enxxx_write_end(),elrefcountliberadocorrespondeaTYPE_A(latareadeescrituraloest\u00e1usando).Sihayalg\u00fanprocesousandounap\u00e1gina,elprocesodemigraci\u00f3ndep\u00e1ginaomitir\u00e1lap\u00e1ginaaljuzgarsiexpected_page_refs()esigualapagerefcount.ElERRORescausadoporelsiguienteproceso:PA(cpu0)kcompactd(cpu1)compact_zoneubifs_write_beginpage_a=grab_cache_page_write_beginadd_to_page_cache_lrulru_cache_addpagevec_add// coloca la p\u00e1gina en el pagevec de la CPU 0 (refcnf = 3, para el proceso de creaci\u00f3n de la p\u00e1gina) ubifs_write_end SetPagePrivate(page_a) // \u00a1no aumenta el n\u00famero de p\u00e1ginas! unlock_page(page_a) put_page(page_a) // refcnt = 2 [...] PB(cpu 0) filemap_read filemap_get_pages add_to_page_cache_lru lru_cache_add __pagevec_lru_add // traverse all pages in cpu 0's pagevec __pagevec_lru_add_fn SetPageLRU(page_a) isolate_migratepages isolate_migratepages_block get_page_unless_zero(page_a) // refcnt = 3 list_add(page_a, from_list) migrate_pages(from_list) __unmap_and_move move_to_new_page ubifs_migrate_page(page_a) migrate_page_move_mapping expected_page_refs get 3 (migration[1] + mapping[1] + private[1]) release_pages put_page_testzero(page_a) // refcnt = 3 page_ref_freeze // refcnt = 0 page_ref_dec_and_test(0 - 1 = -1) page_ref_unfreeze VM_BUG_ON_PAGE(-1 != 0, page) UBIFS no aumenta el recuento de referencias de la p\u00e1gina despu\u00e9s de configurar el indicador privado, lo que hace que la tarea de migraci\u00f3n de la p\u00e1gina crea que ning\u00fan otro proceso utiliza la p\u00e1gina, por lo que se migra la p\u00e1gina. Esto provoca un acceso simult\u00e1neo al recuento de referencias de la p\u00e1gina entre put_page() llamado por otro proceso (por ejemplo, el proceso de lectura llama a lru_cache_add) y page_ref