change_non_present_huge_pmd() rewrites a writable device-private PMD swap entry into a readable one without carrying pmd_swp_uffd_wp() across. The PTE-level change_softleaf_pte() does this correctly; mirror that here, matching what copy_huge_pmd() does for the fork path. Without the carry, a plain mprotect() over a UFFD_WP-marked device-private THP strips the bit and the trap is bypassed on swap-in.
Unified · Split
| @@ -2565,6 +2565,8 @@ static void change_non_present_huge_pmd(struct mm_struct *mm, · 2564 unmodified lines | |||
| 2565 | } else if (softleaf_is_device_private_write(entry)) { | 2565 | } else if (softleaf_is_device_private_write(entry)) { |
| 2566 | entry = make_readable_device_private_entry(swp_offset(entry)); | 2566 | entry = make_readable_device_private_entry(swp_offset(entry)); |
| 2567 | newpmd = swp_entry_to_pmd(entry); | 2567 | newpmd = swp_entry_to_pmd(entry); |
| 2568 | if (pmd_swp_uffd_wp(*pmd)) | ||
| 2569 | newpmd = pmd_swp_mkuffd_wp(newpmd); | ||
| 2568 | } else { | 2570 | } else { |
| 2569 | newpmd = *pmd; | 2571 | newpmd = *pmd; |
| 2570 | } | 2572 | } |