{
    "dataType": "CVE_RECORD",
    "dataVersion": "5.2",
    "cveMetadata": {
        "cveId": "CVE-2021-47635",
        "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "state": "PUBLISHED",
        "assignerShortName": "Linux",
        "dateReserved": "2025-02-26T01:48:21.518Z",
        "datePublished": "2025-02-26T01:54:09.701Z",
        "dateUpdated": "2026-08-05T08:48:41.669Z"
    },
    "containers": {
        "cna": {
            "providerMetadata": {
                "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
                "shortName": "Linux",
                "dateUpdated": "2026-08-05T08:48:41.669Z"
            },
            "descriptions": [
                {
                    "lang": "en",
                    "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\"\n  flags: 0x1fffff80002405(locked|uptodate|owner_priv_1|private|node=0|\n  zone=1|lastcpupid=0x1fffff)\n  page dumped because: VM_BUG_ON_PAGE(page_count(page) != 0)\n  ------------[ cut here ]------------\n  kernel BUG at include/linux/page_ref.h:184!\n  invalid opcode: 0000 [#1] SMP\n  CPU: 3 PID: 38 Comm: kcompactd0 Not tainted 5.15.0-rc5\n  RIP: 0010:migrate_page_move_mapping+0xac3/0xe70\n  Call Trace:\n    ubifs_migrate_page+0x22/0xc0 [ubifs]\n    move_to_new_page+0xb4/0x600\n    migrate_pages+0x1523/0x1cc0\n    compact_zone+0x8c5/0x14b0\n    kcompactd+0x2bc/0x560\n    kthread+0x18c/0x1e0\n    ret_from_fork+0x1f/0x30\n\nBefore the time, we should make clean a concept, what does refcount means\nin page gotten from grab_cache_page_write_begin(). There are 2 situations:\nSituation 1: refcount is 3, page is created by __page_cache_alloc.\n  TYPE_A - the write process is using this page\n  TYPE_B - page is assigned to one certain mapping by calling\n\t   __add_to_page_cache_locked()\n  TYPE_C - page is added into pagevec list corresponding current cpu by\n\t   calling lru_cache_add()\nSituation 2: refcount is 2, page is gotten from the mapping's tree\n  TYPE_B - page has been assigned to one certain mapping\n  TYPE_A - the write process is using this page (by calling\n\t   page_cache_get_speculative())\nFilesystem releases one refcount by calling put_page() in xxx_write_end(),\nthe released refcount corresponds to TYPE_A (write task is using it). If\nthere are any processes using a page, page migration process will skip the\npage by judging whether expected_page_refs() equals to page refcount.\n\nThe BUG is caused by following process:\n    PA(cpu 0)                           kcompactd(cpu 1)\n\t\t\t\tcompact_zone\nubifs_write_begin\n  page_a = grab_cache_page_write_begin\n    add_to_page_cache_lru\n      lru_cache_add\n        pagevec_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 lru_cache_add) and page_ref_unfreeze() called by mi\n---truncated---"
                }
            ],
            "metrics": [
                {
                    "cvssV3_1": {
                        "version": "3.1",
                        "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
                        "baseScore": 7.8,
                        "baseSeverity": "HIGH"
                    },
                    "scenarios": [
                        {
                            "lang": "en",
                            "value": "AV:L - The bug is reached through local VFS writes or mmap write faults on an already-mounted UBIFS volume (write → generic_perform_write → ubifs_write_begin/end, or ubifs_vm_page_mkwrite), not via a network protocol handler.\nAC:L - The attacker controls both I/O sides of the race (dirtying pages via write/mmap and draining pagevecs via concurrent reads) and can induce memory pressure to trigger compaction/migration; a public reproducer exists, so success does not depend on conditions outside attacker influence.\nPR:L - Mounting UBIFS requires CAP_SYS_ADMIN, but on typical embedded/OpenWrt/IoT deployments UBIFS is already mounted; any unprivileged user who can write files on that volume can hit the vulnerable SetPagePrivate paths.\nUI:N - No separate victim action is required once UBIFS is mounted as the system filesystem; the attacker triggers the bug by writing and reading their own files while stressing memory.\nS:U - Impact is confined to the local kernel's memory-management authority (page cache/refcount corruption and possible privilege escalation on the same host), with no VM/IOMMU boundary crossing.\nC:H - Missing get_page on PG_private lets migration freeze a page while a concurrent put races on the refcount, corrupting page lifetime and enabling use-after-free of page-cache pages, which yields an arbitrary read primitive.\nI:H - The same page refcount corruption/UAF during migrate_page_move_mapping enables reuse of freed pages and control-flow hijacking, so integrity impact is high under the UAF/memory-corruption guidance.\nA:H - The demonstrated failure is a kernel BUG in page migration (and without DEBUG_VM, corrupted refcounts still lead to crashes/oopses), so availability impact is high."
                        }
                    ]
                }
            ],
            "affected": [
                {
                    "product": "Linux",
                    "vendor": "Linux",
                    "defaultStatus": "unaffected",
                    "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                    "programFiles": [
                        "fs/ubifs/file.c"
                    ],
                    "versions": [
                        {
                            "version": "1e51764a3c2ac05a23a22b2a95ddee4d9bffb16d",
                            "lessThan": "c34ae24a2590fee96a3a7735ba2fa6cc52306221",
                            "status": "affected",
                            "versionType": "git"
                        },
                        {
                            "version": "1e51764a3c2ac05a23a22b2a95ddee4d9bffb16d",
                            "lessThan": "4f75bab98565afd4f905059c56ec4caba88a7eec",
                            "status": "affected",
                            "versionType": "git"
                        },
                        {
                            "version": "1e51764a3c2ac05a23a22b2a95ddee4d9bffb16d",
                            "lessThan": "5aaa2c0f0052b02c4a982993d4c5bb68fb7cbe22",
                            "status": "affected",
                            "versionType": "git"
                        },
                        {
                            "version": "1e51764a3c2ac05a23a22b2a95ddee4d9bffb16d",
                            "lessThan": "fbeb2139eed65e929ce806c6468e6601ade01b1b",
                            "status": "affected",
                            "versionType": "git"
                        },
                        {
                            "version": "1e51764a3c2ac05a23a22b2a95ddee4d9bffb16d",
                            "lessThan": "3b67db8a6ca83e6ff90b756d3da0c966f61cd37b",
                            "status": "affected",
                            "versionType": "git"
                        }
                    ]
                },
                {
                    "product": "Linux",
                    "vendor": "Linux",
                    "defaultStatus": "affected",
                    "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                    "programFiles": [
                        "fs/ubifs/file.c"
                    ],
                    "versions": [
                        {
                            "version": "2.6.27",
                            "status": "affected"
                        },
                        {
                            "version": "0",
                            "lessThan": "2.6.27",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "5.10.110",
                            "lessThanOrEqual": "5.10.*",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "5.15.33",
                            "lessThanOrEqual": "5.15.*",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "5.16.19",
                            "lessThanOrEqual": "5.16.*",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "5.17.2",
                            "lessThanOrEqual": "5.17.*",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "5.18",
                            "lessThanOrEqual": "*",
                            "status": "unaffected",
                            "versionType": "original_commit_for_fix"
                        }
                    ]
                }
            ],
            "cpeApplicability": [
                {
                    "nodes": [
                        {
                            "operator": "OR",
                            "negate": false,
                            "cpeMatch": [
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "2.6.27",
                                    "versionEndExcluding": "5.10.110"
                                },
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "2.6.27",
                                    "versionEndExcluding": "5.15.33"
                                },
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "2.6.27",
                                    "versionEndExcluding": "5.16.19"
                                },
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "2.6.27",
                                    "versionEndExcluding": "5.17.2"
                                },
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "2.6.27",
                                    "versionEndExcluding": "5.18"
                                }
                            ]
                        }
                    ]
                }
            ],
            "references": [
                {
                    "url": "https://git.kernel.org/stable/c/c34ae24a2590fee96a3a7735ba2fa6cc52306221"
                },
                {
                    "url": "https://git.kernel.org/stable/c/4f75bab98565afd4f905059c56ec4caba88a7eec"
                },
                {
                    "url": "https://git.kernel.org/stable/c/5aaa2c0f0052b02c4a982993d4c5bb68fb7cbe22"
                },
                {
                    "url": "https://git.kernel.org/stable/c/fbeb2139eed65e929ce806c6468e6601ade01b1b"
                },
                {
                    "url": "https://git.kernel.org/stable/c/3b67db8a6ca83e6ff90b756d3da0c966f61cd37b"
                }
            ],
            "title": "ubifs: Fix to add refcount once page is set private",
            "x_generator": {
                "engine": "bippy-1.2.0"
            }
        }
    }
}